diff --git a/.gitattributes b/.gitattributes index 92739fe9c..8266c99a5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,5 @@ constants.py ident export-subst /test export-ignore +/library export-ignore cps/static/css/libs/* linguist-vendored cps/static/js/libs/* linguist-vendored diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..c3d0309ef --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ["https://PayPal.Me/calibreweb",] diff --git a/.gitignore b/.gitignore index 614e99369..1d473adfc 100644 --- a/.gitignore +++ b/.gitignore @@ -23,10 +23,12 @@ vendor/ # calibre-web *.db *.log +cps/cache .idea/ *.bak *.log.* +.key settings.yaml gdrive_credentials diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c6006ad12..2ab32cf93 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,9 +26,9 @@ The Calibre-Web documentation is hosted in the Github [Wiki](https://github.com/ Do not open up a GitHub issue if the bug is a **security vulnerability** in Calibre-Web. Instead, please write an email to "ozzie.fernandez.isaacs@googlemail.com". -Ensure the ***bug was not already reported** by searching on GitHub under [Issues](https://github.com/janeczku/calibre-web/issues). Please also check if a solution for your problem can be found in the [wiki](https://github.com/janeczku/calibre-web/wiki). +Ensure the **bug was not already reported** by searching on GitHub under [Issues](https://github.com/janeczku/calibre-web/issues). Please also check if a solution for your problem can be found in the [wiki](https://github.com/janeczku/calibre-web/wiki). -If you're unable to find an **open issue** addressing the problem, open a [new one](https://github.com/janeczku/calibre-web/issues/new?assignees=&labels=&template=bug_report.md&title=). Be sure to include a **title** and **clear description**, as much relevant information as possible, the **issue form** helps you providing the right information. Deleting the form and just pasting the stack trace doesn't speed up fixing the problem. If your issue could be resolved, consider closing the issue. +If you're unable to find an **open issue** addressing the problem, open a [new one](https://github.com/janeczku/calibre-web/issues/new/choose). Be sure to include a **title** and **clear description**, as much relevant information as possible, the **issue form** helps you providing the right information. Deleting the form and just pasting the stack trace doesn't speed up fixing the problem. If your issue could be resolved, consider closing the issue. ### **Feature Request** diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 896d4535f..1f0eca710 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # About -Calibre-Web is a web app providing a clean interface for browsing, reading and downloading eBooks using an existing [Calibre](https://calibre-ebook.com) database. +Calibre-Web is a web app providing a clean interface for browsing, reading and downloading eBooks using a valid [Calibre](https://calibre-ebook.com) database. [![GitHub License](https://img.shields.io/github/license/janeczku/calibre-web?style=flat-square)](https://github.com/janeczku/calibre-web/blob/master/LICENSE) [![GitHub commit activity](https://img.shields.io/github/commit-activity/w/janeczku/calibre-web?logo=github&style=flat-square&label=commits)]() @@ -19,15 +19,16 @@ Calibre-Web is a web app providing a clean interface for browsing, reading and d - full graphical setup - User management with fine-grained per-user permissions - Admin interface -- User Interface in brazilian, czech, dutch, english, finnish, french, german, greek, hungarian, italian, japanese, khmer, polish, russian, simplified and traditional chinese, spanish, swedish, turkish, ukrainian +- User Interface in brazilian, czech, dutch, english, finnish, french, galician, german, greek, hungarian, indonesian, italian, japanese, khmer, korean, norwegian, polish, russian, simplified and traditional chinese, spanish, swedish, turkish, ukrainian, vietnamese - OPDS feed for eBook reader apps -- Filter and search by titles, authors, tags, series and language +- Filter and search by titles, authors, tags, series, book format and language - Create a custom book collection (shelves) - Support for editing eBook metadata and deleting eBooks from Calibre library +- Support for downloading eBook metadata from various sources, sources can be extended via external plugins - Support for converting eBooks through Calibre binaries - Restrict eBook download to logged-in users - Support for public user registration -- Send eBooks to Kindle devices with the click of a button +- Send eBooks to E-Readers with the click of a button - Sync your Kobo devices through Calibre-Web with your Calibre library - Support for reading eBooks directly in the browser (.txt, .epub, .pdf, .cbr, .cbt, .cbz, .djvu) - Upload new books in many formats, including audio formats (.mp3, .m4a, .m4b) @@ -40,23 +41,21 @@ Calibre-Web is a web app providing a clean interface for browsing, reading and d ## Installation #### Installation via pip (recommended) -1. Install calibre web via pip with the command `pip install calibreweb` (Depending on your OS and or distro the command could also be `pip3`). -2. Optional features can also be installed via pip, please refer to [this page](https://github.com/janeczku/calibre-web/wiki/Dependencies-in-Calibre-Web-Linux-Windows) for details -3. Calibre-Web can be started afterwards by typing `cps` or `python3 -m cps` +1. To avoid problems with already installed python dependencies, it's recommended to create a virtual environment for Calibre-Web +2. Install Calibre-Web via pip with the command `pip install calibreweb` (Depending on your OS and or distro the command could also be `pip3`). +3. Optional features can also be installed via pip, please refer to [this page](https://github.com/janeczku/calibre-web/wiki/Dependencies-in-Calibre-Web-Linux-and-Windows) for details +4. Calibre-Web can be started afterwards by typing `cps` -#### Manual installation -1. Install dependencies by running `pip3 install --target vendor -r requirements.txt` (python3.x). Alternativly set up a python virtual environment. -2. Execute the command: `python3 cps.py` (or `nohup python3 cps.py` - recommended if you want to exit the terminal window) - -Issues with Ubuntu: -Please note that running the above install command can fail on some versions of Ubuntu, saying `"can't combine user with prefix"`. This is a [known bug](https://github.com/pypa/pip/issues/3826) and can be remedied by using the command `pip install --system --target vendor -r requirements.txt` instead. +In the Wiki there are also examples for: a [manual installation](https://github.com/janeczku/calibre-web/wiki/Manual-installation), [installation on Linux Mint](https://github.com/janeczku/calibre-web/wiki/How-To:Install-Calibre-Web-in-Linux-Mint-19-or-20), [installation on a Cloud Provider](https://github.com/janeczku/calibre-web/wiki/How-To:-Install-Calibre-Web-on-a-Cloud-Provider). ## Quick start -Point your browser to `http://localhost:8083` or `http://localhost:8083/opds` for the OPDS catalog -Set `Location of Calibre database` to the path of the folder where your Calibre library (metadata.db) lives, push "submit" button\ -Optionally a Google Drive can be used to host the calibre library [-> Using Google Drive integration](https://github.com/janeczku/calibre-web/wiki/Configuration#using-google-drive-integration) -Go to Login page +Point your browser to `http://localhost:8083` or `http://localhost:8083/opds` for the OPDS catalog \ +Login with default admin login \ +If you don't have a Calibre database already, this [database](https://github.com/janeczku/calibre-web/blob/master/library/metadata.db) can be used. **IMPORTATNT** Please move the database out of the calibre-web folder structure, as it will be overwritten during update. \ +Set `Location of Calibre database` to the path of the folder where your Calibre library (metadata.db) lives, push "submit" button. \ +Optionally a Google Drive can be used to host the calibre library [-> Using Google Drive integration](https://github.com/janeczku/calibre-web/wiki/G-Drive-Setup#using-google-drive-integration) \ +Afterwards you can configure your Calibre-Web instance ([Basic Configuration](https://github.com/janeczku/calibre-web/wiki/Configuration#basic-configuration) and [UI Configuration](https://github.com/janeczku/calibre-web/wiki/Configuration#ui-configuration) on admin page) #### Default admin login: *Username:* admin\ @@ -67,11 +66,14 @@ Go to Login page python 3.5+ -Optionally, to enable on-the-fly conversion from one ebook format to another when using the send-to-kindle feature, or during editing of ebooks metadata: +[Download](https://imagemagick.org/script/download.php) Imagemagick to extract covers from epubs. On Windows the additional installation of [ghostscript](https://ghostscript.com/releases/gsdnld.html) might be necessary to extract covers from pdf files. On Linux Imagemagick and Ghostscript can often be installed using the system package manager. + +Optionally, to enable on-the-fly conversion from one ebook format to another when using the send-to-ereader feature, or during editing of ebooks metadata: [Download and install](https://calibre-ebook.com/download) the Calibre desktop program for your platform and enter the folder including program name (normally /opt/calibre/ebook-convert, or C:\Program Files\calibre\ebook-convert.exe) in the field "calibre's converter tool" on the setup page. -[Download](https://github.com/pgaskin/kepubify/releases/latest) Kepubify tool for your platform and place the binary starting with `kepubify` in Linux: `\opt\kepubify` Windows: `C:\Program Files\kepubify`. +[Download](https://github.com/pgaskin/kepubify/releases/latest) Kepubify tool for your platform and place the binary starting with `kepubify` in Linux: `/opt/kepubify` Windows: `C:\Program Files\kepubify`. + ## Docker Images diff --git a/SECURITY.md b/SECURITY.md index afaf9b0b2..f37c62dc2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,20 +10,36 @@ To receive fixes for security vulnerabilities it is required to always upgrade t ## History -| Fixed in | Description |CVE number | -| ---------- |---------|---------| -| 3rd July 2018 | Guest access acts as a backdoor|| -| V 0.6.7 |Hardcoded secret key for sessions |CVE-2020-12627 | -| V 0.6.13|Calibre-Web Metadata cross site scripting |CVE-2021-25964| -| V 0.6.13|Name of Shelves are only visible to users who can access the corresponding shelf Thanks to @ibarrionuevo|| -| V 0.6.13|JavaScript could get executed in the description field. Thanks to @ranjit-git and Hagai Wechsler (WhiteSource)|| -| V 0.6.13|JavaScript could get executed in a custom column of type "comment" field || -| V 0.6.13|JavaScript could get executed after converting a book to another format with a title containing javascript code|| -| V 0.6.13|JavaScript could get executed after converting a book to another format with a username containing javascript code|| -| V 0.6.13|JavaScript could get executed in the description series, categories or publishers title|| -| V 0.6.13|JavaScript could get executed in the shelf title|| -| V 0.6.13|Login with the old session cookie after logout. Thanks to @ibarrionuevo|| -| V 0.6.14|CSRF was possible. Thanks to @mik317 and Hagai Wechsler (WhiteSource) || -| V 0.6.14|Cross-Site Scripting vulnerability on typeahead inputs. Thanks to @notdodo|| +| Fixed in | Description |CVE number | +|---------------|--------------------------------------------------------------------------------------------------------------------|---------| +| 3rd July 2018 | Guest access acts as a backdoor || +| V 0.6.7 | Hardcoded secret key for sessions |CVE-2020-12627 | +| V 0.6.13 | Calibre-Web Metadata cross site scripting |CVE-2021-25964| +| V 0.6.13 | Name of Shelves are only visible to users who can access the corresponding shelf Thanks to @ibarrionuevo || +| V 0.6.13 | JavaScript could get executed in the description field. Thanks to @ranjit-git and Hagai Wechsler (WhiteSource) || +| V 0.6.13 | JavaScript could get executed in a custom column of type "comment" field || +| V 0.6.13 | JavaScript could get executed after converting a book to another format with a title containing javascript code || +| V 0.6.13 | JavaScript could get executed after converting a book to another format with a username containing javascript code || +| V 0.6.13 | JavaScript could get executed in the description series, categories or publishers title || +| V 0.6.13 | JavaScript could get executed in the shelf title || +| V 0.6.13 | Login with the old session cookie after logout. Thanks to @ibarrionuevo || +| V 0.6.14 | CSRF was possible. Thanks to @mik317 and Hagai Wechsler (WhiteSource) |CVE-2021-25965| +| V 0.6.14 | Migrated some routes to POST-requests (CSRF protection). Thanks to @scara31 |CVE-2021-4164| +| V 0.6.15 | Fix for "javascript:" script links in identifier. Thanks to @scara31 |CVE-2021-4170| +| V 0.6.15 | Cross-Site Scripting vulnerability on uploaded cover file names. Thanks to @ibarrionuevo || +| V 0.6.15 | Creating public shelfs is now denied if user is missing the edit public shelf right. Thanks to @ibarrionuevo || +| V 0.6.15 | Changed error message in case of trying to delete a shelf unauthorized. Thanks to @ibarrionuevo || +| V 0.6.16 | JavaScript could get executed on authors page. Thanks to @alicaz |CVE-2022-0352| +| V 0.6.16 | Localhost can no longer be used to upload covers. Thanks to @scara31 |CVE-2022-0339| +| V 0.6.16 | Another case where public shelfs could be created without permission is prevented. Thanks to @nhiephon |CVE-2022-0273| +| V 0.6.16 | It's prevented to get the name of a private shelfs. Thanks to @nhiephon |CVE-2022-0405| +| V 0.6.17 | The SSRF Protection can no longer be bypassed via an HTTP redirect. Thanks to @416e6e61 |CVE-2022-0767| +| V 0.6.17 | The SSRF Protection can no longer be bypassed via 0.0.0.0 and it's ipv6 equivalent. Thanks to @r0hanSH |CVE-2022-0766| +| V 0.6.18 | Possible SQL Injection is prevented in user table Thanks to Iman Sharafaldin (Forward Security) |CVE-2022-30765| +| V 0.6.18 | The SSRF protection no longer can be bypassed by IPV6/IPV4 embedding. Thanks to @416e6e61 |CVE-2022-0939| +| V 0.6.18 | The SSRF protection no longer can be bypassed to connect to other servers in the local network. Thanks to @michaellrowley |CVE-2022-0990| +## Statement regarding Log4j (CVE-2021-44228 and related) + +Calibre-web is not affected by bugs related to Log4j. Calibre-Web is a python program, therefore not using Java, and not using the Java logging feature log4j. diff --git a/babel.cfg b/babel.cfg index 128f13b68..2b7116e75 100644 --- a/babel.cfg +++ b/babel.cfg @@ -1,3 +1,4 @@ [python: **.py] + +# has to be executed with jinja2 >=2.9 to have autoescape enabled automatically [jinja2: **/templates/**.*ml] -extensions=jinja2.ext.autoescape,jinja2.ext.with_ \ No newline at end of file diff --git a/cps.py b/cps.py index ab9896ce1..e4f9c520c 100755 --- a/cps.py +++ b/cps.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) -# Copyright (C) 2012-2019 OzzieIsaacs +# Copyright (C) 2022 OzzieIsaacs # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,66 +17,18 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys import os +import sys -# Insert local directories into path -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'vendor')) - - -from cps import create_app -from cps import web_server -from cps.opds import opds -from cps.web import web -from cps.jinjia import jinjia -from cps.about import about -from cps.shelf import shelf -from cps.admin import admi -from cps.gdrive import gdrive -from cps.editbooks import editbook -from cps.remotelogin import remotelogin -from cps.search_metadata import meta -from cps.error_handler import init_errorhandler - -try: - from cps.kobo import kobo, get_kobo_activated - from cps.kobo_auth import kobo_auth - kobo_available = get_kobo_activated() -except (ImportError, AttributeError): # Catch also error for not installed flask-WTF (missing csrf decorator) - kobo_available = False - -try: - from cps.oauth_bb import oauth - oauth_available = True -except ImportError: - oauth_available = False - - -def main(): - app = create_app() - - init_errorhandler() - - app.register_blueprint(web) - app.register_blueprint(opds) - app.register_blueprint(jinjia) - app.register_blueprint(about) - app.register_blueprint(shelf) - app.register_blueprint(admi) - app.register_blueprint(remotelogin) - app.register_blueprint(meta) - app.register_blueprint(gdrive) - app.register_blueprint(editbook) - if kobo_available: - app.register_blueprint(kobo) - app.register_blueprint(kobo_auth) - if oauth_available: - app.register_blueprint(oauth) - success = web_server.start() - sys.exit(0 if success else 1) +# Add local path to sys.path so we can import cps +path = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, path) +from cps.main import main if __name__ == '__main__': main() + + + diff --git a/cps/MyLoginManager.py b/cps/MyLoginManager.py index 7c916bd55..2587e1a93 100644 --- a/cps/MyLoginManager.py +++ b/cps/MyLoginManager.py @@ -21,14 +21,32 @@ # along with this program. If not, see . -from flask_login import LoginManager -from flask import session - +from flask_login import LoginManager, confirm_login +from flask import session, current_app +from flask_login.utils import decode_cookie +from flask_login.signals import user_loaded_from_cookie class MyLoginManager(LoginManager): def _session_protection_failed(self): - sess = session._get_current_object() + _session = session._get_current_object() ident = self._session_identifier_generator() - if(sess and not (len(sess) == 1 and sess.get('csrf_token', None))) and ident != sess.get('_id', None): + if(_session and not (len(_session) == 1 + and _session.get('csrf_token', None))) and ident != _session.get('_id', None): return super(). _session_protection_failed() return False + + def _load_user_from_remember_cookie(self, cookie): + user_id = decode_cookie(cookie) + if user_id is not None: + session["_user_id"] = user_id + session["_fresh"] = False + user = None + if self._user_callback: + user = self._user_callback(user_id) + if user is not None: + app = current_app._get_current_object() + user_loaded_from_cookie.send(app, user=user) + # if session was restored from remember me cookie make login valid + confirm_login() + return user + return None diff --git a/cps/__init__.py b/cps/__init__.py index 118b46ffa..9d8cfa925 100644 --- a/cps/__init__.py +++ b/cps/__init__.py @@ -19,29 +19,27 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +__package__ = "cps" import sys import os import mimetypes -from babel import Locale as LC -from babel import negotiate_locale -from babel.core import UnknownLocaleError -from flask import Flask, request, g +from flask import Flask from .MyLoginManager import MyLoginManager -from flask_babel import Babel from flask_principal import Principal -from . import config_sql, logger, cache_buster, cli, ub, db +from . import logger +from .cli import CliParameter +from .constants import CONFIG_DIR from .reverseproxy import ReverseProxied from .server import WebServer from .dep_check import dependency_check - -try: - import lxml - lxml_present = True -except ImportError: - lxml_present = False +from .updater import Updater +from .babel import babel, get_locale +from . import config_sql +from . import cache_buster +from . import ub, db try: from flask_wtf.csrf import CSRFProtect @@ -49,6 +47,7 @@ try: except ImportError: wtf_present = False + mimetypes.init() mimetypes.add_type('application/xhtml+xml', '.xhtml') mimetypes.add_type('application/epub+zip', '.epub') @@ -70,6 +69,8 @@ mimetypes.add_type('application/ogg', '.oga') mimetypes.add_type('text/css', '.css') mimetypes.add_type('text/javascript; charset=UTF-8', '.js') +log = logger.create() + app = Flask(__name__) app.config.update( SESSION_COOKIE_HTTPONLY=True, @@ -78,61 +79,72 @@ app.config.update( WTF_CSRF_SSL_STRICT=False ) - lm = MyLoginManager() -lm.login_view = 'web.login' -lm.anonymous_user = ub.Anonymous -lm.session_protection = 'strong' + +config = config_sql._ConfigSQL() + +cli_param = CliParameter() if wtf_present: csrf = CSRFProtect() - csrf.init_app(app) else: csrf = None -ub.init_db(cli.settingspath) -# pylint: disable=no-member -config = config_sql.load_configuration(ub.session) +calibre_db = db.CalibreDB() web_server = WebServer() -babel = Babel() -_BABEL_TRANSLATIONS = set() +updater_thread = Updater() -log = logger.create() - - -from . import services - -db.CalibreDB.update_config(config) -db.CalibreDB.setup_db(config.config_calibre_dir, cli.settingspath) - - -calibre_db = db.CalibreDB() def create_app(): + lm.login_view = 'web.login' + lm.anonymous_user = ub.Anonymous + lm.session_protection = 'strong' + + if csrf: + csrf.init_app(app) + + cli_param.init() + + ub.init_db(cli_param.settings_path, cli_param.user_credentials) + + # pylint: disable=no-member + config_sql.load_configuration(config, ub.session, cli_param) + + db.CalibreDB.update_config(config) + db.CalibreDB.setup_db(config.config_calibre_dir, cli_param.settings_path) + calibre_db.init_db() + + updater_thread.init_updater(config, web_server) + # Perform dry run of updater and exit afterwards + if cli_param.dry_run: + updater_thread.dry_run() + sys.exit(0) + updater_thread.start() + if sys.version_info < (3, 0): log.info( - '*** Python2 is EOL since end of 2019, this version of Calibre-Web is no longer supporting Python2, please update your installation to Python3 ***') + '*** Python2 is EOL since end of 2019, this version of Calibre-Web is no longer supporting Python2, ' + 'please update your installation to Python3 ***') print( - '*** Python2 is EOL since end of 2019, this version of Calibre-Web is no longer supporting Python2, please update your installation to Python3 ***') + '*** Python2 is EOL since end of 2019, this version of Calibre-Web is no longer supporting Python2, ' + 'please update your installation to Python3 ***') web_server.stop(True) sys.exit(5) - if not lxml_present: - log.info('*** "lxml" is needed for calibre-web to run. Please install it using pip: "pip install lxml" ***') - print('*** "lxml" is needed for calibre-web to run. Please install it using pip: "pip install lxml" ***') - web_server.stop(True) - sys.exit(6) if not wtf_present: - log.info('*** "flask-WTF" is needed for calibre-web to run. Please install it using pip: "pip install flask-WTF" ***') - print('*** "flask-WTF" is needed for calibre-web to run. Please install it using pip: "pip install flask-WTF" ***') + log.info('*** "flask-WTF" is needed for calibre-web to run. ' + 'Please install it using pip: "pip install flask-WTF" ***') + print('*** "flask-WTF" is needed for calibre-web to run. ' + 'Please install it using pip: "pip install flask-WTF" ***') web_server.stop(True) sys.exit(7) for res in dependency_check() + dependency_check(True): - log.info('*** "{}" version does not fit the requirements. Should: {}, Found: {}, please consider installing required version ***' - .format(res['name'], - res['target'], - res['found'])) + log.info('*** "{}" version does not meet the requirements. ' + 'Should: {}, Found: {}, please consider installing required version ***' + .format(res['name'], + res['target'], + res['found'])) app.wsgi_app = ReverseProxied(app.wsgi_app) if os.environ.get('FLASK_DEBUG'): @@ -144,10 +156,13 @@ def create_app(): app.secret_key = os.getenv('SECRET_KEY', config_sql.get_flask_session_key(ub.session)) web_server.init_app(app, config) + if hasattr(babel, "localeselector"): + babel.init_app(app) + babel.localeselector(get_locale) + else: + babel.init_app(app, locale_selector=get_locale) - babel.init_app(app) - _BABEL_TRANSLATIONS.update(str(item) for item in babel.list_translations()) - _BABEL_TRANSLATIONS.add('en') + from . import services if services.ldap: services.ldap.init_app(app, config) @@ -155,34 +170,12 @@ def create_app(): services.goodreads_support.connect(config.config_goodreads_api_key, config.config_goodreads_api_secret, config.config_use_goodreads) + config.store_calibre_uuid(calibre_db, db.Library_Id) + # Register scheduled tasks + from .schedule import register_scheduled_tasks, register_startup_tasks + register_scheduled_tasks(config.schedule_reconnect) + register_startup_tasks() return app -@babel.localeselector -def get_locale(): - # if a user is logged in, use the locale from the user settings - user = getattr(g, 'user', None) - if user is not None and hasattr(user, "locale"): - if user.name != 'Guest': # if the account is the guest account bypass the config lang settings - return user.locale - preferred = list() - if request.accept_languages: - for x in request.accept_languages.values(): - try: - preferred.append(str(LC.parse(x.replace('-', '_')))) - except (UnknownLocaleError, ValueError) as e: - log.debug('Could not parse locale "%s": %s', x, e) - - return negotiate_locale(preferred or ['en'], _BABEL_TRANSLATIONS) - - -@babel.timezoneselector -def get_timezone(): - user = getattr(g, 'user', None) - return user.timezone if user else None - - -from .updater import Updater -updater_thread = Updater() -updater_thread.start() diff --git a/cps/about.py b/cps/about.py index ba5a99af9..7b6cc71af 100644 --- a/cps/about.py +++ b/cps/about.py @@ -25,114 +25,60 @@ import platform import sqlite3 from collections import OrderedDict -import babel, pytz, requests, sqlalchemy -import werkzeug, flask, flask_login, flask_principal, jinja2 +import flask +import flask_login +import jinja2 from flask_babel import gettext as _ -try: - from flask_wtf import __version__ as flaskwtf_version -except ImportError: - flaskwtf_version = _(u'not installed') -from . import db, calibre_db, converter, uploader, server, isoLanguages, constants, gdriveutils, dep_check +from . import db, calibre_db, converter, uploader, constants, dep_check from .render_template import render_title_template -try: - from flask_login import __version__ as flask_loginVersion -except ImportError: - from flask_login.__about__ import __version__ as flask_loginVersion -try: - # pylint: disable=unused-import - import unidecode - # _() necessary to make babel aware of string for translation - unidecode_version = _(u'installed') -except ImportError: - unidecode_version = _(u'not installed') - -try: - from flask_dance import __version__ as flask_danceVersion -except ImportError: - flask_danceVersion = None - -try: - from greenlet import __version__ as greenlet_Version -except ImportError: - greenlet_Version = None - -try: - from scholarly import scholarly - scholarly_version = _(u'installed') -except ImportError: - scholarly_version = _(u'not installed') - -from . import services about = flask.Blueprint('about', __name__) -ret = dict() -req = dep_check.load_dependencys(False) -opt = dep_check.load_dependencys(True) +modules = dict() +req = dep_check.load_dependencies(False) +opt = dep_check.load_dependencies(True) for i in (req + opt): - ret[i[1]] = i[0] + modules[i[1]] = i[0] +modules['Jinja2'] = jinja2.__version__ +modules['pySqlite'] = sqlite3.version +modules['SQLite'] = sqlite3.sqlite_version +sorted_modules = OrderedDict((sorted(modules.items(), key=lambda x: x[0].casefold()))) -if not ret: - _VERSIONS = OrderedDict( - Platform = '{0[0]} {0[2]} {0[3]} {0[4]} {0[5]}'.format(platform.uname()), - Python=sys.version, - Calibre_Web=constants.STABLE_VERSION['version'] + ' - ' - + constants.NIGHTLY_VERSION[0].replace('%','%%') + ' - ' - + constants.NIGHTLY_VERSION[1].replace('%','%%'), - WebServer=server.VERSION, - Flask=flask.__version__, - Flask_Login=flask_loginVersion, - Flask_Principal=flask_principal.__version__, - Flask_WTF=flaskwtf_version, - Werkzeug=werkzeug.__version__, - Babel=babel.__version__, - Jinja2=jinja2.__version__, - Requests=requests.__version__, - SqlAlchemy=sqlalchemy.__version__, - pySqlite=sqlite3.version, - SQLite=sqlite3.sqlite_version, - iso639=isoLanguages.__version__, - pytz=pytz.__version__, - Unidecode=unidecode_version, - Scholarly=scholarly_version, - Flask_SimpleLDAP=u'installed' if bool(services.ldap) else None, - python_LDAP=services.ldapVersion if bool(services.ldapVersion) else None, - Goodreads=u'installed' if bool(services.goodreads_support) else None, - jsonschema=services.SyncToken.__version__ if bool(services.SyncToken) else None, - flask_dance=flask_danceVersion, - greenlet=greenlet_Version - ) - _VERSIONS.update(gdriveutils.get_versions()) - _VERSIONS.update(uploader.get_versions(True)) -else: - _VERSIONS = OrderedDict( - Platform = '{0[0]} {0[2]} {0[3]} {0[4]} {0[5]}'.format(platform.uname()), - Python = sys.version, - Calibre_Web = constants.STABLE_VERSION['version'] + ' - ' - + constants.NIGHTLY_VERSION[0].replace('%', '%%') + ' - ' - + constants.NIGHTLY_VERSION[1].replace('%', '%%'), - Werkzeug = werkzeug.__version__, - Jinja2=jinja2.__version__, - pySqlite = sqlite3.version, - SQLite = sqlite3.sqlite_version, - ) - _VERSIONS.update(ret) - _VERSIONS.update(uploader.get_versions(False)) def collect_stats(): - _VERSIONS['ebook converter'] = _(converter.get_calibre_version()) - _VERSIONS['unrar'] = _(converter.get_unrar_version()) - _VERSIONS['kepubify'] = _(converter.get_kepubify_version()) + if constants.NIGHTLY_VERSION[0] == "$Format:%H$": + calibre_web_version = constants.STABLE_VERSION['version'] + else: + calibre_web_version = (constants.STABLE_VERSION['version'] + ' - ' + + constants.NIGHTLY_VERSION[0].replace('%', '%%') + ' - ' + + constants.NIGHTLY_VERSION[1].replace('%', '%%')) + + if getattr(sys, 'frozen', False): + calibre_web_version += " - Exe-Version" + elif constants.HOME_CONFIG: + calibre_web_version += " - pyPi" + + _VERSIONS = {'Calibre Web': calibre_web_version} + _VERSIONS.update(OrderedDict( + Python=sys.version, + Platform='{0[0]} {0[2]} {0[3]} {0[4]} {0[5]}'.format(platform.uname()), + )) + _VERSIONS.update(uploader.get_magick_version()) + _VERSIONS['Unrar'] = converter.get_unrar_version() + _VERSIONS['Ebook converter'] = converter.get_calibre_version() + _VERSIONS['Kepubify'] = converter.get_kepubify_version() + _VERSIONS.update(sorted_modules) return _VERSIONS + @about.route("/stats") @flask_login.login_required def stats(): counter = calibre_db.session.query(db.Books).count() authors = calibre_db.session.query(db.Authors).count() - categorys = calibre_db.session.query(db.Tags).count() + categories = calibre_db.session.query(db.Tags).count() series = calibre_db.session.query(db.Series).count() return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=collect_stats(), - categorycounter=categorys, seriecounter=series, title=_(u"Statistics"), page="stat") + categorycounter=categories, seriecounter=series, title=_("Statistics"), page="stat") diff --git a/cps/admin.py b/cps/admin.py index 068ac3560..9cc568cd2 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -24,52 +24,57 @@ import os import re import base64 import json -import time import operator +import time +import sys +import string from datetime import datetime, timedelta +from datetime import time as datetime_time +from functools import wraps -from babel import Locale as LC -from babel.dates import format_datetime from flask import Blueprint, flash, redirect, url_for, abort, request, make_response, send_from_directory, g, Response -from flask_login import login_required, current_user, logout_user, confirm_login +from flask_login import login_required, current_user, logout_user from flask_babel import gettext as _ +from flask_babel import get_locale, format_time, format_datetime, format_timedelta from flask import session as flask_session from sqlalchemy import and_ from sqlalchemy.orm.attributes import flag_modified from sqlalchemy.exc import IntegrityError, OperationalError, InvalidRequestError from sqlalchemy.sql.expression import func, or_, text -from . import constants, logger, helper, services -from . import db, calibre_db, ub, web_server, get_locale, config, updater_thread, babel, gdriveutils, kobo_sync_status +from . import constants, logger, helper, services, cli_param +from . import db, calibre_db, ub, web_server, config, updater_thread, gdriveutils, \ + kobo_sync_status, schedule from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash, check_email, \ valid_email, check_username from .gdriveutils import is_gdrive_ready, gdrive_support from .render_template import render_title_template, get_sidebar_config -from . import debug_info, _BABEL_TRANSLATIONS - -try: - from functools import wraps -except ImportError: - pass # We're not using Python 3 +from .services.worker import WorkerThread +from .babel import get_available_translations, get_available_locale, get_user_locale_language +from . import debug_info log = logger.create() feature_support = { - 'ldap': bool(services.ldap), - 'goodreads': bool(services.goodreads_support), - 'kobo': bool(services.kobo), - 'updater': constants.UPDATER_AVAILABLE, - 'gmail': bool(services.gmail) - } + 'ldap': bool(services.ldap), + 'goodreads': bool(services.goodreads_support), + 'kobo': bool(services.kobo), + 'updater': constants.UPDATER_AVAILABLE, + 'gmail': bool(services.gmail), + 'scheduler': schedule.use_APScheduler, + 'gdrive': gdrive_support +} try: import rarfile # pylint: disable=unused-import + feature_support['rar'] = True except (ImportError, SyntaxError): feature_support['rar'] = False try: from .oauth_bb import oauth_check, oauthblueprints + feature_support['oauth'] = True except ImportError as err: log.debug('Cannot import Flask-Dance, login with Oauth will not work: %s', err) @@ -77,8 +82,6 @@ except ImportError as err: oauthblueprints = [] oauth_check = {} - -feature_support['gdrive'] = gdrive_support admi = Blueprint('admin', __name__) @@ -98,20 +101,16 @@ def admin_required(f): @admi.before_app_request def before_request(): - # make remember me function work - if current_user.is_authenticated: - confirm_login() if not ub.check_user_session(current_user.id, flask_session.get('_id')) and 'opds' not in request.path: logout_user() g.constants = constants - g.user = current_user + # g.user = current_user + g.google_site_verification = os.getenv('GOOGLE_SITE_VERIFICATION','') g.allow_registration = config.config_public_reg g.allow_anonymous = config.config_anonbrowse g.allow_upload = config.config_uploading g.current_theme = config.config_theme g.config_authors_max = config.config_authors_max - g.shelves_access = ub.session.query(ub.Shelf).filter( - or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == current_user.id)).order_by(ub.Shelf.name).all() if '/static/' not in request.path and not config.db_configured and \ request.endpoint not in ('admin.ajax_db_config', 'admin.simulatedbchange', @@ -129,33 +128,67 @@ def admin_forbidden(): abort(403) -@admi.route("/shutdown") +@admi.route("/shutdown", methods=["POST"]) @login_required @admin_required def shutdown(): - task = int(request.args.get("parameter").strip()) - showtext = {} + task = request.get_json().get('parameter', -1) + show_text = {} if task in (0, 1): # valid commandos received # close all database connections calibre_db.dispose() ub.dispose() if task == 0: - showtext['text'] = _(u'Server restarted, please reload page') + show_text['text'] = _('Server restarted, please reload page.') else: - showtext['text'] = _(u'Performing shutdown of server, please close window') + show_text['text'] = _('Performing Server shutdown, please close window.') # stop gevent/tornado server web_server.stop(task == 0) - return json.dumps(showtext) + return json.dumps(show_text) if task == 2: log.warning("reconnecting to calibre database") calibre_db.reconnect_db(config, ub.app_DB_path) - showtext['text'] = _(u'Reconnect successful') - return json.dumps(showtext) + show_text['text'] = _('Success! Database Reconnected') + return json.dumps(show_text) - showtext['text'] = _(u'Unknown command') - return json.dumps(showtext), 400 + show_text['text'] = _('Unknown command') + return json.dumps(show_text), 400 + + +@admi.route("/metadata_backup", methods=["POST"]) +@login_required +@admin_required +def queue_metadata_backup(): + show_text = {} + log.warning("Queuing all books for metadata backup") + helper.set_all_metadata_dirty() + show_text['text'] = _('Success! Books queued for Metadata Backup') + return json.dumps(show_text) + + +# method is available without login and not protected by CSRF to make it easy reachable, is per default switched off +# needed for docker applications, as changes on metadata.db from host are not visible to application +@admi.route("/reconnect", methods=['GET']) +def reconnect(): + if cli_param.reconnect_enable: + calibre_db.reconnect_db(config, ub.app_DB_path) + return json.dumps({}) + else: + log.debug("'/reconnect' was accessed but is not enabled") + abort(404) + + +@admi.route("/ajax/updateThumbnails", methods=['POST']) +@admin_required +@login_required +def update_thumbnails(): + content = config.get_scheduled_task_settings() + if content['schedule_generate_book_covers']: + log.info("Update of Cover cache requested") + helper.update_thumbnail_cache() + return "" @admi.route("/admin/view") @@ -164,28 +197,33 @@ def shutdown(): def admin(): version = updater_thread.get_current_version_info() if version is False: - commit = _(u'Unknown') + commit = _('Unknown') else: if 'datetime' in version: commit = version['datetime'] tz = timedelta(seconds=time.timezone if (time.localtime().tm_isdst == 0) else time.altzone) form_date = datetime.strptime(commit[:19], "%Y-%m-%dT%H:%M:%S") - if len(commit) > 19: # check if string has timezone + if len(commit) > 19: # check if string has timezone if commit[19] == '+': form_date -= timedelta(hours=int(commit[20:22]), minutes=int(commit[23:])) elif commit[19] == '-': form_date += timedelta(hours=int(commit[20:22]), minutes=int(commit[23:])) - commit = format_datetime(form_date - tz, format='short', locale=get_locale()) + commit = format_datetime(form_date - tz, format='short') else: commit = version['version'] - allUser = ub.session.query(ub.User).all() + all_user = ub.session.query(ub.User).all() email_settings = config.get_mail_settings() - kobo_support = feature_support['kobo'] and config.config_kobo_sync - return render_title_template("admin.html", allUser=allUser, email=email_settings, config=config, commit=commit, - feature_support=feature_support, kobo_support=kobo_support, - title=_(u"Admin page"), page="admin") + schedule_time = format_time(datetime_time(hour=config.schedule_start_time), format="short") + t = timedelta(hours=config.schedule_duration // 60, minutes=config.schedule_duration % 60) + schedule_duration = format_timedelta(t, threshold=.99) + + return render_title_template("admin.html", allUser=all_user, email=email_settings, config=config, commit=commit, + feature_support=feature_support, schedule_time=schedule_time, + schedule_duration=schedule_duration, + title=_("Admin page"), page="admin") + @admi.route("/admin/dbconfig", methods=["GET", "POST"]) @login_required @@ -204,7 +242,7 @@ def configuration(): config=config, provider=oauthblueprints, feature_support=feature_support, - title=_(u"Basic Configuration"), page="config") + title=_("Basic Configuration"), page="config") @admi.route("/admin/ajaxconfig", methods=["POST"]) @@ -227,21 +265,23 @@ def ajax_db_config(): def calibreweb_alive(): return "", 200 + @admi.route("/admin/viewconfig") @login_required @admin_required def view_configuration(): - read_column = calibre_db.session.query(db.Custom_Columns)\ - .filter(and_(db.Custom_Columns.datatype == 'bool', db.Custom_Columns.mark_for_delete == 0)).all() - restrict_columns = calibre_db.session.query(db.Custom_Columns)\ - .filter(and_(db.Custom_Columns.datatype == 'text', db.Custom_Columns.mark_for_delete == 0)).all() + read_column = calibre_db.session.query(db.CustomColumns) \ + .filter(and_(db.CustomColumns.datatype == 'bool', db.CustomColumns.mark_for_delete == 0)).all() + restrict_columns = calibre_db.session.query(db.CustomColumns) \ + .filter(and_(db.CustomColumns.datatype == 'text', db.CustomColumns.mark_for_delete == 0)).all() languages = calibre_db.speaking_language() - translations = [LC('en')] + babel.list_translations() + translations = get_available_locale() return render_title_template("config_view_edit.html", conf=config, readColumns=read_column, restrictColumns=restrict_columns, languages=languages, translations=translations, - title=_(u"UI Configuration"), page="uiconfig") + title=_("UI Configuration"), page="uiconfig") + @admi.route("/admin/usertable") @login_required @@ -249,23 +289,23 @@ def view_configuration(): def edit_user_table(): visibility = current_user.view_settings.get('useredit', {}) languages = calibre_db.speaking_language() - translations = babel.list_translations() + [LC('en')] - allUser = ub.session.query(ub.User) - tags = calibre_db.session.query(db.Tags)\ - .join(db.books_tags_link)\ - .join(db.Books)\ + translations = get_available_locale() + all_user = ub.session.query(ub.User) + tags = calibre_db.session.query(db.Tags) \ + .join(db.books_tags_link) \ + .join(db.Books) \ .filter(calibre_db.common_filters()) \ - .group_by(text('books_tags_link.tag'))\ + .group_by(text('books_tags_link.tag')) \ .order_by(db.Tags.name).all() if config.config_restricted_column: custom_values = calibre_db.session.query(db.cc_classes[config.config_restricted_column]).all() else: custom_values = [] if not config.config_anonbrowse: - allUser = allUser.filter(ub.User.role.op('&')(constants.ROLE_ANONYMOUS) != constants.ROLE_ANONYMOUS) + all_user = all_user.filter(ub.User.role.op('&')(constants.ROLE_ANONYMOUS) != constants.ROLE_ANONYMOUS) kobo_support = feature_support['kobo'] and config.config_kobo_sync return render_title_template("user_table.html", - users=allUser.all(), + users=all_user.all(), tags=tags, custom_values=custom_values, translations=translations, @@ -274,7 +314,7 @@ def edit_user_table(): all_roles=constants.ALL_ROLES, kobo_support=kobo_support, sidebar_settings=constants.sidebar_settings, - title=_(u"Edit Users"), + title=_("Edit Users"), page="usertable") @@ -286,10 +326,13 @@ def list_users(): limit = int(request.args.get("limit") or 10) search = request.args.get("search") sort = request.args.get("sort", "id") - order = request.args.get("order", "").lower() state = None if sort == "state": state = json.loads(request.args.get("state", "[]")) + else: + if sort not in ub.User.__table__.columns.keys(): + sort = "id" + order = request.args.get("order", "").lower() if sort != "state" and order: order = text(sort + " " + order) @@ -304,8 +347,8 @@ def list_users(): if search: all_user = all_user.filter(or_(func.lower(ub.User.name).ilike("%" + search + "%"), - func.lower(ub.User.kindle_mail).ilike("%" + search + "%"), - func.lower(ub.User.email).ilike("%" + search + "%"))) + func.lower(ub.User.kindle_mail).ilike("%" + search + "%"), + func.lower(ub.User.email).ilike("%" + search + "%"))) if state: users = calibre_db.get_checkbox_sorted(all_user.all(), state, off, limit, request.args.get("order", "").lower()) else: @@ -317,7 +360,7 @@ def list_users(): if user.default_language == "all": user.default = _("All") else: - user.default = LC.parse(user.default_language).get_language_name(get_locale()) + user.default = get_user_locale_language(user.default_language) table_entries = {'totalNotFiltered': total_count, 'total': filtered_count, "rows": users} js_list = json.dumps(table_entries, cls=db.AlchemyEncoder) @@ -325,12 +368,14 @@ def list_users(): response.headers["Content-Type"] = "application/json; charset=utf-8" return response + @admi.route("/ajax/deleteuser", methods=['POST']) @login_required @admin_required def delete_user(): user_ids = request.form.to_dict(flat=False) users = None + message = "" if "userid[]" in user_ids: users = ub.session.query(ub.User).filter(ub.User.id.in_(user_ids['userid[]'])).all() elif "userid" in user_ids: @@ -358,11 +403,12 @@ def delete_user(): success.extend(errors) return Response(json.dumps(success), mimetype='application/json') + @admi.route("/ajax/getlocale") @login_required @admin_required def table_get_locale(): - locale = babel.list_translations() + [LC('en')] + locale = get_available_locale() ret = list() current_locale = get_locale() for loc in locale: @@ -417,30 +463,30 @@ def edit_list_user(param): if user.name == "Guest": raise Exception(_("Guest Name can't be changed")) user.name = check_username(vals['value']) - elif param =='email': + elif param == 'email': user.email = check_email(vals['value']) - elif param =='kobo_only_shelves_sync': + elif param == 'kobo_only_shelves_sync': user.kobo_only_shelves_sync = int(vals['value'] == 'true') elif param == 'kindle_mail': user.kindle_mail = valid_email(vals['value']) if vals['value'] else "" elif param.endswith('role'): value = int(vals['field_index']) if user.name == "Guest" and value in \ - [constants.ROLE_ADMIN, constants.ROLE_PASSWD, constants.ROLE_EDIT_SHELFS]: + [constants.ROLE_ADMIN, constants.ROLE_PASSWD, constants.ROLE_EDIT_SHELFS]: raise Exception(_("Guest can't have this role")) # check for valid value, last on checks for power of 2 value - if value > 0 and value <= constants.ROLE_VIEWER and (value & value-1 == 0 or value == 1): + if value > 0 and value <= constants.ROLE_VIEWER and (value & value - 1 == 0 or value == 1): if vals['value'] == 'true': user.role |= value elif vals['value'] == 'false': if value == constants.ROLE_ADMIN: - if not ub.session.query(ub.User).\ - filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN, - ub.User.id != user.id).count(): + if not ub.session.query(ub.User). \ + filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN, + ub.User.id != user.id).count(): return Response( json.dumps([{'type': "danger", - 'message':_(u"No admin user remaining, can't remove admin role", - nick=user.name)}]), mimetype='application/json') + 'message': _("No admin user remaining, can't remove admin role", + nick=user.name)}]), mimetype='application/json') user.role &= ~value else: raise Exception(_("Value has to be true or false")) @@ -451,7 +497,7 @@ def edit_list_user(param): if user.name == "Guest" and value == constants.SIDEBAR_READ_AND_UNREAD: raise Exception(_("Guest can't have this view")) # check for valid value, last on checks for power of 2 value - if value > 0 and value <= constants.SIDEBAR_LIST and (value & value-1 == 0 or value == 1): + if value > 0 and value <= constants.SIDEBAR_LIST and (value & value - 1 == 0 or value == 1): if vals['value'] == 'true': user.sidebar_view |= value elif vals['value'] == 'false': @@ -463,7 +509,7 @@ def edit_list_user(param): elif param == 'locale': if user.name == "Guest": raise Exception(_("Guest's Locale is determined automatically and can't be set")) - if vals['value'] in _BABEL_TRANSLATIONS: + if vals['value'] in get_available_translations(): user.locale = vals['value'] else: raise Exception(_("No Valid Locale Given")) @@ -481,7 +527,7 @@ def edit_list_user(param): else: return _("Parameter not found"), 400 except Exception as ex: - log.debug_or_exception(ex) + log.error_or_exception(ex) return str(ex), 400 ub.session_commit() return "" @@ -503,20 +549,6 @@ def update_table_settings(): return "Invalid request", 400 return "" -def check_valid_read_column(column): - if column != "0": - if not calibre_db.session.query(db.Custom_Columns).filter(db.Custom_Columns.id == column) \ - .filter(and_(db.Custom_Columns.datatype == 'bool', db.Custom_Columns.mark_for_delete == 0)).all(): - return False - return True - -def check_valid_restricted_column(column): - if column != "0": - if not calibre_db.session.query(db.Custom_Columns).filter(db.Custom_Columns.id == column) \ - .filter(and_(db.Custom_Columns.datatype == 'text', db.Custom_Columns.mark_for_delete == 0)).all(): - return False - return True - @admi.route("/admin/viewconfig", methods=["POST"]) @login_required @@ -530,13 +562,13 @@ def update_view_configuration(): calibre_db.update_title_sort(config) if not check_valid_read_column(to_save.get("config_read_column", "0")): - flash(_(u"Invalid Read Column"), category="error") + flash(_("Invalid Read Column"), category="error") log.debug("Invalid Read column") return view_configuration() _config_int(to_save, "config_read_column") if not check_valid_restricted_column(to_save.get("config_restricted_column", "0")): - flash(_(u"Invalid Restricted Column"), category="error") + flash(_("Invalid Restricted Column"), category="error") log.debug("Invalid Restricted Column") return view_configuration() _config_int(to_save, "config_restricted_column") @@ -548,7 +580,6 @@ def update_view_configuration(): _config_string(to_save, "config_default_language") _config_string(to_save, "config_default_locale") - config.config_default_role = constants.selected_roles(to_save) config.config_default_role &= ~constants.ROLE_ANONYMOUS @@ -557,7 +588,7 @@ def update_view_configuration(): config.config_default_show |= constants.DETAIL_RANDOM config.save() - flash(_(u"Calibre-Web configuration updated"), category="success") + flash(_("Calibre-Web configuration updated"), category="success") log.debug("Calibre-Web configuration updated") before_request() @@ -585,11 +616,18 @@ def load_dialogtexts(element_id): elif element_id == "restrictions": texts["main"] = _('Are you sure you want to change the selected restrictions for the selected user(s)?') elif element_id == "sidebar_view": - texts["main"] = _('Are you sure you want to change the selected visibility restrictions for the selected user(s)?') + texts["main"] = _('Are you sure you want to change the selected visibility restrictions ' + 'for the selected user(s)?') elif element_id == "kobo_only_shelves_sync": texts["main"] = _('Are you sure you want to change shelf sync behavior for the selected user(s)?') elif element_id == "db_submit": texts["main"] = _('Are you sure you want to change Calibre library location?') + elif element_id == "admin_refresh_cover_cache": + texts["main"] = _('Calibre-Web will search for updated Covers ' + 'and update Cover Thumbnails, this may take a while?') + elif element_id == "btnfullsync": + texts["main"] = _("Are you sure you want delete Calibre-Web's sync database " + "to force a full sync with your Kobo Reader?") return json.dumps(texts) @@ -612,7 +650,7 @@ def edit_domain(allow): @admin_required def add_domain(allow): domain_name = request.form.to_dict()['domainname'].replace('*', '%').replace('?', '_').lower() - check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name)\ + check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name) \ .filter(ub.Registration.allow == allow).first() if not check: new_domain = ub.Registration(domain=domain_name, allow=allow) @@ -718,43 +756,13 @@ def edit_restriction(res_type, user_id): return "" -def restriction_addition(element, list_func): - elementlist = list_func() - if elementlist == ['']: - elementlist = [] - if not element['add_element'] in elementlist: - elementlist += [element['add_element']] - return ','.join(elementlist) +@admi.route("/ajax/addrestriction/", methods=['POST']) +@login_required +@admin_required +def add_user_0_restriction(res_type): + return add_restriction(res_type, 0) -def restriction_deletion(element, list_func): - elementlist = list_func() - if element['Element'] in elementlist: - elementlist.remove(element['Element']) - return ','.join(elementlist) - - -def prepare_tags(user, action, tags_name, id_list): - if "tags" in tags_name: - tags = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(id_list)).all() - if not tags: - raise Exception(_("Tag not found")) - new_tags_list = [x.name for x in tags] - else: - tags = calibre_db.session.query(db.cc_classes[config.config_restricted_column])\ - .filter(db.cc_classes[config.config_restricted_column].id.in_(id_list)).all() - new_tags_list = [x.value for x in tags] - saved_tags_list = user.__dict__[tags_name].split(",") if len(user.__dict__[tags_name]) else [] - if action == "remove": - saved_tags_list = [x for x in saved_tags_list if x not in new_tags_list] - elif action == "add": - saved_tags_list.extend(x for x in new_tags_list if x not in saved_tags_list) - else: - raise Exception(_("Invalid Action")) - return ",".join(saved_tags_list) - - -@admi.route("/ajax/addrestriction/", defaults={"user_id": 0}, methods=['POST']) @admi.route("/ajax/addrestriction//", methods=['POST']) @login_required @admin_required @@ -801,7 +809,13 @@ def add_restriction(res_type, user_id): return "" -@admi.route("/ajax/deleterestriction/", defaults={"user_id": 0}, methods=['POST']) +@admi.route("/ajax/deleterestriction/", methods=['POST']) +@login_required +@admin_required +def delete_user_0_restriction(res_type): + return delete_restriction(res_type, 0) + + @admi.route("/ajax/deleterestriction//", methods=['POST']) @login_required @admin_required @@ -828,10 +842,10 @@ def delete_restriction(res_type, user_id): usr = current_user if element['id'].startswith('a'): usr.allowed_tags = restriction_deletion(element, usr.list_allowed_tags) - ub.session_commit("Deleted allowed tags of user {}: {}".format(usr.name, usr.list_allowed_tags)) + ub.session_commit("Deleted allowed tags of user {}: {}".format(usr.name, element['Element'])) elif element['id'].startswith('d'): usr.denied_tags = restriction_deletion(element, usr.list_denied_tags) - ub.session_commit("Deleted denied tags of user {}: {}".format(usr.name, usr.list_allowed_tags)) + ub.session_commit("Deleted denied tag of user {}: {}".format(usr.name, element['Element'])) elif res_type == 3: # Columns per user if isinstance(user_id, int): usr = ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first() @@ -840,12 +854,12 @@ def delete_restriction(res_type, user_id): if element['id'].startswith('a'): usr.allowed_column_value = restriction_deletion(element, usr.list_allowed_column_values) ub.session_commit("Deleted allowed columns of user {}: {}".format(usr.name, - usr.list_allowed_column_values)) + usr.list_allowed_column_values())) elif element['id'].startswith('d'): usr.denied_column_value = restriction_deletion(element, usr.list_denied_column_values) ub.session_commit("Deleted denied columns of user {}: {}".format(usr.name, - usr.list_denied_column_values)) + usr.list_denied_column_values())) return "" @@ -854,16 +868,16 @@ def delete_restriction(res_type, user_id): @login_required @admin_required def list_restriction(res_type, user_id): - if res_type == 0: # Tags as template - restrict = [{'Element': x, 'type':_('Deny'), 'id': 'd'+str(i) } - for i,x in enumerate(config.list_denied_tags()) if x != ''] - allow = [{'Element': x, 'type': _('Allow'), 'id': 'a'+str(i)} + if res_type == 0: # Tags as template + restrict = [{'Element': x, 'type': _('Deny'), 'id': 'd' + str(i)} + for i, x in enumerate(config.list_denied_tags()) if x != ''] + allow = [{'Element': x, 'type': _('Allow'), 'id': 'a' + str(i)} for i, x in enumerate(config.list_allowed_tags()) if x != ''] json_dumps = restrict + allow elif res_type == 1: # CustomC as template - restrict = [{'Element': x, 'type': _('Deny'), 'id': 'd'+str(i)} + restrict = [{'Element': x, 'type': _('Deny'), 'id': 'd' + str(i)} for i, x in enumerate(config.list_denied_column_values()) if x != ''] - allow = [{'Element': x, 'type': _('Allow'), 'id': 'a'+str(i)} + allow = [{'Element': x, 'type': _('Allow'), 'id': 'a' + str(i)} for i, x in enumerate(config.list_allowed_column_values()) if x != ''] json_dumps = restrict + allow elif res_type == 2: # Tags per user @@ -871,9 +885,9 @@ def list_restriction(res_type, user_id): usr = ub.session.query(ub.User).filter(ub.User.id == user_id).first() else: usr = current_user - restrict = [{'Element': x, 'type': _('Deny'), 'id': 'd'+str(i)} + restrict = [{'Element': x, 'type': _('Deny'), 'id': 'd' + str(i)} for i, x in enumerate(usr.list_denied_tags()) if x != ''] - allow = [{'Element': x, 'type': _('Allow'), 'id': 'a'+str(i)} + allow = [{'Element': x, 'type': _('Allow'), 'id': 'a' + str(i)} for i, x in enumerate(usr.list_allowed_tags()) if x != ''] json_dumps = restrict + allow elif res_type == 3: # CustomC per user @@ -881,19 +895,28 @@ def list_restriction(res_type, user_id): usr = ub.session.query(ub.User).filter(ub.User.id == user_id).first() else: usr = current_user - restrict = [{'Element': x, 'type': _('Deny'), 'id': 'd'+str(i)} + restrict = [{'Element': x, 'type': _('Deny'), 'id': 'd' + str(i)} for i, x in enumerate(usr.list_denied_column_values()) if x != ''] - allow = [{'Element': x, 'type': _('Allow'), 'id': 'a'+str(i)} + allow = [{'Element': x, 'type': _('Allow'), 'id': 'a' + str(i)} for i, x in enumerate(usr.list_allowed_column_values()) if x != ''] json_dumps = restrict + allow else: json_dumps = "" js = json.dumps(json_dumps) - response = make_response(js) #.replace("'", '"') + response = make_response(js) response.headers["Content-Type"] = "application/json; charset=utf-8" return response +@admi.route("/ajax/fullsync", methods=["POST"]) +@login_required +def ajax_fullsync(): + count = ub.session.query(ub.KoboSyncedBooks).filter(current_user.id == ub.KoboSyncedBooks.user_id).delete() + message = _("{} sync entries deleted").format(count) + ub.session_commit(message) + return Response(json.dumps([{"type": "success", "message": message}]), mimetype='application/json') + + @admi.route("/ajax/pathchooser/") @login_required @admin_required @@ -901,6 +924,71 @@ def ajax_pathchooser(): return pathchooser() +def check_valid_read_column(column): + if column != "0": + if not calibre_db.session.query(db.CustomColumns).filter(db.CustomColumns.id == column) \ + .filter(and_(db.CustomColumns.datatype == 'bool', db.CustomColumns.mark_for_delete == 0)).all(): + return False + return True + + +def check_valid_restricted_column(column): + if column != "0": + if not calibre_db.session.query(db.CustomColumns).filter(db.CustomColumns.id == column) \ + .filter(and_(db.CustomColumns.datatype == 'text', db.CustomColumns.mark_for_delete == 0)).all(): + return False + return True + + +def restriction_addition(element, list_func): + elementlist = list_func() + if elementlist == ['']: + elementlist = [] + if not element['add_element'] in elementlist: + elementlist += [element['add_element']] + return ','.join(elementlist) + + +def restriction_deletion(element, list_func): + elementlist = list_func() + if element['Element'] in elementlist: + elementlist.remove(element['Element']) + return ','.join(elementlist) + + +def prepare_tags(user, action, tags_name, id_list): + if "tags" in tags_name: + tags = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(id_list)).all() + if not tags: + raise Exception(_("Tag not found")) + new_tags_list = [x.name for x in tags] + else: + tags = calibre_db.session.query(db.cc_classes[config.config_restricted_column]) \ + .filter(db.cc_classes[config.config_restricted_column].id.in_(id_list)).all() + new_tags_list = [x.value for x in tags] + saved_tags_list = user.__dict__[tags_name].split(",") if len(user.__dict__[tags_name]) else [] + if action == "remove": + saved_tags_list = [x for x in saved_tags_list if x not in new_tags_list] + elif action == "add": + saved_tags_list.extend(x for x in new_tags_list if x not in saved_tags_list) + else: + raise Exception(_("Invalid Action")) + return ",".join(saved_tags_list) + + +def get_drives(current): + drive_letters = [] + for d in string.ascii_uppercase: + if os.path.exists('{}:'.format(d)) and current[0].lower() != d.lower(): + drive = "{}:\\".format(d) + data = {"name": drive, "fullpath": drive} + data["sort"] = "_" + data["fullpath"].lower() + data["type"] = "dir" + data["size"] = "" + drive_letters.append(data) + return drive_letters + + def pathchooser(): browse_for = "folder" folder_only = request.args.get('folder', False) == "true" @@ -908,40 +996,41 @@ def pathchooser(): path = os.path.normpath(request.args.get('path', "")) if os.path.isfile(path): - oldfile = path + old_file = path path = os.path.dirname(path) else: - oldfile = "" + old_file = "" absolute = False if os.path.isdir(path): - # if os.path.isabs(path): cwd = os.path.realpath(path) absolute = True - # else: - # cwd = os.path.relpath(path) else: cwd = os.getcwd() cwd = os.path.normpath(os.path.realpath(cwd)) - parentdir = os.path.dirname(cwd) + parent_dir = os.path.dirname(cwd) if not absolute: if os.path.realpath(cwd) == os.path.realpath("/"): cwd = os.path.relpath(cwd) else: cwd = os.path.relpath(cwd) + os.path.sep - parentdir = os.path.relpath(parentdir) + os.path.sep + parent_dir = os.path.relpath(parent_dir) + os.path.sep - if os.path.realpath(cwd) == os.path.realpath("/"): - parentdir = "" + files = [] + if os.path.realpath(cwd) == os.path.realpath("/") \ + or (sys.platform == "win32" and os.path.realpath(cwd)[1:] == os.path.realpath("/")[1:]): + # we are in root + parent_dir = "" + if sys.platform == "win32": + files = get_drives(cwd) try: folders = os.listdir(cwd) except Exception: folders = [] - files = [] for f in folders: try: data = {"name": f, "fullpath": os.path.join(cwd, f)} @@ -974,9 +1063,9 @@ def pathchooser(): context = { "cwd": cwd, "files": files, - "parentdir": parentdir, + "parentdir": parent_dir, "type": browse_for, - "oldfile": oldfile, + "oldfile": old_file, "absolute": absolute, } return json.dumps(context) @@ -1014,12 +1103,12 @@ def _configuration_gdrive_helper(to_save): if not gdrive_secrets: return _configuration_result(_('client_secrets.json Is Not Configured For Web Application')) gdriveutils.update_settings( - gdrive_secrets['client_id'], - gdrive_secrets['client_secret'], - gdrive_secrets['redirect_uris'][0] - ) + gdrive_secrets['client_id'], + gdrive_secrets['client_secret'], + gdrive_secrets['redirect_uris'][0] + ) - # always show google drive settings, but in case of error deny support + # always show Google Drive settings, but in case of error deny support new_gdrive_value = (not gdrive_error) and ("config_use_google_drive" in to_save) if config.config_use_google_drive and not new_gdrive_value: config.config_google_drive_watch_changes_response = {} @@ -1144,15 +1233,434 @@ def simulatedbchange(): return Response(json.dumps({"change": db_change, "valid": db_valid}), mimetype='application/json') +@admi.route("/admin/user/new", methods=["GET", "POST"]) +@login_required +@admin_required +def new_user(): + content = ub.User() + languages = calibre_db.speaking_language() + translations = get_available_locale() + kobo_support = feature_support['kobo'] and config.config_kobo_sync + if request.method == "POST": + to_save = request.form.to_dict() + _handle_new_user(to_save, content, languages, translations, kobo_support) + else: + content.role = config.config_default_role + content.sidebar_view = config.config_default_show + content.locale = config.config_default_locale + content.default_language = config.config_default_language + return render_title_template("user_edit.html", new_user=1, content=content, + config=config, translations=translations, + languages=languages, title=_("Add New User"), page="newuser", + kobo_support=kobo_support, registered_oauth=oauth_check) + + +@admi.route("/admin/mailsettings") +@login_required +@admin_required +def edit_mailsettings(): + content = config.get_mail_settings() + return render_title_template("email_edit.html", content=content, title=_("Edit Email Server Settings"), + page="mailset", feature_support=feature_support) + + +@admi.route("/admin/mailsettings", methods=["POST"]) +@login_required +@admin_required +def update_mailsettings(): + to_save = request.form.to_dict() + _config_int(to_save, "mail_server_type") + if to_save.get("invalidate"): + config.mail_gmail_token = {} + try: + flag_modified(config, "mail_gmail_token") + except AttributeError: + pass + elif to_save.get("gmail"): + try: + config.mail_gmail_token = services.gmail.setup_gmail(config.mail_gmail_token) + flash(_("Success! Gmail Account Verified."), category="success") + except Exception as ex: + flash(str(ex), category="error") + log.error(ex) + return edit_mailsettings() + + else: + _config_int(to_save, "mail_port") + _config_int(to_save, "mail_use_ssl") + _config_string(to_save, "mail_password") + _config_int(to_save, "mail_size", lambda y: int(y) * 1024 * 1024) + config.mail_server = to_save.get('mail_server', "").strip() + config.mail_from = to_save.get('mail_from', "").strip() + config.mail_login = to_save.get('mail_login', "").strip() + try: + config.save() + except (OperationalError, InvalidRequestError) as e: + ub.session.rollback() + log.error_or_exception("Settings Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") + return edit_mailsettings() + except Exception as e: + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") + return edit_mailsettings() + + if to_save.get("test"): + if current_user.email: + result = send_test_mail(current_user.email, current_user.name) + if result is None: + flash(_("Test e-mail queued for sending to %(email)s, please check Tasks for result", + email=current_user.email), category="info") + else: + flash(_("There was an error sending the Test e-mail: %(res)s", res=result), category="error") + else: + flash(_("Please configure your e-mail address first..."), category="error") + else: + flash(_("Email Server Settings updated"), category="success") + + return edit_mailsettings() + + +@admi.route("/admin/scheduledtasks") +@login_required +@admin_required +def edit_scheduledtasks(): + content = config.get_scheduled_task_settings() + time_field = list() + duration_field = list() + + for n in range(24): + time_field.append((n, format_time(datetime_time(hour=n), format="short", ))) + for n in range(5, 65, 5): + t = timedelta(hours=n // 60, minutes=n % 60) + duration_field.append((n, format_timedelta(t, threshold=.97))) + + return render_title_template("schedule_edit.html", + config=content, + starttime=time_field, + duration=duration_field, + title=_("Edit Scheduled Tasks Settings")) + + +@admi.route("/admin/scheduledtasks", methods=["POST"]) +@login_required +@admin_required +def update_scheduledtasks(): + error = False + to_save = request.form.to_dict() + if 0 <= int(to_save.get("schedule_start_time")) <= 23: + _config_int(to_save, "schedule_start_time") + else: + flash(_("Invalid start time for task specified"), category="error") + error = True + if 0 < int(to_save.get("schedule_duration")) <= 60: + _config_int(to_save, "schedule_duration") + else: + flash(_("Invalid duration for task specified"), category="error") + error = True + _config_checkbox(to_save, "schedule_generate_book_covers") + _config_checkbox(to_save, "schedule_generate_series_covers") + _config_checkbox(to_save, "schedule_reconnect") + + if not error: + try: + config.save() + flash(_("Scheduled tasks settings updated"), category="success") + + # Cancel any running tasks + schedule.end_scheduled_tasks() + + # Re-register tasks with new settings + schedule.register_scheduled_tasks(config.schedule_reconnect) + except IntegrityError: + ub.session.rollback() + log.error("An unknown error occurred while saving scheduled tasks settings") + flash(_("Oops! An unknown error occurred. Please try again later."), category="error") + except OperationalError: + ub.session.rollback() + log.error("Settings DB is not Writeable") + flash(_("Settings DB is not Writeable"), category="error") + + return edit_scheduledtasks() + + +@admi.route("/admin/user/", methods=["GET", "POST"]) +@login_required +@admin_required +def edit_user(user_id): + content = ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first() # type: ub.User + if not content or (not config.config_anonbrowse and content.name == "Guest"): + flash(_("User not found"), category="error") + return redirect(url_for('admin.admin')) + languages = calibre_db.speaking_language(return_all_languages=True) + translations = get_available_locale() + kobo_support = feature_support['kobo'] and config.config_kobo_sync + if request.method == "POST": + to_save = request.form.to_dict() + resp = _handle_edit_user(to_save, content, languages, translations, kobo_support) + if resp: + return resp + return render_title_template("user_edit.html", + translations=translations, + languages=languages, + new_user=0, + content=content, + config=config, + registered_oauth=oauth_check, + mail_configured=config.get_mail_server_configured(), + kobo_support=kobo_support, + title=_("Edit User %(nick)s", nick=content.name), + page="edituser") + + +@admi.route("/admin/resetpassword/", methods=["POST"]) +@login_required +@admin_required +def reset_user_password(user_id): + if current_user is not None and current_user.is_authenticated: + ret, message = reset_password(user_id) + if ret == 1: + log.debug("Password for user %s reset", message) + flash(_("Success! Password for user %(user)s reset", user=message), category="success") + elif ret == 0: + log.error("An unknown error occurred. Please try again later.") + flash(_("Oops! An unknown error occurred. Please try again later."), category="error") + else: + log.error("Please configure the SMTP mail settings.") + flash(_("Oops! Please configure the SMTP mail settings."), category="error") + return redirect(url_for('admin.admin')) + + +@admi.route("/admin/logfile") +@login_required +@admin_required +def view_logfile(): + logfiles = {0: logger.get_logfile(config.config_logfile), + 1: logger.get_accesslogfile(config.config_access_logfile)} + return render_title_template("logviewer.html", + title=_("Logfile viewer"), + accesslog_enable=config.config_access_log, + log_enable=bool(config.config_logfile != logger.LOG_TO_STDOUT), + logfiles=logfiles, + page="logfile") + + +@admi.route("/ajax/log/") +@login_required +@admin_required +def send_logfile(logtype): + if logtype == 1: + logfile = logger.get_accesslogfile(config.config_access_logfile) + return send_from_directory(os.path.dirname(logfile), + os.path.basename(logfile)) + if logtype == 0: + logfile = logger.get_logfile(config.config_logfile) + return send_from_directory(os.path.dirname(logfile), + os.path.basename(logfile)) + else: + return "" + + +@admi.route("/admin/logdownload/") +@login_required +@admin_required +def download_log(logtype): + if logtype == 0: + file_name = logger.get_logfile(config.config_logfile) + elif logtype == 1: + file_name = logger.get_accesslogfile(config.config_access_logfile) + else: + abort(404) + if logger.is_valid_logfile(file_name): + return debug_info.assemble_logfiles(file_name) + abort(404) + + +@admi.route("/admin/debug") +@login_required +@admin_required +def download_debug(): + return debug_info.send_debug() + + +@admi.route("/get_update_status", methods=['GET']) +@login_required +@admin_required +def get_update_status(): + if feature_support['updater']: + log.info("Update status requested") + return updater_thread.get_available_updates(request.method) + else: + return '' + + +@admi.route("/get_updater_status", methods=['GET', 'POST']) +@login_required +@admin_required +def get_updater_status(): + status = {} + if feature_support['updater']: + if request.method == "POST": + commit = request.form.to_dict() + if "start" in commit and commit['start'] == 'True': + txt = { + "1": _(u'Requesting update package'), + "2": _(u'Downloading update package'), + "3": _(u'Unzipping update package'), + "4": _(u'Replacing files'), + "5": _(u'Database connections are closed'), + "6": _(u'Stopping server'), + "7": _(u'Update finished, please press okay and reload page'), + "8": _(u'Update failed:') + u' ' + _(u'HTTP Error'), + "9": _(u'Update failed:') + u' ' + _(u'Connection error'), + "10": _(u'Update failed:') + u' ' + _(u'Timeout while establishing connection'), + "11": _(u'Update failed:') + u' ' + _(u'General error'), + "12": _(u'Update failed:') + u' ' + _(u'Update file could not be saved in temp dir'), + "13": _(u'Update failed:') + u' ' + _(u'Files could not be replaced during update') + } + status['text'] = txt + updater_thread.status = 0 + updater_thread.resume() + status['status'] = updater_thread.get_update_status() + elif request.method == "GET": + try: + status['status'] = updater_thread.get_update_status() + if status['status'] == -1: + status['status'] = 7 + except Exception: + status['status'] = 11 + return json.dumps(status) + return '' + + +def ldap_import_create_user(user, user_data): + user_login_field = extract_dynamic_field_from_filter(user, config.config_ldap_user_object) + + try: + username = user_data[user_login_field][0].decode('utf-8') + except KeyError as ex: + log.error("Failed to extract LDAP user: %s - %s", user, ex) + message = _(u'Failed to extract at least One LDAP User') + return 0, message + + # check for duplicate username + if ub.session.query(ub.User).filter(func.lower(ub.User.name) == username.lower()).first(): + # if ub.session.query(ub.User).filter(ub.User.name == username).first(): + log.warning("LDAP User %s Already in Database", user_data) + return 0, None + + ereader_mail = '' + if 'mail' in user_data: + useremail = user_data['mail'][0].decode('utf-8') + if len(user_data['mail']) > 1: + ereader_mail = user_data['mail'][1].decode('utf-8') + + else: + log.debug('No Mail Field Found in LDAP Response') + useremail = username + '@email.com' + + try: + # check for duplicate email + useremail = check_email(useremail) + except Exception as ex: + log.warning("LDAP Email Error: {}, {}".format(user_data, ex)) + return 0, None + content = ub.User() + content.name = username + content.password = '' # dummy password which will be replaced by ldap one + content.email = useremail + content.kindle_mail = ereader_mail + content.default_language = config.config_default_language + content.locale = config.config_default_locale + content.role = config.config_default_role + content.sidebar_view = config.config_default_show + content.allowed_tags = config.config_allowed_tags + content.denied_tags = config.config_denied_tags + content.allowed_column_value = config.config_allowed_column_value + content.denied_column_value = config.config_denied_column_value + ub.session.add(content) + try: + ub.session.commit() + return 1, None # increase no of users + except Exception as ex: + log.warning("Failed to create LDAP user: %s - %s", user, ex) + ub.session.rollback() + message = _(u'Failed to Create at Least One LDAP User') + return 0, message + + +@admi.route('/import_ldap_users', methods=["POST"]) +@login_required +@admin_required +def import_ldap_users(): + showtext = {} + try: + new_users = services.ldap.get_group_members(config.config_ldap_group_name) + except (services.ldap.LDAPException, TypeError, AttributeError, KeyError) as e: + log.error_or_exception(e) + showtext['text'] = _(u'Error: %(ldaperror)s', ldaperror=e) + return json.dumps(showtext) + if not new_users: + log.debug('LDAP empty response') + showtext['text'] = _(u'Error: No user returned in response of LDAP server') + return json.dumps(showtext) + + imported = 0 + for username in new_users: + user = username.decode('utf-8') + if '=' in user: + # if member object field is empty take user object as filter + if config.config_ldap_member_user_object: + query_filter = config.config_ldap_member_user_object + else: + query_filter = config.config_ldap_user_object + try: + user_identifier = extract_user_identifier(user, query_filter) + except Exception as ex: + log.warning(ex) + continue + else: + user_identifier = user + query_filter = None + try: + user_data = services.ldap.get_object_details(user=user_identifier, query_filter=query_filter) + except AttributeError as ex: + log.error_or_exception(ex) + continue + if user_data: + user_count, message = ldap_import_create_user(user, user_data) + if message: + showtext['text'] = message + else: + imported += user_count + else: + log.warning("LDAP User: %s Not Found", user) + showtext['text'] = _(u'At Least One LDAP User Not Found in Database') + if not showtext: + showtext['text'] = _(u'{} User Successfully Imported'.format(imported)) + return json.dumps(showtext) + + +@admi.route("/ajax/canceltask", methods=['POST']) +@login_required +@admin_required +def cancel_task(): + task_id = request.get_json().get('task_id', None) + worker = WorkerThread.get_instance() + worker.end_task(task_id) + return "" + + def _db_simulate_change(): param = request.form.to_dict() - to_save = {} + to_save = dict() to_save['config_calibre_dir'] = re.sub(r'[\\/]metadata\.db$', '', param['config_calibre_dir'], flags=re.IGNORECASE).strip() - db_change = config.config_calibre_dir != to_save["config_calibre_dir"] and config.config_calibre_dir - db_valid = calibre_db.check_valid_db(to_save["config_calibre_dir"], ub.app_DB_path) + db_valid, db_change = calibre_db.check_valid_db(to_save["config_calibre_dir"], + ub.app_DB_path, + config.config_calibre_uuid) + db_change = bool(db_change and config.config_calibre_dir) return db_change, db_valid @@ -1165,15 +1673,16 @@ def _db_configuration_update_helper(): '', to_save['config_calibre_dir'], flags=re.IGNORECASE) + db_valid = False try: db_change, db_valid = _db_simulate_change() # gdrive_error drive setup gdrive_error = _configuration_gdrive_helper(to_save) - except (OperationalError, InvalidRequestError): + except (OperationalError, InvalidRequestError) as e: ub.session.rollback() - log.error("Settings DB is not Writeable") - _db_configuration_result(_("Settings DB is not Writeable"), gdrive_error) + log.error_or_exception("Settings Database error: {}".format(e)) + _db_configuration_result(_("Oops! Database Error: %(error)s.", error=e.orig), gdrive_error) try: metadata_db = os.path.join(to_save['config_calibre_dir'], "metadata.db") if config.config_use_google_drive and is_gdrive_ready() and not os.path.exists(metadata_db): @@ -1182,18 +1691,34 @@ def _db_configuration_update_helper(): except Exception as ex: return _db_configuration_result('{}'.format(ex), gdrive_error) - if db_change or not db_valid or not config.db_configured: - if not calibre_db.setup_db(to_save['config_calibre_dir'], ub.app_DB_path): - return _db_configuration_result(_('DB Location is not Valid, Please Enter Correct Path'), - gdrive_error) + if db_change or not db_valid or not config.db_configured \ + or config.config_calibre_dir != to_save["config_calibre_dir"]: + if not os.path.exists(metadata_db) or not to_save['config_calibre_dir']: + return _db_configuration_result(_('DB Location is not Valid, Please Enter Correct Path'), gdrive_error) + else: + calibre_db.setup_db(to_save['config_calibre_dir'], ub.app_DB_path) + config.store_calibre_uuid(calibre_db, db.Library_Id) + # if db changed -> delete shelfs, delete download books, delete read books, kobo sync... + if db_change: + log.info("Calibre Database changed, all Calibre-Web info related to old Database gets deleted") + ub.session.query(ub.Downloads).delete() + ub.session.query(ub.ArchivedBook).delete() + ub.session.query(ub.ReadBook).delete() + ub.session.query(ub.BookShelf).delete() + ub.session.query(ub.Bookmark).delete() + ub.session.query(ub.KoboReadingState).delete() + ub.session.query(ub.KoboStatistics).delete() + ub.session.query(ub.KoboSyncedBooks).delete() + helper.delete_thumbnail_cache() + ub.session_commit() _config_string(to_save, "config_calibre_dir") calibre_db.update_config(config) if not os.access(os.path.join(config.config_calibre_dir, "metadata.db"), os.W_OK): - flash(_(u"DB is not Writeable"), category="warning") - # warning = {'type': "warning", 'message': _(u"DB is not Writeable")} + flash(_("DB is not Writeable"), category="warning") config.save() return _db_configuration_result(None, gdrive_error) + def _configuration_update_helper(): reboot_required = False to_save = request.form.to_dict() @@ -1212,7 +1737,7 @@ def _configuration_update_helper(): _config_checkbox_int(to_save, "config_unicode_filename") # Reboot on config_anonbrowse with enabled ldap, as decoraters are changed in this case reboot_required |= (_config_checkbox_int(to_save, "config_anonbrowse") - and config.config_login_type == constants.LOGIN_LDAP) + and config.config_login_type == constants.LOGIN_LDAP) _config_checkbox_int(to_save, "config_public_reg") _config_checkbox_int(to_save, "config_register_email") reboot_required |= _config_checkbox_int(to_save, "config_kobo_sync") @@ -1272,10 +1797,10 @@ def _configuration_update_helper(): unrar_status = helper.check_unrar(config.config_rarfile_location) if unrar_status: return _configuration_result(unrar_status) - except (OperationalError, InvalidRequestError): + except (OperationalError, InvalidRequestError) as e: ub.session.rollback() - log.error("Settings DB is not Writeable") - _configuration_result(_("Settings DB is not Writeable")) + log.error_or_exception("Settings Database error: {}".format(e)) + _configuration_result(_("Oops! Database Error: %(error)s.", error=e.orig)) config.save() if reboot_required: @@ -1283,6 +1808,7 @@ def _configuration_update_helper(): return _configuration_result(None, reboot_required) + def _configuration_result(error_flash=None, reboot=False): resp = {} if error_flash: @@ -1290,9 +1816,9 @@ def _configuration_result(error_flash=None, reboot=False): config.load() resp['result'] = [{'type': "danger", 'message': error_flash}] else: - resp['result'] = [{'type': "success", 'message':_(u"Calibre-Web configuration updated")}] + resp['result'] = [{'type': "success", 'message': _("Calibre-Web configuration updated")}] resp['reboot'] = reboot - resp['config_upload']= config.config_upload_formats + resp['config_upload'] = config.config_upload_formats return Response(json.dumps(resp), mimetype='application/json') @@ -1321,7 +1847,7 @@ def _db_configuration_result(error_flash=None, gdrive_error=None): gdriveError=gdrive_error, gdrivefolders=gdrivefolders, feature_support=feature_support, - title=_(u"Database Configuration"), page="dbconfig") + title=_("Database Configuration"), page="dbconfig") def _handle_new_user(to_save, content, languages, translations, kobo_support): @@ -1337,21 +1863,21 @@ def _handle_new_user(to_save, content, languages, translations, kobo_support): try: if not to_save["name"] or not to_save["email"] or not to_save["password"]: log.info("Missing entries on new user") - raise Exception(_(u"Please fill out all fields!")) + raise Exception(_("Oops! Please complete all fields.")) content.email = check_email(to_save["email"]) - # Query User name, if not existing, change + # Query username, if not existing, change content.name = check_username(to_save["name"]) if to_save.get("kindle_mail"): content.kindle_mail = valid_email(to_save["kindle_mail"]) if config.config_public_reg and not check_valid_domain(content.email): log.info("E-mail: {} for new user is not from valid domain".format(content.email)) - raise Exception(_(u"E-mail is not from valid domain")) + raise Exception(_("E-mail is not from valid domain")) except Exception as ex: flash(str(ex), category="error") return render_title_template("user_edit.html", new_user=1, content=content, config=config, translations=translations, - languages=languages, title=_(u"Add new user"), page="newuser", + languages=languages, title=_("Add new user"), page="newuser", kobo_support=kobo_support, registered_oauth=oauth_check) try: content.allowed_tags = config.config_allowed_tags @@ -1362,17 +1888,18 @@ def _handle_new_user(to_save, content, languages, translations, kobo_support): content.kobo_only_shelves_sync = to_save.get("kobo_only_shelves_sync", 0) == "on" ub.session.add(content) ub.session.commit() - flash(_(u"User '%(user)s' created", user=content.name), category="success") + flash(_("User '%(user)s' created", user=content.name), category="success") log.debug("User {} created".format(content.name)) return redirect(url_for('admin.admin')) except IntegrityError: ub.session.rollback() log.error("Found an existing account for {} or {}".format(content.name, content.email)) - flash(_("Found an existing account for this e-mail address or name."), category="error") - except OperationalError: + flash(_("Oops! An account already exists for this Email. or name."), category="error") + except OperationalError as e: ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") + log.error_or_exception("Settings Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") + def _delete_user(content): if ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN, @@ -1385,16 +1912,25 @@ def _delete_user(content): for us in ub.session.query(ub.Shelf).filter(content.id == ub.Shelf.user_id): ub.session.query(ub.BookShelf).filter(us.id == ub.BookShelf.shelf).delete() ub.session.query(ub.Shelf).filter(content.id == ub.Shelf.user_id).delete() + ub.session.query(ub.Bookmark).filter(content.id == ub.Bookmark.user_id).delete() ub.session.query(ub.User).filter(ub.User.id == content.id).delete() + ub.session.query(ub.ArchivedBook).filter(ub.ArchivedBook.user_id == content.id).delete() + ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.user_id == content.id).delete() + ub.session.query(ub.User_Sessions).filter(ub.User_Sessions.user_id == content.id).delete() + ub.session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.user_id == content.id).delete() + # delete KoboReadingState and all it's children + kobo_entries = ub.session.query(ub.KoboReadingState).filter(ub.KoboReadingState.user_id == content.id).all() + for kobo_entry in kobo_entries: + ub.session.delete(kobo_entry) ub.session_commit() - log.info(u"User {} deleted".format(content.name)) - return(_(u"User '%(nick)s' deleted", nick=content.name)) + log.info("User {} deleted".format(content.name)) + return _("User '%(nick)s' deleted", nick=content.name) else: - log.warning(_(u"Can't delete Guest User")) - raise Exception(_(u"Can't delete Guest User")) + log.warning(_("Can't delete Guest User")) + raise Exception(_("Can't delete Guest User")) else: - log.warning(u"No admin user remaining, can't delete user") - raise Exception(_(u"No admin user remaining, can't delete user")) + log.warning("No admin user remaining, can't delete user") + raise Exception(_("No admin user remaining, can't delete user")) def _handle_edit_user(to_save, content, languages, translations, kobo_support): @@ -1421,7 +1957,7 @@ def _handle_edit_user(to_save, content, languages, translations, kobo_support): content.role &= ~constants.ROLE_ANONYMOUS val = [int(k[5:]) for k in to_save if k.startswith('show_')] - sidebar = get_sidebar_config() + sidebar, __ = get_sidebar_config() for element in sidebar: value = element['visibility'] if value in val and not content.check_visibility(value): @@ -1446,9 +1982,12 @@ def _handle_edit_user(to_save, content, languages, translations, kobo_support): if to_save.get("locale"): content.locale = to_save["locale"] try: - if to_save.get("email", content.email) != content.email: - content.email = check_email(to_save["email"]) - # Query User name, if not existing, change + new_email = valid_email(to_save.get("email", content.email)) + if not new_email: + raise Exception(_("Email can't be empty and has to be a valid Email")) + if new_email != content.email: + content.email = check_email(new_email) + # Query username, if not existing, change if to_save.get("name", content.name) != content.name: if to_save.get("name") == "Guest": raise Exception(_("Guest Name can't be changed")) @@ -1467,365 +2006,24 @@ def _handle_edit_user(to_save, content, languages, translations, kobo_support): content=content, config=config, registered_oauth=oauth_check, - title=_(u"Edit User %(nick)s", nick=content.name), + title=_("Edit User %(nick)s", nick=content.name), page="edituser") try: ub.session_commit() - flash(_(u"User '%(nick)s' updated", nick=content.name), category="success") + flash(_("User '%(nick)s' updated", nick=content.name), category="success") except IntegrityError as ex: ub.session.rollback() log.error("An unknown error occurred while changing user: {}".format(str(ex))) - flash(_(u"An unknown error occurred. Please try again later."), category="error") - except OperationalError: + flash(_("Oops! An unknown error occurred. Please try again later."), category="error") + except OperationalError as e: ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") + log.error_or_exception("Settings Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") return "" -@admi.route("/admin/user/new", methods=["GET", "POST"]) -@login_required -@admin_required -def new_user(): - content = ub.User() - languages = calibre_db.speaking_language() - translations = [LC('en')] + babel.list_translations() - kobo_support = feature_support['kobo'] and config.config_kobo_sync - if request.method == "POST": - to_save = request.form.to_dict() - _handle_new_user(to_save, content, languages, translations, kobo_support) - else: - content.role = config.config_default_role - content.sidebar_view = config.config_default_show - content.locale = config.config_default_locale - content.default_language = config.config_default_language - return render_title_template("user_edit.html", new_user=1, content=content, - config=config, translations=translations, - languages=languages, title=_(u"Add new user"), page="newuser", - kobo_support=kobo_support, registered_oauth=oauth_check) - - -@admi.route("/admin/mailsettings") -@login_required -@admin_required -def edit_mailsettings(): - content = config.get_mail_settings() - return render_title_template("email_edit.html", content=content, title=_(u"Edit E-mail Server Settings"), - page="mailset", feature_support=feature_support) - - -@admi.route("/admin/mailsettings", methods=["POST"]) -@login_required -@admin_required -def update_mailsettings(): - to_save = request.form.to_dict() - _config_int(to_save, "mail_server_type") - if to_save.get("invalidate"): - config.mail_gmail_token = {} - try: - flag_modified(config, "mail_gmail_token") - except AttributeError: - pass - elif to_save.get("gmail"): - try: - config.mail_gmail_token = services.gmail.setup_gmail(config.mail_gmail_token) - flash(_(u"Gmail Account Verification Successful"), category="success") - except Exception as ex: - flash(str(ex), category="error") - log.error(ex) - return edit_mailsettings() - - else: - _config_string(to_save, "mail_server") - _config_int(to_save, "mail_port") - _config_int(to_save, "mail_use_ssl") - _config_string(to_save, "mail_login") - _config_string(to_save, "mail_password") - _config_string(to_save, "mail_from") - _config_int(to_save, "mail_size", lambda y: int(y)*1024*1024) - try: - config.save() - except (OperationalError, InvalidRequestError): - ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") - return edit_mailsettings() - - if to_save.get("test"): - if current_user.email: - result = send_test_mail(current_user.email, current_user.name) - if result is None: - flash(_(u"Test e-mail queued for sending to %(email)s, please check Tasks for result", - email=current_user.email), category="info") - else: - flash(_(u"There was an error sending the Test e-mail: %(res)s", res=result), category="error") - else: - flash(_(u"Please configure your e-mail address first..."), category="error") - else: - flash(_(u"E-mail server settings updated"), category="success") - - return edit_mailsettings() - - -@admi.route("/admin/user/", methods=["GET", "POST"]) -@login_required -@admin_required -def edit_user(user_id): - content = ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first() # type: ub.User - if not content or (not config.config_anonbrowse and content.name == "Guest"): - flash(_(u"User not found"), category="error") - return redirect(url_for('admin.admin')) - languages = calibre_db.speaking_language() - translations = babel.list_translations() + [LC('en')] - kobo_support = feature_support['kobo'] and config.config_kobo_sync - if request.method == "POST": - to_save = request.form.to_dict() - resp = _handle_edit_user(to_save, content, languages, translations, kobo_support) - if resp: - return resp - return render_title_template("user_edit.html", - translations=translations, - languages=languages, - new_user=0, - content=content, - config=config, - registered_oauth=oauth_check, - mail_configured=config.get_mail_server_configured(), - kobo_support=kobo_support, - title=_(u"Edit User %(nick)s", nick=content.name), - page="edituser") - - -@admi.route("/admin/resetpassword/") -@login_required -@admin_required -def reset_user_password(user_id): - if current_user is not None and current_user.is_authenticated: - ret, message = reset_password(user_id) - if ret == 1: - log.debug(u"Password for user %s reset", message) - flash(_(u"Password for user %(user)s reset", user=message), category="success") - elif ret == 0: - log.error(u"An unknown error occurred. Please try again later.") - flash(_(u"An unknown error occurred. Please try again later."), category="error") - else: - log.error(u"Please configure the SMTP mail settings first...") - flash(_(u"Please configure the SMTP mail settings first..."), category="error") - return redirect(url_for('admin.admin')) - - -@admi.route("/admin/logfile") -@login_required -@admin_required -def view_logfile(): - logfiles = {0: logger.get_logfile(config.config_logfile), - 1: logger.get_accesslogfile(config.config_access_logfile)} - return render_title_template("logviewer.html", - title=_(u"Logfile viewer"), - accesslog_enable=config.config_access_log, - log_enable=bool(config.config_logfile != logger.LOG_TO_STDOUT), - logfiles=logfiles, - page="logfile") - - -@admi.route("/ajax/log/") -@login_required -@admin_required -def send_logfile(logtype): - if logtype == 1: - logfile = logger.get_accesslogfile(config.config_access_logfile) - return send_from_directory(os.path.dirname(logfile), - os.path.basename(logfile)) - if logtype == 0: - logfile = logger.get_logfile(config.config_logfile) - return send_from_directory(os.path.dirname(logfile), - os.path.basename(logfile)) - else: - return "" - - -@admi.route("/admin/logdownload/") -@login_required -@admin_required -def download_log(logtype): - if logtype == 0: - file_name = logger.get_logfile(config.config_logfile) - elif logtype == 1: - file_name = logger.get_accesslogfile(config.config_access_logfile) - else: - abort(404) - if logger.is_valid_logfile(file_name): - return debug_info.assemble_logfiles(file_name) - abort(404) - - -@admi.route("/admin/debug") -@login_required -@admin_required -def download_debug(): - return debug_info.send_debug() - - -@admi.route("/get_update_status", methods=['GET']) -@login_required -@admin_required -def get_update_status(): - if feature_support['updater']: - log.info(u"Update status requested") - return updater_thread.get_available_updates(request.method, locale=get_locale()) - else: - return '' - - -@admi.route("/get_updater_status", methods=['GET', 'POST']) -@login_required -@admin_required -def get_updater_status(): - status = {} - if feature_support['updater']: - if request.method == "POST": - commit = request.form.to_dict() - if "start" in commit and commit['start'] == 'True': - text = { - "1": _(u'Requesting update package'), - "2": _(u'Downloading update package'), - "3": _(u'Unzipping update package'), - "4": _(u'Replacing files'), - "5": _(u'Database connections are closed'), - "6": _(u'Stopping server'), - "7": _(u'Update finished, please press okay and reload page'), - "8": _(u'Update failed:') + u' ' + _(u'HTTP Error'), - "9": _(u'Update failed:') + u' ' + _(u'Connection error'), - "10": _(u'Update failed:') + u' ' + _(u'Timeout while establishing connection'), - "11": _(u'Update failed:') + u' ' + _(u'General error'), - "12": _(u'Update failed:') + u' ' + _(u'Update file could not be saved in temp dir'), - "13": _(u'Update failed:') + u' ' + _(u'Files could not be replaced during update') - } - status['text'] = text - updater_thread.status = 0 - updater_thread.resume() - status['status'] = updater_thread.get_update_status() - elif request.method == "GET": - try: - status['status'] = updater_thread.get_update_status() - if status['status'] == -1: - status['status'] = 7 - except Exception: - status['status'] = 11 - return json.dumps(status) - return '' - - -def ldap_import_create_user(user, user_data): - user_login_field = extract_dynamic_field_from_filter(user, config.config_ldap_user_object) - - try: - username = user_data[user_login_field][0].decode('utf-8') - except KeyError as ex: - log.error("Failed to extract LDAP user: %s - %s", user, ex) - message = _(u'Failed to extract at least One LDAP User') - return 0, message - - # check for duplicate username - if ub.session.query(ub.User).filter(func.lower(ub.User.name) == username.lower()).first(): - # if ub.session.query(ub.User).filter(ub.User.name == username).first(): - log.warning("LDAP User %s Already in Database", user_data) - return 0, None - - kindlemail = '' - if 'mail' in user_data: - useremail = user_data['mail'][0].decode('utf-8') - if len(user_data['mail']) > 1: - kindlemail = user_data['mail'][1].decode('utf-8') - - else: - log.debug('No Mail Field Found in LDAP Response') - useremail = username + '@email.com' - - try: - # check for duplicate email - useremail = check_email(useremail) - except Exception as ex: - log.warning("LDAP Email Error: {}, {}".format(user_data, ex)) - return 0, None - content = ub.User() - content.name = username - content.password = '' # dummy password which will be replaced by ldap one - content.email = useremail - content.kindle_mail = kindlemail - content.default_language = config.config_default_language - content.locale = config.config_default_locale - content.role = config.config_default_role - content.sidebar_view = config.config_default_show - content.allowed_tags = config.config_allowed_tags - content.denied_tags = config.config_denied_tags - content.allowed_column_value = config.config_allowed_column_value - content.denied_column_value = config.config_denied_column_value - ub.session.add(content) - try: - ub.session.commit() - return 1, None # increase no of users - except Exception as ex: - log.warning("Failed to create LDAP user: %s - %s", user, ex) - ub.session.rollback() - message = _(u'Failed to Create at Least One LDAP User') - return 0, message - - -@admi.route('/import_ldap_users') -@login_required -@admin_required -def import_ldap_users(): - showtext = {} - try: - new_users = services.ldap.get_group_members(config.config_ldap_group_name) - except (services.ldap.LDAPException, TypeError, AttributeError, KeyError) as e: - log.debug_or_exception(e) - showtext['text'] = _(u'Error: %(ldaperror)s', ldaperror=e) - return json.dumps(showtext) - if not new_users: - log.debug('LDAP empty response') - showtext['text'] = _(u'Error: No user returned in response of LDAP server') - return json.dumps(showtext) - - imported = 0 - for username in new_users: - user = username.decode('utf-8') - if '=' in user: - # if member object field is empty take user object as filter - if config.config_ldap_member_user_object: - query_filter = config.config_ldap_member_user_object - else: - query_filter = config.config_ldap_user_object - try: - user_identifier = extract_user_identifier(user, query_filter) - except Exception as ex: - log.warning(ex) - continue - else: - user_identifier = user - query_filter = None - try: - user_data = services.ldap.get_object_details(user=user_identifier, query_filter=query_filter) - except AttributeError as ex: - log.debug_or_exception(ex) - continue - if user_data: - user_count, message = ldap_import_create_user(user, user_data) - if message: - showtext['text'] = message - else: - imported += user_count - else: - log.warning("LDAP User: %s Not Found", user) - showtext['text'] = _(u'At Least One LDAP User Not Found in Database') - if not showtext: - showtext['text'] = _(u'{} User Successfully Imported'.format(imported)) - return json.dumps(showtext) - - def extract_user_data_from_field(user, field): - match = re.search(field + r"=([\.\d\s\w-]+)", user, re.IGNORECASE | re.UNICODE) + match = re.search(field + r"=([@\.\d\s\w-]+)", user, re.IGNORECASE | re.UNICODE) if match: return match.group(1) else: diff --git a/cps/babel.py b/cps/babel.py new file mode 100644 index 000000000..e6c32806e --- /dev/null +++ b/cps/babel.py @@ -0,0 +1,40 @@ +from babel import negotiate_locale +from flask_babel import Babel, Locale +from babel.core import UnknownLocaleError +from flask import request +from flask_login import current_user + +from . import logger + +log = logger.create() + +babel = Babel() + +def get_locale(): + # if a user is logged in, use the locale from the user settings + if current_user is not None and hasattr(current_user, "locale"): + # if the account is the guest account bypass the config lang settings + if current_user.name != 'Guest': + return current_user.locale + + preferred = list() + if request.accept_languages: + for x in request.accept_languages.values(): + try: + preferred.append(str(Locale.parse(x.replace('-', '_')))) + except (UnknownLocaleError, ValueError) as e: + log.debug('Could not parse locale "%s": %s', x, e) + + return negotiate_locale(preferred or ['en'], get_available_translations()) + + +def get_user_locale_language(user_language): + return Locale.parse(user_language).get_language_name(get_locale()) + + +def get_available_locale(): + return [Locale('en')] + babel.list_translations() + + +def get_available_translations(): + return set(str(item) for item in get_available_locale()) diff --git a/cps/cache_buster.py b/cps/cache_buster.py index 9619d6054..eb6b74332 100644 --- a/cps/cache_buster.py +++ b/cps/cache_buster.py @@ -47,20 +47,23 @@ def init_cache_busting(app): for filename in filenames: # compute version component rooted_filename = os.path.join(dirpath, filename) - with open(rooted_filename, 'rb') as f: - file_hash = hashlib.md5(f.read()).hexdigest()[:7] # nosec + try: + with open(rooted_filename, 'rb') as f: + file_hash = hashlib.md5(f.read()).hexdigest()[:7] # nosec + # save version to tables + file_path = rooted_filename.replace(static_folder, "") + file_path = file_path.replace("\\", "/") # Convert Windows path to web path + hash_table[file_path] = file_hash + except PermissionError: + log.error("No permission to access {} file.".format(rooted_filename)) - # save version to tables - file_path = rooted_filename.replace(static_folder, "") - file_path = file_path.replace("\\", "/") # Convert Windows path to web path - hash_table[file_path] = file_hash log.debug('Finished computing cache-busting values') - def bust_filename(filename): - return hash_table.get(filename, "") + def bust_filename(file_name): + return hash_table.get(file_name, "") - def unbust_filename(filename): - return filename.split("?", 1)[0] + def unbust_filename(file_name): + return file_name.split("?", 1)[0] @app.url_defaults # pylint: disable=unused-variable diff --git a/cps/cli.py b/cps/cli.py index 3685e8e24..6f58dcc49 100644 --- a/cps/cli.py +++ b/cps/cli.py @@ -24,82 +24,107 @@ import socket from .constants import CONFIG_DIR as _CONFIG_DIR from .constants import STABLE_VERSION as _STABLE_VERSION from .constants import NIGHTLY_VERSION as _NIGHTLY_VERSION +from .constants import DEFAULT_SETTINGS_FILE, DEFAULT_GDRIVE_FILE def version_info(): if _NIGHTLY_VERSION[1].startswith('$Format'): - return "Calibre-Web version: %s - unkown git-clone" % _STABLE_VERSION['version'] + return "Calibre-Web version: %s - unknown git-clone" % _STABLE_VERSION['version'] return "Calibre-Web version: %s -%s" % (_STABLE_VERSION['version'], _NIGHTLY_VERSION[1]) -parser = argparse.ArgumentParser(description='Calibre Web is a web app' - ' providing a interface for browsing, reading and downloading eBooks\n', prog='cps.py') -parser.add_argument('-p', metavar='path', help='path and name to settings db, e.g. /opt/cw.db') -parser.add_argument('-g', metavar='path', help='path and name to gdrive db, e.g. /opt/gd.db') -parser.add_argument('-c', metavar='path', - help='path and name to SSL certfile, e.g. /opt/test.cert, works only in combination with keyfile') -parser.add_argument('-k', metavar='path', - help='path and name to SSL keyfile, e.g. /opt/test.key, works only in combination with certfile') -parser.add_argument('-v', '--version', action='version', help='Shows version number and exits Calibre-web', - version=version_info()) -parser.add_argument('-i', metavar='ip-address', help='Server IP-Address to listen') -parser.add_argument('-s', metavar='user:pass', help='Sets specific username to new password') -parser.add_argument('-f', action='store_true', help='Flag is depreciated and will be removed in next version') -args = parser.parse_args() +class CliParameter(object): -settingspath = args.p or os.path.join(_CONFIG_DIR, "app.db") -gdpath = args.g or os.path.join(_CONFIG_DIR, "gdrive.db") + def init(self): + self.arg_parser() -# handle and check parameter for ssl encryption -certfilepath = None -keyfilepath = None -if args.c: - if os.path.isfile(args.c): - certfilepath = args.c - else: - print("Certfile path is invalid. Exiting...") - sys.exit(1) + def arg_parser(self): + parser = argparse.ArgumentParser(description='Calibre Web is a web app providing ' + 'a interface for browsing, reading and downloading eBooks\n', + prog='cps.py') + parser.add_argument('-p', metavar='path', help='path and name to settings db, e.g. /opt/cw.db') + parser.add_argument('-g', metavar='path', help='path and name to gdrive db, e.g. /opt/gd.db') + parser.add_argument('-c', metavar='path', help='path and name to SSL certfile, e.g. /opt/test.cert, ' + 'works only in combination with keyfile') + parser.add_argument('-k', metavar='path', help='path and name to SSL keyfile, e.g. /opt/test.key, ' + 'works only in combination with certfile') + parser.add_argument('-v', '--version', action='version', help='Shows version number and exits Calibre-Web', + version=version_info()) + parser.add_argument('-i', metavar='ip-address', help='Server IP-Address to listen') + parser.add_argument('-s', metavar='user:pass', + help='Sets specific username to new password and exits Calibre-Web') + parser.add_argument('-f', action='store_true', help='Flag is depreciated and will be removed in next version') + parser.add_argument('-l', action='store_true', help='Allow loading covers from localhost') + parser.add_argument('-d', action='store_true', help='Dry run of updater to check file permissions in advance ' + 'and exits Calibre-Web') + parser.add_argument('-r', action='store_true', help='Enable public database reconnect route under /reconnect') + args = parser.parse_args() -if args.c == "": - certfilepath = "" + self.settings_path = args.p or os.path.join(_CONFIG_DIR, DEFAULT_SETTINGS_FILE) + self.gd_path = args.g or os.path.join(_CONFIG_DIR, DEFAULT_GDRIVE_FILE) -if args.k: - if os.path.isfile(args.k): - keyfilepath = args.k - else: - print("Keyfile path is invalid. Exiting...") - sys.exit(1) + if os.path.isdir(self.settings_path): + self.settings_path = os.path.join(self.settings_path, DEFAULT_SETTINGS_FILE) -if (args.k and not args.c) or (not args.k and args.c): - print("Certfile and Keyfile have to be used together. Exiting...") - sys.exit(1) + if os.path.isdir(self.gd_path): + self.gd_path = os.path.join(self.gd_path, DEFAULT_GDRIVE_FILE) -if args.k == "": - keyfilepath = "" - -# handle and check ip address argument -ip_address = args.i or None -if ip_address: - try: - # try to parse the given ip address with socket - if hasattr(socket, 'inet_pton'): - if ':' in ip_address: - socket.inet_pton(socket.AF_INET6, ip_address) + # handle and check parameter for ssl encryption + self.certfilepath = None + self.keyfilepath = None + if args.c: + if os.path.isfile(args.c): + self.certfilepath = args.c else: - socket.inet_pton(socket.AF_INET, ip_address) - else: - # on windows python < 3.4, inet_pton is not available - # inet_atom only handles IPv4 addresses - socket.inet_aton(ip_address) - except socket.error as err: - print(ip_address, ':', err) - sys.exit(1) + print("Certfile path is invalid. Exiting...") + sys.exit(1) -# handle and check user password argument -user_credentials = args.s or None -if user_credentials and ":" not in user_credentials: - print("No valid 'username:password' format") - sys.exit(3) + if args.c == "": + self.certfilepath = "" -if args.f: - print("Warning: -f flag is depreciated and will be removed in next version") + if args.k: + if os.path.isfile(args.k): + self.keyfilepath = args.k + else: + print("Keyfile path is invalid. Exiting...") + sys.exit(1) + + if (args.k and not args.c) or (not args.k and args.c): + print("Certfile and Keyfile have to be used together. Exiting...") + sys.exit(1) + + if args.k == "": + self.keyfilepath = "" + + # dry run updater + self.dry_run = args.d or None + # enable reconnect endpoint for docker database reconnect + self.reconnect_enable = args.r or os.environ.get("CALIBRE_RECONNECT", None) + # load covers from localhost + self.allow_localhost = args.l or os.environ.get("CALIBRE_LOCALHOST", None) + # handle and check ip address argument + self.ip_address = args.i or None + if self.ip_address: + try: + # try to parse the given ip address with socket + if hasattr(socket, 'inet_pton'): + if ':' in self.ip_address: + socket.inet_pton(socket.AF_INET6, self.ip_address) + else: + socket.inet_pton(socket.AF_INET, self.ip_address) + else: + # on Windows python < 3.4, inet_pton is not available + # inet_atom only handles IPv4 addresses + socket.inet_aton(self.ip_address) + except socket.error as err: + print(self.ip_address, ':', err) + sys.exit(1) + + # handle and check user password argument + self.user_credentials = args.s or None + if self.user_credentials and ":" not in self.user_credentials: + print("No valid 'username:password' format") + sys.exit(3) + + if args.f: + print("Warning: -f flag is depreciated and will be removed in next version") diff --git a/cps/comic.py b/cps/comic.py index b094c60fb..766b4584d 100644 --- a/cps/comic.py +++ b/cps/comic.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) -# Copyright (C) 2018 OzzieIsaacs +# Copyright (C) 2018-2022 OzzieIsaacs # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,19 +18,16 @@ import os -from . import logger, isoLanguages +from . import logger, isoLanguages, cover from .constants import BookMeta - -log = logger.create() - - try: from wand.image import Image use_IM = True except (ImportError, RuntimeError) as e: use_IM = False +log = logger.create() try: from comicapi.comicarchive import ComicArchive, MetaDataStyle @@ -51,37 +48,16 @@ except (ImportError, LookupError) as e: use_rarfile = False use_comic_meta = False -NO_JPEG_EXTENSIONS = ['.png', '.webp', '.bmp'] -COVER_EXTENSIONS = ['.png', '.webp', '.bmp', '.jpg', '.jpeg'] -def _cover_processing(tmp_file_name, img, extension): - tmp_cover_name = os.path.join(os.path.dirname(tmp_file_name), 'cover.jpg') - if use_IM: - # convert to jpg because calibre only supports jpg - if extension in NO_JPEG_EXTENSIONS: - with Image(filename=tmp_file_name) as imgc: - imgc.format = 'jpeg' - imgc.transform_colorspace('rgb') - imgc.save(tmp_cover_name) - return tmp_cover_name - - if not img: - return None - - with open(tmp_cover_name, 'wb') as f: - f.write(img) - return tmp_cover_name - - -def _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable): - cover_data = None +def _extract_cover_from_archive(original_file_extension, tmp_file_name, rar_executable): + cover_data = extension = None if original_file_extension.upper() == '.CBZ': cf = zipfile.ZipFile(tmp_file_name) for name in cf.namelist(): ext = os.path.splitext(name) if len(ext) > 1: extension = ext[1].lower() - if extension in COVER_EXTENSIONS: + if extension in cover.COVER_EXTENSIONS: cover_data = cf.read(name) break elif original_file_extension.upper() == '.CBT': @@ -90,44 +66,44 @@ def _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecu ext = os.path.splitext(name) if len(ext) > 1: extension = ext[1].lower() - if extension in COVER_EXTENSIONS: + if extension in cover.COVER_EXTENSIONS: cover_data = cf.extractfile(name).read() break elif original_file_extension.upper() == '.CBR' and use_rarfile: try: - rarfile.UNRAR_TOOL = rarExecutable + rarfile.UNRAR_TOOL = rar_executable cf = rarfile.RarFile(tmp_file_name) - for name in cf.getnames(): + for name in cf.namelist(): ext = os.path.splitext(name) if len(ext) > 1: extension = ext[1].lower() - if extension in COVER_EXTENSIONS: + if extension in cover.COVER_EXTENSIONS: cover_data = cf.read(name) break except Exception as ex: - log.debug('Rarfile failed with error: %s', ex) - return cover_data + log.debug('Rarfile failed with error: {}'.format(ex)) + return cover_data, extension -def _extractCover(tmp_file_name, original_file_extension, rarExecutable): +def _extract_cover(tmp_file_name, original_file_extension, rar_executable): cover_data = extension = None if use_comic_meta: - archive = ComicArchive(tmp_file_name, rar_exe_path=rarExecutable) + archive = ComicArchive(tmp_file_name, rar_exe_path=rar_executable) for index, name in enumerate(archive.getPageNameList()): ext = os.path.splitext(name) if len(ext) > 1: extension = ext[1].lower() - if extension in COVER_EXTENSIONS: + if extension in cover.COVER_EXTENSIONS: cover_data = archive.getPage(index) break else: - cover_data = _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable) - return _cover_processing(tmp_file_name, cover_data, extension) + cover_data, extension = _extract_cover_from_archive(original_file_extension, tmp_file_name, rar_executable) + return cover.cover_processing(tmp_file_name, cover_data, extension) -def get_comic_info(tmp_file_path, original_file_name, original_file_extension, rarExecutable): +def get_comic_info(tmp_file_path, original_file_name, original_file_extension, rar_executable): if use_comic_meta: - archive = ComicArchive(tmp_file_path, rar_exe_path=rarExecutable) + archive = ComicArchive(tmp_file_path, rar_exe_path=rar_executable) if archive.seemsToBeAComicArchive(): if archive.hasMetadata(MetaDataStyle.CIX): style = MetaDataStyle.CIX @@ -137,34 +113,38 @@ def get_comic_info(tmp_file_path, original_file_name, original_file_extension, r style = None # if style is not None: - loadedMetadata = archive.readMetadata(style) + loaded_metadata = archive.readMetadata(style) - lang = loadedMetadata.language or "" - loadedMetadata.language = isoLanguages.get_lang3(lang) + lang = loaded_metadata.language or "" + loaded_metadata.language = isoLanguages.get_lang3(lang) return BookMeta( file_path=tmp_file_path, extension=original_file_extension, - title=loadedMetadata.title or original_file_name, + title=loaded_metadata.title or original_file_name, author=" & ".join([credit["person"] - for credit in loadedMetadata.credits if credit["role"] == "Writer"]) or u'Unknown', - cover=_extractCover(tmp_file_path, original_file_extension, rarExecutable), - description=loadedMetadata.comments or "", + for credit in loaded_metadata.credits if credit["role"] == "Writer"]) or 'Unknown', + cover=_extract_cover(tmp_file_path, original_file_extension, rar_executable), + description=loaded_metadata.comments or "", tags="", - series=loadedMetadata.series or "", - series_id=loadedMetadata.issue or "", - languages=loadedMetadata.language, - publisher="") + series=loaded_metadata.series or "", + series_id=loaded_metadata.issue or "", + languages=loaded_metadata.language, + publisher="", + pubdate="", + identifiers=[]) return BookMeta( file_path=tmp_file_path, extension=original_file_extension, title=original_file_name, - author=u'Unknown', - cover=_extractCover(tmp_file_path, original_file_extension, rarExecutable), + author='Unknown', + cover=_extract_cover(tmp_file_path, original_file_extension, rar_executable), description="", tags="", series="", series_id="", languages="", - publisher="") + publisher="", + pubdate="", + identifiers=[]) diff --git a/cps/config_sql.py b/cps/config_sql.py index ebc4ca240..b6419a843 100644 --- a/cps/config_sql.py +++ b/cps/config_sql.py @@ -29,12 +29,13 @@ try: except ImportError: from sqlalchemy.ext.declarative import declarative_base -from . import constants, cli, logger +from . import constants, logger log = logger.create() _Base = declarative_base() + class _Flask_Settings(_Base): __tablename__ = 'flask_settings' @@ -62,18 +63,19 @@ class _Settings(_Base): mail_gmail_token = Column(JSON, default={}) config_calibre_dir = Column(String) + config_calibre_uuid = Column(String) config_port = Column(Integer, default=constants.DEFAULT_PORT) config_external_port = Column(Integer, default=constants.DEFAULT_PORT) config_certfile = Column(String) config_keyfile = Column(String) - config_trustedhosts = Column(String,default='') - config_calibre_web_title = Column(String, default=u'Calibre-Web') + config_trustedhosts = Column(String, default='') + config_calibre_web_title = Column(String, default='Calibre-Web') config_books_per_page = Column(Integer, default=60) config_random_books = Column(Integer, default=4) config_authors_max = Column(Integer, default=0) config_read_column = Column(Integer, default=0) - config_title_regex = Column(String, default=r'^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+') - config_mature_content_tags = Column(String, default='') + config_title_regex = Column(String, default=r'^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines|Le|La|Les|L\'|Un|Une)\s+') + # config_mature_content_tags = Column(String, default='') config_theme = Column(Integer, default=0) config_log_level = Column(SmallInteger, default=logger.DEFAULT_LOG_LEVEL) @@ -122,7 +124,7 @@ class _Settings(_Base): config_ldap_key_path = Column(String, default="") config_ldap_dn = Column(String, default='dc=example,dc=org') config_ldap_user_object = Column(String, default='uid=%s') - config_ldap_member_user_object = Column(String, default='') # + config_ldap_member_user_object = Column(String, default='') config_ldap_openldap = Column(Boolean, default=True) config_ldap_group_object_filter = Column(String, default='(&(objectclass=posixGroup)(cn=%s))') config_ldap_group_members_field = Column(String, default='memberUid') @@ -133,13 +135,19 @@ class _Settings(_Base): config_calibre = Column(String) config_rarfile_location = Column(String, default=None) config_upload_formats = Column(String, default=','.join(constants.EXTENSIONS_UPLOAD)) - config_unicode_filename =Column(Boolean, default=False) + config_unicode_filename = Column(Boolean, default=False) config_updatechannel = Column(Integer, default=constants.UPDATE_STABLE) config_reverse_proxy_login_header_name = Column(String) config_allow_reverse_proxy_header_login = Column(Boolean, default=False) + schedule_start_time = Column(Integer, default=4) + schedule_duration = Column(Integer, default=10) + schedule_generate_book_covers = Column(Boolean, default=False) + schedule_generate_series_covers = Column(Boolean, default=False) + schedule_reconnect = Column(Boolean, default=False) + def __repr__(self): return self.__class__.__name__ @@ -147,12 +155,16 @@ class _Settings(_Base): # Class holds all application specific settings in calibre-web class _ConfigSQL(object): # pylint: disable=no-member - def __init__(self, session): + def __init__(self): + pass + + def init_config(self, session, cli): self._session = session self._settings = None self.db_configured = None self.config_calibre_dir = None self.load() + self.cli = cli change = False if self.config_converterpath == None: # pylint: disable=access-member-before-definition @@ -160,7 +172,6 @@ class _ConfigSQL(object): self.config_converterpath = autodetect_calibre_binary() if self.config_kepubifypath == None: # pylint: disable=access-member-before-definition - change = True self.config_kepubifypath = autodetect_kepubify_binary() @@ -170,7 +181,6 @@ class _ConfigSQL(object): if change: self.save() - def _read_from_storage(self): if self._settings is None: log.debug("_ConfigSQL._read_from_storage") @@ -178,22 +188,21 @@ class _ConfigSQL(object): return self._settings def get_config_certfile(self): - if cli.certfilepath: - return cli.certfilepath - if cli.certfilepath == "": + if self.cli.certfilepath: + return self.cli.certfilepath + if self.cli.certfilepath == "": return None return self.config_certfile def get_config_keyfile(self): - if cli.keyfilepath: - return cli.keyfilepath - if cli.certfilepath == "": + if self.cli.keyfilepath: + return self.cli.keyfilepath + if self.cli.certfilepath == "": return None return self.config_keyfile - @staticmethod - def get_config_ipaddress(): - return cli.ip_address or "" + def get_config_ipaddress(self): + return self.cli.ip_address or "" def _has_role(self, role_flag): return constants.has_flag(self.config_default_role, role_flag) @@ -248,12 +257,14 @@ class _ConfigSQL(object): return logger.get_level_name(self.config_log_level) def get_mail_settings(self): - return {k:v for k, v in self.__dict__.items() if k.startswith('mail_')} + return {k: v for k, v in self.__dict__.items() if k.startswith('mail_')} def get_mail_server_configured(self): return bool((self.mail_server != constants.DEFAULT_MAIL_SERVER and self.mail_server_type == 0) or (self.mail_gmail_token != {} and self.mail_server_type == 1)) + def get_scheduled_task_settings(self): + return {k: v for k, v in self.__dict__.items() if k.startswith('schedule_')} def set_from_dictionary(self, dictionary, field, convertor=None, default=None, encode=None): """Possibly updates a field of this object. @@ -285,13 +296,12 @@ class _ConfigSQL(object): def toDict(self): storage = {} for k, v in self.__dict__.items(): - if k[0] != '_' and not k.endswith("password") and not k.endswith("secret"): + if k[0] != '_' and not k.endswith("password") and not k.endswith("secret") and not k == "cli": storage[k] = v return storage - def load(self): - '''Load all configuration values from the underlying storage.''' + """Load all configuration values from the underlying storage.""" s = self._read_from_storage() # type: _Settings for k, v in s.__dict__.items(): if k[0] != '_': @@ -304,9 +314,8 @@ class _ConfigSQL(object): have_metadata_db = bool(self.config_calibre_dir) if have_metadata_db: - if not self.config_use_google_drive: - db_file = os.path.join(self.config_calibre_dir, 'metadata.db') - have_metadata_db = os.path.isfile(db_file) + db_file = os.path.join(self.config_calibre_dir, 'metadata.db') + have_metadata_db = os.path.isfile(db_file) self.db_configured = have_metadata_db constants.EXTENSIONS_UPLOAD = [x.lstrip().rstrip().lower() for x in self.config_upload_formats.split(',')] if os.environ.get('FLASK_DEBUG'): @@ -325,7 +334,7 @@ class _ConfigSQL(object): self._session.rollback() def save(self): - '''Apply all configuration values to the underlying storage.''' + """Apply all configuration values to the underlying storage.""" s = self._read_from_storage() # type: _Settings for k, v in self.__dict__.items(): @@ -351,6 +360,15 @@ class _ConfigSQL(object): # self.config_calibre_dir = None self.save() + def store_calibre_uuid(self, calibre_db, Library_table): + try: + calibre_uuid = calibre_db.session.query(Library_table).one_or_none() + if self.config_calibre_uuid != calibre_uuid.uuid: + self.config_calibre_uuid = calibre_uuid.uuid + self.save() + except AttributeError: + pass + def _migrate_table(session, orm_class): changed = False @@ -373,9 +391,9 @@ def _migrate_table(session, orm_class): else: column_type = column.type alter_table = text("ALTER TABLE %s ADD COLUMN `%s` %s %s" % (orm_class.__tablename__, - column_name, - column_type, - column_default)) + column_name, + column_type, + column_default)) log.debug(alter_table) session.execute(alter_table) changed = True @@ -403,6 +421,7 @@ def autodetect_calibre_binary(): return element return "" + def autodetect_unrar_binary(): if sys.platform == "win32": calibre_path = ["C:\\program files\\WinRar\\unRAR.exe", @@ -414,6 +433,7 @@ def autodetect_unrar_binary(): return element return "" + def autodetect_kepubify_binary(): if sys.platform == "win32": calibre_path = ["C:\\program files\\kepubify\\kepubify-windows-64Bit.exe", @@ -425,6 +445,7 @@ def autodetect_kepubify_binary(): return element return "" + def _migrate_database(session): # make sure the table is created, if it does not exist _Base.metadata.create_all(session.bind) @@ -432,26 +453,21 @@ def _migrate_database(session): _migrate_table(session, _Flask_Settings) -def load_configuration(session): +def load_configuration(conf, session, cli): _migrate_database(session) if not session.query(_Settings).count(): session.add(_Settings()) session.commit() - conf = _ConfigSQL(session) - # Migrate from global restrictions to user based restrictions - #if bool(conf.config_default_show & constants.MATURE_CONTENT) and conf.config_denied_tags == "": - # conf.config_denied_tags = conf.config_mature_content_tags - # conf.save() - # session.query(ub.User).filter(ub.User.mature_content != True). \ - # update({"denied_tags": conf.config_mature_content_tags}, synchronize_session=False) - # session.commit() - return conf + # conf = _ConfigSQL() + conf.init_config(session, cli) + # return conf -def get_flask_session_key(session): - flask_settings = session.query(_Flask_Settings).one_or_none() + +def get_flask_session_key(_session): + flask_settings = _session.query(_Flask_Settings).one_or_none() if flask_settings == None: flask_settings = _Flask_Settings(os.urandom(32)) - session.add(flask_settings) - session.commit() + _session.add(flask_settings) + _session.commit() return flask_settings.flask_session_key diff --git a/cps/constants.py b/cps/constants.py index e37ad900d..376e1097c 100644 --- a/cps/constants.py +++ b/cps/constants.py @@ -21,28 +21,37 @@ import os from collections import namedtuple from sqlalchemy import __version__ as sql_version -sqlalchemy_version2 = ([int(x) for x in sql_version.split('.')] >= [2,0,0]) +sqlalchemy_version2 = ([int(x) for x in sql_version.split('.')] >= [2, 0, 0]) + +# APP_MODE - production, development, or test +APP_MODE = os.environ.get('APP_MODE', 'production') # if installed via pip this variable is set to true (empty file with name .HOMEDIR present) HOME_CONFIG = os.path.isfile(os.path.join(os.path.dirname(os.path.abspath(__file__)), '.HOMEDIR')) -#In executables updater is not available, so variable is set to False there +# In executables updater is not available, so variable is set to False there UPDATER_AVAILABLE = True # Base dir is parent of current file, necessary if called from different folder -BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),os.pardir)) +BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)) STATIC_DIR = os.path.join(BASE_DIR, 'cps', 'static') TEMPLATES_DIR = os.path.join(BASE_DIR, 'cps', 'templates') TRANSLATIONS_DIR = os.path.join(BASE_DIR, 'cps', 'translations') +# Cache dir - use CACHE_DIR environment variable, otherwise use the default directory: cps/cache +DEFAULT_CACHE_DIR = os.path.join(BASE_DIR, 'cps', 'cache') +CACHE_DIR = os.environ.get('CACHE_DIR', DEFAULT_CACHE_DIR) + if HOME_CONFIG: - home_dir = os.path.join(os.path.expanduser("~"),".calibre-web") + home_dir = os.path.join(os.path.expanduser("~"), ".calibre-web") if not os.path.exists(home_dir): os.makedirs(home_dir) CONFIG_DIR = os.environ.get('CALIBRE_DBPATH', home_dir) else: CONFIG_DIR = os.environ.get('CALIBRE_DBPATH', BASE_DIR) +DEFAULT_SETTINGS_FILE = "app.db" +DEFAULT_GDRIVE_FILE = "gdrive.db" ROLE_USER = 0 << 0 ROLE_ADMIN = 1 << 0 @@ -133,11 +142,14 @@ except ValueError: del env_CALIBRE_PORT -EXTENSIONS_AUDIO = {'mp3', 'mp4', 'ogg', 'opus', 'wav', 'flac', 'm4a', 'm4b'} -EXTENSIONS_CONVERT_FROM = ['pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', 'txt', 'htmlz', 'rtf', 'odt','cbz','cbr'] -EXTENSIONS_CONVERT_TO = ['pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', 'txt', 'htmlz', 'rtf', 'odt'] -EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'kepub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx', - 'fb2', 'html', 'rtf', 'lit', 'odt', 'mp3', 'mp4', 'ogg', 'opus', 'wav', 'flac', 'm4a', 'm4b'} +EXTENSIONS_AUDIO = {'mp3', 'mp4', 'ogg', 'opus', 'wav', 'flac', 'm4a', 'm4b'} +EXTENSIONS_CONVERT_FROM = ['pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', + 'txt', 'htmlz', 'rtf', 'odt', 'cbz', 'cbr'] +EXTENSIONS_CONVERT_TO = ['pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', + 'lit', 'lrf', 'txt', 'htmlz', 'rtf', 'odt'] +EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'kepub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', + 'prc', 'doc', 'docx', 'fb2', 'html', 'rtf', 'lit', 'odt', 'mp3', 'mp4', 'ogg', + 'opus', 'wav', 'flac', 'm4a', 'm4b'} def has_flag(value, bit_flag): @@ -149,16 +161,29 @@ def selected_roles(dictionary): # :rtype: BookMeta BookMeta = namedtuple('BookMeta', 'file_path, extension, title, author, cover, description, tags, series, ' - 'series_id, languages, publisher') + 'series_id, languages, publisher, pubdate, identifiers') -STABLE_VERSION = {'version': '0.6.15 Beta'} +STABLE_VERSION = {'version': '0.6.20 Beta'} -NIGHTLY_VERSION = {} +NIGHTLY_VERSION = dict() NIGHTLY_VERSION[0] = '$Format:%H$' NIGHTLY_VERSION[1] = '$Format:%cI$' # NIGHTLY_VERSION[0] = 'bb7d2c6273ae4560e83950d36d64533343623a57' # NIGHTLY_VERSION[1] = '2018-09-09T10:13:08+02:00' +# CACHE +CACHE_TYPE_THUMBNAILS = 'thumbnails' + +# Thumbnail Types +THUMBNAIL_TYPE_COVER = 1 +THUMBNAIL_TYPE_SERIES = 2 +THUMBNAIL_TYPE_AUTHOR = 3 + +# Thumbnails Sizes +COVER_THUMBNAIL_ORIGINAL = 0 +COVER_THUMBNAIL_SMALL = 1 +COVER_THUMBNAIL_MEDIUM = 2 +COVER_THUMBNAIL_LARGE = 3 # clean-up the module namespace del sys, os, namedtuple diff --git a/cps/converter.py b/cps/converter.py index fcbabbfc1..981b39097 100644 --- a/cps/converter.py +++ b/cps/converter.py @@ -18,7 +18,8 @@ import os import re -from flask_babel import gettext as _ + +from flask_babel import lazy_gettext as N_ from . import config, logger from .subproc_wrapper import process_wait @@ -26,10 +27,9 @@ from .subproc_wrapper import process_wait log = logger.create() -# _() necessary to make babel aware of string for translation -_NOT_CONFIGURED = _('not configured') -_NOT_INSTALLED = _('not installed') -_EXECUTION_ERROR = _('Execution permissions missing') +# strings getting translated when used +_NOT_INSTALLED = N_('not installed') +_EXECUTION_ERROR = N_('Execution permissions missing') def _get_command_version(path, pattern, argument=None): @@ -48,14 +48,15 @@ def _get_command_version(path, pattern, argument=None): def get_calibre_version(): - return _get_command_version(config.config_converterpath, r'ebook-convert.*\(calibre', '--version') \ - or _NOT_CONFIGURED + return _get_command_version(config.config_converterpath, r'ebook-convert.*\(calibre', '--version') def get_unrar_version(): - return _get_command_version(config.config_rarfile_location, r'UNRAR.*\d') or _NOT_CONFIGURED + unrar_version = _get_command_version(config.config_rarfile_location, r'UNRAR.*\d') + if unrar_version == "not installed": + unrar_version = _get_command_version(config.config_rarfile_location, r'unrar.*\d', '-V') + return unrar_version + def get_kepubify_version(): - return _get_command_version(config.config_kepubifypath, r'kepubify\s','--version') or _NOT_CONFIGURED - - + return _get_command_version(config.config_kepubifypath, r'kepubify\s', '--version') diff --git a/cps/cover.py b/cps/cover.py new file mode 100644 index 000000000..5dd295342 --- /dev/null +++ b/cps/cover.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2022 OzzieIsaacs +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os + +try: + from wand.image import Image + use_IM = True +except (ImportError, RuntimeError) as e: + use_IM = False + + +NO_JPEG_EXTENSIONS = ['.png', '.webp', '.bmp'] +COVER_EXTENSIONS = ['.png', '.webp', '.bmp', '.jpg', '.jpeg'] + + +def cover_processing(tmp_file_name, img, extension): + tmp_cover_name = os.path.join(os.path.dirname(tmp_file_name), 'cover.jpg') + if extension in NO_JPEG_EXTENSIONS: + if use_IM: + with Image(blob=img) as imgc: + imgc.format = 'jpeg' + imgc.transform_colorspace('rgb') + imgc.save(filename=tmp_cover_name) + return tmp_cover_name + else: + return None + if img: + with open(tmp_cover_name, 'wb') as f: + f.write(img) + return tmp_cover_name + else: + return None diff --git a/cps/db.py b/cps/db.py index 800fb3dd1..eb3e0f0ae 100644 --- a/cps/db.py +++ b/cps/db.py @@ -17,13 +17,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys import os import re -import ast import json from datetime import datetime +from urllib.parse import quote +import unidecode +from sqlite3 import OperationalError as sqliteOperationalError from sqlalchemy import create_engine from sqlalchemy import Table, Column, ForeignKey, CheckConstraint from sqlalchemy import String, Integer, Boolean, TIMESTAMP, Float @@ -40,9 +41,8 @@ from sqlalchemy.pool import StaticPool from sqlalchemy.sql.expression import and_, true, false, text, func, or_ from sqlalchemy.ext.associationproxy import association_proxy from flask_login import current_user -from babel import Locale as LC -from babel.core import UnknownLocaleError from flask_babel import gettext as _ +from flask_babel import get_locale from flask import flash from . import logger, ub, isoLanguages @@ -50,11 +50,6 @@ from .pagination import Pagination from weakref import WeakSet -try: - import unidecode - use_unidecode = True -except ImportError: - use_unidecode = False log = logger.create() @@ -94,6 +89,12 @@ books_publishers_link = Table('books_publishers_link', Base.metadata, ) +class Library_Id(Base): + __tablename__ = 'library_id' + id = Column(Integer, primary_key=True) + uuid = Column(String, nullable=False) + + class Identifiers(Base): __tablename__ = 'identifiers' @@ -107,85 +108,91 @@ class Identifiers(Base): self.type = id_type self.book = book - def formatType(self): + def format_type(self): format_type = self.type.lower() if format_type == 'amazon': - return u"Amazon" + return "Amazon" elif format_type.startswith("amazon_"): - return u"Amazon.{0}".format(format_type[7:]) + return "Amazon.{0}".format(format_type[7:]) elif format_type == "isbn": - return u"ISBN" + return "ISBN" elif format_type == "doi": - return u"DOI" + return "DOI" elif format_type == "douban": - return u"Douban" + return "Douban" elif format_type == "goodreads": - return u"Goodreads" + return "Goodreads" elif format_type == "babelio": - return u"Babelio" + return "Babelio" elif format_type == "google": - return u"Google Books" + return "Google Books" elif format_type == "kobo": - return u"Kobo" + return "Kobo" elif format_type == "litres": - return u"ЛитРес" + return "ЛитРес" elif format_type == "issn": - return u"ISSN" + return "ISSN" elif format_type == "isfdb": - return u"ISFDB" + return "ISFDB" if format_type == "lubimyczytac": - return u"Lubimyczytac" + return "Lubimyczytac" + if format_type == "databazeknih": + return "Databáze knih" else: return self.type def __repr__(self): format_type = self.type.lower() if format_type == "amazon" or format_type == "asin": - return u"https://amazon.com/dp/{0}".format(self.val) + return "https://amazon.com/dp/{0}".format(self.val) elif format_type.startswith('amazon_'): - return u"https://amazon.{0}/dp/{1}".format(format_type[7:], self.val) + return "https://amazon.{0}/dp/{1}".format(format_type[7:], self.val) elif format_type == "isbn": - return u"https://www.worldcat.org/isbn/{0}".format(self.val) + return "https://www.worldcat.org/isbn/{0}".format(self.val) elif format_type == "doi": - return u"https://dx.doi.org/{0}".format(self.val) + return "https://dx.doi.org/{0}".format(self.val) elif format_type == "goodreads": - return u"https://www.goodreads.com/book/show/{0}".format(self.val) + return "https://www.goodreads.com/book/show/{0}".format(self.val) elif format_type == "babelio": - return u"https://www.babelio.com/livres/titre/{0}".format(self.val) + return "https://www.babelio.com/livres/titre/{0}".format(self.val) elif format_type == "douban": - return u"https://book.douban.com/subject/{0}".format(self.val) + return "https://book.douban.com/subject/{0}".format(self.val) elif format_type == "google": - return u"https://books.google.com/books?id={0}".format(self.val) + return "https://books.google.com/books?id={0}".format(self.val) elif format_type == "kobo": - return u"https://www.kobo.com/ebook/{0}".format(self.val) + return "https://www.kobo.com/ebook/{0}".format(self.val) elif format_type == "lubimyczytac": - return u"https://lubimyczytac.pl/ksiazka/{0}/ksiazka".format(self.val) + return "https://lubimyczytac.pl/ksiazka/{0}/ksiazka".format(self.val) elif format_type == "litres": - return u"https://www.litres.ru/{0}".format(self.val) + return "https://www.litres.ru/{0}".format(self.val) elif format_type == "issn": - return u"https://portal.issn.org/resource/ISSN/{0}".format(self.val) + return "https://portal.issn.org/resource/ISSN/{0}".format(self.val) elif format_type == "isfdb": - return u"http://www.isfdb.org/cgi-bin/pl.cgi?{0}".format(self.val) + return "http://www.isfdb.org/cgi-bin/pl.cgi?{0}".format(self.val) + elif format_type == "databazeknih": + return "https://www.databazeknih.cz/knihy/{0}".format(self.val) + elif self.val.lower().startswith("javascript:"): + return quote(self.val) else: - return u"{0}".format(self.val) + return "{0}".format(self.val) class Comments(Base): __tablename__ = 'comments' id = Column(Integer, primary_key=True) + book = Column(Integer, ForeignKey('books.id'), nullable=False, unique=True) text = Column(String(collation='NOCASE'), nullable=False) - book = Column(Integer, ForeignKey('books.id'), nullable=False) - def __init__(self, text, book): - self.text = text + def __init__(self, comment, book): + self.text = comment self.book = book def get(self): return self.text def __repr__(self): - return u"".format(self.text) + return "".format(self.text) class Tags(Base): @@ -201,7 +208,7 @@ class Tags(Base): return self.name def __repr__(self): - return u"".format(self.name) + return "".format(self.name) class Authors(Base): @@ -221,7 +228,7 @@ class Authors(Base): return self.name def __repr__(self): - return u"".format(self.name, self.sort, self.link) + return "".format(self.name, self.sort, self.link) class Series(Base): @@ -239,7 +246,7 @@ class Series(Base): return self.name def __repr__(self): - return u"".format(self.name, self.sort) + return "".format(self.name, self.sort) class Ratings(Base): @@ -255,7 +262,7 @@ class Ratings(Base): return self.rating def __repr__(self): - return u"".format(self.rating) + return "".format(self.rating) class Languages(Base): @@ -274,7 +281,7 @@ class Languages(Base): return self.lang_code def __repr__(self): - return u"".format(self.lang_code) + return "".format(self.lang_code) class Publishers(Base): @@ -292,7 +299,7 @@ class Publishers(Base): return self.name def __repr__(self): - return u"".format(self.name, self.sort) + return "".format(self.name, self.sort) class Data(Base): @@ -316,7 +323,16 @@ class Data(Base): return self.name def __repr__(self): - return u"".format(self.book, self.format, self.uncompressed_size, self.name) + return "".format(self.book, self.format, self.uncompressed_size, self.name) + + +class Metadata_Dirtied(Base): + __tablename__ = 'metadata_dirtied' + id = Column(Integer, primary_key=True, autoincrement=True) + book = Column(Integer, ForeignKey('books.id'), nullable=False, unique=True) + + def __init__(self, book): + self.book = book class Books(Base): @@ -338,15 +354,15 @@ class Books(Base): isbn = Column(String(collation='NOCASE'), default="") flags = Column(Integer, nullable=False, default=1) - authors = relationship('Authors', secondary=books_authors_link, backref='books') - tags = relationship('Tags', secondary=books_tags_link, backref='books', order_by="Tags.name") - comments = relationship('Comments', backref='books') - data = relationship('Data', backref='books') - series = relationship('Series', secondary=books_series_link, backref='books') - ratings = relationship('Ratings', secondary=books_ratings_link, backref='books') - languages = relationship('Languages', secondary=books_languages_link, backref='books') - publishers = relationship('Publishers', secondary=books_publishers_link, backref='books') - identifiers = relationship('Identifiers', backref='books') + authors = relationship(Authors, secondary=books_authors_link, backref='books') + tags = relationship(Tags, secondary=books_tags_link, backref='books', order_by="Tags.name") + comments = relationship(Comments, backref='books') + data = relationship(Data, backref='books') + series = relationship(Series, secondary=books_series_link, backref='books') + ratings = relationship(Ratings, secondary=books_ratings_link, backref='books') + languages = relationship(Languages, secondary=books_languages_link, backref='books') + publishers = relationship(Publishers, secondary=books_publishers_link, backref='books') + identifiers = relationship(Identifiers, backref='books') def __init__(self, title, sort, author_sort, timestamp, pubdate, series_index, last_modified, path, has_cover, authors, tags, languages=None): @@ -360,18 +376,17 @@ class Books(Base): self.path = path self.has_cover = (has_cover != None) - def __repr__(self): - return u"".format(self.title, self.sort, self.author_sort, + return "".format(self.title, self.sort, self.author_sort, self.timestamp, self.pubdate, self.series_index, self.last_modified, self.path, self.has_cover) @property def atom_timestamp(self): - return (self.timestamp.strftime('%Y-%m-%dT%H:%M:%S+00:00') or '') + return self.timestamp.strftime('%Y-%m-%dT%H:%M:%S+00:00') or '' -class Custom_Columns(Base): +class CustomColumns(Base): __tablename__ = 'custom_columns' id = Column(Integer, primary_key=True) @@ -385,9 +400,33 @@ class Custom_Columns(Base): normalized = Column(Boolean) def get_display_dict(self): - display_dict = ast.literal_eval(self.display) + display_dict = json.loads(self.display) return display_dict + def to_json(self, value, extra, sequence): + content = dict() + content['table'] = "custom_column_" + str(self.id) + content['column'] = "value" + content['datatype'] = self.datatype + content['is_multiple'] = None if not self.is_multiple else self.is_multiple + content['kind'] = "field" + content['name'] = self.name + content['search_terms'] = ['#' + self.label] + content['label'] = self.label + content['colnum'] = self.id + content['display'] = self.get_display_dict() + content['is_custom'] = True + content['is_category'] = self.datatype in ['text', 'rating', 'enumeration', 'series'] + content['link_column'] = "value" + content['category_sort'] = "value" + content['is_csp'] = False + content['is_editable'] = self.editable + content['rec_index'] = sequence + 22 # toDo why ?? + content['#value#'] = value + content['#extra#'] = extra + content['is_multiple2'] = {} + return json.dumps(content, ensure_ascii=False) + class AlchemyEncoder(json.JSONEncoder): @@ -429,7 +468,7 @@ class AlchemyEncoder(json.JSONEncoder): return json.JSONEncoder.default(self, o) -class CalibreDB(): +class CalibreDB: _init = False engine = None config = None @@ -438,22 +477,27 @@ class CalibreDB(): # instances alive once they reach the end of their respective scopes instances = WeakSet() - def __init__(self, expire_on_commit=True): + def __init__(self, expire_on_commit=True, init=False): """ Initialize a new CalibreDB session """ self.session = None + if init: + self.init_db(expire_on_commit) + + + def init_db(self, expire_on_commit=True): if self._init: - self.initSession(expire_on_commit) + self.init_session(expire_on_commit) self.instances.add(self) - def initSession(self, expire_on_commit=True): + def init_session(self, expire_on_commit=True): self.session = self.session_factory() self.session.expire_on_commit = expire_on_commit self.update_title_sort(self.config) @classmethod - def setup_db_cc_classes(self, cc): + def setup_db_cc_classes(cls, cc): cc_ids = [] books_custom_column_links = {} for row in cc: @@ -524,25 +568,31 @@ class CalibreDB(): return cc_classes @classmethod - def check_valid_db(cls, config_calibre_dir, app_db_path): + def check_valid_db(cls, config_calibre_dir, app_db_path, config_calibre_uuid): if not config_calibre_dir: - return False + return False, False dbpath = os.path.join(config_calibre_dir, "metadata.db") if not os.path.exists(dbpath): - return False + return False, False try: check_engine = create_engine('sqlite://', - echo=False, - isolation_level="SERIALIZABLE", - connect_args={'check_same_thread': False}, - poolclass=StaticPool) + echo=False, + isolation_level="SERIALIZABLE", + connect_args={'check_same_thread': False}, + poolclass=StaticPool) with check_engine.begin() as connection: connection.execute(text("attach database '{}' as calibre;".format(dbpath))) connection.execute(text("attach database '{}' as app_settings;".format(app_db_path))) + local_session = scoped_session(sessionmaker()) + local_session.configure(bind=connection) + database_uuid = local_session().query(Library_Id).one_or_none() + # local_session.dispose() + check_engine.connect() + db_change = config_calibre_uuid != database_uuid.uuid except Exception: - return False - return True + return False, False + return True, db_change @classmethod def update_config(cls, config): @@ -550,19 +600,16 @@ class CalibreDB(): @classmethod def setup_db(cls, config_calibre_dir, app_db_path): - # cls.config = config cls.dispose() - # toDo: if db changed -> delete shelfs, delete download books, delete read boks, kobo sync?? - if not config_calibre_dir: cls.config.invalidate() - return False + return None dbpath = os.path.join(config_calibre_dir, "metadata.db") if not os.path.exists(dbpath): cls.config.invalidate() - return False + return None try: cls.engine = create_engine('sqlite://', @@ -578,7 +625,7 @@ class CalibreDB(): # conn.text_factory = lambda b: b.decode(errors = 'ignore') possible fix for #1302 except Exception as ex: cls.config.invalidate(ex) - return False + return None cls.config.db_configured = True @@ -587,16 +634,16 @@ class CalibreDB(): cc = conn.execute(text("SELECT id, datatype FROM custom_columns")) cls.setup_db_cc_classes(cc) except OperationalError as e: - log.debug_or_exception(e) + log.error_or_exception(e) + return None cls.session_factory = scoped_session(sessionmaker(autocommit=False, autoflush=True, bind=cls.engine)) for inst in cls.instances: - inst.initSession() + inst.init_session() cls._init = True - return True def get_book(self, book_id): return self.session.query(Books).filter(Books.id == book_id).first() @@ -605,30 +652,60 @@ class CalibreDB(): return self.session.query(Books).filter(Books.id == book_id). \ filter(self.common_filters(allow_show_archived)).first() + def get_book_read_archived(self, book_id, read_column, allow_show_archived=False): + if not read_column: + bd = (self.session.query(Books, ub.ReadBook.read_status, ub.ArchivedBook.is_archived).select_from(Books) + .join(ub.ReadBook, and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == book_id), + isouter=True)) + else: + try: + read_column = cc_classes[read_column] + bd = (self.session.query(Books, read_column.value, ub.ArchivedBook.is_archived).select_from(Books) + .join(read_column, read_column.book == book_id, + isouter=True)) + except (KeyError, AttributeError, IndexError): + log.error("Custom Column No.{} does not exist in calibre database".format(read_column)) + # Skip linking read column and return None instead of read status + bd = self.session.query(Books, None, ub.ArchivedBook.is_archived) + return (bd.filter(Books.id == book_id) + .join(ub.ArchivedBook, and_(Books.id == ub.ArchivedBook.book_id, + int(current_user.id) == ub.ArchivedBook.user_id), isouter=True) + .filter(self.common_filters(allow_show_archived)).first()) + def get_book_by_uuid(self, book_uuid): return self.session.query(Books).filter(Books.uuid == book_uuid).first() def get_book_format(self, book_id, file_format): return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == file_format).first() + def set_metadata_dirty(self, book_id): + if not self.session.query(Metadata_Dirtied).filter(Metadata_Dirtied.book == book_id).one_or_none(): + self.session.add(Metadata_Dirtied(book_id)) + + def delete_dirty_metadata(self, book_id): + try: + self.session.query(Metadata_Dirtied).filter(Metadata_Dirtied.book == book_id).delete() + self.session.commit() + except (OperationalError) as e: + self.session.rollback() + log.error("Database error: {}".format(e)) + # Language and content filters for displaying in the UI - def common_filters(self, allow_show_archived=False): + def common_filters(self, allow_show_archived=False, return_all_languages=False): if not allow_show_archived: - archived_books = ( - ub.session.query(ub.ArchivedBook) - .filter(ub.ArchivedBook.user_id == int(current_user.id)) - .filter(ub.ArchivedBook.is_archived == True) - .all() - ) + archived_books = (ub.session.query(ub.ArchivedBook) + .filter(ub.ArchivedBook.user_id == int(current_user.id)) + .filter(ub.ArchivedBook.is_archived == True) + .all()) archived_book_ids = [archived_book.book_id for archived_book in archived_books] archived_filter = Books.id.notin_(archived_book_ids) else: archived_filter = true() - if current_user.filter_language() != "all": - lang_filter = Books.languages.any(Languages.lang_code == current_user.filter_language()) - else: + if current_user.filter_language() == "all" or return_all_languages: lang_filter = true() + else: + lang_filter = Books.languages.any(Languages.lang_code == current_user.filter_language()) negtags_list = current_user.list_denied_tags() postags_list = current_user.list_allowed_tags() neg_content_tags_filter = false() if negtags_list == [''] else Books.tags.any(Tags.name.in_(negtags_list)) @@ -638,17 +715,17 @@ class CalibreDB(): pos_cc_list = current_user.allowed_column_value.split(',') pos_content_cc_filter = true() if pos_cc_list == [''] else \ getattr(Books, 'custom_column_' + str(self.config.config_restricted_column)). \ - any(cc_classes[self.config.config_restricted_column].value.in_(pos_cc_list)) + any(cc_classes[self.config.config_restricted_column].value.in_(pos_cc_list)) neg_cc_list = current_user.denied_column_value.split(',') neg_content_cc_filter = false() if neg_cc_list == [''] else \ getattr(Books, 'custom_column_' + str(self.config.config_restricted_column)). \ - any(cc_classes[self.config.config_restricted_column].value.in_(neg_cc_list)) - except (KeyError, AttributeError): + any(cc_classes[self.config.config_restricted_column].value.in_(neg_cc_list)) + except (KeyError, AttributeError, IndexError): pos_content_cc_filter = false() neg_content_cc_filter = true() - log.error(u"Custom Column No.%d is not existing in calibre database", - self.config.config_restricted_column) - flash(_("Custom Column No.%(column)d is not existing in calibre database", + log.error("Custom Column No.{} does not exist in calibre database".format( + self.config.config_restricted_column)) + flash(_("Custom Column No.%(column)d does not exist in calibre database", column=self.config.config_restricted_column), category="error") @@ -658,10 +735,32 @@ class CalibreDB(): return and_(lang_filter, pos_content_tags_filter, ~neg_content_tags_filter, pos_content_cc_filter, ~neg_content_cc_filter, archived_filter) + def generate_linked_query(self, config_read_column, database): + if not config_read_column: + query = (self.session.query(database, ub.ArchivedBook.is_archived, ub.ReadBook.read_status) + .select_from(Books) + .outerjoin(ub.ReadBook, + and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == Books.id))) + else: + try: + read_column = cc_classes[config_read_column] + query = (self.session.query(database, ub.ArchivedBook.is_archived, read_column.value) + .select_from(Books) + .outerjoin(read_column, read_column.book == Books.id)) + except (KeyError, AttributeError, IndexError): + log.error("Custom Column No.{} does not exist in calibre database".format(config_read_column)) + # Skip linking read column and return None instead of read status + query = self.session.query(database, None, ub.ArchivedBook.is_archived) + return query.outerjoin(ub.ArchivedBook, and_(Books.id == ub.ArchivedBook.book_id, + int(current_user.id) == ub.ArchivedBook.user_id)) + @staticmethod - def get_checkbox_sorted(inputlist, state, offset, limit, order): + def get_checkbox_sorted(inputlist, state, offset, limit, order, combo=False): outcome = list() - elementlist = {ele.id: ele for ele in inputlist} + if combo: + elementlist = {ele[0].id: ele for ele in inputlist} + else: + elementlist = {ele.id: ele for ele in inputlist} for entry in state: try: outcome.append(elementlist[entry]) @@ -675,33 +774,42 @@ class CalibreDB(): return outcome[offset:offset + limit] # Fill indexpage with all requested data from database - def fill_indexpage(self, page, pagesize, database, db_filter, order, *join): - return self.fill_indexpage_with_archived_books(page, pagesize, database, db_filter, order, False, *join) + def fill_indexpage(self, page, pagesize, database, db_filter, order, + join_archive_read=False, config_read_column=0, *join): + return self.fill_indexpage_with_archived_books(page, database, pagesize, db_filter, order, False, + join_archive_read, config_read_column, *join) - def fill_indexpage_with_archived_books(self, page, pagesize, database, db_filter, order, allow_show_archived, - *join): + def fill_indexpage_with_archived_books(self, page, database, pagesize, db_filter, order, allow_show_archived, + join_archive_read, config_read_column, *join): pagesize = pagesize or self.config.config_books_per_page if current_user.show_detail_random(): - randm = self.session.query(Books) \ - .filter(self.common_filters(allow_show_archived)) \ - .order_by(func.random()) \ - .limit(self.config.config_random_books).all() + random_query = self.generate_linked_query(config_read_column, database) + randm = (random_query.filter(self.common_filters(allow_show_archived)) + .order_by(func.random()) + .limit(self.config.config_random_books).all()) else: randm = false() + if join_archive_read: + query = self.generate_linked_query(config_read_column, database) + else: + query = self.session.query(database) off = int(int(pagesize) * (page - 1)) - query = self.session.query(database) - if len(join) == 6: - query = query.outerjoin(join[0], join[1]).outerjoin(join[2]).outerjoin(join[3], join[4]).outerjoin(join[5]) - if len(join) == 5: - query = query.outerjoin(join[0], join[1]).outerjoin(join[2]).outerjoin(join[3], join[4]) - if len(join) == 4: - query = query.outerjoin(join[0], join[1]).outerjoin(join[2]).outerjoin(join[3]) - if len(join) == 3: - query = query.outerjoin(join[0], join[1]).outerjoin(join[2]) - elif len(join) == 2: - query = query.outerjoin(join[0], join[1]) - elif len(join) == 1: - query = query.outerjoin(join[0]) + + indx = len(join) + element = 0 + while indx: + if indx >= 3: + query = query.outerjoin(join[element], join[element+1]).outerjoin(join[element+2]) + indx -= 3 + element += 3 + elif indx == 2: + query = query.outerjoin(join[element], join[element+1]) + indx -= 2 + element += 2 + elif indx == 1: + query = query.outerjoin(join[element]) + indx -= 1 + element += 1 query = query.filter(db_filter)\ .filter(self.common_filters(allow_show_archived)) entries = list() @@ -711,29 +819,48 @@ class CalibreDB(): len(query.all())) entries = query.order_by(*order).offset(off).limit(pagesize).all() except Exception as ex: - log.debug_or_exception(ex) - #for book in entries: - # book = self.order_authors(book) + log.error_or_exception(ex) + # display authors in right order + entries = self.order_authors(entries, True, join_archive_read) return entries, randm, pagination # Orders all Authors in the list according to authors sort - def order_authors(self, entry): - sort_authors = entry.author_sort.split('&') - authors_ordered = list() - error = False - ids = [a.id for a in entry.authors] - for auth in sort_authors: - results = self.session.query(Authors).filter(Authors.sort == auth.lstrip().strip()).all() - # ToDo: How to handle not found authorname - if not len(results): - error = True - break - for r in results: - if r.id in ids: - authors_ordered.append(r) - if not error: - entry.authors = authors_ordered - return entry + def order_authors(self, entries, list_return=False, combined=False): + # entries_copy = copy.deepcopy(entries) + # entries_copy =[] + for entry in entries: + if combined: + sort_authors = entry.Books.author_sort.split('&') + ids = [a.id for a in entry.Books.authors] + + else: + sort_authors = entry.author_sort.split('&') + ids = [a.id for a in entry.authors] + authors_ordered = list() + # error = False + for auth in sort_authors: + results = self.session.query(Authors).filter(Authors.sort == auth.lstrip().strip()).all() + # ToDo: How to handle not found author name + if not len(results): + log.error("Author {} not found to display name in right order".format(auth.strip())) + # error = True + break + for r in results: + if r.id in ids: + authors_ordered.append(r) + ids.remove(r.id) + for author_id in ids: + result = self.session.query(Authors).filter(Authors.id == author_id).first() + authors_ordered.append(result) + + if list_return: + if combined: + entry.Books.authors = authors_ordered + else: + entry.ordered_authors = authors_ordered + else: + return authors_ordered + return entries def get_typeahead(self, database, query, replace=('', ''), tag_filter=true()): query = query or '' @@ -747,21 +874,21 @@ class CalibreDB(): def check_exists_book(self, authr, title): self.session.connection().connection.connection.create_function("lower", 1, lcase) q = list() - authorterms = re.split(r'\s*&\s*', authr) - for authorterm in authorterms: - q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + authorterm + "%"))) + author_terms = re.split(r'\s*&\s*', authr) + for author_term in author_terms: + q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + author_term + "%"))) return self.session.query(Books) \ .filter(and_(Books.authors.any(and_(*q)), func.lower(Books.title).ilike("%" + title + "%"))).first() - def search_query(self, term, *join): + def search_query(self, term, config, *join): term.strip().lower() self.session.connection().connection.connection.create_function("lower", 1, lcase) q = list() - authorterms = re.split("[, ]+", term) - for authorterm in authorterms: - q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + authorterm + "%"))) - query = self.session.query(Books) + author_terms = re.split("[, ]+", term) + for author_term in author_terms: + q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + author_term + "%"))) + query = self.generate_linked_query(config.config_read_column, Books) if len(join) == 6: query = query.outerjoin(join[0], join[1]).outerjoin(join[2]).outerjoin(join[3], join[4]).outerjoin(join[5]) if len(join) == 3: @@ -770,19 +897,42 @@ class CalibreDB(): query = query.outerjoin(join[0], join[1]) elif len(join) == 1: query = query.outerjoin(join[0]) - return query.filter(self.common_filters(True)).filter( - or_(Books.tags.any(func.lower(Tags.name).ilike("%" + term + "%")), - Books.series.any(func.lower(Series.name).ilike("%" + term + "%")), - Books.authors.any(and_(*q)), - Books.publishers.any(func.lower(Publishers.name).ilike("%" + term + "%")), - func.lower(Books.title).ilike("%" + term + "%") - )) + + cc = self.get_cc_columns(config, filter_config_custom_read=True) + filter_expression = [Books.tags.any(func.lower(Tags.name).ilike("%" + term + "%")), + Books.series.any(func.lower(Series.name).ilike("%" + term + "%")), + Books.authors.any(and_(*q)), + Books.publishers.any(func.lower(Publishers.name).ilike("%" + term + "%")), + func.lower(Books.title).ilike("%" + term + "%")] + for c in cc: + if c.datatype not in ["datetime", "rating", "bool", "int", "float"]: + filter_expression.append( + getattr(Books, + 'custom_column_' + str(c.id)).any( + func.lower(cc_classes[c.id].value).ilike("%" + term + "%"))) + return query.filter(self.common_filters(True)).filter(or_(*filter_expression)) + + def get_cc_columns(self, config, filter_config_custom_read=False): + tmp_cc = self.session.query(CustomColumns).filter(CustomColumns.datatype.notin_(cc_exceptions)).all() + cc = [] + r = None + if config.config_columns_to_ignore: + r = re.compile(config.config_columns_to_ignore) + + for col in tmp_cc: + if filter_config_custom_read and config.config_read_column and config.config_read_column == col.id: + continue + if r and r.match(col.name): + continue + cc.append(col) + + return cc # read search results from calibre-database and return it (function is used for feed and simple search - def get_search_results(self, term, offset=None, order=None, limit=None, *join): + def get_search_results(self, term, config, offset=None, order=None, limit=None, *join): order = order[0] if order else [Books.sort] pagination = None - result = self.search_query(term, *join).order_by(*order).all() + result = self.search_query(term, config, *join).order_by(*order).all() result_count = len(result) if offset != None and limit != None: offset = int(offset) @@ -792,22 +942,44 @@ class CalibreDB(): offset = 0 limit_all = result_count - ub.store_ids(result) - return result[offset:limit_all], result_count, pagination + ub.store_combo_ids(result) + entries = self.order_authors(result[offset:limit_all], list_return=True, combined=True) + + return entries, result_count, pagination # Creates for all stored languages a translated speaking name in the array for the UI - def speaking_language(self, languages=None): - from . import get_locale + def speaking_language(self, languages=None, return_all_languages=False, with_count=False, reverse_order=False): - if not languages: - languages = self.session.query(Languages) \ - .join(books_languages_link) \ - .join(Books) \ - .filter(self.common_filters()) \ - .group_by(text('books_languages_link.lang_code')).all() - for lang in languages: - lang.name = isoLanguages.get_language_name(get_locale(), lang.lang_code) - return languages + if with_count: + if not languages: + languages = self.session.query(Languages, func.count('books_languages_link.book'))\ + .join(books_languages_link).join(Books)\ + .filter(self.common_filters(return_all_languages=return_all_languages)) \ + .group_by(text('books_languages_link.lang_code')).all() + tags = list() + for lang in languages: + tag = Category(isoLanguages.get_language_name(get_locale(), lang[0].lang_code), lang[0].lang_code) + tags.append([tag, lang[1]]) + # Append all books without language to list + if not return_all_languages: + no_lang_count = (self.session.query(Books) + .outerjoin(books_languages_link).outerjoin(Languages) + .filter(Languages.lang_code == None) + .filter(self.common_filters()) + .count()) + if no_lang_count: + tags.append([Category(_("None"), "none"), no_lang_count]) + return sorted(tags, key=lambda x: x[0].name.lower(), reverse=reverse_order) + else: + if not languages: + languages = self.session.query(Languages) \ + .join(books_languages_link) \ + .join(Books) \ + .filter(self.common_filters(return_all_languages=return_all_languages)) \ + .group_by(text('books_languages_link.lang_code')).all() + for lang in languages: + lang.name = isoLanguages.get_language_name(get_locale(), lang.lang_code) + return sorted(languages, key=lambda x: x.name, reverse=reverse_order) def update_title_sort(self, config, conn=None): # user defined sort function for calibre databases (Series, etc.) @@ -821,7 +993,10 @@ class CalibreDB(): return title.strip() conn = conn or self.session.connection().connection.connection - conn.create_function("title_sort", 1, _title_sort) + try: + conn.create_function("title_sort", 1, _title_sort) + except sqliteOperationalError: + pass @classmethod def dispose(cls): @@ -866,6 +1041,25 @@ def lcase(s): try: return unidecode.unidecode(s.lower()) except Exception as ex: - log = logger.create() - log.debug_or_exception(ex) + _log = logger.create() + _log.error_or_exception(ex) return s.lower() + + +class Category: + name = None + id = None + count = None + rating = None + + def __init__(self, name, cat_id, rating=None): + self.name = name + self.id = cat_id + self.rating = rating + self.count = 1 + +'''class Count: + count = None + + def __init__(self, count): + self.count = count''' diff --git a/cps/debug_info.py b/cps/debug_info.py index dd5e858ed..6cb30edba 100644 --- a/cps/debug_info.py +++ b/cps/debug_info.py @@ -22,6 +22,7 @@ import glob import zipfile import json from io import BytesIO +from flask_babel.speaklater import LazyString import os @@ -32,6 +33,13 @@ from .about import collect_stats log = logger.create() +class lazyEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, LazyString): + return str(obj) + # Let the base class default method raise the TypeError + return json.JSONEncoder.default(self, obj) + def assemble_logfiles(file_name): log_list = sorted(glob.glob(file_name + '*'), reverse=True) wfd = BytesIO() @@ -57,8 +65,8 @@ def send_debug(): file_list.remove(element) memory_zip = BytesIO() with zipfile.ZipFile(memory_zip, 'w', compression=zipfile.ZIP_DEFLATED) as zf: - zf.writestr('settings.txt', json.dumps(config.toDict())) - zf.writestr('libs.txt', json.dumps(collect_stats())) + zf.writestr('settings.txt', json.dumps(config.toDict(), sort_keys=True, indent=2)) + zf.writestr('libs.txt', json.dumps(collect_stats(), sort_keys=True, indent=2, cls=lazyEncoder)) for fp in file_list: zf.write(fp, os.path.basename(fp)) memory_zip.seek(0) diff --git a/cps/dep_check.py b/cps/dep_check.py index 12436d1d1..bc015756a 100644 --- a/cps/dep_check.py +++ b/cps/dep_check.py @@ -1,14 +1,16 @@ import os import re +import sys +import json from .constants import BASE_DIR try: - from importlib_metadata import version + from importlib.metadata import version importlib = True ImportNotFound = BaseException except ImportError: importlib = False - + version = None if not importlib: try: @@ -18,8 +20,16 @@ if not importlib: except ImportError as e: pkgresources = False -def load_dependencys(optional=False): + +def load_dependencies(optional=False): deps = list() + if getattr(sys, 'frozen', False): + pip_installed = os.path.join(BASE_DIR, ".pip_installed") + if os.path.exists(pip_installed): + with open(pip_installed) as f: + exe_deps = json.loads("".join(f.readlines())) + else: + return deps if importlib or pkgresources: if optional: req_path = os.path.join(BASE_DIR, "optional-requirements.txt") @@ -31,11 +41,14 @@ def load_dependencys(optional=False): if not line.startswith('#') and not line == '\n' and not line.startswith('git'): res = re.match(r'(.*?)([<=>\s]+)([\d\.]+),?\s?([<=>\s]+)?([\d\.]+)?', line.strip()) try: - if importlib: - dep_version = version(res.group(1)) + if getattr(sys, 'frozen', False): + dep_version = exe_deps[res.group(1).lower().replace('_', '-')] else: - dep_version = pkg_resources.get_distribution(res.group(1)).version - except ImportNotFound: + if importlib: + dep_version = version(res.group(1)) + else: + dep_version = pkg_resources.get_distribution(res.group(1)).version + except (ImportNotFound, KeyError): if optional: continue dep_version = "not installed" @@ -45,38 +58,38 @@ def load_dependencys(optional=False): def dependency_check(optional=False): d = list() - deps = load_dependencys(optional) + deps = load_dependencies(optional) for dep in deps: try: dep_version_int = [int(x) for x in dep[0].split('.')] low_check = [int(x) for x in dep[3].split('.')] high_check = [int(x) for x in dep[5].split('.')] except AttributeError: - high_check = None + high_check = [] except ValueError: d.append({'name': dep[1], - 'target': "available", - 'found': "Not available" - }) + 'target': "available", + 'found': "Not available" + }) continue if dep[2].strip() == "==": if dep_version_int != low_check: d.append({'name': dep[1], - 'found': dep[0], - "target": dep[2] + dep[3]}) + 'found': dep[0], + "target": dep[2] + dep[3]}) continue elif dep[2].strip() == ">=": if dep_version_int < low_check: d.append({'name': dep[1], - 'found': dep[0], - "target": dep[2] + dep[3]}) + 'found': dep[0], + "target": dep[2] + dep[3]}) continue elif dep[2].strip() == ">": if dep_version_int <= low_check: d.append({'name': dep[1], - 'found': dep[0], - "target": dep[2] + dep[3]}) + 'found': dep[0], + "target": dep[2] + dep[3]}) continue if dep[4] and dep[5]: if dep[4].strip() == "<": diff --git a/cps/editbooks.py b/cps/editbooks.py old mode 100644 new mode 100755 index 3403f46f7..9ce5ce479 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -25,54 +25,45 @@ from datetime import datetime import json from shutil import copyfile from uuid import uuid4 -from markupsafe import escape +from markupsafe import escape # dependency of flask +from functools import wraps + try: from lxml.html.clean import clean_html except ImportError: - pass - - -# Improve this to check if scholarly is available in a global way, like other pythonic libraries -try: - from scholarly import scholarly - have_scholar = True -except ImportError: - have_scholar = False + clean_html = None from flask import Blueprint, request, flash, redirect, url_for, abort, Markup, Response from flask_babel import gettext as _ +from flask_babel import lazy_gettext as N_ +from flask_babel import get_locale from flask_login import current_user, login_required -from sqlalchemy.exc import OperationalError, IntegrityError -from sqlite3 import OperationalError as sqliteOperationalError +from sqlalchemy.exc import OperationalError, IntegrityError, InterfaceError +from sqlalchemy.orm.exc import StaleDataError + from . import constants, logger, isoLanguages, gdriveutils, uploader, helper, kobo_sync_status -from . import config, get_locale, ub, db -from . import calibre_db +from . import config, ub, db, calibre_db from .services.worker import WorkerThread from .tasks.upload import TaskUpload from .render_template import render_title_template from .usermanagement import login_required_if_no_ano - -try: - from functools import wraps -except ImportError: - pass # We're not using Python 3 +from .kobo_sync_status import change_archived_books - - -editbook = Blueprint('editbook', __name__) +editbook = Blueprint('edit-book', __name__) log = logger.create() def upload_required(f): @wraps(f) def inner(*args, **kwargs): - if current_user.role_upload() or current_user.role_admin(): + if current_user.role_upload(): return f(*args, **kwargs) abort(403) return inner + def edit_required(f): @wraps(f) def inner(*args, **kwargs): @@ -82,177 +73,697 @@ def edit_required(f): return inner -def search_objects_remove(db_book_object, db_type, input_elements): - del_elements = [] - for c_elements in db_book_object: - found = False - if db_type == 'languages': - type_elements = c_elements.lang_code - elif db_type == 'custom': - type_elements = c_elements.value - else: - type_elements = c_elements.name - for inp_element in input_elements: - if inp_element.lower() == type_elements.lower(): - # if inp_element == type_elements: - found = True - break - # if the element was not found in the new list, add it to remove list - if not found: - del_elements.append(c_elements) - return del_elements - -def search_objects_add(db_book_object, db_type, input_elements): - add_elements = [] - for inp_element in input_elements: - found = False - for c_elements in db_book_object: - if db_type == 'languages': - type_elements = c_elements.lang_code - elif db_type == 'custom': - type_elements = c_elements.value - else: - type_elements = c_elements.name - if inp_element.lower() == type_elements.lower(): # Lowercase check - found = True - break - if not found: - add_elements.append(inp_element) - return add_elements - - -def remove_objects(db_book_object, db_session, del_elements): - changed = False - if len(del_elements) > 0: - for del_element in del_elements: - db_book_object.remove(del_element) - changed = True - if len(del_element.books) == 0: - db_session.delete(del_element) - return changed - -def add_objects(db_book_object, db_object, db_session, db_type, add_elements): - changed = False - if db_type == 'languages': - db_filter = db_object.lang_code - elif db_type == 'custom': - db_filter = db_object.value - else: - db_filter = db_object.name - for add_element in add_elements: - # check if a element with that name exists - db_element = db_session.query(db_object).filter(db_filter == add_element).first() - # if no element is found add it - # if new_element is None: - if db_type == 'author': - new_element = db_object(add_element, helper.get_sorted_author(add_element.replace('|', ',')), "") - elif db_type == 'series': - new_element = db_object(add_element, add_element) - elif db_type == 'custom': - new_element = db_object(value=add_element) - elif db_type == 'publisher': - new_element = db_object(add_element, None) - else: # db_type should be tag or language - new_element = db_object(add_element) - if db_element is None: - changed = True - db_session.add(new_element) - db_book_object.append(new_element) - else: - db_element = create_objects_for_addition(db_element, add_element, db_type) - changed = True - # add element to book - changed = True - db_book_object.append(db_element) - return changed - - -def create_objects_for_addition(db_element, add_element, db_type): - if db_type == 'custom': - if db_element.value != add_element: - db_element.value = add_element # ToDo: Before new_element, but this is not plausible - elif db_type == 'languages': - if db_element.lang_code != add_element: - db_element.lang_code = add_element - elif db_type == 'series': - if db_element.name != add_element: - db_element.name = add_element - db_element.sort = add_element - elif db_type == 'author': - if db_element.name != add_element: - db_element.name = add_element - db_element.sort = add_element.replace('|', ',') - elif db_type == 'publisher': - if db_element.name != add_element: - db_element.name = add_element - db_element.sort = None - elif db_element.name != add_element: - db_element.name = add_element - return db_element - - -# Modifies different Database objects, first check if elements if elements have to be deleted, -# because they are no longer used, than check if elements have to be added to database -def modify_database_object(input_elements, db_book_object, db_object, db_session, db_type): - # passing input_elements not as a list may lead to undesired results - if not isinstance(input_elements, list): - raise TypeError(str(input_elements) + " should be passed as a list") - input_elements = [x for x in input_elements if x != ''] - # we have all input element (authors, series, tags) names now - # 1. search for elements to remove - del_elements = search_objects_remove(db_book_object, db_type, input_elements) - # 2. search for elements that need to be added - add_elements = search_objects_add(db_book_object, db_type, input_elements) - # if there are elements to remove, we remove them now - changed = remove_objects(db_book_object, db_session, del_elements) - # if there are elements to add, we add them now! - if len(add_elements) > 0: - changed |= add_objects(db_book_object, db_object, db_session, db_type, add_elements) - return changed - - -def modify_identifiers(input_identifiers, db_identifiers, db_session): - """Modify Identifiers to match input information. - input_identifiers is a list of read-to-persist Identifiers objects. - db_identifiers is a list of already persisted list of Identifiers objects.""" - changed = False - error = False - input_dict = dict([(identifier.type.lower(), identifier) for identifier in input_identifiers]) - if len(input_identifiers) != len(input_dict): - error = True - db_dict = dict([(identifier.type.lower(), identifier) for identifier in db_identifiers ]) - # delete db identifiers not present in input or modify them with input val - for identifier_type, identifier in db_dict.items(): - if identifier_type not in input_dict.keys(): - db_session.delete(identifier) - changed = True - else: - input_identifier = input_dict[identifier_type] - identifier.type = input_identifier.type - identifier.val = input_identifier.val - # add input identifiers not present in db - for identifier_type, identifier in input_dict.items(): - if identifier_type not in db_dict.keys(): - db_session.add(identifier) - changed = True - return changed, error - -@editbook.route("/ajax/delete/") +@editbook.route("/ajax/delete/", methods=["POST"]) @login_required def delete_book_from_details(book_id): - return Response(delete_book(book_id, "", True), mimetype='application/json') + return Response(delete_book_from_table(book_id, "", True), mimetype='application/json') -@editbook.route("/delete/", defaults={'book_format': ""}) -@editbook.route("/delete//") +@editbook.route("/delete/", defaults={'book_format': ""}, methods=["POST"]) +@editbook.route("/delete//", methods=["POST"]) @login_required def delete_book_ajax(book_id, book_format): - return delete_book(book_id, book_format, False) + return delete_book_from_table(book_id, book_format, False) + + +@editbook.route("/admin/book/", methods=['GET']) +@login_required_if_no_ano +@edit_required +def show_edit_book(book_id): + return render_edit_book(book_id) + + +@editbook.route("/admin/book/", methods=['POST']) +@login_required_if_no_ano +@edit_required +def edit_book(book_id): + modify_date = False + edit_error = False + + # create the function for sorting... + calibre_db.update_title_sort(config) + + book = calibre_db.get_filtered_book(book_id, allow_show_archived=True) + # Book not found + if not book: + flash(_("Oops! Selected book is unavailable. File does not exist or is not accessible"), + category="error") + return redirect(url_for("web.index")) + + to_save = request.form.to_dict() + + try: + # Update folder of book on local disk + edited_books_id = None + title_author_error = None + # handle book title change + title_change = handle_title_on_edit(book, to_save["book_title"]) + # handle book author change + input_authors, author_change, renamed = handle_author_on_edit(book, to_save["author_name"]) + if author_change or title_change: + edited_books_id = book.id + modify_date = True + title_author_error = helper.update_dir_structure(edited_books_id, + config.config_calibre_dir, + input_authors[0], + renamed_author=renamed) + if title_author_error: + flash(title_author_error, category="error") + calibre_db.session.rollback() + book = calibre_db.get_filtered_book(book_id, allow_show_archived=True) + + # handle upload other formats from local disk + meta = upload_single_file(request, book, book_id) + # only merge metadata if file was uploaded and no error occurred (meta equals not false or none) + if meta: + merge_metadata(to_save, meta) + # handle upload covers from local disk + cover_upload_success = upload_cover(request, book) + if cover_upload_success: + book.has_cover = 1 + modify_date = True + + # upload new covers or new file formats to google drive + if config.config_use_google_drive: + gdriveutils.updateGdriveCalibreFromLocal() + + if to_save.get("cover_url", None): + if not current_user.role_upload(): + edit_error = True + flash(_("User has no rights to upload cover"), category="error") + if to_save["cover_url"].endswith('/static/generic_cover.jpg'): + book.has_cover = 0 + else: + result, error = helper.save_cover_from_url(to_save["cover_url"].strip(), book.path) + if result is True: + book.has_cover = 1 + modify_date = True + helper.replace_cover_thumbnail_cache(book.id) + else: + flash(error, category="error") + + # Add default series_index to book + modify_date |= edit_book_series_index(to_save["series_index"], book) + # Handle book comments/description + modify_date |= edit_book_comments(Markup(to_save['description']).unescape(), book) + # Handle identifiers + input_identifiers = identifier_list(to_save, book) + modification, warning = modify_identifiers(input_identifiers, book.identifiers, calibre_db.session) + if warning: + flash(_("Identifiers are not Case Sensitive, Overwriting Old Identifier"), category="warning") + modify_date |= modification + # Handle book tags + modify_date |= edit_book_tags(to_save['tags'], book) + # Handle book series + modify_date |= edit_book_series(to_save["series"], book) + # handle book publisher + modify_date |= edit_book_publisher(to_save['publisher'], book) + # handle book languages + try: + modify_date |= edit_book_languages(to_save['languages'], book) + except ValueError as e: + flash(str(e), category="error") + edit_error = True + # handle book ratings + modify_date |= edit_book_ratings(to_save, book) + # handle cc data + modify_date |= edit_all_cc_data(book_id, book, to_save) + + if to_save.get("pubdate", None): + try: + book.pubdate = datetime.strptime(to_save["pubdate"], "%Y-%m-%d") + except ValueError as e: + book.pubdate = db.Books.DEFAULT_PUBDATE + flash(str(e), category="error") + edit_error = True + else: + book.pubdate = db.Books.DEFAULT_PUBDATE + + if modify_date: + book.last_modified = datetime.utcnow() + kobo_sync_status.remove_synced_book(edited_books_id, all=True) + calibre_db.set_metadata_dirty(book.id) + + calibre_db.session.merge(book) + calibre_db.session.commit() + if config.config_use_google_drive: + gdriveutils.updateGdriveCalibreFromLocal() + if meta is not False \ + and edit_error is not True \ + and title_author_error is not True \ + and cover_upload_success is not False: + flash(_("Metadata successfully updated"), category="success") + if "detail_view" in to_save: + return redirect(url_for('web.show_book', book_id=book.id)) + else: + return render_edit_book(book_id) + except ValueError as e: + log.error_or_exception("Error: {}".format(e)) + calibre_db.session.rollback() + flash(str(e), category="error") + return redirect(url_for('web.show_book', book_id=book.id)) + except (OperationalError, IntegrityError, StaleDataError, InterfaceError) as e: + log.error_or_exception("Database error: {}".format(e)) + calibre_db.session.rollback() + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") + return redirect(url_for('web.show_book', book_id=book.id)) + except Exception as ex: + log.error_or_exception(ex) + calibre_db.session.rollback() + flash(_("Error editing book: {}".format(ex)), category="error") + return redirect(url_for('web.show_book', book_id=book.id)) + + +@editbook.route("/upload", methods=["POST"]) +@login_required_if_no_ano +@upload_required +def upload(): + if not config.config_uploading: + abort(404) + if request.method == 'POST' and 'btn-upload' in request.files: + for requested_file in request.files.getlist("btn-upload"): + try: + modify_date = False + # create the function for sorting... + calibre_db.update_title_sort(config) + calibre_db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4())) + + meta, error = file_handling_on_upload(requested_file) + if error: + return error + + db_book, input_authors, title_dir, renamed_authors = create_book_on_upload(modify_date, meta) + + # Comments need book id therefore only possible after flush + modify_date |= edit_book_comments(Markup(meta.description).unescape(), db_book) + + book_id = db_book.id + title = db_book.title + if config.config_use_google_drive: + helper.upload_new_file_gdrive(book_id, + input_authors[0], + renamed_authors, + title, + title_dir, + meta.file_path, + meta.extension.lower()) + else: + error = helper.update_dir_structure(book_id, + config.config_calibre_dir, + input_authors[0], + meta.file_path, + title_dir + meta.extension.lower(), + renamed_author=renamed_authors) + + move_coverfile(meta, db_book) + + if modify_date: + calibre_db.set_metadata_dirty(book_id) + # save data to database, reread data + calibre_db.session.commit() + + if config.config_use_google_drive: + gdriveutils.updateGdriveCalibreFromLocal() + if error: + flash(error, category="error") + link = '{}'.format(url_for('web.show_book', book_id=book_id), escape(title)) + upload_text = N_("File %(file)s uploaded", file=link) + WorkerThread.add(current_user.name, TaskUpload(upload_text, escape(title))) + helper.add_book_to_thumbnail_cache(book_id) + + if len(request.files.getlist("btn-upload")) < 2: + if current_user.role_edit() or current_user.role_admin(): + resp = {"location": url_for('edit-book.show_edit_book', book_id=book_id)} + return Response(json.dumps(resp), mimetype='application/json') + else: + resp = {"location": url_for('web.show_book', book_id=book_id)} + return Response(json.dumps(resp), mimetype='application/json') + except (OperationalError, IntegrityError, StaleDataError) as e: + calibre_db.session.rollback() + log.error_or_exception("Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") + return Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json') + + +@editbook.route("/admin/book/convert/", methods=['POST']) +@login_required_if_no_ano +@edit_required +def convert_bookformat(book_id): + # check to see if we have form fields to work with - if not send user back + book_format_from = request.form.get('book_format_from', None) + book_format_to = request.form.get('book_format_to', None) + + if (book_format_from is None) or (book_format_to is None): + flash(_("Source or destination format for conversion missing"), category="error") + return redirect(url_for('edit-book.show_edit_book', book_id=book_id)) + + log.info('converting: book id: %s from: %s to: %s', book_id, book_format_from, book_format_to) + rtn = helper.convert_book_format(book_id, config.config_calibre_dir, book_format_from.upper(), + book_format_to.upper(), current_user.name) + + if rtn is None: + flash(_("Book successfully queued for converting to %(book_format)s", + book_format=book_format_to), + category="success") + else: + flash(_("There was an error converting this book: %(res)s", res=rtn), category="error") + return redirect(url_for('edit-book.show_edit_book', book_id=book_id)) + + +@editbook.route("/ajax/getcustomenum/") +@login_required +def table_get_custom_enum(c_id): + ret = list() + cc = (calibre_db.session.query(db.CustomColumns) + .filter(db.CustomColumns.id == c_id) + .filter(db.CustomColumns.datatype.notin_(db.cc_exceptions)).one_or_none()) + ret.append({'value': "", 'text': ""}) + for idx, en in enumerate(cc.get_display_dict()['enum_values']): + ret.append({'value': en, 'text': en}) + return json.dumps(ret) + + +@editbook.route("/ajax/editbooks/", methods=['POST']) +@login_required_if_no_ano +@edit_required +def edit_list_book(param): + vals = request.form.to_dict() + book = calibre_db.get_book(vals['pk']) + sort_param = "" + ret = "" + try: + if param == 'series_index': + edit_book_series_index(vals['value'], book) + ret = Response(json.dumps({'success': True, 'newValue': book.series_index}), mimetype='application/json') + elif param == 'tags': + edit_book_tags(vals['value'], book) + ret = Response(json.dumps({'success': True, 'newValue': ', '.join([tag.name for tag in book.tags])}), + mimetype='application/json') + elif param == 'series': + edit_book_series(vals['value'], book) + ret = Response(json.dumps({'success': True, 'newValue': ', '.join([serie.name for serie in book.series])}), + mimetype='application/json') + elif param == 'publishers': + edit_book_publisher(vals['value'], book) + ret = Response(json.dumps({'success': True, + 'newValue': ', '.join([publisher.name for publisher in book.publishers])}), + mimetype='application/json') + elif param == 'languages': + invalid = list() + edit_book_languages(vals['value'], book, invalid=invalid) + if invalid: + ret = Response(json.dumps({'success': False, + 'msg': 'Invalid languages in request: {}'.format(','.join(invalid))}), + mimetype='application/json') + else: + lang_names = list() + for lang in book.languages: + lang_names.append(isoLanguages.get_language_name(get_locale(), lang.lang_code)) + ret = Response(json.dumps({'success': True, 'newValue': ', '.join(lang_names)}), + mimetype='application/json') + elif param == 'author_sort': + book.author_sort = vals['value'] + ret = Response(json.dumps({'success': True, 'newValue': book.author_sort}), + mimetype='application/json') + elif param == 'title': + sort_param = book.sort + if handle_title_on_edit(book, vals.get('value', "")): + rename_error = helper.update_dir_structure(book.id, config.config_calibre_dir) + if not rename_error: + ret = Response(json.dumps({'success': True, 'newValue': book.title}), + mimetype='application/json') + else: + ret = Response(json.dumps({'success': False, + 'msg': rename_error}), + mimetype='application/json') + elif param == 'sort': + book.sort = vals['value'] + ret = Response(json.dumps({'success': True, 'newValue': book.sort}), + mimetype='application/json') + elif param == 'comments': + edit_book_comments(vals['value'], book) + ret = Response(json.dumps({'success': True, 'newValue': book.comments[0].text}), + mimetype='application/json') + elif param == 'authors': + input_authors, __, renamed = handle_author_on_edit(book, vals['value'], vals.get('checkA', None) == "true") + rename_error = helper.update_dir_structure(book.id, config.config_calibre_dir, input_authors[0], + renamed_author=renamed) + if not rename_error: + ret = Response(json.dumps({ + 'success': True, + 'newValue': ' & '.join([author.replace('|', ',') for author in input_authors])}), + mimetype='application/json') + else: + ret = Response(json.dumps({'success': False, + 'msg': rename_error}), + mimetype='application/json') + elif param == 'is_archived': + is_archived = change_archived_books(book.id, vals['value'] == "True", + message="Book {} archive bit set to: {}".format(book.id, vals['value'])) + if is_archived: + kobo_sync_status.remove_synced_book(book.id) + return "" + elif param == 'read_status': + ret = helper.edit_book_read_status(book.id, vals['value'] == "True") + if ret: + return ret, 400 + elif param.startswith("custom_column_"): + new_val = dict() + new_val[param] = vals['value'] + edit_single_cc_data(book.id, book, param[14:], new_val) + # ToDo: Very hacky find better solution + if vals['value'] in ["True", "False"]: + ret = "" + else: + ret = Response(json.dumps({'success': True, 'newValue': vals['value']}), + mimetype='application/json') + else: + return _("Parameter not found"), 400 + book.last_modified = datetime.utcnow() + + calibre_db.session.commit() + # revert change for sort if automatic fields link is deactivated + if param == 'title' and vals.get('checkT') == "false": + book.sort = sort_param + calibre_db.session.commit() + except (OperationalError, IntegrityError, StaleDataError) as e: + calibre_db.session.rollback() + log.error_or_exception("Database error: {}".format(e)) + ret = Response(json.dumps({'success': False, + 'msg': 'Database error: {}'.format(e.orig)}), + mimetype='application/json') + return ret + + +@editbook.route("/ajax/sort_value//") +@login_required +def get_sorted_entry(field, bookid): + if field in ['title', 'authors', 'sort', 'author_sort']: + book = calibre_db.get_filtered_book(bookid) + if book: + if field == 'title': + return json.dumps({'sort': book.sort}) + elif field == 'authors': + return json.dumps({'author_sort': book.author_sort}) + if field == 'sort': + return json.dumps({'sort': book.title}) + if field == 'author_sort': + return json.dumps({'author_sort': book.author}) + return "" + + +@editbook.route("/ajax/simulatemerge", methods=['POST']) +@login_required +@edit_required +def simulate_merge_list_book(): + vals = request.get_json().get('Merge_books') + if vals: + to_book = calibre_db.get_book(vals[0]).title + vals.pop(0) + if to_book: + from_book = [] + for book_id in vals: + from_book.append(calibre_db.get_book(book_id).title) + return json.dumps({'to': to_book, 'from': from_book}) + return "" + + +@editbook.route("/ajax/mergebooks", methods=['POST']) +@login_required +@edit_required +def merge_list_book(): + vals = request.get_json().get('Merge_books') + to_file = list() + if vals: + # load all formats from target book + to_book = calibre_db.get_book(vals[0]) + vals.pop(0) + if to_book: + for file in to_book.data: + to_file.append(file.format) + to_name = helper.get_valid_filename(to_book.title, + chars=96) + ' - ' + helper.get_valid_filename(to_book.authors[0].name, + chars=96) + for book_id in vals: + from_book = calibre_db.get_book(book_id) + if from_book: + for element in from_book.data: + if element.format not in to_file: + # create new data entry with: book_id, book_format, uncompressed_size, name + filepath_new = os.path.normpath(os.path.join(config.config_calibre_dir, + to_book.path, + to_name + "." + element.format.lower())) + filepath_old = os.path.normpath(os.path.join(config.config_calibre_dir, + from_book.path, + element.name + "." + element.format.lower())) + copyfile(filepath_old, filepath_new) + to_book.data.append(db.Data(to_book.id, + element.format, + element.uncompressed_size, + to_name)) + delete_book_from_table(from_book.id, "", True) + return json.dumps({'success': True}) + return "" + + +@editbook.route("/ajax/xchange", methods=['POST']) +@login_required +@edit_required +def table_xchange_author_title(): + vals = request.get_json().get('xchange') + edited_books_id = False + if vals: + for val in vals: + modify_date = False + book = calibre_db.get_book(val) + authors = book.title + book.authors = calibre_db.order_authors([book]) + author_names = [] + for authr in book.authors: + author_names.append(authr.name.replace('|', ',')) + + title_change = handle_title_on_edit(book, " ".join(author_names)) + input_authors, author_change, renamed = handle_author_on_edit(book, authors) + if author_change or title_change: + edited_books_id = book.id + modify_date = True + + if config.config_use_google_drive: + gdriveutils.updateGdriveCalibreFromLocal() + + if edited_books_id: + # toDo: Handle error + edit_error = helper.update_dir_structure(edited_books_id, config.config_calibre_dir, input_authors[0], + renamed_author=renamed) + if modify_date: + book.last_modified = datetime.utcnow() + calibre_db.set_metadata_dirty(book.id) + try: + calibre_db.session.commit() + except (OperationalError, IntegrityError, StaleDataError) as e: + calibre_db.session.rollback() + log.error_or_exception("Database error: %s", e) + return json.dumps({'success': False}) + + if config.config_use_google_drive: + gdriveutils.updateGdriveCalibreFromLocal() + return json.dumps({'success': True}) + return "" + + +def merge_metadata(to_save, meta): + if to_save.get('author_name', "") == _('Unknown'): + to_save['author_name'] = '' + if to_save.get('book_title', "") == _('Unknown'): + to_save['book_title'] = '' + for s_field, m_field in [ + ('tags', 'tags'), ('author_name', 'author'), ('series', 'series'), + ('series_index', 'series_id'), ('languages', 'languages'), + ('book_title', 'title')]: + to_save[s_field] = to_save[s_field] or getattr(meta, m_field, '') + to_save["description"] = to_save["description"] or Markup( + getattr(meta, 'description', '')).unescape() + + +def identifier_list(to_save, book): + """Generate a list of Identifiers from form information""" + id_type_prefix = 'identifier-type-' + id_val_prefix = 'identifier-val-' + result = [] + for type_key, type_value in to_save.items(): + if not type_key.startswith(id_type_prefix): + continue + val_key = id_val_prefix + type_key[len(id_type_prefix):] + if val_key not in to_save.keys(): + continue + result.append(db.Identifiers(to_save[val_key], type_value, book.id)) + return result + + +def prepare_authors(authr): + # handle authors + input_authors = authr.split('&') + # handle_authors(input_authors) + input_authors = list(map(lambda it: it.strip().replace(',', '|'), input_authors)) + # Remove duplicates in authors list + input_authors = helper.uniq(input_authors) + + # we have all author names now + if input_authors == ['']: + input_authors = [_('Unknown')] # prevent empty Author + + renamed = list() + for in_aut in input_authors: + renamed_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == in_aut).first() + if renamed_author and in_aut != renamed_author.name: + renamed.append(renamed_author.name) + all_books = calibre_db.session.query(db.Books) \ + .filter(db.Books.authors.any(db.Authors.name == renamed_author.name)).all() + sorted_renamed_author = helper.get_sorted_author(renamed_author.name) + sorted_old_author = helper.get_sorted_author(in_aut) + for one_book in all_books: + one_book.author_sort = one_book.author_sort.replace(sorted_renamed_author, sorted_old_author) + return input_authors, renamed + + +def prepare_authors_on_upload(title, authr): + if title != _('Unknown') and authr != _('Unknown'): + entry = calibre_db.check_exists_book(authr, title) + if entry: + log.info("Uploaded book probably exists in library") + flash(_("Uploaded book probably exists in the library, consider to change before upload new: ") + + Markup(render_title_template('book_exists_flash.html', entry=entry)), category="warning") + + input_authors, renamed = prepare_authors(authr) + + sort_authors_list = list() + db_author = None + for inp in input_authors: + stored_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == inp).first() + if not stored_author: + if not db_author: + db_author = db.Authors(inp, helper.get_sorted_author(inp), "") + calibre_db.session.add(db_author) + calibre_db.session.commit() + sort_author = helper.get_sorted_author(inp) + else: + if not db_author: + db_author = stored_author + sort_author = stored_author.sort + sort_authors_list.append(sort_author) + sort_authors = ' & '.join(sort_authors_list) + return sort_authors, input_authors, db_author, renamed + + +def create_book_on_upload(modify_date, meta): + title = meta.title + authr = meta.author + sort_authors, input_authors, db_author, renamed_authors = prepare_authors_on_upload(title, authr) + + title_dir = helper.get_valid_filename(title, chars=96) + author_dir = helper.get_valid_filename(db_author.name, chars=96) + + # combine path and normalize path from Windows systems + path = os.path.join(author_dir, title_dir).replace('\\', '/') + + try: + pubdate = datetime.strptime(meta.pubdate[:10], "%Y-%m-%d") + except ValueError: + pubdate = datetime(101, 1, 1) + + # Calibre adds books with utc as timezone + db_book = db.Books(title, "", sort_authors, datetime.utcnow(), pubdate, + '1', datetime.utcnow(), path, meta.cover, db_author, [], "") + + modify_date |= modify_database_object(input_authors, db_book.authors, db.Authors, calibre_db.session, + 'author') + + # Add series_index to book + modify_date |= edit_book_series_index(meta.series_id, db_book) + + # add languages + invalid = [] + modify_date |= edit_book_languages(meta.languages, db_book, upload_mode=True, invalid=invalid) + if invalid: + for lang in invalid: + flash(_("'%(langname)s' is not a valid language", langname=lang), category="warning") + + # handle tags + modify_date |= edit_book_tags(meta.tags, db_book) + + # handle publisher + modify_date |= edit_book_publisher(meta.publisher, db_book) + + # handle series + modify_date |= edit_book_series(meta.series, db_book) + + # Add file to book + file_size = os.path.getsize(meta.file_path) + db_data = db.Data(db_book, meta.extension.upper()[1:], file_size, title_dir) + db_book.data.append(db_data) + calibre_db.session.add(db_book) + + # flush content, get db_book.id available + calibre_db.session.flush() + + # Handle identifiers now that db_book.id is available + identifier_list = [] + for type_key, type_value in meta.identifiers: + identifier_list.append(db.Identifiers(type_value, type_key, db_book.id)) + modification, warning = modify_identifiers(identifier_list, db_book.identifiers, calibre_db.session) + if warning: + flash(_("Identifiers are not Case Sensitive, Overwriting Old Identifier"), category="warning") + modify_date |= modification + + return db_book, input_authors, title_dir, renamed_authors + + +def file_handling_on_upload(requested_file): + # check if file extension is correct + if '.' in requested_file.filename: + file_ext = requested_file.filename.rsplit('.', 1)[-1].lower() + if file_ext not in constants.EXTENSIONS_UPLOAD and '' not in constants.EXTENSIONS_UPLOAD: + flash( + _("File extension '%(ext)s' is not allowed to be uploaded to this server", + ext=file_ext), category="error") + return None, Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json') + else: + flash(_('File to be uploaded must have an extension'), category="error") + return None, Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json') + + # extract metadata from file + try: + meta = uploader.upload(requested_file, config.config_rarfile_location) + except (IOError, OSError): + log.error("File %s could not saved to temp dir", requested_file.filename) + flash(_("File %(filename)s could not saved to temp dir", + filename=requested_file.filename), category="error") + return None, Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json') + return meta, None + + +def move_coverfile(meta, db_book): + # move cover to final directory, including book id + if meta.cover: + cover_file = meta.cover + else: + cover_file = os.path.join(constants.STATIC_DIR, 'generic_cover.jpg') + new_cover_path = os.path.join(config.config_calibre_dir, db_book.path) + try: + os.makedirs(new_cover_path, exist_ok=True) + copyfile(cover_file, os.path.join(new_cover_path, "cover.jpg")) + if meta.cover: + os.unlink(meta.cover) + except OSError as e: + log.error("Failed to move cover file %s: %s", new_cover_path, e) + flash(_("Failed to Move Cover File %(file)s: %(error)s", file=new_cover_path, + error=e), + category="error") def delete_whole_book(book_id, book): - # delete book from Shelfs, Downloads, Read list + # delete book from shelves, Downloads, Read list ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).delete() ub.session.query(ub.ReadBook).filter(ub.ReadBook.book_id == book_id).delete() ub.delete_download(book_id) @@ -260,14 +771,14 @@ def delete_whole_book(book_id, book): # check if only this book links to: # author, language, series, tags, custom columns - modify_database_object([u''], book.authors, db.Authors, calibre_db.session, 'author') + modify_database_object([''], book.authors, db.Authors, calibre_db.session, 'author') modify_database_object([u''], book.tags, db.Tags, calibre_db.session, 'tags') modify_database_object([u''], book.series, db.Series, calibre_db.session, 'series') modify_database_object([u''], book.languages, db.Languages, calibre_db.session, 'languages') modify_database_object([u''], book.publishers, db.Publishers, calibre_db.session, 'publishers') - cc = calibre_db.session.query(db.Custom_Columns). \ - filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() + cc = calibre_db.session.query(db.CustomColumns). \ + filter(db.CustomColumns.datatype.notin_(db.cc_exceptions)).all() for c in cc: cc_string = "custom_column_" + str(c.id) if not c.is_multiple: @@ -297,18 +808,18 @@ def delete_whole_book(book_id, book): calibre_db.session.query(db.Books).filter(db.Books.id == book_id).delete() -def render_delete_book_result(book_format, jsonResponse, warning, book_id): +def render_delete_book_result(book_format, json_response, warning, book_id): if book_format: - if jsonResponse: - return json.dumps([warning, {"location": url_for("editbook.edit_book", book_id=book_id), + if json_response: + return json.dumps([warning, {"location": url_for("edit-book.show_edit_book", book_id=book_id), "type": "success", "format": book_format, "message": _('Book Format Successfully Deleted')}]) else: flash(_('Book Format Successfully Deleted'), category="success") - return redirect(url_for('editbook.edit_book', book_id=book_id)) + return redirect(url_for('edit-book.show_edit_book', book_id=book_id)) else: - if jsonResponse: + if json_response: return json.dumps([warning, {"location": url_for('web.index'), "type": "success", "format": book_format, @@ -318,7 +829,7 @@ def render_delete_book_result(book_format, jsonResponse, warning, book_id): return redirect(url_for('web.index')) -def delete_book(book_id, book_format, jsonResponse): +def delete_book_from_table(book_id, book_format, json_response): warning = {} if current_user.role_delete_books(): book = calibre_db.get_book(book_id) @@ -326,20 +837,20 @@ def delete_book(book_id, book_format, jsonResponse): try: result, error = helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper()) if not result: - if jsonResponse: - return json.dumps([{"location": url_for("editbook.edit_book", book_id=book_id), - "type": "danger", - "format": "", - "message": error}]) + if json_response: + return json.dumps([{"location": url_for("edit-book.show_edit_book", book_id=book_id), + "type": "danger", + "format": "", + "message": error}]) else: flash(error, category="error") - return redirect(url_for('editbook.edit_book', book_id=book_id)) + return redirect(url_for('edit-book.show_edit_book', book_id=book_id)) if error: - if jsonResponse: - warning = {"location": url_for("editbook.edit_book", book_id=book_id), - "type": "warning", - "format": "", - "message": error} + if json_response: + warning = {"location": url_for("edit-book.show_edit_book", book_id=book_id), + "type": "warning", + "format": "", + "message": error} else: flash(error, category="warning") if not book_format: @@ -347,45 +858,57 @@ def delete_book(book_id, book_format, jsonResponse): else: calibre_db.session.query(db.Data).filter(db.Data.book == book.id).\ filter(db.Data.format == book_format).delete() + if book_format.upper() in ['KEPUB', 'EPUB', 'EPUB3']: + kobo_sync_status.remove_synced_book(book.id, True) calibre_db.session.commit() except Exception as ex: - log.debug_or_exception(ex) + log.error_or_exception(ex) calibre_db.session.rollback() - if jsonResponse: - return json.dumps([{"location": url_for("editbook.edit_book", book_id=book_id), + if json_response: + return json.dumps([{"location": url_for("edit-book.show_edit_book", book_id=book_id), "type": "danger", "format": "", "message": ex}]) else: flash(str(ex), category="error") - return redirect(url_for('editbook.edit_book', book_id=book_id)) + return redirect(url_for('edit-book.show_edit_book', book_id=book_id)) else: # book not found log.error('Book with id "%s" could not be deleted: not found', book_id) - return render_delete_book_result(book_format, jsonResponse, warning, book_id) + return render_delete_book_result(book_format, json_response, warning, book_id) + message = _("You are missing permissions to delete books") + if json_response: + return json.dumps({"location": url_for("edit-book.show_edit_book", book_id=book_id), + "type": "danger", + "format": "", + "message": message}) + else: + flash(message, category="error") + return redirect(url_for('edit-book.show_edit_book', book_id=book_id)) def render_edit_book(book_id): - cc = calibre_db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() + cc = calibre_db.session.query(db.CustomColumns).filter(db.CustomColumns.datatype.notin_(db.cc_exceptions)).all() book = calibre_db.get_filtered_book(book_id, allow_show_archived=True) if not book: - flash(_(u"Oops! Selected book title is unavailable. File does not exist or is not accessible"), category="error") + flash(_("Oops! Selected book is unavailable. File does not exist or is not accessible"), + category="error") return redirect(url_for("web.index")) for lang in book.languages: lang.language_name = isoLanguages.get_language_name(get_locale(), lang.lang_code) - book = calibre_db.order_authors(book) + book.authors = calibre_db.order_authors([book]) author_names = [] for authr in book.authors: author_names.append(authr.name.replace('|', ',')) - # Option for showing convertbook button - valid_source_formats=list() + # Option for showing convert_book button + valid_source_formats = list() allowed_conversion_formats = list() - kepub_possible=None + kepub_possible = None if config.config_converterpath: for file in book.data: if file.format.lower() in constants.EXTENSIONS_CONVERT_FROM: @@ -404,7 +927,7 @@ def render_edit_book(book_id): if kepub_possible: allowed_conversion_formats.append('kepub') return render_title_template('book_edit.html', book=book, authors=author_names, cc=cc, - title=_(u"edit metadata"), page="editbook", + title=_("edit metadata"), page="editbook", conversion_formats=allowed_conversion_formats, config=config, source_formats=valid_source_formats) @@ -412,18 +935,18 @@ def render_edit_book(book_id): def edit_book_ratings(to_save, book): changed = False - if to_save["rating"].strip(): + if to_save.get("rating", "").strip(): old_rating = False if len(book.ratings) > 0: old_rating = book.ratings[0].rating - ratingx2 = int(float(to_save["rating"]) * 2) - if ratingx2 != old_rating: + rating_x2 = int(float(to_save.get("rating", "")) * 2) + if rating_x2 != old_rating: changed = True - is_rating = calibre_db.session.query(db.Ratings).filter(db.Ratings.rating == ratingx2).first() + is_rating = calibre_db.session.query(db.Ratings).filter(db.Ratings.rating == rating_x2).first() if is_rating: book.ratings.append(is_rating) else: - new_rating = db.Ratings(rating=ratingx2) + new_rating = db.Ratings(rating=rating_x2) book.ratings.append(new_rating) if old_rating: book.ratings.remove(book.ratings[0]) @@ -433,6 +956,7 @@ def edit_book_ratings(to_save, book): changed = True return changed + def edit_book_tags(tags, book): input_tags = tags.split(',') input_tags = list(map(lambda it: it.strip(), input_tags)) @@ -449,48 +973,48 @@ def edit_book_series(series, book): def edit_book_series_index(series_index, book): # Add default series_index to book - modif_date = False + modify_date = False series_index = series_index or '1' if not series_index.replace('.', '', 1).isdigit(): flash(_("%(seriesindex)s is not a valid number, skipping", seriesindex=series_index), category="warning") return False - if book.series_index != series_index: + if str(book.series_index) != series_index: book.series_index = series_index - modif_date = True - return modif_date + modify_date = True + return modify_date # Handle book comments/description def edit_book_comments(comments, book): - modif_date = False + modify_date = False if comments: comments = clean_html(comments) if len(book.comments): if book.comments[0].text != comments: book.comments[0].text = comments - modif_date = True + modify_date = True else: if comments: - book.comments.append(db.Comments(text=comments, book=book.id)) - modif_date = True - return modif_date + book.comments.append(db.Comments(comment=comments, book=book.id)) + modify_date = True + return modify_date -def edit_book_languages(languages, book, upload=False, invalid=None): +def edit_book_languages(languages, book, upload_mode=False, invalid=None): input_languages = languages.split(',') unknown_languages = [] - if not upload: + if not upload_mode: input_l = isoLanguages.get_language_codes(get_locale(), input_languages, unknown_languages) else: input_l = isoLanguages.get_valid_language_codes(get_locale(), input_languages, unknown_languages) - for l in unknown_languages: - log.error('%s is not a valid language', l) + for lang in unknown_languages: + log.error("'%s' is not a valid language", lang) if isinstance(invalid, list): - invalid.append(l) + invalid.append(lang) else: - flash(_(u"%(langname)s is not a valid language", langname=l), category="warning") + raise ValueError(_("'%(langname)s' is not a valid language", langname=lang)) # ToDo: Not working correct - if upload and len(input_l) == 1: + if upload_mode and len(input_l) == 1: # If the language of the file is excluded from the users view, it's not imported, to allow the user to view # the book it's language is set to the filter language if input_l[0] != current_user.filter_language() and current_user.filter_language() != "all": @@ -574,17 +1098,20 @@ def edit_cc_data_string(book, c, to_save, cc_db_value, cc_string): getattr(book, cc_string).append(new_cc) return changed, to_save + def edit_single_cc_data(book_id, book, column_id, to_save): - cc = (calibre_db.session.query(db.Custom_Columns) - .filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)) - .filter(db.Custom_Columns.id == column_id) + cc = (calibre_db.session.query(db.CustomColumns) + .filter(db.CustomColumns.datatype.notin_(db.cc_exceptions)) + .filter(db.CustomColumns.id == column_id) .all()) return edit_cc_data(book_id, book, to_save, cc) + def edit_all_cc_data(book_id, book, to_save): - cc = calibre_db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() + cc = calibre_db.session.query(db.CustomColumns).filter(db.CustomColumns.datatype.notin_(db.cc_exceptions)).all() return edit_cc_data(book_id, book, to_save, cc) + def edit_cc_data(book_id, book, to_save, cc): changed = False for c in cc: @@ -617,23 +1144,27 @@ def edit_cc_data(book_id, book, to_save, cc): 'custom') return changed -def upload_single_file(request, book, book_id): + +# returns None if no file is uploaded +# returns False if an error occurs, in all other cases the ebook metadata is returned +def upload_single_file(file_request, book, book_id): # Check and handle Uploaded file - if 'btn-upload-format' in request.files: - requested_file = request.files['btn-upload-format'] + requested_file = file_request.files.get('btn-upload-format', None) + if requested_file: # check for empty request if requested_file.filename != '': if not current_user.role_upload(): - abort(403) + flash(_("User has no rights to upload additional file formats"), category="error") + return False if '.' in requested_file.filename: file_ext = requested_file.filename.rsplit('.', 1)[-1].lower() if file_ext not in constants.EXTENSIONS_UPLOAD and '' not in constants.EXTENSIONS_UPLOAD: flash(_("File extension '%(ext)s' is not allowed to be uploaded to this server", ext=file_ext), category="error") - return redirect(url_for('web.show_book', book_id=book.id)) + return False else: flash(_('File to be uploaded must have an extension'), category="error") - return redirect(url_for('web.show_book', book_id=book.id)) + return False file_name = book.path.rsplit('/', 1)[-1] filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path)) @@ -644,13 +1175,13 @@ def upload_single_file(request, book, book_id): try: os.makedirs(filepath) except OSError: - flash(_(u"Failed to create path %(path)s (Permission denied).", path=filepath), category="error") - return redirect(url_for('web.show_book', book_id=book.id)) + flash(_("Failed to create path %(path)s (Permission denied).", path=filepath), category="error") + return False try: requested_file.save(saved_filename) except OSError: - flash(_(u"Failed to store file %(file)s.", file=saved_filename), category="error") - return redirect(url_for('web.show_book', book_id=book.id)) + flash(_("Failed to store file %(file)s.", file=saved_filename), category="error") + return False file_size = os.path.getsize(saved_filename) is_format = calibre_db.get_book_format(book_id, file_ext.upper()) @@ -664,31 +1195,34 @@ def upload_single_file(request, book, book_id): calibre_db.session.add(db_format) calibre_db.session.commit() calibre_db.update_title_sort(config) - except (OperationalError, IntegrityError) as e: + except (OperationalError, IntegrityError, StaleDataError) as e: calibre_db.session.rollback() - log.error('Database error: %s', e) - flash(_(u"Database error: %(error)s.", error=e), category="error") - return redirect(url_for('web.show_book', book_id=book.id)) + log.error_or_exception("Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") + return False # return redirect(url_for('web.show_book', book_id=book.id)) # Queue uploader info link = '{}'.format(url_for('web.show_book', book_id=book.id), escape(book.title)) - uploadText=_(u"File format %(ext)s added to %(book)s", ext=file_ext.upper(), book=link) - WorkerThread.add(current_user.name, TaskUpload(uploadText)) + upload_text = N_("File format %(ext)s added to %(book)s", ext=file_ext.upper(), book=link) + WorkerThread.add(current_user.name, TaskUpload(upload_text, escape(book.title))) return uploader.process( saved_filename, *os.path.splitext(requested_file.filename), rarExecutable=config.config_rarfile_location) + return None -def upload_cover(request, book): - if 'btn-upload-cover' in request.files: - requested_file = request.files['btn-upload-cover'] +def upload_cover(cover_request, book): + requested_file = cover_request.files.get('btn-upload-cover', None) + if requested_file: # check for empty request if requested_file.filename != '': if not current_user.role_upload(): - abort(403) + flash(_("User has no rights to upload cover"), category="error") + return False ret, message = helper.save_cover(requested_file, book.path) if ret is True: + helper.replace_cover_thumbnail_cache(book.id) return True else: flash(message, category="error") @@ -709,13 +1243,7 @@ def handle_title_on_edit(book, book_title): def handle_author_on_edit(book, author_name, update_stored=True): # handle author(s) - input_authors = author_name.split('&') - input_authors = list(map(lambda it: it.strip().replace(',', '|'), input_authors)) - # Remove duplicates in authors list - input_authors = helper.uniq(input_authors) - # we have all author names now - if input_authors == ['']: - input_authors = [_(u'Unknown')] # prevent empty Author + input_authors, renamed = prepare_authors(author_name) change = modify_database_object(input_authors, book.authors, db.Authors, calibre_db.session, 'author') @@ -733,560 +1261,159 @@ def handle_author_on_edit(book, author_name, update_stored=True): if book.author_sort != sort_authors and update_stored: book.author_sort = sort_authors change = True - return input_authors, change + return input_authors, change, renamed -@editbook.route("/admin/book/", methods=['GET', 'POST']) -@login_required_if_no_ano -@edit_required -def edit_book(book_id): - modif_date = False +def search_objects_remove(db_book_object, db_type, input_elements): + del_elements = [] + for c_elements in db_book_object: + found = False + if db_type == 'languages': + type_elements = c_elements.lang_code + elif db_type == 'custom': + type_elements = c_elements.value + else: + type_elements = c_elements.name + for inp_element in input_elements: + if inp_element.lower() == type_elements.lower(): + found = True + break + # if the element was not found in the new list, add it to remove list + if not found: + del_elements.append(c_elements) + return del_elements - # create the function for sorting... - try: - calibre_db.update_title_sort(config) - except sqliteOperationalError as e: - log.debug_or_exception(e) - calibre_db.session.rollback() - # Show form - if request.method != 'POST': - return render_edit_book(book_id) - - book = calibre_db.get_filtered_book(book_id, allow_show_archived=True) - - # Book not found - if not book: - flash(_(u"Oops! Selected book title is unavailable. File does not exist or is not accessible"), category="error") - return redirect(url_for("web.index")) - - meta = upload_single_file(request, book, book_id) - if upload_cover(request, book) is True: - book.has_cover = 1 - modif_date = True - try: - to_save = request.form.to_dict() - merge_metadata(to_save, meta) - # Update book - edited_books_id = None - - # handle book title - title_change = handle_title_on_edit(book, to_save["book_title"]) - - input_authors, authorchange = handle_author_on_edit(book, to_save["author_name"]) - if authorchange or title_change: - edited_books_id = book.id - modif_date = True - - if config.config_use_google_drive: - gdriveutils.updateGdriveCalibreFromLocal() - - error = False - if edited_books_id: - error = helper.update_dir_stucture(edited_books_id, config.config_calibre_dir, input_authors[0]) - - if not error: - if "cover_url" in to_save: - if to_save["cover_url"]: - if not current_user.role_upload(): - return "", (403) - if to_save["cover_url"].endswith('/static/generic_cover.jpg'): - book.has_cover = 0 - else: - result, error = helper.save_cover_from_url(to_save["cover_url"], book.path) - if result is True: - book.has_cover = 1 - modif_date = True - else: - flash(error, category="error") - - # Add default series_index to book - modif_date |= edit_book_series_index(to_save["series_index"], book) - # Handle book comments/description - modif_date |= edit_book_comments(Markup(to_save['description']).unescape(), book) - # Handle identifiers - input_identifiers = identifier_list(to_save, book) - modification, warning = modify_identifiers(input_identifiers, book.identifiers, calibre_db.session) - if warning: - flash(_("Identifiers are not Case Sensitive, Overwriting Old Identifier"), category="warning") - modif_date |= modification - # Handle book tags - modif_date |= edit_book_tags(to_save['tags'], book) - # Handle book series - modif_date |= edit_book_series(to_save["series"], book) - # handle book publisher - modif_date |= edit_book_publisher(to_save['publisher'], book) - # handle book languages - modif_date |= edit_book_languages(to_save['languages'], book) - # handle book ratings - modif_date |= edit_book_ratings(to_save, book) - # handle cc data - modif_date |= edit_all_cc_data(book_id, book, to_save) - - if to_save["pubdate"]: - try: - book.pubdate = datetime.strptime(to_save["pubdate"], "%Y-%m-%d") - except ValueError: - book.pubdate = db.Books.DEFAULT_PUBDATE +def search_objects_add(db_book_object, db_type, input_elements): + add_elements = [] + for inp_element in input_elements: + found = False + for c_elements in db_book_object: + if db_type == 'languages': + type_elements = c_elements.lang_code + elif db_type == 'custom': + type_elements = c_elements.value else: - book.pubdate = db.Books.DEFAULT_PUBDATE - - if modif_date: - book.last_modified = datetime.utcnow() - kobo_sync_status.remove_synced_book(edited_books_id) - - calibre_db.session.merge(book) - calibre_db.session.commit() - if config.config_use_google_drive: - gdriveutils.updateGdriveCalibreFromLocal() - if "detail_view" in to_save: - return redirect(url_for('web.show_book', book_id=book.id)) - else: - flash(_("Metadata successfully updated"), category="success") - return render_edit_book(book_id) - else: - calibre_db.session.rollback() - flash(error, category="error") - return render_edit_book(book_id) - except Exception as ex: - log.debug_or_exception(ex) - calibre_db.session.rollback() - flash(_("Error editing book, please check logfile for details"), category="error") - return redirect(url_for('web.show_book', book_id=book.id)) + type_elements = c_elements.name + if inp_element == type_elements: + found = True + break + if not found: + add_elements.append(inp_element) + return add_elements -def merge_metadata(to_save, meta): - if to_save['author_name'] == _(u'Unknown'): - to_save['author_name'] = '' - if to_save['book_title'] == _(u'Unknown'): - to_save['book_title'] = '' - for s_field, m_field in [ - ('tags', 'tags'), ('author_name', 'author'), ('series', 'series'), - ('series_index', 'series_id'), ('languages', 'languages'), - ('book_title', 'title')]: - to_save[s_field] = to_save[s_field] or getattr(meta, m_field, '') - to_save["description"] = to_save["description"] or Markup( - getattr(meta, 'description', '')).unescape() +def remove_objects(db_book_object, db_session, del_elements): + changed = False + if len(del_elements) > 0: + for del_element in del_elements: + db_book_object.remove(del_element) + changed = True + if len(del_element.books) == 0: + db_session.delete(del_element) + return changed -def identifier_list(to_save, book): - """Generate a list of Identifiers from form information""" - id_type_prefix = 'identifier-type-' - id_val_prefix = 'identifier-val-' - result = [] - for type_key, type_value in to_save.items(): - if not type_key.startswith(id_type_prefix): - continue - val_key = id_val_prefix + type_key[len(id_type_prefix):] - if val_key not in to_save.keys(): - continue - result.append(db.Identifiers(to_save[val_key], type_value, book.id)) - return result - - -def prepare_authors_on_upload(title, authr): - if title != _(u'Unknown') and authr != _(u'Unknown'): - entry = calibre_db.check_exists_book(authr, title) - if entry: - log.info("Uploaded book probably exists in library") - flash(_(u"Uploaded book probably exists in the library, consider to change before upload new: ") - + Markup(render_title_template('book_exists_flash.html', entry=entry)), category="warning") - - # handle authors - input_authors = authr.split('&') - # handle_authors(input_authors) - input_authors = list(map(lambda it: it.strip().replace(',', '|'), input_authors)) - # Remove duplicates in authors list - input_authors = helper.uniq(input_authors) - - # we have all author names now - if input_authors == ['']: - input_authors = [_(u'Unknown')] # prevent empty Author - - sort_authors_list = list() - db_author = None - for inp in input_authors: - stored_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == inp).first() - if not stored_author: - if not db_author: - db_author = db.Authors(inp, helper.get_sorted_author(inp), "") - calibre_db.session.add(db_author) - calibre_db.session.commit() - sort_author = helper.get_sorted_author(inp) - else: - if not db_author: - db_author = stored_author - sort_author = stored_author.sort - sort_authors_list.append(sort_author) - sort_authors = ' & '.join(sort_authors_list) - return sort_authors, input_authors, db_author - - -def create_book_on_upload(modif_date, meta): - title = meta.title - authr = meta.author - sort_authors, input_authors, db_author = prepare_authors_on_upload(title, authr) - - title_dir = helper.get_valid_filename(title) - author_dir = helper.get_valid_filename(db_author.name) - - # combine path and normalize path from windows systems - path = os.path.join(author_dir, title_dir).replace('\\', '/') - - # Calibre adds books with utc as timezone - db_book = db.Books(title, "", sort_authors, datetime.utcnow(), datetime(101, 1, 1), - '1', datetime.utcnow(), path, meta.cover, db_author, [], "") - - modif_date |= modify_database_object(input_authors, db_book.authors, db.Authors, calibre_db.session, - 'author') - - # Add series_index to book - modif_date |= edit_book_series_index(meta.series_id, db_book) - - # add languages - modif_date |= edit_book_languages(meta.languages, db_book, upload=True) - - # handle tags - modif_date |= edit_book_tags(meta.tags, db_book) - - # handle publisher - modif_date |= edit_book_publisher(meta.publisher, db_book) - - # handle series - modif_date |= edit_book_series(meta.series, db_book) - - # Add file to book - file_size = os.path.getsize(meta.file_path) - db_data = db.Data(db_book, meta.extension.upper()[1:], file_size, title_dir) - db_book.data.append(db_data) - calibre_db.session.add(db_book) - - # flush content, get db_book.id available - calibre_db.session.flush() - return db_book, input_authors, title_dir - -def file_handling_on_upload(requested_file): - # check if file extension is correct - if '.' in requested_file.filename: - file_ext = requested_file.filename.rsplit('.', 1)[-1].lower() - if file_ext not in constants.EXTENSIONS_UPLOAD and '' not in constants.EXTENSIONS_UPLOAD: - flash( - _("File extension '%(ext)s' is not allowed to be uploaded to this server", - ext=file_ext), category="error") - return None, Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json') +def add_objects(db_book_object, db_object, db_session, db_type, add_elements): + changed = False + if db_type == 'languages': + db_filter = db_object.lang_code + elif db_type == 'custom': + db_filter = db_object.value else: - flash(_('File to be uploaded must have an extension'), category="error") - return None, Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json') - - # extract metadata from file - try: - meta = uploader.upload(requested_file, config.config_rarfile_location) - except (IOError, OSError): - log.error("File %s could not saved to temp dir", requested_file.filename) - flash(_(u"File %(filename)s could not saved to temp dir", - filename=requested_file.filename), category="error") - return None, Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json') - return meta, None - - -def move_coverfile(meta, db_book): - # move cover to final directory, including book id - if meta.cover: - coverfile = meta.cover - else: - coverfile = os.path.join(constants.STATIC_DIR, 'generic_cover.jpg') - new_coverpath = os.path.join(config.config_calibre_dir, db_book.path, "cover.jpg") - try: - copyfile(coverfile, new_coverpath) - if meta.cover: - os.unlink(meta.cover) - except OSError as e: - log.error("Failed to move cover file %s: %s", new_coverpath, e) - flash(_(u"Failed to Move Cover File %(file)s: %(error)s", file=new_coverpath, - error=e), - category="error") - - -@editbook.route("/upload", methods=["GET", "POST"]) -@login_required_if_no_ano -@upload_required -def upload(): - if not config.config_uploading: - abort(404) - if request.method == 'POST' and 'btn-upload' in request.files: - for requested_file in request.files.getlist("btn-upload"): - try: - modif_date = False - # create the function for sorting... - calibre_db.update_title_sort(config) - calibre_db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4())) - - meta, error = file_handling_on_upload(requested_file) - if error: - return error - - db_book, input_authors, title_dir = create_book_on_upload(modif_date, meta) - - # Comments needs book id therefore only possible after flush - modif_date |= edit_book_comments(Markup(meta.description).unescape(), db_book) - - book_id = db_book.id - title = db_book.title - - error = helper.update_dir_structure_file(book_id, - config.config_calibre_dir, - input_authors[0], - meta.file_path, - title_dir + meta.extension.lower()) - - move_coverfile(meta, db_book) - - # save data to database, reread data - calibre_db.session.commit() - - if config.config_use_google_drive: - gdriveutils.updateGdriveCalibreFromLocal() - if error: - flash(error, category="error") - link = '{}'.format(url_for('web.show_book', book_id=book_id), escape(title)) - uploadText = _(u"File %(file)s uploaded", file=link) - WorkerThread.add(current_user.name, TaskUpload(uploadText)) - - if len(request.files.getlist("btn-upload")) < 2: - if current_user.role_edit() or current_user.role_admin(): - resp = {"location": url_for('editbook.edit_book', book_id=book_id)} - return Response(json.dumps(resp), mimetype='application/json') - else: - resp = {"location": url_for('web.show_book', book_id=book_id)} - return Response(json.dumps(resp), mimetype='application/json') - except (OperationalError, IntegrityError) as e: - calibre_db.session.rollback() - log.error("Database error: %s", e) - flash(_(u"Database error: %(error)s.", error=e), category="error") - return Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json') - -@editbook.route("/admin/book/convert/", methods=['POST']) -@login_required_if_no_ano -@edit_required -def convert_bookformat(book_id): - # check to see if we have form fields to work with - if not send user back - book_format_from = request.form.get('book_format_from', None) - book_format_to = request.form.get('book_format_to', None) - - if (book_format_from is None) or (book_format_to is None): - flash(_(u"Source or destination format for conversion missing"), category="error") - return redirect(url_for('editbook.edit_book', book_id=book_id)) - - log.info('converting: book id: %s from: %s to: %s', book_id, book_format_from, book_format_to) - rtn = helper.convert_book_format(book_id, config.config_calibre_dir, book_format_from.upper(), - book_format_to.upper(), current_user.name) - - if rtn is None: - flash(_(u"Book successfully queued for converting to %(book_format)s", - book_format=book_format_to), - category="success") - else: - flash(_(u"There was an error converting this book: %(res)s", res=rtn), category="error") - return redirect(url_for('editbook.edit_book', book_id=book_id)) - -@editbook.route("/ajax/getcustomenum/") -@login_required -def table_get_custom_enum(c_id): - ret = list() - cc = (calibre_db.session.query(db.Custom_Columns) - .filter(db.Custom_Columns.id == c_id) - .filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).one_or_none()) - ret.append({'value': "", 'text': ""}) - for idx, en in enumerate(cc.get_display_dict()['enum_values']): - ret.append({'value': en, 'text': en}) - return json.dumps(ret) - - -@editbook.route("/ajax/editbooks/", methods=['POST']) -@login_required_if_no_ano -@edit_required -def edit_list_book(param): - vals = request.form.to_dict() - book = calibre_db.get_book(vals['pk']) - ret = "" - if param =='series_index': - edit_book_series_index(vals['value'], book) - ret = Response(json.dumps({'success': True, 'newValue': book.series_index}), mimetype='application/json') - elif param =='tags': - edit_book_tags(vals['value'], book) - ret = Response(json.dumps({'success': True, 'newValue': ', '.join([tag.name for tag in book.tags])}), - mimetype='application/json') - elif param =='series': - edit_book_series(vals['value'], book) - ret = Response(json.dumps({'success': True, 'newValue': ', '.join([serie.name for serie in book.series])}), - mimetype='application/json') - elif param =='publishers': - edit_book_publisher(vals['value'], book) - ret = Response(json.dumps({'success': True, - 'newValue': ', '.join([publisher.name for publisher in book.publishers])}), - mimetype='application/json') - elif param =='languages': - invalid = list() - edit_book_languages(vals['value'], book, invalid=invalid) - if invalid: - ret = Response(json.dumps({'success': False, - 'msg': 'Invalid languages in request: {}'.format(','.join(invalid))}), - mimetype='application/json') + db_filter = db_object.name + for add_element in add_elements: + # check if an element with that name exists + db_element = db_session.query(db_object).filter(db_filter == add_element).first() + # if no element is found add it + if db_type == 'author': + new_element = db_object(add_element, helper.get_sorted_author(add_element.replace('|', ',')), "") + elif db_type == 'series': + new_element = db_object(add_element, add_element) + elif db_type == 'custom': + new_element = db_object(value=add_element) + elif db_type == 'publisher': + new_element = db_object(add_element, None) + else: # db_type should be tag or language + new_element = db_object(add_element) + if db_element is None: + changed = True + db_session.add(new_element) + db_book_object.append(new_element) else: - lang_names = list() - for lang in book.languages: - lang_names.append(isoLanguages.get_language_name(get_locale(), lang.lang_code)) - ret = Response(json.dumps({'success': True, 'newValue': ', '.join(lang_names)}), - mimetype='application/json') - elif param =='author_sort': - book.author_sort = vals['value'] - ret = Response(json.dumps({'success': True, 'newValue': book.author_sort}), - mimetype='application/json') - elif param == 'title': - sort = book.sort - handle_title_on_edit(book, vals.get('value', "")) - helper.update_dir_stucture(book.id, config.config_calibre_dir) - ret = Response(json.dumps({'success': True, 'newValue': book.title}), - mimetype='application/json') - elif param =='sort': - book.sort = vals['value'] - ret = Response(json.dumps({'success': True, 'newValue': book.sort}), - mimetype='application/json') - elif param =='comments': - edit_book_comments(vals['value'], book) - ret = Response(json.dumps({'success': True, 'newValue': book.comments[0].text}), - mimetype='application/json') - elif param =='authors': - input_authors, __ = handle_author_on_edit(book, vals['value'], vals.get('checkA', None) == "true") - helper.update_dir_stucture(book.id, config.config_calibre_dir, input_authors[0]) - ret = Response(json.dumps({'success': True, - 'newValue': ' & '.join([author.replace('|',',') for author in input_authors])}), - mimetype='application/json') - elif param.startswith("custom_column_"): - new_val = dict() - new_val[param] = vals['value'] - edit_single_cc_data(book.id, book, param[14:], new_val) - ret = Response(json.dumps({'success': True, 'newValue': vals['value']}), - mimetype='application/json') - - book.last_modified = datetime.utcnow() - try: - calibre_db.session.commit() - # revert change for sort if automatic fields link is deactivated - if param == 'title' and vals.get('checkT') == "false": - book.sort = sort - calibre_db.session.commit() - except (OperationalError, IntegrityError) as e: - calibre_db.session.rollback() - log.error("Database error: %s", e) - return ret + db_element = create_objects_for_addition(db_element, add_element, db_type) + # add element to book + changed = True + db_book_object.append(db_element) + return changed -@editbook.route("/ajax/sort_value//") -@login_required -def get_sorted_entry(field, bookid): - if field in ['title', 'authors', 'sort', 'author_sort']: - book = calibre_db.get_filtered_book(bookid) - if book: - if field == 'title': - return json.dumps({'sort': book.sort}) - elif field == 'authors': - return json.dumps({'author_sort': book.author_sort}) - if field == 'sort': - return json.dumps({'sort': book.title}) - if field == 'author_sort': - return json.dumps({'author_sort': book.author}) - return "" +def create_objects_for_addition(db_element, add_element, db_type): + if db_type == 'custom': + if db_element.value != add_element: + db_element.value = add_element + elif db_type == 'languages': + if db_element.lang_code != add_element: + db_element.lang_code = add_element + elif db_type == 'series': + if db_element.name != add_element: + db_element.name = add_element + db_element.sort = add_element + elif db_type == 'author': + if db_element.name != add_element: + db_element.name = add_element + db_element.sort = helper.get_sorted_author(add_element.replace('|', ',')) + elif db_type == 'publisher': + if db_element.name != add_element: + db_element.name = add_element + db_element.sort = None + elif db_element.name != add_element: + db_element.name = add_element + return db_element -@editbook.route("/ajax/simulatemerge", methods=['POST']) -@login_required -@edit_required -def simulate_merge_list_book(): - vals = request.get_json().get('Merge_books') - if vals: - to_book = calibre_db.get_book(vals[0]).title - vals.pop(0) - if to_book: - for book_id in vals: - from_book = [] - from_book.append(calibre_db.get_book(book_id).title) - return json.dumps({'to': to_book, 'from': from_book}) - return "" +# Modifies different Database objects, first check if elements have to be deleted, +# because they are no longer used, than check if elements have to be added to database +def modify_database_object(input_elements, db_book_object, db_object, db_session, db_type): + # passing input_elements not as a list may lead to undesired results + if not isinstance(input_elements, list): + raise TypeError(str(input_elements) + " should be passed as a list") + input_elements = [x for x in input_elements if x != ''] + # we have all input element (authors, series, tags) names now + # 1. search for elements to remove + del_elements = search_objects_remove(db_book_object, db_type, input_elements) + # 2. search for elements that need to be added + add_elements = search_objects_add(db_book_object, db_type, input_elements) + # if there are elements to remove, we remove them now + changed = remove_objects(db_book_object, db_session, del_elements) + # if there are elements to add, we add them now! + if len(add_elements) > 0: + changed |= add_objects(db_book_object, db_object, db_session, db_type, add_elements) + return changed -@editbook.route("/ajax/mergebooks", methods=['POST']) -@login_required -@edit_required -def merge_list_book(): - vals = request.get_json().get('Merge_books') - to_file = list() - if vals: - # load all formats from target book - to_book = calibre_db.get_book(vals[0]) - vals.pop(0) - if to_book: - for file in to_book.data: - to_file.append(file.format) - to_name = helper.get_valid_filename(to_book.title) + ' - ' + \ - helper.get_valid_filename(to_book.authors[0].name) - for book_id in vals: - from_book = calibre_db.get_book(book_id) - if from_book: - for element in from_book.data: - if element.format not in to_file: - # create new data entry with: book_id, book_format, uncompressed_size, name - filepath_new = os.path.normpath(os.path.join(config.config_calibre_dir, - to_book.path, - to_name + "." + element.format.lower())) - filepath_old = os.path.normpath(os.path.join(config.config_calibre_dir, - from_book.path, - element.name + "." + element.format.lower())) - copyfile(filepath_old, filepath_new) - to_book.data.append(db.Data(to_book.id, - element.format, - element.uncompressed_size, - to_name)) - delete_book(from_book.id,"", True) - return json.dumps({'success': True}) - return "" - -@editbook.route("/ajax/xchange", methods=['POST']) -@login_required -@edit_required -def table_xchange_author_title(): - vals = request.get_json().get('xchange') - if vals: - for val in vals: - modif_date = False - book = calibre_db.get_book(val) - authors = book.title - entries = calibre_db.order_authors(book) - author_names = [] - for authr in entries.authors: - author_names.append(authr.name.replace('|', ',')) - - title_change = handle_title_on_edit(book, " ".join(author_names)) - input_authors, authorchange = handle_author_on_edit(book, authors) - if authorchange or title_change: - edited_books_id = book.id - modif_date = True - - if config.config_use_google_drive: - gdriveutils.updateGdriveCalibreFromLocal() - - if edited_books_id: - helper.update_dir_stucture(edited_books_id, config.config_calibre_dir, input_authors[0]) - if modif_date: - book.last_modified = datetime.utcnow() - try: - calibre_db.session.commit() - except (OperationalError, IntegrityError) as e: - calibre_db.session.rollback() - log.error("Database error: %s", e) - return json.dumps({'success': False}) - - if config.config_use_google_drive: - gdriveutils.updateGdriveCalibreFromLocal() - return json.dumps({'success': True}) - return "" +def modify_identifiers(input_identifiers, db_identifiers, db_session): + """Modify Identifiers to match input information. + input_identifiers is a list of read-to-persist Identifiers objects. + db_identifiers is a list of already persisted list of Identifiers objects.""" + changed = False + error = False + input_dict = dict([(identifier.type.lower(), identifier) for identifier in input_identifiers]) + if len(input_identifiers) != len(input_dict): + error = True + db_dict = dict([(identifier.type.lower(), identifier) for identifier in db_identifiers]) + # delete db identifiers not present in input or modify them with input val + for identifier_type, identifier in db_dict.items(): + if identifier_type not in input_dict.keys(): + db_session.delete(identifier) + changed = True + else: + input_identifier = input_dict[identifier_type] + identifier.type = input_identifier.type + identifier.val = input_identifier.val + # add input identifiers not present in db + for identifier_type, identifier in input_dict.items(): + if identifier_type not in db_dict.keys(): + db_session.add(identifier) + changed = True + return changed, error diff --git a/cps/epub.py b/cps/epub.py index cbbdcbbde..91d701768 100644 --- a/cps/epub.py +++ b/cps/epub.py @@ -20,24 +20,26 @@ import os import zipfile from lxml import etree -from . import isoLanguages +from . import isoLanguages, cover from .helper import split_authors from .constants import BookMeta - -def extractCover(zipFile, coverFile, coverpath, tmp_file_name): - if coverFile is None: +def _extract_cover(zip_file, cover_file, cover_path, tmp_file_name): + if cover_file is None: return None else: - zipCoverPath = os.path.join(coverpath, coverFile).replace('\\', '/') - cf = zipFile.read(zipCoverPath) + cf = extension = None + zip_cover_path = os.path.join(cover_path, cover_file).replace('\\', '/') + prefix = os.path.splitext(tmp_file_name)[0] - tmp_cover_name = prefix + '.' + os.path.basename(zipCoverPath) - image = open(tmp_cover_name, 'wb') - image.write(cf) - image.close() - return tmp_cover_name + tmp_cover_name = prefix + '.' + os.path.basename(zip_cover_path) + ext = os.path.splitext(tmp_cover_name) + if len(ext) > 1: + extension = ext[1].lower() + if extension in cover.COVER_EXTENSIONS: + cf = zip_file.read(zip_cover_path) + return cover.cover_processing(tmp_file_name, cf, extension) def get_epub_info(tmp_file_path, original_file_name, original_file_extension): @@ -47,36 +49,44 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension): 'dc': 'http://purl.org/dc/elements/1.1/' } - epubZip = zipfile.ZipFile(tmp_file_path) + epub_zip = zipfile.ZipFile(tmp_file_path) - txt = epubZip.read('META-INF/container.xml') + txt = epub_zip.read('META-INF/container.xml') tree = etree.fromstring(txt) - cfname = tree.xpath('n:rootfiles/n:rootfile/@full-path', namespaces=ns)[0] - cf = epubZip.read(cfname) + cf_name = tree.xpath('n:rootfiles/n:rootfile/@full-path', namespaces=ns)[0] + cf = epub_zip.read(cf_name) tree = etree.fromstring(cf) - coverpath = os.path.dirname(cfname) + cover_path = os.path.dirname(cf_name) p = tree.xpath('/pkg:package/pkg:metadata', namespaces=ns)[0] epub_metadata = {} - for s in ['title', 'description', 'creator', 'language', 'subject']: + for s in ['title', 'description', 'creator', 'language', 'subject', 'publisher', 'date']: tmp = p.xpath('dc:%s/text()' % s, namespaces=ns) if len(tmp) > 0: if s == 'creator': epub_metadata[s] = ' & '.join(split_authors(tmp)) elif s == 'subject': epub_metadata[s] = ', '.join(tmp) + elif s == 'date': + epub_metadata[s] = tmp[0][:10] else: epub_metadata[s] = tmp[0] else: - epub_metadata[s] = u'Unknown' + epub_metadata[s] = 'Unknown' - if epub_metadata['subject'] == u'Unknown': + if epub_metadata['subject'] == 'Unknown': epub_metadata['subject'] = '' - if epub_metadata['description'] == u'Unknown': + if epub_metadata['publisher'] == 'Unknown': + epub_metadata['publisher'] = '' + + if epub_metadata['date'] == 'Unknown': + epub_metadata['date'] = '' + + if epub_metadata['description'] == 'Unknown': description = tree.xpath("//*[local-name() = 'description']/text()") if len(description) > 0: epub_metadata['description'] = description @@ -86,9 +96,20 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension): lang = epub_metadata['language'].split('-', 1)[0].lower() epub_metadata['language'] = isoLanguages.get_lang3(lang) - epub_metadata = parse_epbub_series(ns, tree, epub_metadata) + epub_metadata = parse_epub_series(ns, tree, epub_metadata) - coverfile = parse_ebpub_cover(ns, tree, epubZip, coverpath, tmp_file_path) + cover_file = parse_epub_cover(ns, tree, epub_zip, cover_path, tmp_file_path) + + identifiers = [] + for node in p.xpath('dc:identifier', namespaces=ns): + try: + identifier_name = node.attrib.values()[-1] + except IndexError: + continue + identifier_value = node.text + if identifier_name in ('uuid', 'calibre') or identifier_value is None: + continue + identifiers.append([identifier_name, identifier_value]) if not epub_metadata['title']: title = original_file_name @@ -100,45 +121,57 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension): extension=original_file_extension, title=title.encode('utf-8').decode('utf-8'), author=epub_metadata['creator'].encode('utf-8').decode('utf-8'), - cover=coverfile, + cover=cover_file, description=epub_metadata['description'], tags=epub_metadata['subject'].encode('utf-8').decode('utf-8'), series=epub_metadata['series'].encode('utf-8').decode('utf-8'), series_id=epub_metadata['series_id'].encode('utf-8').decode('utf-8'), languages=epub_metadata['language'], - publisher="") + publisher=epub_metadata['publisher'].encode('utf-8').decode('utf-8'), + pubdate=epub_metadata['date'], + identifiers=identifiers) -def parse_ebpub_cover(ns, tree, epubZip, coverpath, tmp_file_path): - coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover-image']/@href", namespaces=ns) - coverfile = None - if len(coversection) > 0: - coverfile = extractCover(epubZip, coversection[0], coverpath, tmp_file_path) - else: + +def parse_epub_cover(ns, tree, epub_zip, cover_path, tmp_file_path): + cover_section = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover-image']/@href", namespaces=ns) + cover_file = None + # if len(cover_section) > 0: + for cs in cover_section: + cover_file = _extract_cover(epub_zip, cs, cover_path, tmp_file_path) + if cover_file: + break + if not cover_file: meta_cover = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='cover']/@content", namespaces=ns) if len(meta_cover) > 0: - coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='"+meta_cover[0]+"']/@href", namespaces=ns) + cover_section = tree.xpath( + "/pkg:package/pkg:manifest/pkg:item[@id='"+meta_cover[0]+"']/@href", namespaces=ns) + if not cover_section: + cover_section = tree.xpath( + "/pkg:package/pkg:manifest/pkg:item[@properties='" + meta_cover[0] + "']/@href", namespaces=ns) else: - coversection = tree.xpath("/pkg:package/pkg:guide/pkg:reference/@href", namespaces=ns) - if len(coversection) > 0: - filetype = coversection[0].rsplit('.', 1)[-1] + cover_section = tree.xpath("/pkg:package/pkg:guide/pkg:reference/@href", namespaces=ns) + for cs in cover_section: + filetype = cs.rsplit('.', 1)[-1] if filetype == "xhtml" or filetype == "html": # if cover is (x)html format - markup = epubZip.read(os.path.join(coverpath, coversection[0])) - markupTree = etree.fromstring(markup) + markup = epub_zip.read(os.path.join(cover_path, cs)) + markup_tree = etree.fromstring(markup) # no matter xhtml or html with no namespace - imgsrc = markupTree.xpath("//*[local-name() = 'img']/@src") + img_src = markup_tree.xpath("//*[local-name() = 'img']/@src") # Alternative image source - if not len(imgsrc): - imgsrc = markupTree.xpath("//attribute::*[contains(local-name(), 'href')]") - if len(imgsrc): - # imgsrc maybe startwith "../"" so fullpath join then relpath to cwd - filename = os.path.relpath(os.path.join(os.path.dirname(os.path.join(coverpath, coversection[0])), - imgsrc[0])) - coverfile = extractCover(epubZip, filename, "", tmp_file_path) + if not len(img_src): + img_src = markup_tree.xpath("//attribute::*[contains(local-name(), 'href')]") + if len(img_src): + # img_src maybe start with "../"" so fullpath join then relpath to cwd + filename = os.path.relpath(os.path.join(os.path.dirname(os.path.join(cover_path, cover_section[0])), + img_src[0])) + cover_file = _extract_cover(epub_zip, filename, "", tmp_file_path) else: - coverfile = extractCover(epubZip, coversection[0], coverpath, tmp_file_path) - return coverfile + cover_file = _extract_cover(epub_zip, cs, cover_path, tmp_file_path) + if cover_file: break + return cover_file -def parse_epbub_series(ns, tree, epub_metadata): + +def parse_epub_series(ns, tree, epub_metadata): series = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='calibre:series']/@content", namespaces=ns) if len(series) > 0: epub_metadata['series'] = series[0] diff --git a/cps/error_handler.py b/cps/error_handler.py index 37b7500e5..7c003bdb3 100644 --- a/cps/error_handler.py +++ b/cps/error_handler.py @@ -17,6 +17,7 @@ # along with this program. If not, see . import traceback + from flask import render_template from werkzeug.exceptions import default_exceptions try: @@ -42,8 +43,9 @@ def error_http(error): def internal_error(error): return render_template('http_error.html', - error_code="Internal Server Error", - error_name=str(error), + error_code="500 Internal Server Error", + error_name='The server encountered an internal error and was unable to complete your ' + 'request. There is an error in the application.', issue=True, unconfigured=False, error_stack=traceback.format_exc().split("\n"), diff --git a/cps/fb2.py b/cps/fb2.py index 21586736f..81eae579f 100644 --- a/cps/fb2.py +++ b/cps/fb2.py @@ -38,19 +38,19 @@ def get_fb2_info(tmp_file_path, original_file_extension): if len(last_name): last_name = last_name[0] else: - last_name = u'' + last_name = '' middle_name = element.xpath('fb:middle-name/text()', namespaces=ns) if len(middle_name): middle_name = middle_name[0] else: - middle_name = u'' + middle_name = '' first_name = element.xpath('fb:first-name/text()', namespaces=ns) if len(first_name): first_name = first_name[0] else: - first_name = u'' - return (first_name + u' ' - + middle_name + u' ' + first_name = '' + return (first_name + ' ' + + middle_name + ' ' + last_name) author = str(", ".join(map(get_author, authors))) @@ -59,12 +59,12 @@ def get_fb2_info(tmp_file_path, original_file_extension): if len(title): title = str(title[0]) else: - title = u'' + title = '' description = tree.xpath('/fb:FictionBook/fb:description/fb:publish-info/fb:book-name/text()', namespaces=ns) if len(description): description = str(description[0]) else: - description = u'' + description = '' return BookMeta( file_path=tmp_file_path, @@ -77,4 +77,6 @@ def get_fb2_info(tmp_file_path, original_file_extension): series="", series_id="", languages="", - publisher="") + publisher="", + pubdate="", + identifiers=[]) diff --git a/cps/fs.py b/cps/fs.py new file mode 100644 index 000000000..996499c3e --- /dev/null +++ b/cps/fs.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2020 mmonkey +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from . import logger +from .constants import CACHE_DIR +from os import makedirs, remove +from os.path import isdir, isfile, join +from shutil import rmtree + + +class FileSystem: + _instance = None + _cache_dir = CACHE_DIR + + def __new__(cls): + if cls._instance is None: + cls._instance = super(FileSystem, cls).__new__(cls) + cls.log = logger.create() + return cls._instance + + def get_cache_dir(self, cache_type=None): + if not isdir(self._cache_dir): + try: + makedirs(self._cache_dir) + except OSError: + self.log.info(f'Failed to create path {self._cache_dir} (Permission denied).') + raise + + path = join(self._cache_dir, cache_type) + if cache_type and not isdir(path): + try: + makedirs(path) + except OSError: + self.log.info(f'Failed to create path {path} (Permission denied).') + raise + + return path if cache_type else self._cache_dir + + def get_cache_file_dir(self, filename, cache_type=None): + path = join(self.get_cache_dir(cache_type), filename[:2]) + if not isdir(path): + try: + makedirs(path) + except OSError: + self.log.info(f'Failed to create path {path} (Permission denied).') + raise + + return path + + def get_cache_file_path(self, filename, cache_type=None): + return join(self.get_cache_file_dir(filename, cache_type), filename) if filename else None + + def get_cache_file_exists(self, filename, cache_type=None): + path = self.get_cache_file_path(filename, cache_type) + return isfile(path) + + def delete_cache_dir(self, cache_type=None): + if not cache_type and isdir(self._cache_dir): + try: + rmtree(self._cache_dir) + except OSError: + self.log.info(f'Failed to delete path {self._cache_dir} (Permission denied).') + raise + + path = join(self._cache_dir, cache_type) + if cache_type and isdir(path): + try: + rmtree(path) + except OSError: + self.log.info(f'Failed to delete path {path} (Permission denied).') + raise + + def delete_cache_file(self, filename, cache_type=None): + path = self.get_cache_file_path(filename, cache_type) + if isfile(path): + try: + remove(path) + except OSError: + self.log.info(f'Failed to delete path {path} (Permission denied).') + raise diff --git a/cps/gdrive.py b/cps/gdrive.py index 6ca73ca9f..832350e13 100644 --- a/cps/gdrive.py +++ b/cps/gdrive.py @@ -55,7 +55,7 @@ def authenticate_google_drive(): try: authUrl = gdriveutils.Gauth.Instance().auth.GetAuthUrl() except gdriveutils.InvalidConfigError: - flash(_(u'Google Drive setup not completed, try to deactivate and activate Google Drive again'), + flash(_('Google Drive setup not completed, try to deactivate and activate Google Drive again'), category="error") return redirect(url_for('web.index')) return redirect(authUrl) @@ -91,9 +91,9 @@ def watch_gdrive(): config.save() except HttpError as e: reason=json.loads(e.content)['error']['errors'][0] - if reason['reason'] == u'push.webhookUrlUnauthorized': - flash(_(u'Callback domain is not verified, ' - u'please follow steps to verify domain in google developer console'), category="error") + if reason['reason'] == 'push.webhookUrlUnauthorized': + flash(_('Callback domain is not verified, ' + 'please follow steps to verify domain in google developer console'), category="error") else: flash(reason['message'], category="error") @@ -109,7 +109,7 @@ def revoke_watch_gdrive(): try: gdriveutils.stopChannel(gdriveutils.Gdrive.Instance().drive, last_watch_response['id'], last_watch_response['resourceId']) - except HttpError: + except (HttpError, AttributeError): pass config.config_google_drive_watch_changes_response = {} config.save() @@ -152,7 +152,7 @@ try: move(os.path.join(tmp_dir, "tmp_metadata.db"), dbpath) calibre_db.reconnect_db(config, ub.app_DB_path) except Exception as ex: - log.debug_or_exception(ex) + log.error_or_exception(ex) return '' except AttributeError: pass diff --git a/cps/gdriveutils.py b/cps/gdriveutils.py index 878c1f9f7..0a9d3cd1e 100644 --- a/cps/gdriveutils.py +++ b/cps/gdriveutils.py @@ -32,13 +32,10 @@ try: from sqlalchemy.orm import declarative_base except ImportError: from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.exc import OperationalError, InvalidRequestError +from sqlalchemy.exc import OperationalError, InvalidRequestError, IntegrityError +from sqlalchemy.orm.exc import StaleDataError from sqlalchemy.sql.expression import text -try: - from six import __version__ as six_version -except ImportError: - six_version = "not installed" try: from httplib2 import __version__ as httplib2_version except ImportError: @@ -56,16 +53,18 @@ try: from pydrive2.auth import GoogleAuth from pydrive2.drive import GoogleDrive from pydrive2.auth import RefreshError + from pydrive2.files import ApiRequestError except ImportError as err: try: from pydrive.auth import GoogleAuth from pydrive.drive import GoogleDrive from pydrive.auth import RefreshError + from pydrive.files import ApiRequestError except ImportError as err: importError = err gdrive_support = False -from . import logger, cli, config +from . import logger, cli_param, config from .constants import CONFIG_DIR as _CONFIG_DIR @@ -79,7 +78,7 @@ if gdrive_support: if not logger.is_debug_enabled(): logger.get('googleapiclient.discovery').setLevel(logger.logging.ERROR) else: - log.debug("Cannot import pydrive,httplib2, using gdrive will not work: %s", importError) + log.debug("Cannot import pydrive, httplib2, using gdrive will not work: {}".format(importError)) class Singleton: @@ -139,11 +138,12 @@ class Gdrive: def __init__(self): self.drive = getDrive(gauth=Gauth.Instance().auth) + def is_gdrive_ready(): return os.path.exists(SETTINGS_YAML) and os.path.exists(CREDENTIALS) -engine = create_engine('sqlite:///{0}'.format(cli.gdpath), echo=False) +engine = create_engine('sqlite:///{0}'.format(cli_param.gd_path), echo=False) Base = declarative_base() # Open session for database connection @@ -191,10 +191,11 @@ def migrate(): session.execute('ALTER TABLE gdrive_ids2 RENAME to gdrive_ids') break -if not os.path.exists(cli.gdpath): +if not os.path.exists(cli_param.gd_path): try: Base.metadata.create_all(engine) - except Exception: + except Exception as ex: + log.error("Error connect to database: {} - {}".format(cli_param.gd_path, ex)) raise migrate() @@ -210,9 +211,9 @@ def getDrive(drive=None, gauth=None): try: gauth.Refresh() except RefreshError as e: - log.error("Google Drive error: %s", e) + log.error("Google Drive error: {}".format(e)) except Exception as ex: - log.debug_or_exception(ex) + log.error_or_exception(ex) else: # Initialize the saved creds gauth.Authorize() @@ -222,7 +223,7 @@ def getDrive(drive=None, gauth=None): try: drive.auth.Refresh() except RefreshError as e: - log.error("Google Drive error: %s", e) + log.error("Google Drive error: {}".format(e)) return drive def listRootFolders(): @@ -231,7 +232,7 @@ def listRootFolders(): folder = "'root' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = false" fileList = drive.ListFile({'q': folder}).GetList() except (ServerNotFoundError, ssl.SSLError, RefreshError) as e: - log.info("GDrive Error %s" % e) + log.info("GDrive Error {}".format(e)) fileList = [] return fileList @@ -269,8 +270,7 @@ def getEbooksFolderId(drive=None): try: session.commit() except OperationalError as ex: - log.error("gdrive.db DB is not Writeable") - log.debug('Database error: %s', ex) + log.error_or_exception('Database error: {}'.format(ex)) session.rollback() return gDriveId.gdrive_id @@ -286,6 +286,7 @@ def getFile(pathId, fileName, drive): def getFolderId(path, drive): # drive = getDrive(drive) + currentFolderId = None try: currentFolderId = getEbooksFolderId(drive) sqlCheckPath = path if path[-1] == '/' else path + '/' @@ -318,10 +319,14 @@ def getFolderId(path, drive): session.commit() else: currentFolderId = storedPathName.gdrive_id - except OperationalError as ex: - log.error("gdrive.db DB is not Writeable") - log.debug('Database error: %s', ex) + except (OperationalError, IntegrityError, StaleDataError) as ex: + log.error_or_exception('Database error: {}'.format(ex)) session.rollback() + except ApiRequestError as ex: + log.error('{} {}'.format(ex.error['message'], path)) + session.rollback() + except RefreshError as ex: + log.error(ex) return currentFolderId @@ -355,16 +360,27 @@ def moveGdriveFolderRemote(origin_file, target_folder): children = drive.auth.service.children().list(folderId=previous_parents).execute() gFileTargetDir = getFileFromEbooksFolder(None, target_folder) if not gFileTargetDir: - # Folder is not existing, create, and move folder gFileTargetDir = drive.CreateFile( {'title': target_folder, 'parents': [{"kind": "drive#fileLink", 'id': getEbooksFolderId()}], "mimeType": "application/vnd.google-apps.folder"}) gFileTargetDir.Upload() - # Move the file to the new folder - drive.auth.service.files().update(fileId=origin_file['id'], - addParents=gFileTargetDir['id'], - removeParents=previous_parents, - fields='id, parents').execute() + # Move the file to the new folder + drive.auth.service.files().update(fileId=origin_file['id'], + addParents=gFileTargetDir['id'], + removeParents=previous_parents, + fields='id, parents').execute() + + elif gFileTargetDir['title'] != target_folder: + # Folder is not existing, create, and move folder + drive.auth.service.files().patch(fileId=origin_file['id'], + body={'title': target_folder}, + fields='title').execute() + else: + # Move the file to the new folder + drive.auth.service.files().update(fileId=origin_file['id'], + addParents=gFileTargetDir['id'], + removeParents=previous_parents, + fields='id, parents').execute() # if previous_parents has no children anymore, delete original fileparent if len(children['items']) == 1: deleteDatabaseEntry(previous_parents) @@ -412,24 +428,24 @@ def uploadFileToEbooksFolder(destFile, f): splitDir = destFile.split('/') for i, x in enumerate(splitDir): if i == len(splitDir)-1: - existingFiles = drive.ListFile({'q': "title = '%s' and '%s' in parents and trashed = false" % + existing_Files = drive.ListFile({'q': "title = '%s' and '%s' in parents and trashed = false" % (x.replace("'", r"\'"), parent['id'])}).GetList() - if len(existingFiles) > 0: - driveFile = existingFiles[0] + if len(existing_Files) > 0: + driveFile = existing_Files[0] else: driveFile = drive.CreateFile({'title': x, 'parents': [{"kind": "drive#fileLink", 'id': parent['id']}], }) driveFile.SetContentFile(f) driveFile.Upload() else: - existingFolder = drive.ListFile({'q': "title = '%s' and '%s' in parents and trashed = false" % + existing_Folder = drive.ListFile({'q': "title = '%s' and '%s' in parents and trashed = false" % (x.replace("'", r"\'"), parent['id'])}).GetList() - if len(existingFolder) == 0: + if len(existing_Folder) == 0: parent = drive.CreateFile({'title': x, 'parents': [{"kind": "drive#fileLink", 'id': parent['id']}], "mimeType": "application/vnd.google-apps.folder"}) parent.Upload() else: - parent = existingFolder[0] + parent = existing_Folder[0] def watchChange(drive, channel_id, channel_type, channel_address, @@ -528,8 +544,8 @@ def deleteDatabaseOnChange(): session.commit() except (OperationalError, InvalidRequestError) as ex: session.rollback() - log.debug('Database error: %s', ex) - log.error(u"GDrive DB is not Writeable") + log.error_or_exception('Database error: {}'.format(ex)) + session.rollback() def updateGdriveCalibreFromLocal(): @@ -540,15 +556,14 @@ def updateGdriveCalibreFromLocal(): # update gdrive.db on edit of books title def updateDatabaseOnEdit(ID,newPath): - sqlCheckPath = newPath if newPath[-1] == '/' else newPath + u'/' + sqlCheckPath = newPath if newPath[-1] == '/' else newPath + '/' storedPathName = session.query(GdriveId).filter(GdriveId.gdrive_id == ID).first() if storedPathName: storedPathName.path = sqlCheckPath try: session.commit() except OperationalError as ex: - log.error("gdrive.db DB is not Writeable") - log.debug('Database error: %s', ex) + log.error_or_exception('Database error: {}'.format(ex)) session.rollback() @@ -558,12 +573,12 @@ def deleteDatabaseEntry(ID): try: session.commit() except OperationalError as ex: - log.error("gdrive.db DB is not Writeable") - log.debug('Database error: %s', ex) + log.error_or_exception('Database error: {}'.format(ex)) session.rollback() # Gets cover file from gdrive +# ToDo: Check is this right everyone get read permissions on cover files? def get_cover_via_gdrive(cover_path): df = getFileFromEbooksFolder(cover_path, 'cover.jpg') if df: @@ -580,8 +595,30 @@ def get_cover_via_gdrive(cover_path): try: session.commit() except OperationalError as ex: - log.error("gdrive.db DB is not Writeable") - log.debug('Database error: %s', ex) + log.error_or_exception('Database error: {}'.format(ex)) + session.rollback() + return df.metadata.get('webContentLink') + else: + return None + +# Gets cover file from gdrive +def get_metadata_backup_via_gdrive(metadata_path): + df = getFileFromEbooksFolder(metadata_path, 'metadata.opf') + if df: + if not session.query(PermissionAdded).filter(PermissionAdded.gdrive_id == df['id']).first(): + df.GetPermissions() + df.InsertPermission({ + 'type': 'anyone', + 'value': 'anyone', + 'role': 'writer', # ToDo needs write access + 'withLink': True}) + permissionAdded = PermissionAdded() + permissionAdded.gdrive_id = df['id'] + session.add(permissionAdded) + try: + session.commit() + except OperationalError as ex: + log.error_or_exception('Database error: {}'.format(ex)) session.rollback() return df.metadata.get('webContentLink') else: @@ -603,7 +640,7 @@ def do_gdrive_download(df, headers, convert_encoding=False): def stream(convert_encoding): for byte in s: - headers = {"Range": 'bytes=%s-%s' % (byte[0], byte[1])} + headers = {"Range": 'bytes={}-{}'.format(byte[0], byte[1])} resp, content = df.auth.Get_Http_Object().request(download_url, headers=headers) if resp.status == 206: if convert_encoding: @@ -611,7 +648,7 @@ def do_gdrive_download(df, headers, convert_encoding=False): content = content.decode(result['encoding']).encode('utf-8') yield content else: - log.warning('An error occurred: %s', resp) + log.warning('An error occurred: {}'.format(resp)) return return Response(stream_with_context(stream(convert_encoding)), headers=headers) @@ -668,8 +705,3 @@ def get_error_text(client_secrets=None): return 'Callback url (redirect url) is missing in client_secrets.json' if client_secrets: client_secrets.update(filedata['web']) - - -def get_versions(): - return {'six': six_version, - 'httplib2': httplib2_version} diff --git a/cps/gevent_wsgi.py b/cps/gevent_wsgi.py new file mode 100644 index 000000000..b044f31b7 --- /dev/null +++ b/cps/gevent_wsgi.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2022 OzzieIsaacs +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +from gevent.pywsgi import WSGIHandler + +class MyWSGIHandler(WSGIHandler): + def get_environ(self): + env = super().get_environ() + path, __ = self.path.split('?', 1) if '?' in self.path else (self.path, '') + env['RAW_URI'] = path + return env + + diff --git a/cps/helper.py b/cps/helper.py index 08970d0ff..7fc2edc90 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -17,47 +17,48 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys import os import io import mimetypes import re import shutil -import time -import unicodedata +import socket from datetime import datetime, timedelta from tempfile import gettempdir - import requests -from babel.dates import format_datetime -from babel.units import format_unit +import unidecode + from flask import send_from_directory, make_response, redirect, abort, url_for from flask_babel import gettext as _ +from flask_babel import lazy_gettext as N_ +from flask_babel import get_locale from flask_login import current_user -from sqlalchemy.sql.expression import true, false, and_, text, func +from sqlalchemy.sql.expression import true, false, and_, or_, text, func +from sqlalchemy.exc import InvalidRequestError, OperationalError from werkzeug.datastructures import Headers from werkzeug.security import generate_password_hash from markupsafe import escape +from urllib.parse import quote try: - from urllib.parse import quote + import advocate + from advocate.exceptions import UnacceptableAddressException + use_advocate = True except ImportError: - from urllib import quote + use_advocate = False + advocate = requests + UnacceptableAddressException = MissingSchema = BaseException -try: - import unidecode - use_unidecode = True -except ImportError: - use_unidecode = False - -from . import calibre_db +from . import calibre_db, cli_param from .tasks.convert import TaskConvert -from . import logger, config, get_locale, db, ub +from . import logger, config, db, ub, fs from . import gdriveutils as gd -from .constants import STATIC_DIR as _STATIC_DIR +from .constants import STATIC_DIR as _STATIC_DIR, CACHE_TYPE_THUMBNAILS, THUMBNAIL_TYPE_COVER, THUMBNAIL_TYPE_SERIES from .subproc_wrapper import process_wait -from .services.worker import WorkerThread, STAT_WAITING, STAT_FAIL, STAT_STARTED, STAT_FINISH_SUCCESS +from .services.worker import WorkerThread from .tasks.mail import TaskEmail +from .tasks.thumbnail import TaskClearCoverThumbnailCache, TaskGenerateCoverThumbnails +from .tasks.metadata_backup import TaskBackupMetadata log = logger.create() @@ -72,181 +73,181 @@ except (ImportError, RuntimeError) as e: # Convert existing book entry to new format -def convert_book_format(book_id, calibrepath, old_book_format, new_book_format, user_id, kindle_mail=None): +def convert_book_format(book_id, calibre_path, old_book_format, new_book_format, user_id, ereader_mail=None): book = calibre_db.get_book(book_id) data = calibre_db.get_book_format(book.id, old_book_format) - file_path = os.path.join(calibrepath, book.path, data.name) if not data: - error_message = _(u"%(format)s format not found for book id: %(book)d", format=old_book_format, book=book_id) + error_message = _("%(format)s format not found for book id: %(book)d", format=old_book_format, book=book_id) log.error("convert_book_format: %s", error_message) return error_message + file_path = os.path.join(calibre_path, book.path, data.name) if config.config_use_google_drive: if not gd.getFileFromEbooksFolder(book.path, data.name + "." + old_book_format.lower()): - error_message = _(u"%(format)s not found on Google Drive: %(fn)s", + error_message = _("%(format)s not found on Google Drive: %(fn)s", format=old_book_format, fn=data.name + "." + old_book_format.lower()) return error_message else: if not os.path.exists(file_path + "." + old_book_format.lower()): - error_message = _(u"%(format)s not found: %(fn)s", + error_message = _("%(format)s not found: %(fn)s", format=old_book_format, fn=data.name + "." + old_book_format.lower()) return error_message # read settings and append converter task to queue - if kindle_mail: + if ereader_mail: settings = config.get_mail_settings() - settings['subject'] = _('Send to Kindle') # pretranslate Subject for e-mail - settings['body'] = _(u'This e-mail has been sent via Calibre-Web.') + settings['subject'] = _('Send to eReader') # pretranslate Subject for Email + settings['body'] = _('This Email has been sent via Calibre-Web.') else: settings = dict() link = '{}'.format(url_for('web.show_book', book_id=book.id), escape(book.title)) # prevent xss - txt = u"{} -> {}: {}".format( + txt = "{} -> {}: {}".format( old_book_format.upper(), new_book_format.upper(), link) settings['old_book_format'] = old_book_format settings['new_book_format'] = new_book_format - WorkerThread.add(user_id, TaskConvert(file_path, book.id, txt, settings, kindle_mail, user_id)) + WorkerThread.add(user_id, TaskConvert(file_path, book.id, txt, settings, ereader_mail, user_id)) return None -def send_test_mail(kindle_mail, user_name): - WorkerThread.add(user_name, TaskEmail(_(u'Calibre-Web test e-mail'), None, None, - config.get_mail_settings(), kindle_mail, _(u"Test e-mail"), - _(u'This e-mail has been sent via Calibre-Web.'))) +# Texts are not lazy translated as they are supposed to get send out as is +def send_test_mail(ereader_mail, user_name): + WorkerThread.add(user_name, TaskEmail(_('Calibre-Web Test Email'), None, None, + config.get_mail_settings(), ereader_mail, N_("Test Email"), + _('This Email has been sent via Calibre-Web.'))) return # Send registration email or password reset email, depending on parameter resend (False means welcome email) def send_registration_mail(e_mail, user_name, default_password, resend=False): - txt = "Hello %s!\r\n" % user_name + txt = "Hi %s!\r\n" % user_name if not resend: - txt += "Your new account at Calibre-Web has been created. Thanks for joining us!\r\n" - txt += "Please log in to your account using the following informations:\r\n" - txt += "User name: %s\r\n" % user_name + txt += "Your account at Calibre-Web has been created.\r\n" + txt += "Please log in using the following information:\r\n" + txt += "Username: %s\r\n" % user_name txt += "Password: %s\r\n" % default_password - txt += "Don't forget to change your password after first login.\r\n" - txt += "Sincerely\r\n\r\n" - txt += "Your Calibre-Web team" + txt += "Don't forget to change your password after your first login.\r\n" + txt += "Regards,\r\n\r\n" + txt += "Calibre-Web" WorkerThread.add(None, TaskEmail( - subject=_(u'Get Started with Calibre-Web'), + subject=_('Get Started with Calibre-Web'), filepath=None, attachment=None, settings=config.get_mail_settings(), recipient=e_mail, - taskMessage=_(u"Registration e-mail for user: %(name)s", name=user_name), + task_message=N_("Registration Email for user: %(name)s", name=user_name), text=txt )) return -def check_send_to_kindle_with_converter(formats): - bookformats = list() - if 'EPUB' in formats and 'MOBI' not in formats: - bookformats.append({'format': 'Mobi', - 'convert': 1, - 'text': _('Convert %(orig)s to %(format)s and send to Kindle', - orig='Epub', - format='Mobi')}) - if 'AZW3' in formats and not 'MOBI' in formats: - bookformats.append({'format': 'Mobi', - 'convert': 2, - 'text': _('Convert %(orig)s to %(format)s and send to Kindle', - orig='Azw3', - format='Mobi')}) - return bookformats +def check_send_to_ereader_with_converter(formats): + book_formats = list() + if 'MOBI' in formats and 'EPUB' not in formats: + book_formats.append({'format': 'Epub', + 'convert': 1, + 'text': _('Convert %(orig)s to %(format)s and send to eReader', + orig='Mobi', + format='Epub')}) + if 'AZW3' in formats and 'EPUB' not in formats: + book_formats.append({'format': 'Epub', + 'convert': 2, + 'text': _('Convert %(orig)s to %(format)s and send to eReader', + orig='Azw3', + format='Epub')}) + return book_formats -def check_send_to_kindle(entry): +def check_send_to_ereader(entry): """ - returns all available book formats for sending to Kindle + returns all available book formats for sending to eReader """ formats = list() - bookformats = list() + book_formats = list() if len(entry.data): for ele in iter(entry.data): if ele.uncompressed_size < config.mail_size: formats.append(ele.format) + if 'EPUB' in formats: + book_formats.append({'format': 'Epub', + 'convert': 0, + 'text': _('Send %(format)s to eReader', format='Epub')}) if 'MOBI' in formats: - bookformats.append({'format': 'Mobi', - 'convert': 0, - 'text': _('Send %(format)s to Kindle', format='Mobi')}) + book_formats.append({'format': 'Mobi', + 'convert': 0, + 'text': _('Send %(format)s to eReader', format='Mobi')}) if 'PDF' in formats: - bookformats.append({'format': 'Pdf', - 'convert': 0, - 'text': _('Send %(format)s to Kindle', format='Pdf')}) + book_formats.append({'format': 'Pdf', + 'convert': 0, + 'text': _('Send %(format)s to eReader', format='Pdf')}) if 'AZW' in formats: - bookformats.append({'format': 'Azw', - 'convert': 0, - 'text': _('Send %(format)s to Kindle', format='Azw')}) + book_formats.append({'format': 'Azw', + 'convert': 0, + 'text': _('Send %(format)s to eReader', format='Azw')}) if config.config_converterpath: - bookformats.extend(check_send_to_kindle_with_converter(formats)) - return bookformats + book_formats.extend(check_send_to_ereader_with_converter(formats)) + return book_formats else: - log.error(u'Cannot find book entry %d', entry.id) + log.error('Cannot find book entry %d', entry.id) return None # Check if a reader is existing for any of the book formats, if not, return empty list, otherwise return # list with supported formats def check_read_formats(entry): - EXTENSIONS_READER = {'TXT', 'PDF', 'EPUB', 'CBZ', 'CBT', 'CBR', 'DJVU'} - bookformats = list() + extensions_reader = {'TXT', 'PDF', 'EPUB', 'CBZ', 'CBT', 'CBR', 'DJVU'} + book_formats = list() if len(entry.data): for ele in iter(entry.data): - if ele.format.upper() in EXTENSIONS_READER: - bookformats.append(ele.format.lower()) - return bookformats + if ele.format.upper() in extensions_reader: + book_formats.append(ele.format.lower()) + return book_formats # Files are processed in the following order/priority: -# 1: If Mobi file is existing, it's directly send to kindle email, -# 2: If Epub file is existing, it's converted and send to kindle email, -# 3: If Pdf file is existing, it's directly send to kindle email -def send_mail(book_id, book_format, convert, kindle_mail, calibrepath, user_id): +# 1: If Mobi file is existing, it's directly send to eReader email, +# 2: If Epub file is existing, it's converted and send to eReader email, +# 3: If Pdf file is existing, it's directly send to eReader email +def send_mail(book_id, book_format, convert, ereader_mail, calibrepath, user_id): """Send email with attachments""" book = calibre_db.get_book(book_id) if convert == 1: # returns None if success, otherwise errormessage - return convert_book_format(book_id, calibrepath, u'epub', book_format.lower(), user_id, kindle_mail) + return convert_book_format(book_id, calibrepath, 'epub', book_format.lower(), user_id, ereader_mail) if convert == 2: # returns None if success, otherwise errormessage - return convert_book_format(book_id, calibrepath, u'azw3', book_format.lower(), user_id, kindle_mail) + return convert_book_format(book_id, calibrepath, 'azw3', book_format.lower(), user_id, ereader_mail) for entry in iter(book.data): if entry.format.upper() == book_format.upper(): converted_file_name = entry.name + '.' + book_format.lower() link = '{}'.format(url_for('web.show_book', book_id=book_id), escape(book.title)) - EmailText = _(u"%(book)s send to Kindle", book=link) - WorkerThread.add(user_id, TaskEmail(_(u"Send to Kindle"), book.path, converted_file_name, - config.get_mail_settings(), kindle_mail, - EmailText, _(u'This e-mail has been sent via Calibre-Web.'))) + email_text = N_("%(book)s send to eReader", book=link) + WorkerThread.add(user_id, TaskEmail(_("Send to eReader"), book.path, converted_file_name, + config.get_mail_settings(), ereader_mail, + email_text, _('This Email has been sent via Calibre-Web.'))) return - return _(u"The requested file could not be read. Maybe wrong permissions?") + return _("The requested file could not be read. Maybe wrong permissions?") -def get_valid_filename(value, replace_whitespace=True): +def get_valid_filename(value, replace_whitespace=True, chars=128): """ Returns the given string converted to a string that can be used for a clean filename. Limits num characters to 128 max. """ - if value[-1:] == u'.': - value = value[:-1]+u'_' + if value[-1:] == '.': + value = value[:-1]+'_' value = value.replace("/", "_").replace(":", "_").strip('\0') - if use_unidecode: - if not config.config_unicode_filename: - value = (unidecode.unidecode(value)) - else: - value = value.replace(u'§', u'SS') - value = value.replace(u'ß', u'ss') - value = unicodedata.normalize('NFKD', value) - re_slugify = re.compile(r'[\W\s-]', re.UNICODE) - value = re_slugify.sub('', value) + if config.config_unicode_filename: + value = (unidecode.unidecode(value)) if replace_whitespace: # *+:\"/<>? are replaced by _ - value = re.sub(r'[*+:\\\"/<>?]+', u'_', value, flags=re.U) + value = re.sub(r'[*+:\\\"/<>?]+', '_', value, flags=re.U) # pipe has to be replaced with comma - value = re.sub(r'[|]+', u',', value, flags=re.U) - value = value[:128].strip() + value = re.sub(r'[|]+', ',', value, flags=re.U) + + value = value.encode('utf-8')[:chars].decode('utf-8', errors='ignore').strip() + if not value: raise ValueError("Filename cannot be empty") return value @@ -269,6 +270,7 @@ def split_authors(values): def get_sorted_author(value): + value2 = None try: if ',' not in value: regexes = [r"^(JR|SR)\.?$", r"^I{1,3}\.?$", r"^IV\.?$"] @@ -294,9 +296,59 @@ def get_sorted_author(value): return value2 -# Deletes a book fro the local filestorage, returns True if deleting is successfull, otherwise false +def edit_book_read_status(book_id, read_status=None): + if not config.config_read_column: + book = ub.session.query(ub.ReadBook).filter(and_(ub.ReadBook.user_id == int(current_user.id), + ub.ReadBook.book_id == book_id)).first() + if book: + if read_status is None: + if book.read_status == ub.ReadBook.STATUS_FINISHED: + book.read_status = ub.ReadBook.STATUS_UNREAD + else: + book.read_status = ub.ReadBook.STATUS_FINISHED + else: + book.read_status = ub.ReadBook.STATUS_FINISHED if read_status else ub.ReadBook.STATUS_UNREAD + else: + read_book = ub.ReadBook(user_id=current_user.id, book_id=book_id) + read_book.read_status = ub.ReadBook.STATUS_FINISHED + book = read_book + if not book.kobo_reading_state: + kobo_reading_state = ub.KoboReadingState(user_id=current_user.id, book_id=book_id) + kobo_reading_state.current_bookmark = ub.KoboBookmark() + kobo_reading_state.statistics = ub.KoboStatistics() + book.kobo_reading_state = kobo_reading_state + ub.session.merge(book) + ub.session_commit("Book {} readbit toggled".format(book_id)) + else: + try: + calibre_db.update_title_sort(config) + book = calibre_db.get_filtered_book(book_id) + book_read_status = getattr(book, 'custom_column_' + str(config.config_read_column)) + if len(book_read_status): + if read_status is None: + book_read_status[0].value = not book_read_status[0].value + else: + book_read_status[0].value = read_status is True + calibre_db.session.commit() + else: + cc_class = db.cc_classes[config.config_read_column] + new_cc = cc_class(value=read_status or 1, book=book_id) + calibre_db.session.add(new_cc) + calibre_db.session.commit() + except (KeyError, AttributeError, IndexError): + log.error( + "Custom Column No.{} does not exist in calibre database".format(config.config_read_column)) + return "Custom Column No.{} does not exist in calibre database".format(config.config_read_column) + except (OperationalError, InvalidRequestError) as ex: + calibre_db.session.rollback() + log.error("Read status could not set: {}".format(ex)) + return _("Read status could not set: {}".format(ex.orig)) + return "" + + +# Deletes a book from the local filestorage, returns True if deleting is successful, otherwise false def delete_book_file(book, calibrepath, book_format=None): - # check that path is 2 elements deep, check that target path has no subfolders + # check that path is 2 elements deep, check that target path has no sub folders if book.path.count('/') == 1: path = os.path.join(calibrepath, book.path) if book_format: @@ -317,15 +369,15 @@ def delete_book_file(book, calibrepath, book_format=None): id=book.id, path=book.path) shutil.rmtree(path) - except (IOError, OSError) as e: - log.error("Deleting book %s failed: %s", book.id, e) - return False, _("Deleting book %(id)s failed: %(message)s", id=book.id, message=e) + except (IOError, OSError) as ex: + log.error("Deleting book %s failed: %s", book.id, ex) + return False, _("Deleting book %(id)s failed: %(message)s", id=book.id, message=ex) authorpath = os.path.join(calibrepath, os.path.split(book.path)[0]) if not os.listdir(authorpath): try: shutil.rmtree(authorpath) - except (IOError, OSError) as e: - log.error("Deleting authorpath for book %s failed: %s", book.id, e) + except (IOError, OSError) as ex: + log.error("Deleting authorpath for book %s failed: %s", book.id, ex) return True, None log.error("Deleting book %s from database only, book path in database not valid: %s", @@ -335,119 +387,203 @@ def delete_book_file(book, calibrepath, book_format=None): path=book.path) -# Moves files in file storage during author/title rename, or from temp dir to file storage -def update_dir_structure_file(book_id, calibrepath, first_author, orignal_filepath, db_filename): - # get book database entry from id, if original path overwrite source with original_filepath - localbook = calibre_db.get_book(book_id) - if orignal_filepath: - path = orignal_filepath - else: - path = os.path.join(calibrepath, localbook.path) +def clean_author_database(renamed_author, calibre_path="", local_book=None, gdrive=None): + valid_filename_authors = [get_valid_filename(r, chars=96) for r in renamed_author] + for r in renamed_author: + if local_book: + all_books = [local_book] + else: + all_books = calibre_db.session.query(db.Books) \ + .filter(db.Books.authors.any(db.Authors.name == r)).all() + for book in all_books: + book_author_path = book.path.split('/')[0] + if book_author_path in valid_filename_authors or local_book: + new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first() + all_new_authordir = get_valid_filename(new_author.name, chars=96) + all_titledir = book.path.split('/')[1] + all_new_path = os.path.join(calibre_path, all_new_authordir, all_titledir) + all_new_name = get_valid_filename(book.title, chars=42) + ' - ' \ + + get_valid_filename(new_author.name, chars=42) + # change location in database to new author/title path + book.path = os.path.join(all_new_authordir, all_titledir).replace('\\', '/') + for file_format in book.data: + if not gdrive: + shutil.move(os.path.normcase(os.path.join(all_new_path, + file_format.name + '.' + file_format.format.lower())), + os.path.normcase(os.path.join(all_new_path, + all_new_name + '.' + file_format.format.lower()))) + else: + g_file = gd.getFileFromEbooksFolder(all_new_path, + file_format.name + '.' + file_format.format.lower()) + if g_file: + gd.moveGdriveFileRemote(g_file, all_new_name + '.' + file_format.format.lower()) + gd.updateDatabaseOnEdit(g_file['id'], all_new_name + '.' + file_format.format.lower()) + else: + log.error("File {} not found on gdrive" + .format(all_new_path, file_format.name + '.' + file_format.format.lower())) + file_format.name = all_new_name - # Create (current) authordir and titledir from database - authordir = localbook.path.split('/')[0] - titledir = localbook.path.split('/')[1] - # Create new_authordir from parameter or from database - # Create new titledir from database and add id +def rename_all_authors(first_author, renamed_author, calibre_path="", localbook=None, gdrive=False): + # Create new_author_dir from parameter or from database + # Create new title_dir from database and add id if first_author: - new_authordir = get_valid_filename(first_author) - else: - new_authordir = get_valid_filename(localbook.authors[0].name) - new_titledir = get_valid_filename(localbook.title) + " (" + str(book_id) + ")" - - if titledir != new_titledir or authordir != new_authordir or orignal_filepath: - new_path = os.path.join(calibrepath, new_authordir, new_titledir) - new_name = get_valid_filename(localbook.title) + ' - ' + get_valid_filename(new_authordir) - try: - if orignal_filepath: - if not os.path.isdir(new_path): - os.makedirs(new_path) - shutil.move(os.path.normcase(path), os.path.normcase(os.path.join(new_path, db_filename))) - log.debug("Moving title: %s to %s/%s", path, new_path, new_name) - # Check new path is not valid path + new_authordir = get_valid_filename(first_author, chars=96) + for r in renamed_author: + new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first() + old_author_dir = get_valid_filename(r, chars=96) + new_author_rename_dir = get_valid_filename(new_author.name, chars=96) + if gdrive: + g_file = gd.getFileFromEbooksFolder(None, old_author_dir) + if g_file: + gd.moveGdriveFolderRemote(g_file, new_author_rename_dir) else: - if not os.path.exists(new_path): - # move original path to new path - log.debug("Moving title: %s to %s", path, new_path) - shutil.move(os.path.normcase(path), os.path.normcase(new_path)) - else: # path is valid copy only files to new location (merge) - log.info("Moving title: %s into existing: %s", path, new_path) - # Take all files and subfolder from old path (strange command) - for dir_name, __, file_list in os.walk(path): - for file in file_list: - shutil.move(os.path.normcase(os.path.join(dir_name, file)), - os.path.normcase(os.path.join(new_path + dir_name[len(path):], file))) - # os.unlink(os.path.normcase(os.path.join(dir_name, file))) - # change location in database to new author/title path - localbook.path = os.path.join(new_authordir, new_titledir).replace('\\','/') - except (OSError) as ex: - log.error("Rename title from: %s to %s: %s", path, new_path, ex) - log.debug(ex, exc_info=True) - return _("Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s", - src=path, dest=new_path, error=str(ex)) + if os.path.isdir(os.path.join(calibre_path, old_author_dir)): + try: + old_author_path = os.path.join(calibre_path, old_author_dir) + new_author_path = os.path.join(calibre_path, new_author_rename_dir) + shutil.move(os.path.normcase(old_author_path), os.path.normcase(new_author_path)) + except OSError as ex: + log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex) + log.debug(ex, exc_info=True) + return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s", + src=old_author_path, dest=new_author_path, error=str(ex)) + else: + new_authordir = get_valid_filename(localbook.authors[0].name, chars=96) + return new_authordir - # Rename all files from old names to new names - try: - for file_format in localbook.data: - shutil.move(os.path.normcase( - os.path.join(new_path, file_format.name + '.' + file_format.format.lower())), - os.path.normcase(os.path.join(new_path, new_name + '.' + file_format.format.lower()))) - file_format.name = new_name - if not orignal_filepath and len(os.listdir(os.path.dirname(path))) == 0: - shutil.rmtree(os.path.dirname(path)) - except (OSError) as ex: - log.error("Rename file in path %s to %s: %s", new_path, new_name, ex) - log.debug(ex, exc_info=True) - return _("Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s", - src=new_path, dest=new_name, error=str(ex)) - return False -def update_dir_structure_gdrive(book_id, first_author): - error = False +# Moves files in file storage during author/title rename, or from temp dir to file storage +def update_dir_structure_file(book_id, calibre_path, first_author, original_filepath, db_filename, renamed_author): + # get book database entry from id, if original path overwrite source with original_filepath + local_book = calibre_db.get_book(book_id) + if original_filepath: + path = original_filepath + else: + path = os.path.join(calibre_path, local_book.path) + + # Create (current) author_dir and title_dir from database + author_dir = local_book.path.split('/')[0] + title_dir = local_book.path.split('/')[1] + + # Create new_author_dir from parameter or from database + # Create new title_dir from database and add id + new_author_dir = rename_all_authors(first_author, renamed_author, calibre_path, local_book) + if first_author: + if first_author.lower() in [r.lower() for r in renamed_author]: + if os.path.isdir(os.path.join(calibre_path, new_author_dir)): + path = os.path.join(calibre_path, new_author_dir, title_dir) + + new_title_dir = get_valid_filename(local_book.title, chars=96) + " (" + str(book_id) + ")" + + if title_dir != new_title_dir or author_dir != new_author_dir or original_filepath: + error = move_files_on_change(calibre_path, + new_author_dir, + new_title_dir, + local_book, + db_filename, + original_filepath, + path) + if error: + return error + + # Rename all files from old names to new names + return rename_files_on_change(first_author, renamed_author, local_book, original_filepath, path, calibre_path) + + +def upload_new_file_gdrive(book_id, first_author, renamed_author, title, title_dir, original_filepath, filename_ext): + book = calibre_db.get_book(book_id) + file_name = get_valid_filename(title, chars=42) + ' - ' + \ + get_valid_filename(first_author, chars=42) + filename_ext + rename_all_authors(first_author, renamed_author, gdrive=True) + gdrive_path = os.path.join(get_valid_filename(first_author, chars=96), + title_dir + " (" + str(book_id) + ")") + book.path = gdrive_path.replace("\\", "/") + gd.uploadFileToEbooksFolder(os.path.join(gdrive_path, file_name).replace("\\", "/"), original_filepath) + return rename_files_on_change(first_author, renamed_author, local_book=book, gdrive=True) + + + +def update_dir_structure_gdrive(book_id, first_author, renamed_author): book = calibre_db.get_book(book_id) - path = book.path authordir = book.path.split('/')[0] - if first_author: - new_authordir = get_valid_filename(first_author) - else: - new_authordir = get_valid_filename(book.authors[0].name) titledir = book.path.split('/')[1] - new_titledir = get_valid_filename(book.title) + u" (" + str(book_id) + u")" + new_authordir = rename_all_authors(first_author, renamed_author, gdrive=True) + new_titledir = get_valid_filename(book.title, chars=96) + " (" + str(book_id) + ")" if titledir != new_titledir: - gFile = gd.getFileFromEbooksFolder(os.path.dirname(book.path), titledir) - if gFile: - gFile['title'] = new_titledir - gFile.Upload() - book.path = book.path.split('/')[0] + u'/' + new_titledir - path = book.path - gd.updateDatabaseOnEdit(gFile['id'], book.path) # only child folder affected + g_file = gd.getFileFromEbooksFolder(os.path.dirname(book.path), titledir) + if g_file: + gd.moveGdriveFileRemote(g_file, new_titledir) + book.path = book.path.split('/')[0] + '/' + new_titledir + gd.updateDatabaseOnEdit(g_file['id'], book.path) # only child folder affected else: - error = _(u'File %(file)s not found on Google Drive', file=book.path) # file not found + return _('File %(file)s not found on Google Drive', file=book.path) # file not found - if authordir != new_authordir: - gFile = gd.getFileFromEbooksFolder(os.path.dirname(book.path), new_titledir) - if gFile: - gd.moveGdriveFolderRemote(gFile, new_authordir) - book.path = new_authordir + u'/' + book.path.split('/')[1] - path = book.path - gd.updateDatabaseOnEdit(gFile['id'], book.path) + if authordir != new_authordir and authordir not in renamed_author: + g_file = gd.getFileFromEbooksFolder(os.path.dirname(book.path), new_titledir) + if g_file: + gd.moveGdriveFolderRemote(g_file, new_authordir) + book.path = new_authordir + '/' + book.path.split('/')[1] + gd.updateDatabaseOnEdit(g_file['id'], book.path) else: - error = _(u'File %(file)s not found on Google Drive', file=authordir) # file not found + return _('File %(file)s not found on Google Drive', file=authordir) # file not found + + # change location in database to new author/title path + book.path = os.path.join(new_authordir, new_titledir).replace('\\', '/') + return rename_files_on_change(first_author, renamed_author, book, gdrive=True) + + +def move_files_on_change(calibre_path, new_authordir, new_titledir, localbook, db_filename, original_filepath, path): + new_path = os.path.join(calibre_path, new_authordir, new_titledir) + new_name = get_valid_filename(localbook.title, chars=96) + ' - ' + new_authordir + try: + if original_filepath: + if not os.path.isdir(new_path): + os.makedirs(new_path) + shutil.move(os.path.normcase(original_filepath), os.path.normcase(os.path.join(new_path, db_filename))) + log.debug("Moving title: %s to %s/%s", original_filepath, new_path, new_name) + else: + # Check new path is not valid path + if not os.path.exists(new_path): + # move original path to new path + log.debug("Moving title: %s to %s", path, new_path) + shutil.move(os.path.normcase(path), os.path.normcase(new_path)) + else: # path is valid copy only files to new location (merge) + log.info("Moving title: %s into existing: %s", path, new_path) + # Take all files and subfolder from old path (strange command) + for dir_name, __, file_list in os.walk(path): + for file in file_list: + shutil.move(os.path.normcase(os.path.join(dir_name, file)), + os.path.normcase(os.path.join(new_path + dir_name[len(path):], file))) + # change location in database to new author/title path + localbook.path = os.path.join(new_authordir, new_titledir).replace('\\', '/') + except OSError as ex: + log.error_or_exception("Rename title from {} to {} failed with error: {}".format(path, new_path, ex)) + return _("Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s", + src=path, dest=new_path, error=str(ex)) + return False + + +def rename_files_on_change(first_author, + renamed_author, + local_book, + original_filepath="", + path="", + calibre_path="", + gdrive=False): # Rename all files from old names to new names - - if authordir != new_authordir or titledir != new_titledir: - new_name = get_valid_filename(book.title) + u' - ' + get_valid_filename(new_authordir) - for file_format in book.data: - gFile = gd.getFileFromEbooksFolder(path, file_format.name + u'.' + file_format.format.lower()) - if not gFile: - error = _(u'File %(file)s not found on Google Drive', file=file_format.name) # file not found - break - gd.moveGdriveFileRemote(gFile, new_name + u'.' + file_format.format.lower()) - file_format.name = new_name - return error + try: + clean_author_database(renamed_author, calibre_path, gdrive=gdrive) + if first_author and first_author not in renamed_author: + clean_author_database([first_author], calibre_path, local_book, gdrive) + if not gdrive and not renamed_author and not original_filepath and len(os.listdir(os.path.dirname(path))) == 0: + shutil.rmtree(os.path.dirname(path)) + except (OSError, FileNotFoundError) as ex: + log.error_or_exception("Error in rename file in path {}".format(ex)) + return _("Error in rename file in path: {}".format(str(ex))) + return False def delete_book_gdrive(book, book_format): @@ -457,14 +593,14 @@ def delete_book_gdrive(book, book_format): for entry in book.data: if entry.format.upper() == book_format: name = entry.name + '.' + book_format - gFile = gd.getFileFromEbooksFolder(book.path, name) + g_file = gd.getFileFromEbooksFolder(book.path, name) else: - gFile = gd.getFileFromEbooksFolder(os.path.dirname(book.path), book.path.split('/')[1]) - if gFile: - gd.deleteDatabaseEntry(gFile['id']) - gFile.Trash() + g_file = gd.getFileFromEbooksFolder(os.path.dirname(book.path), book.path.split('/')[1]) + if g_file: + gd.deleteDatabaseEntry(g_file['id']) + g_file.Trash() else: - error = _(u'Book path %(path)s not found on Google Drive', path=book.path) # file not found + error = _('Book path %(path)s not found on Google Drive', path=book.path) # file not found return error is None, error @@ -494,48 +630,64 @@ def generate_random_password(): def uniq(inpt): output = [] - inpt = [ " ".join(inp.split()) for inp in inpt] + inpt = [" ".join(inp.split()) for inp in inpt] for x in inpt: if x not in output: output.append(x) return output + def check_email(email): email = valid_email(email) if ub.session.query(ub.User).filter(func.lower(ub.User.email) == email.lower()).first(): - log.error(u"Found an existing account for this e-mail address") - raise Exception(_(u"Found an existing account for this e-mail address")) + log.error("Found an existing account for this Email address") + raise Exception(_("Found an existing account for this Email address")) return email def check_username(username): username = username.strip() if ub.session.query(ub.User).filter(func.lower(ub.User.name) == username.lower()).scalar(): - log.error(u"This username is already taken") - raise Exception (_(u"This username is already taken")) + log.error("This username is already taken") + raise Exception(_("This username is already taken")) return username def valid_email(email): email = email.strip() - # Regex according to https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email#validation - if not re.search(r"^[\w.!#$%&'*+\\/=?^_`{|}~-]+@[\w](?:[\w-]{0,61}[\w])?(?:\.[\w](?:[\w-]{0,61}[\w])?)*$", - email): - log.error(u"Invalid e-mail address format") - raise Exception(_(u"Invalid e-mail address format")) + # if email is not deleted + if email: + # Regex according to https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email#validation + if not re.search(r"^[\w.!#$%&'*+\\/=?^_`{|}~-]+@[\w](?:[\w-]{0,61}[\w])?(?:\.[\w](?:[\w-]{0,61}[\w])?)*$", + email): + log.error("Invalid Email address format") + raise Exception(_("Invalid Email address format")) return email # ################################# External interface ################################# -def update_dir_stucture(book_id, calibrepath, first_author=None, orignal_filepath=None, db_filename=None): +def update_dir_structure(book_id, + calibre_path, + first_author=None, # change author of book to this author + original_filepath=None, + db_filename=None, + renamed_author=None): + renamed_author = renamed_author or [] if config.config_use_google_drive: - return update_dir_structure_gdrive(book_id, first_author) + return update_dir_structure_gdrive(book_id, first_author, renamed_author) else: - return update_dir_structure_file(book_id, calibrepath, first_author, orignal_filepath, db_filename) + return update_dir_structure_file(book_id, + calibre_path, + first_author, + original_filepath, + db_filename, renamed_author) def delete_book(book, calibrepath, book_format): + if not book_format: + clear_cover_thumbnail_cache(book.id) ## here it breaks + calibre_db.delete_dirty_metadata(book.id) if config.config_use_google_drive: return delete_book_gdrive(book, book_format) else: @@ -544,24 +696,38 @@ def delete_book(book, calibrepath, book_format): def get_cover_on_failure(use_generic_cover): if use_generic_cover: - return send_from_directory(_STATIC_DIR, "generic_cover.jpg") - else: - return None + try: + return send_from_directory(_STATIC_DIR, "generic_cover.jpg") + except PermissionError: + log.error("No permission to access generic_cover.jpg file.") + abort(403) + abort(404) -def get_book_cover(book_id): +def get_book_cover(book_id, resolution=None): book = calibre_db.get_filtered_book(book_id, allow_show_archived=True) - return get_book_cover_internal(book, use_generic_cover_on_failure=True) + return get_book_cover_internal(book, use_generic_cover_on_failure=True, resolution=resolution) -def get_book_cover_with_uuid(book_uuid, - use_generic_cover_on_failure=True): +# Called only by kobo sync -> cover not found should be answered with 404 and not with default cover +def get_book_cover_with_uuid(book_uuid, resolution=None): book = calibre_db.get_book_by_uuid(book_uuid) - return get_book_cover_internal(book, use_generic_cover_on_failure) + return get_book_cover_internal(book, use_generic_cover_on_failure=False, resolution=resolution) -def get_book_cover_internal(book, use_generic_cover_on_failure): +def get_book_cover_internal(book, use_generic_cover_on_failure, resolution=None): if book and book.has_cover: + + # Send the book cover thumbnail if it exists in cache + if resolution: + thumbnail = get_book_cover_thumbnail(book, resolution) + if thumbnail: + cache = fs.FileSystem() + if cache.get_cache_file_exists(thumbnail.filename, CACHE_TYPE_THUMBNAILS): + return send_from_directory(cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), + thumbnail.filename) + + # Send the book cover from Google Drive if configured if config.config_use_google_drive: try: if not gd.is_gdrive_ready(): @@ -570,11 +736,13 @@ def get_book_cover_internal(book, use_generic_cover_on_failure): if path: return redirect(path) else: - log.error('%s/cover.jpg not found on Google Drive', book.path) + log.error('{}/cover.jpg not found on Google Drive'.format(book.path)) return get_cover_on_failure(use_generic_cover_on_failure) except Exception as ex: - log.debug_or_exception(ex) + log.error_or_exception(ex) return get_cover_on_failure(use_generic_cover_on_failure) + + # Send the book cover from the Calibre directory else: cover_file_path = os.path.join(config.config_calibre_dir, book.path) if os.path.isfile(os.path.join(cover_file_path, "cover.jpg")): @@ -585,20 +753,82 @@ def get_book_cover_internal(book, use_generic_cover_on_failure): return get_cover_on_failure(use_generic_cover_on_failure) +def get_book_cover_thumbnail(book, resolution): + if book and book.has_cover: + return ub.session \ + .query(ub.Thumbnail) \ + .filter(ub.Thumbnail.type == THUMBNAIL_TYPE_COVER) \ + .filter(ub.Thumbnail.entity_id == book.id) \ + .filter(ub.Thumbnail.resolution == resolution) \ + .filter(or_(ub.Thumbnail.expiration.is_(None), ub.Thumbnail.expiration > datetime.utcnow())) \ + .first() + + +def get_series_thumbnail_on_failure(series_id, resolution): + book = calibre_db.session \ + .query(db.Books) \ + .join(db.books_series_link) \ + .join(db.Series) \ + .filter(db.Series.id == series_id) \ + .filter(db.Books.has_cover == 1) \ + .first() + + return get_book_cover_internal(book, use_generic_cover_on_failure=True, resolution=resolution) + + +def get_series_cover_thumbnail(series_id, resolution=None): + return get_series_cover_internal(series_id, resolution) + + +def get_series_cover_internal(series_id, resolution=None): + # Send the series thumbnail if it exists in cache + if resolution: + thumbnail = get_series_thumbnail(series_id, resolution) + if thumbnail: + cache = fs.FileSystem() + if cache.get_cache_file_exists(thumbnail.filename, CACHE_TYPE_THUMBNAILS): + return send_from_directory(cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), + thumbnail.filename) + + return get_series_thumbnail_on_failure(series_id, resolution) + + +def get_series_thumbnail(series_id, resolution): + return ub.session \ + .query(ub.Thumbnail) \ + .filter(ub.Thumbnail.type == THUMBNAIL_TYPE_SERIES) \ + .filter(ub.Thumbnail.entity_id == series_id) \ + .filter(ub.Thumbnail.resolution == resolution) \ + .filter(or_(ub.Thumbnail.expiration.is_(None), ub.Thumbnail.expiration > datetime.utcnow())) \ + .first() + + # saves book cover from url def save_cover_from_url(url, book_path): try: - img = requests.get(url, timeout=(10, 200)) # ToDo: Error Handling + if cli_param.allow_localhost: + img = requests.get(url, timeout=(10, 200), allow_redirects=False) # ToDo: Error Handling + elif use_advocate: + img = advocate.get(url, timeout=(10, 200), allow_redirects=False) # ToDo: Error Handling + else: + log.error("python module advocate is not installed but is needed") + return False, _("Python module 'advocate' is not installed but is needed for cover uploads") img.raise_for_status() return save_cover(img, book_path) - except (requests.exceptions.HTTPError, + except (socket.gaierror, + requests.exceptions.HTTPError, + requests.exceptions.InvalidURL, requests.exceptions.ConnectionError, requests.exceptions.Timeout) as ex: - log.info(u'Cover Download Error %s', ex) + # "Invalid host" can be the result of a redirect response + log.error(u'Cover Download Error %s', ex) return False, _("Error Downloading Cover") except MissingDelegateError as ex: log.info(u'File Format Error %s', ex) return False, _("Cover Format Error") + except UnacceptableAddressException as e: + log.error("Localhost or local network was accessed for cover upload") + return False, _("You are not allowed to access localhost or the local network for cover uploads") def save_cover_from_filestorage(filepath, saved_filename, img): @@ -607,8 +837,8 @@ def save_cover_from_filestorage(filepath, saved_filename, img): try: os.makedirs(filepath) except OSError: - log.error(u"Failed to create path for cover") - return False, _(u"Failed to create path for cover") + log.error("Failed to create path for cover") + return False, _("Failed to create path for cover") try: # upload of jgp file without wand if isinstance(img, requests.Response): @@ -623,8 +853,8 @@ def save_cover_from_filestorage(filepath, saved_filename, img): # upload of jpg/png... from hdd img.save(os.path.join(filepath, saved_filename)) except (IOError, OSError): - log.error(u"Cover-file is not a valid image file, or could not be stored") - return False, _(u"Cover-file is not a valid image file, or could not be stored") + log.error("Cover-file is not a valid image file, or could not be stored") + return False, _("Cover-file is not a valid image file, or could not be stored") return True, None @@ -633,24 +863,23 @@ def save_cover(img, book_path): content_type = img.headers.get('content-type') if use_IM: - if content_type not in ('image/jpeg', 'image/png', 'image/webp', 'image/bmp'): + if content_type not in ('image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/bmp'): log.error("Only jpg/jpeg/png/webp/bmp files are supported as coverfile") return False, _("Only jpg/jpeg/png/webp/bmp files are supported as coverfile") # convert to jpg because calibre only supports jpg - if content_type != 'image/jpg': - try: - if hasattr(img, 'stream'): - imgc = Image(blob=img.stream) - else: - imgc = Image(blob=io.BytesIO(img.content)) - imgc.format = 'jpeg' - imgc.transform_colorspace("rgb") - img = imgc - except BlobError: - log.error("Invalid cover file content") - return False, _("Invalid cover file content") + try: + if hasattr(img, 'stream'): + imgc = Image(blob=img.stream) + else: + imgc = Image(blob=io.BytesIO(img.content)) + imgc.format = 'jpeg' + imgc.transform_colorspace("rgb") + img = imgc + except (BlobError, MissingDelegateError): + log.error("Invalid cover file content") + return False, _("Invalid cover file content") else: - if content_type not in 'image/jpeg': + if content_type not in ['image/jpeg', 'image/jpg']: log.error("Only jpg/jpeg files are supported as coverfile") return False, _("Only jpg/jpeg files are supported as coverfile") @@ -661,7 +890,7 @@ def save_cover(img, book_path): os.mkdir(tmp_dir) ret, message = save_cover_from_filestorage(tmp_dir, "uploaded_cover.jpg", img) if ret is True: - gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg').replace("\\","/"), + gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg').replace("\\", "/"), os.path.join(tmp_dir, "uploaded_cover.jpg")) log.info("Cover is saved on Google Drive") return True, None @@ -673,9 +902,9 @@ def save_cover(img, book_path): def do_download_file(book, book_format, client, data, headers): if config.config_use_google_drive: - startTime = time.time() + # startTime = time.time() df = gd.getFileFromEbooksFolder(book.path, data.name + "." + book_format) - log.debug('%s', time.time() - startTime) + # log.debug('%s', time.time() - startTime) if df: return gd.do_gdrive_download(df, headers) else: @@ -699,23 +928,23 @@ def do_download_file(book, book_format, client, data, headers): ################################## -def check_unrar(unrarLocation): - if not unrarLocation: +def check_unrar(unrar_location): + if not unrar_location: return - if not os.path.exists(unrarLocation): + if not os.path.exists(unrar_location): return _('Unrar binary file not found') try: - unrarLocation = [unrarLocation] - value = process_wait(unrarLocation, pattern='UNRAR (.*) freeware') + unrar_location = [unrar_location] + value = process_wait(unrar_location, pattern='UNRAR (.*) freeware') if value: version = value.group(1) log.debug("unrar version %s", version) except (OSError, UnicodeDecodeError) as err: - log.debug_or_exception(err) - return _('Error excecuting UnRar') + log.error_or_exception(err) + return _('Error executing UnRar') def json_serial(obj): @@ -733,54 +962,6 @@ def json_serial(obj): raise TypeError("Type %s not serializable" % type(obj)) -# helper function for displaying the runtime of tasks -def format_runtime(runtime): - retVal = "" - if runtime.days: - retVal = format_unit(runtime.days, 'duration-day', length="long", locale=get_locale()) + ', ' - mins, seconds = divmod(runtime.seconds, 60) - hours, minutes = divmod(mins, 60) - # ToDo: locale.number_symbols._data['timeSeparator'] -> localize time separator ? - if hours: - retVal += '{:d}:{:02d}:{:02d}s'.format(hours, minutes, seconds) - elif minutes: - retVal += '{:2d}:{:02d}s'.format(minutes, seconds) - else: - retVal += '{:2d}s'.format(seconds) - return retVal - - -# helper function to apply localize status information in tasklist entries -def render_task_status(tasklist): - renderedtasklist = list() - for __, user, __, task in tasklist: - if user == current_user.name or current_user.role_admin(): - ret = {} - if task.start_time: - ret['starttime'] = format_datetime(task.start_time, format='short', locale=get_locale()) - ret['runtime'] = format_runtime(task.runtime) - - # localize the task status - if isinstance(task.stat, int): - if task.stat == STAT_WAITING: - ret['status'] = _(u'Waiting') - elif task.stat == STAT_FAIL: - ret['status'] = _(u'Failed') - elif task.stat == STAT_STARTED: - ret['status'] = _(u'Started') - elif task.stat == STAT_FINISH_SUCCESS: - ret['status'] = _(u'Finished') - else: - ret['status'] = _(u'Unknown Status') - - ret['taskMessage'] = "{}: {}".format(_(task.name), task.message) - ret['progress'] = "{} %".format(int(task.progress * 100)) - ret['user'] = escape(user) # prevent xss - renderedtasklist.append(ret) - - return renderedtasklist - - def tags_filters(): negtags_list = current_user.list_denied_tags() postags_list = current_user.list_allowed_tags() @@ -803,27 +984,10 @@ def check_valid_domain(domain_text): return not len(result) -def get_cc_columns(filter_config_custom_read=False): - tmpcc = calibre_db.session.query(db.Custom_Columns)\ - .filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() - cc = [] - r = None - if config.config_columns_to_ignore: - r = re.compile(config.config_columns_to_ignore) - - for col in tmpcc: - if filter_config_custom_read and config.config_read_column and config.config_read_column == col.id: - continue - if r and r.match(col.name): - continue - cc.append(col) - - return cc - - def get_download_link(book_id, book_format, client): book_format = book_format.split(".")[0] - book = calibre_db.get_filtered_book(book_id) + book = calibre_db.get_filtered_book(book_id, allow_show_archived=True) + data1= "" if book: data1 = calibre_db.get_book_format(book.id, book_format.upper()) else: @@ -844,3 +1008,36 @@ def get_download_link(book_id, book_format, client): return do_download_file(book, book_format, client, data1, headers) else: abort(404) + + +def clear_cover_thumbnail_cache(book_id): + if config.schedule_generate_book_covers: + WorkerThread.add(None, TaskClearCoverThumbnailCache(book_id), hidden=True) + + +def replace_cover_thumbnail_cache(book_id): + if config.schedule_generate_book_covers: + WorkerThread.add(None, TaskClearCoverThumbnailCache(book_id), hidden=True) + WorkerThread.add(None, TaskGenerateCoverThumbnails(book_id), hidden=True) + + +def delete_thumbnail_cache(): + WorkerThread.add(None, TaskClearCoverThumbnailCache(-1)) + + +def add_book_to_thumbnail_cache(book_id): + if config.schedule_generate_book_covers: + WorkerThread.add(None, TaskGenerateCoverThumbnails(book_id), hidden=True) + + +def update_thumbnail_cache(): + if config.schedule_generate_book_covers: + WorkerThread.add(None, TaskGenerateCoverThumbnails()) + + +def set_all_metadata_dirty(): + WorkerThread.add(None, TaskBackupMetadata(export_language=get_locale(), + translated_title=_("Cover"), + set_dirty=True, + task_message=N_("Queue all books for metadata backup")), + hidden=False) diff --git a/cps/isoLanguages.py b/cps/isoLanguages.py index e220f63e0..31e3dade3 100644 --- a/cps/isoLanguages.py +++ b/cps/isoLanguages.py @@ -49,7 +49,7 @@ except ImportError: def get_language_names(locale): - return _LANGUAGE_NAMES.get(locale) + return _LANGUAGE_NAMES.get(str(locale)) def get_language_name(locale, lang_code): @@ -57,6 +57,7 @@ def get_language_name(locale, lang_code): return get_language_names(locale)[lang_code] except KeyError: log.error('Missing translation for language name: {}'.format(lang_code)) + return "Unknown" def get_language_codes(locale, language_names, remainder=None): diff --git a/cps/iso_language_names.py b/cps/iso_language_names.py index 07848b9cd..7016b393f 100644 --- a/cps/iso_language_names.py +++ b/cps/iso_language_names.py @@ -55,6 +55,7 @@ LANGUAGE_NAMES = { "bik": "bikolština", "bin": "bini", "bis": "bislamština", + "bit": "berinomo", "bla": "siksika", "bod": "tibetština", "bos": "bosenština", @@ -101,6 +102,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (macrolanguage)", "dsb": "Sorbian; Lower", + "dse": "holandský znakový jazyk", "dua": "dualština", "dum": "Dutch; Middle (ca. 1050-1350)", "dyu": "djula", @@ -112,6 +114,7 @@ LANGUAGE_NAMES = { "elx": "elamština", "eng": "Angličtina", "enm": "Angličtina; středověká (1100-1500)", + "enu": "Enu", "epo": "esperanto", "est": "estonština", "eus": "baskičtina", @@ -162,6 +165,7 @@ LANGUAGE_NAMES = { "hil": "hiligayonština", "hin": "hindština", "hit": "chetitština", + "hmj": "Ge", "hmn": "hmongština", "hmo": "hiri motu", "hrv": "chorvatština", @@ -476,6 +480,7 @@ LANGUAGE_NAMES = { "bik": "Bikol", "bin": "Bini", "bis": "Bislama", + "bit": "Berinomo", "bla": "Blackfoot", "bod": "Tibetisch", "bos": "Bosnisch", @@ -522,6 +527,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (Makrosprache)", "dsb": "Sorbisch; Nieder", + "dse": "Niederländische Zeichensprache", "dua": "Duala", "dum": "Niederländisch; Mittel (ca. 1050-1350)", "dyu": "Dyula", @@ -533,6 +539,7 @@ LANGUAGE_NAMES = { "elx": "Elamisch", "eng": "Englisch", "enm": "Mittelenglisch", + "enu": "Enu", "epo": "Esperanto", "est": "Estnisch", "eus": "Baskisch", @@ -583,6 +590,7 @@ LANGUAGE_NAMES = { "hil": "Hiligaynon", "hin": "Hindi", "hit": "Hethitisch", + "hmj": "Ge", "hmn": "Miao-Sprachen", "hmo": "Hiri-Motu", "hrv": "Kroatisch", @@ -892,6 +900,7 @@ LANGUAGE_NAMES = { "bel": "Λευκωρωσικά", "bem": "Bemba (Zambia)", "ben": "Μπενγκάλι", + "bit": "Berinomo", "bho": "Bhojpuri", "bik": "Bikol", "byn": "Bilin", @@ -938,6 +947,7 @@ LANGUAGE_NAMES = { "dgr": "Dogrib", "dua": "Duala", "nld": "Ολλανδικά", + "dse": "Ολλανδική νοηματική γλώσσα", "dyu": "Dyula", "dzo": "Dzongkha", "efi": "Efik", @@ -945,6 +955,7 @@ LANGUAGE_NAMES = { "eka": "Ekajuk", "elx": "Elamite", "eng": "Αγγλικά", + "enu": "Enu", "myv": "Erzya", "epo": "Εσπεράντο", "est": "Εσθονικά", @@ -965,6 +976,7 @@ LANGUAGE_NAMES = { "lug": "Ganda", "gay": "Gayo", "gba": "Gbaya (Central African Republic)", + "hmj": "Ge", "gez": "Geez", "kat": "Γεωργιανά", "deu": "Γερμανικά", @@ -1273,6 +1285,7 @@ LANGUAGE_NAMES = { "bik": "Bicolano", "bin": "Bini", "bis": "Bislama", + "bit": "Berinomo", "bla": "Siksiká", "bod": "Tibetano", "bos": "Bosnio", @@ -1319,6 +1332,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (macrolengua)", "dsb": "Bajo sorabo", + "dse": "Lengua de signos neerlandesa", "dua": "Duala", "dum": "Neerlandés medio (ca. 1050-1350)", "dyu": "Diula", @@ -1330,6 +1344,7 @@ LANGUAGE_NAMES = { "elx": "Elamita", "eng": "Inglés", "enm": "Inglés medio (1100-1500)", + "enu": "Enu", "epo": "Esperanto", "est": "Estonio", "eus": "Vasco", @@ -1380,6 +1395,7 @@ LANGUAGE_NAMES = { "hil": "Hiligainón", "hin": "Hindi", "hit": "Hitita", + "hmj": "Ge", "hmn": "Hmong", "hmo": "Hiri motu", "hrv": "Croata", @@ -1694,6 +1710,7 @@ LANGUAGE_NAMES = { "bik": "bikol", "bin": "bini", "bis": "bislama", + "bit": "Berinomo", "bla": "mustajalka (siksika)", "bod": "tiibetti", "bos": "bosnia", @@ -1740,6 +1757,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (macrolanguage)", "dsb": "alasorbi", + "dse": "Dutch Sign Language", "dua": "duala", "dum": "Dutch; Middle (ca. 1050-1350)", "dyu": "dyula", @@ -1751,6 +1769,7 @@ LANGUAGE_NAMES = { "elx": "elami", "eng": "englanti", "enm": "keskienglanti", + "enu": "Enu", "epo": "esperanto", "est": "viro", "eus": "baski", @@ -1801,6 +1820,7 @@ LANGUAGE_NAMES = { "hil": "hiligaynon", "hin": "hindi", "hit": "heetti", + "hmj": "Ge", "hmn": "hmong", "hmo": "hiri-motu", "hrv": "kroatia", @@ -2115,6 +2135,7 @@ LANGUAGE_NAMES = { "bik": "bikol", "bin": "bini", "bis": "bislama", + "bit": "berinomo", "bla": "pied-noir", "bod": "tibétain", "bos": "bosniaque", @@ -2161,6 +2182,7 @@ LANGUAGE_NAMES = { "div": "dhivehi", "doi": "dogri (macrolangue)", "dsb": "bas-sorbien", + "dse": "langue des signes néerlandaise", "dua": "duala", "dum": "néerlandais moyen (environ 1050-1350)", "dyu": "dioula", @@ -2172,6 +2194,7 @@ LANGUAGE_NAMES = { "elx": "élamite", "eng": "anglais", "enm": "anglais moyen (1100-1500)", + "enu": "enu", "epo": "espéranto", "est": "estonien", "eus": "basque", @@ -2222,6 +2245,7 @@ LANGUAGE_NAMES = { "hil": "hiligaynon", "hin": "hindi", "hit": "hittite", + "hmj": "ge", "hmn": "hmong", "hmo": "hiri Motu", "hrv": "croate", @@ -2493,6 +2517,384 @@ LANGUAGE_NAMES = { "zxx": "pas de contenu linguistique", "zza": "zaza" }, + "gl": { + "abk": "Abjaziano", + "ace": "Achinés", + "ach": "Acolí", + "ada": "Adangme", + "ady": "Adigué", + "aar": "Afar", + "afh": "Afrihili", + "afr": "Africáner", + "ain": "Ainu (Xapón)", + "aka": "Akan", + "akk": "Acadio", + "sqi": "Albanian", + "ale": "Aleutiano", + "amh": "Amhárico", + "anp": "Angika", + "ara": "Árabe", + "arg": "Aragonés", + "arp": "Arapaho", + "arw": "Arawak", + "hye": "Armenian", + "asm": "Asamés", + "ast": "Asturiano", + "ava": "Avárico", + "ave": "Avéstico", + "awa": "Awadhi", + "aym": "Aymara", + "aze": "Acerbaixano", + "ban": "Balinés", + "bal": "Baluchi", + "bam": "Bambara", + "bas": "Basa (Camerún)", + "bak": "Bashkir", + "eus": "Vasco", + "bej": "Beja", + "bel": "Bielorruso", + "bem": "Bemba (Zambia)", + "ben": "Bengalí", + "bit": "Berinomo", + "bho": "Bhojpuri", + "bik": "Bikol", + "byn": "Bilin", + "bin": "Bini", + "bis": "Bislama", + "zbl": "Símbolos Blis", + "bos": "Bosnio", + "bra": "Braj", + "bre": "Bretón", + "bug": "Buginés", + "bul": "Búlgaro", + "bua": "Buriat", + "mya": "Birmano", + "cad": "Caddo", + "cat": "Catalán", + "ceb": "Cebuano", + "chg": "Chagatai", + "cha": "Chamorro", + "che": "Checheno", + "chr": "Cherokee", + "chy": "Cheyenne", + "chb": "Chibcha", + "zho": "Chinés", + "chn": "Chinook; argot", + "chp": "Chipewyan", + "cho": "Choctaw", + "cht": "Cholón", + "chk": "Chuukese", + "chv": "Chuvash", + "cop": "Copto", + "cor": "Cornish", + "cos": "Corso", + "cre": "Cree", + "mus": "Creek", + "hrv": "Croata", + "ces": "Checo", + "dak": "Dakota", + "dan": "Danés", + "dar": "Dargwa", + "del": "Delaware", + "div": "Dhivehi", + "din": "Dinka", + "doi": "Dogri (macrolingua)", + "dgr": "Dogrib", + "dua": "Duala", + "nld": "Holandés", + "dse": "Lingua de signos holandés", + "dyu": "Dyula", + "dzo": "Dzongkha", + "efi": "Efik", + "egy": "Exipcio (antigo)", + "eka": "Ekajuk", + "elx": "Elamita", + "eng": "Inglés", + "enu": "Enu", + "myv": "Erzya", + "epo": "Esperanto", + "est": "Estonio", + "ewe": "Ewe", + "ewo": "Ewondo", + "fan": "Fang (Guinea ecuatorial)", + "fat": "Fanti", + "fao": "Feroés", + "fij": "Fixino", + "fil": "Filipino", + "fin": "Finés", + "fon": "Fon", + "fra": "Francés", + "fur": "Friuliano", + "ful": "Fulah", + "gaa": "Ga", + "glg": "Galego", + "lug": "Ganda", + "gay": "Gayo", + "gba": "Gbaya (República centroafricana)", + "hmj": "Ge", + "gez": "Geez", + "kat": "Xeorxiano", + "deu": "Alemán", + "gil": "Gilbertés", + "gon": "Gondi", + "gor": "Gorontalo", + "got": "Gótico", + "grb": "Grebo", + "grn": "Guaraní", + "guj": "Gujarati", + "gwi": "Gwichʼin", + "hai": "Haida", + "hau": "Haussa", + "haw": "Hawaiano", + "heb": "Hebreo", + "her": "Herero", + "hil": "Hiligaynon", + "hin": "Hindi", + "hmo": "Hiri Motu", + "hit": "Hitita", + "hmn": "Hmong", + "hun": "Húngaro", + "hup": "Hupa", + "iba": "Iban", + "isl": "Islandés", + "ido": "Ido", + "ibo": "Igbo", + "ilo": "Iloko", + "ind": "Indonesio", + "inh": "Ingush", + "ina": "Interlingua (lingua internacional auxiliar)", + "ile": "Interlingue", + "iku": "Inuktitut", + "ipk": "Inupiak", + "gle": "Irlandés", + "ita": "Italiano", + "jpn": "Xaponés", + "jav": "Xavanés", + "jrb": "Xudeu-Árabe", + "jpr": "Xudeu-Persa", + "kbd": "Kabardian", + "kab": "Kabyle", + "kac": "Kachin", + "kal": "Kalaallisut", + "xal": "Kalmyk", + "kam": "Kamba (Kenya)", + "kan": "Kannada", + "kau": "Kanuri", + "kaa": "Kara-Kalpak", + "krc": "Karachay-Balkar", + "krl": "Karelian", + "kas": "Kashmiri", + "csb": "Kashubiano", + "kaw": "Kawi", + "kaz": "Kazako", + "kha": "Khasi", + "kho": "Khotanese", + "kik": "Kikuyu", + "kmb": "Kimbundu", + "kin": "Kinyarwanda", + "kir": "Kirghizo", + "tlh": "Klingon", + "kom": "Komi", + "kon": "Kongo", + "kok": "Konkani (macrolingua)", + "kor": "Coreano", + "kos": "Kosraeano", + "kpe": "Kpelle", + "kua": "Kuanyama", + "kum": "Kumyk", + "kur": "Kurdo", + "kru": "Kurukh", + "kut": "Kutenai", + "lad": "Ladino", + "lah": "Lahnda", + "lam": "Lamba", + "lao": "Laosiano", + "lat": "Latín", + "lav": "Letón", + "lez": "Lezghiano", + "lim": "Limburgués", + "lin": "Lingala", + "lit": "Lituano", + "jbo": "Lojban", + "loz": "Lozi", + "lub": "Luba-Katanga", + "lua": "Luba-Lulua", + "lui": "Luiseno", + "smj": "Sami Lule", + "lun": "Lunda", + "luo": "Luo (Kenia e Tanzania)", + "lus": "Lushai", + "ltz": "Luxemburgués", + "mkd": "Macedonio", + "mad": "Madurese", + "mag": "Magahi", + "mai": "Maithili", + "mak": "Makasar", + "mlg": "Malgache", + "msa": "Malayo (macroLingua)", + "mal": "Malayalamo", + "mlt": "Maltés", + "mnc": "Manchu", + "mdr": "Mandar", + "man": "Mandingo", + "mni": "Manipuri", + "glv": "Manx [Gaélico de Manx]", + "mri": "Maorí", + "arn": "Mapudungun", + "mar": "Marath", + "chm": "Mari (Rusia)", + "mah": "Marshalés", + "mwr": "Marwari", + "mas": "Masai", + "men": "Mende (Sierra Leone)", + "mic": "Mi'kmaq", + "min": "Minangkabau", + "mwl": "Mirandés", + "moh": "Mohawk", + "mdf": "Moksha", + "lol": "Mongo", + "mon": "Mongolian", + "mos": "Mossi", + "mul": "Varios idiomas", + "nqo": "N'Ko", + "nau": "Naurí", + "nav": "Navajo", + "ndo": "Ndonga", + "nap": "Neapolitano", + "nia": "Nias", + "niu": "Niués", + "zxx": "Sen contido lingüístico", + "nog": "Nogai", + "nor": "Noruegués", + "nob": "Noruego Bokmål", + "nno": "Noruegués nynorsk", + "nym": "Nyamwezi", + "nya": "Nyanja", + "nyn": "Nyankole", + "nyo": "Nyoro", + "nzi": "Nzima", + "oci": "Occitano (después de 1500)", + "oji": "Ojibwa", + "orm": "Oromo (Afan)", + "osa": "Osage", + "oss": "Osetio", + "pal": "Pahlavi", + "pau": "Palauan", + "pli": "Pali", + "pam": "Pampanga", + "pag": "Pangasinan", + "pan": "Punjabí", + "pap": "Papiamento", + "fas": "Persa", + "phn": "Fenicio", + "pon": "Pohnpeian", + "pol": "Polaco", + "por": "Portugués", + "pus": "Pashtún", + "que": "Quechúa", + "raj": "Rajasthani", + "rap": "Rapanui", + "ron": "Romanés", + "roh": "Romanche", + "rom": "Romaní", + "run": "Kiroundi", + "rus": "Ruso", + "smo": "Samoano", + "sad": "Sandawe", + "sag": "Sango", + "san": "Sánscrito", + "sat": "Santali", + "srd": "Sardo", + "sas": "Sasak", + "sco": "Escocés", + "sel": "Selkup", + "srp": "Serbio", + "srr": "Serer", + "shn": "Shan", + "sna": "Shona", + "scn": "Siciliano", + "sid": "Sidamo", + "bla": "Siksika", + "snd": "Sindhi", + "sin": "Cingalés", + "den": "Eslavo (Athapascan)", + "slk": "Eslovaco", + "slv": "Esloveno", + "sog": "Sogdian", + "som": "Somalí", + "snk": "Soninke", + "spa": "Español", + "srn": "Sranan Tongo", + "suk": "Sukuma", + "sux": "Sumerio", + "sun": "Sundanés", + "sus": "Susu", + "swa": "Swahili (macrolingua)", + "ssw": "Siswati", + "swe": "Sueco", + "syr": "Syriac", + "tgl": "Tagalo", + "tah": "Tahitiano", + "tgk": "Tajiko", + "tmh": "Tamashek", + "tam": "Tamil", + "tat": "Tártaro", + "tel": "Telougou", + "ter": "Tereno", + "tet": "Tetum", + "tha": "Thai", + "bod": "Tibetano", + "tig": "Tigre", + "tir": "Tigrinya", + "tem": "Timne", + "tiv": "Tiv", + "tli": "Tlingit", + "tpi": "Tok Pisin", + "tkl": "Tokelau", + "tog": "Tonga (Nyasa)", + "ton": "Tonga (Islas Tonga)", + "tsi": "Tsimshian", + "tso": "Tsonga", + "tsn": "Setchwana", + "tum": "Tumbuka", + "tur": "Turco", + "tuk": "Turkmeno", + "tvl": "Tuvalu", + "tyv": "Tuvinian", + "twi": "Tchi", + "udm": "Udmurt", + "uga": "Ugarítico", + "uig": "Uiguro", + "ukr": "Ucraíno", + "umb": "Umbundu", + "mis": "Idiomas no codificados", + "und": "Sen determinar", + "urd": "Urdu", + "uzb": "Uzbeko", + "vai": "Vai", + "ven": "Venda", + "vie": "Vietnamita", + "vol": "Volapük", + "vot": "Votic", + "wln": "Valón", + "war": "Waray (Filipinas)", + "was": "Washo", + "cym": "Galés", + "wal": "Wolaytta", + "wol": "Wolof", + "xho": "Xhosa", + "sah": "Yakut", + "yao": "Yao", + "yap": "Yapese", + "yid": "Yiddish", + "yor": "Yoruba", + "zap": "Zapoteco", + "zza": "Zaza", + "zen": "Zenaga", + "zha": "Zhuang", + "zul": "Zulú", + "zun": "Zuni" + }, "hu": { "aar": "Afar", "abk": "Abház", @@ -2536,6 +2938,7 @@ LANGUAGE_NAMES = { "bik": "bikol", "bin": "bini", "bis": "biszlama", + "bit": "Berinomo", "bla": "szikszika", "bod": "tibeti", "bos": "bosnyák", @@ -2582,6 +2985,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (macrolanguage)", "dsb": "Sorbian; Lower", + "dse": "Dutch Sign Language", "dua": "duala", "dum": "Dutch; Middle (ca. 1050-1350)", "dyu": "djula", @@ -2593,6 +2997,7 @@ LANGUAGE_NAMES = { "elx": "elamita", "eng": "angol", "enm": "angol; középkori (1100-1500)", + "enu": "Enu", "epo": "eszperantó", "est": "észt", "eus": "Baszk", @@ -2643,6 +3048,7 @@ LANGUAGE_NAMES = { "hil": "hiligajnon", "hin": "hindi", "hit": "hettita", + "hmj": "Ge", "hmn": "hmong", "hmo": "hiri motu", "hrv": "horvát", @@ -2914,6 +3320,384 @@ LANGUAGE_NAMES = { "zxx": "No linguistic content", "zza": "Zaza" }, + "id": { + "abk": "Abkhazian", + "ace": "Achinese", + "ach": "Acoli", + "ada": "Adangme", + "ady": "Adyghe", + "aar": "Afar", + "afh": "Afrihili", + "afr": "Afrika", + "ain": "Ainu (Japan)", + "aka": "Akan", + "akk": "Akkadian", + "sqi": "Albanian", + "ale": "Aleut", + "amh": "Amharic", + "anp": "Angika", + "ara": "Arab", + "arg": "Aragonese", + "arp": "Arapaho", + "arw": "Arawak", + "hye": "Armenia", + "asm": "Assam", + "ast": "Asturian", + "ava": "Avaric", + "ave": "Avestan", + "awa": "Awadhi", + "aym": "Aymara", + "aze": "Azerbaijani", + "ban": "Balinese", + "bal": "Baluchi", + "bam": "Bambara", + "bas": "Basa (Cameroon)", + "bak": "Bashkir", + "eus": "Basque", + "bej": "Beja", + "bel": "Belarusian", + "bem": "Bemba (Zambia)", + "ben": "Bengal", + "bit": "Berinomo", + "bho": "Bhojpuri", + "bik": "Bikol", + "byn": "Bilin", + "bin": "Bini", + "bis": "Bislama", + "zbl": "Blissymbols", + "bos": "Bosnian", + "bra": "Braj", + "bre": "Breton", + "bug": "Bugis", + "bul": "Bulgaria", + "bua": "Buriat", + "mya": "Burma", + "cad": "Caddo", + "cat": "Catalan", + "ceb": "Cebuano", + "chg": "Chagatai", + "cha": "Chamorro", + "che": "Chechen", + "chr": "Cherokee", + "chy": "Cheyenne", + "chb": "Chibcha", + "zho": "Cina", + "chn": "Chinook jargon", + "chp": "Chipewyan", + "cho": "Choctaw", + "cht": "Cholón", + "chk": "Chuukese", + "chv": "Chuvash", + "cop": "Koptik", + "cor": "Cornish", + "cos": "Corsican", + "cre": "Cree", + "mus": "Creek", + "hrv": "Kroasia", + "ces": "Ceko", + "dak": "Dakota", + "dan": "Denmark", + "dar": "Dargwa", + "del": "Delaware", + "div": "Dhivehi", + "din": "Dinka", + "doi": "Dogri (macrolanguage)", + "dgr": "Dogrib", + "dua": "Duala", + "nld": "Belanda", + "dse": "Dutch Sign Language", + "dyu": "Dyula", + "dzo": "Dzongkha", + "efi": "Efik", + "egy": "Mesir Kuno", + "eka": "Ekajuk", + "elx": "Elamite", + "eng": "Inggris", + "enu": "Enu", + "myv": "Erzya", + "epo": "Esperanto", + "est": "Estonia", + "ewe": "Ewe", + "ewo": "Ewondo", + "fan": "Fang (Equatorial Guinea)", + "fat": "Fanti", + "fao": "Faro", + "fij": "Fiji", + "fil": "Filipino", + "fin": "Finlandia", + "fon": "Fon", + "fra": "Prancis", + "fur": "Friulian", + "ful": "Fulah", + "gaa": "Ga", + "glg": "Galician", + "lug": "Ganda", + "gay": "Gayo", + "gba": "Gbaya (Central African Republic)", + "hmj": "Ge", + "gez": "Geez", + "kat": "Georgian", + "deu": "Jerman", + "gil": "Gilbertese", + "gon": "Gondi", + "gor": "Gorontalo", + "got": "Gothik", + "grb": "Grebo", + "grn": "Guarani", + "guj": "Gujarati", + "gwi": "Gwichʼin", + "hai": "Haida", + "hau": "Hausa", + "haw": "Hawaii", + "heb": "Israel", + "her": "Herero", + "hil": "Hiligaynon", + "hin": "Hindi", + "hmo": "Hiri Motu", + "hit": "Hittite", + "hmn": "Hmong", + "hun": "Hungaria", + "hup": "Hupa", + "iba": "Iban", + "isl": "Islandia", + "ido": "Ido", + "ibo": "Igbo", + "ilo": "Iloko", + "ind": "Bahasa Indonesia", + "inh": "Ingush", + "ina": "Interlingua (International Auxiliary Language Association)", + "ile": "Interlingue", + "iku": "Inuktitut", + "ipk": "Inupiaq", + "gle": "Irlandia", + "ita": "Italia", + "jpn": "Jepang", + "jav": "Javanese", + "jrb": "Judeo-Arabic", + "jpr": "Judeo-Persian", + "kbd": "Kabardian", + "kab": "Kabyle", + "kac": "Kachin", + "kal": "Kalaallisut", + "xal": "Kalmyk", + "kam": "Kamba (Kenya)", + "kan": "Kannada", + "kau": "Kanuri", + "kaa": "Kara-Kalpak", + "krc": "Karachay-Balkar", + "krl": "Karelian", + "kas": "Kashmir", + "csb": "Kashubian", + "kaw": "Kawi", + "kaz": "Kazakh", + "kha": "Khasi", + "kho": "Khotanese", + "kik": "Kikuyu", + "kmb": "Kimbundu", + "kin": "Kinyarwanda", + "kir": "Kirghiz", + "tlh": "Klingon", + "kom": "Komi", + "kon": "Kongo", + "kok": "Konkani (macrolanguage)", + "kor": "Korea", + "kos": "Kosraean", + "kpe": "Kpelle", + "kua": "Kuanyama", + "kum": "Kumyk", + "kur": "Kurdish", + "kru": "Kurukh", + "kut": "Kutenai", + "lad": "Ladino", + "lah": "Lahnda", + "lam": "Lamba", + "lao": "Lao", + "lat": "Latin", + "lav": "Latvian", + "lez": "Lezghian", + "lim": "Limburgan", + "lin": "Lingala", + "lit": "Lithuania", + "jbo": "Lojban", + "loz": "Lozi", + "lub": "Luba-Katanga", + "lua": "Luba-Lulua", + "lui": "Luiseno", + "smj": "Lule Sami", + "lun": "Lunda", + "luo": "Luo (Kenya and Tanzania)", + "lus": "Lushai", + "ltz": "Luxembourgish", + "mkd": "Masedonian", + "mad": "Madurese", + "mag": "Magahi", + "mai": "Maithili", + "mak": "Makasar", + "mlg": "Malagasi", + "msa": "Malay (macrolanguage)", + "mal": "Malayalam", + "mlt": "Maltese", + "mnc": "Manchu", + "mdr": "Mandar", + "man": "Mandingo", + "mni": "Manipuri", + "glv": "Manx", + "mri": "Maori", + "arn": "Mapudungun", + "mar": "Marathi", + "chm": "Mari (Russia)", + "mah": "Marshallese", + "mwr": "Marwari", + "mas": "Masai", + "men": "Mende (Sierra Leone)", + "mic": "Mi'kmaq", + "min": "Minangkabau", + "mwl": "Mirandese", + "moh": "Mohawk", + "mdf": "Moksha", + "lol": "Mongo", + "mon": "Mongolian", + "mos": "Mossi", + "mul": "Multiple languages", + "nqo": "N'Ko", + "nau": "Nauru", + "nav": "Navajo", + "ndo": "Ndonga", + "nap": "Neapolitan", + "nia": "Nias", + "niu": "Niuean", + "zxx": "No linguistic content", + "nog": "Nogai", + "nor": "Norwegian", + "nob": "Norwegian Bokmål", + "nno": "Norwegian Nynorsk", + "nym": "Nyamwezi", + "nya": "Nyanja", + "nyn": "Nyankole", + "nyo": "Nyoro", + "nzi": "Nzima", + "oci": "Occitan (post 1500)", + "oji": "Ojibwa", + "orm": "Oromo", + "osa": "Osage", + "oss": "Ossetian", + "pal": "Pahlavi", + "pau": "Palauan", + "pli": "Pali", + "pam": "Pampanga", + "pag": "Pangasinan", + "pan": "Panjabi", + "pap": "Papiamento", + "fas": "Persian", + "phn": "Phoenician", + "pon": "Pohnpeian", + "pol": "Polandia", + "por": "Portugis", + "pus": "Pashto", + "que": "Quechua", + "raj": "Rajasthani", + "rap": "Rapanui", + "ron": "Rumania", + "roh": "Romansh", + "rom": "Romany", + "run": "Rundi", + "rus": "Rusia", + "smo": "Samoan", + "sad": "Sandawe", + "sag": "Sango", + "san": "Sanskrit", + "sat": "Santali", + "srd": "Sardinian", + "sas": "Sasak", + "sco": "Scots", + "sel": "Selkup", + "srp": "Serbia", + "srr": "Serer", + "shn": "Shan", + "sna": "Shona", + "scn": "Sicilian", + "sid": "Sidamo", + "bla": "Siksika", + "snd": "Sindhi", + "sin": "Sinhala", + "den": "Slave (Athapascan)", + "slk": "Slovakia", + "slv": "Slovenia", + "sog": "Sogdian", + "som": "Somali", + "snk": "Soninke", + "spa": "Spanyol", + "srn": "Sranan Tongo", + "suk": "Sukuma", + "sux": "Sumerian", + "sun": "Sundan", + "sus": "Susu", + "swa": "Swahili (macrolanguage)", + "ssw": "Swati", + "swe": "Swedia", + "syr": "Syriac", + "tgl": "Tagalog", + "tah": "Tahitian", + "tgk": "Tajik", + "tmh": "Tamashek", + "tam": "Tamil", + "tat": "Tatar", + "tel": "Telugu", + "ter": "Tereno", + "tet": "Tetum", + "tha": "Thailand", + "bod": "Tibet", + "tig": "Tigre", + "tir": "Tigrinya", + "tem": "Timne", + "tiv": "Tiv", + "tli": "Tlingit", + "tpi": "Tok Pisin", + "tkl": "Tokelau", + "tog": "Tonga (Nyasa)", + "ton": "Tonga (Tonga Islands)", + "tsi": "Tsimshian", + "tso": "Tsonga", + "tsn": "Tswana", + "tum": "Tumbuka", + "tur": "Turki", + "tuk": "Turkmen", + "tvl": "Tuvalu", + "tyv": "Tuvinian", + "twi": "Twi", + "udm": "Udmurt", + "uga": "Ugaritic", + "uig": "Uighur", + "ukr": "Ukrainian", + "umb": "Umbundu", + "mis": "Uncoded languages", + "und": "Undetermined", + "urd": "Urdu", + "uzb": "Uzbek", + "vai": "Vai", + "ven": "Venda", + "vie": "Vietnamese", + "vol": "Volapük", + "vot": "Votic", + "wln": "Wallon", + "war": "Waray (Philippines)", + "was": "Washo", + "cym": "Welsh", + "wal": "Wolaytta", + "wol": "Wolof", + "xho": "Xhosa", + "sah": "Yakut", + "yao": "Yao", + "yap": "Yapese", + "yid": "Yiddish", + "yor": "Yoruba", + "zap": "Zapotec", + "zza": "Zaza", + "zen": "Zenaga", + "zha": "Zhuang", + "zul": "Zulu", + "zun": "Zuni" + }, "it": { "aar": "Afar", "abk": "Abkhazian", @@ -2957,6 +3741,7 @@ LANGUAGE_NAMES = { "bik": "bicol", "bin": "Bini", "bis": "bislama", + "bit": "Berinomo", "bla": "Siksika", "bod": "Tibetano", "bos": "Bosniaco", @@ -3003,6 +3788,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (macrolingua)", "dsb": "Lusaziano inferiore", + "dse": "Olandense (linguaggio dei segni)", "dua": "Duala", "dum": "Olandese medio (ca. 1050-1350)", "dyu": "Diula", @@ -3014,6 +3800,7 @@ LANGUAGE_NAMES = { "elx": "Elamitico", "eng": "Inglese", "enm": "Inglese medio (1100-1500)", + "enu": "Enu", "epo": "Esperanto", "est": "Estone", "eus": "Basco", @@ -3064,6 +3851,7 @@ LANGUAGE_NAMES = { "hil": "Hiligayna", "hin": "Hindi", "hit": "hittite", + "hmj": "Ge", "hmn": "Hmong", "hmo": "Hiri motu", "hrv": "Croato", @@ -3378,6 +4166,7 @@ LANGUAGE_NAMES = { "bik": "ビコル語", "bin": "ビニ語", "bis": "ビスラマ語", + "bit": "Berinomo", "bla": "ブラックフット語", "bod": "チベット語", "bos": "ボスニア語", @@ -3424,6 +4213,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (macrolanguage)", "dsb": "Sorbian; Lower", + "dse": "Dutch Sign Language", "dua": "ドゥアラ語", "dum": "Dutch; Middle (ca. 1050-1350)", "dyu": "デュラ語", @@ -3435,6 +4225,7 @@ LANGUAGE_NAMES = { "elx": "エラム語", "eng": "英語", "enm": "英語; 中世 (1100-1500)", + "enu": "Enu", "epo": "エスペラント", "est": "エストニア語", "eus": "バスク語", @@ -3485,6 +4276,7 @@ LANGUAGE_NAMES = { "hil": "ヒリジャノン語", "hin": "ヒンディー語", "hit": "ヒッタイト語", + "hmj": "Ge", "hmn": "フモング語", "hmo": "ヒリモトゥ語", "hrv": "クロアチア語", @@ -3799,6 +4591,7 @@ LANGUAGE_NAMES = { "bik": "Bikol", "bin": "Bini", "bis": "Bislama", + "bit": "Berinomo", "bla": "Siksika", "bod": "Tibetan", "bos": "Bosnian", @@ -3845,6 +4638,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (macrolanguage)", "dsb": "Sorbian; Lower", + "dse": "Dutch Sign Language", "dua": "Duala", "dum": "Dutch; Middle (ca. 1050-1350)", "dyu": "Dyula", @@ -3856,6 +4650,7 @@ LANGUAGE_NAMES = { "elx": "Elamite", "eng": "English", "enm": "English; Middle (1100-1500)", + "enu": "Enu", "epo": "Esperanto", "est": "Estonian", "eus": "Basque", @@ -3906,6 +4701,7 @@ LANGUAGE_NAMES = { "hil": "Hiligaynon", "hin": "Hindi", "hit": "Hittite", + "hmj": "Ge", "hmn": "Hmong", "hmo": "Hiri Motu", "hrv": "Croatian", @@ -4177,6 +4973,384 @@ LANGUAGE_NAMES = { "zxx": "No linguistic content", "zza": "Zaza" }, + "ko": { + "abk": "압하스어", + "ace": "아체어", + "ach": "아촐리어", + "ada": "Adangme", + "ady": "Adyghe", + "aar": "아파르어", + "afh": "Afrihili", + "afr": "아프리칸스어", + "ain": "Ainu (Japan)", + "aka": "Akan", + "akk": "Akkadian", + "sqi": "Albanian", + "ale": "Aleut", + "amh": "Amharic", + "anp": "Angika", + "ara": "아라비아어", + "arg": "Aragonese", + "arp": "Arapaho", + "arw": "Arawak", + "hye": "아르메니아어", + "asm": "Assamese", + "ast": "Asturian", + "ava": "Avaric", + "ave": "아베스타어", + "awa": "Awadhi", + "aym": "Aymara", + "aze": "Azerbaijani", + "ban": "발리 문자", + "bal": "Baluchi", + "bam": "Bambara", + "bas": "Basa (Cameroon)", + "bak": "Bashkir", + "eus": "바스크어", + "bej": "Beja", + "bel": "벨로루시어", + "bem": "Bemba (Zambia)", + "ben": "벵골 문자", + "bit": "Berinomo", + "bho": "Bhojpuri", + "bik": "Bikol", + "byn": "Bilin", + "bin": "Bini", + "bis": "Bislama", + "zbl": "Blissymbols", + "bos": "Bosnian", + "bra": "Braj", + "bre": "Breton", + "bug": "부기 문자", + "bul": "불가리아어", + "bua": "Buriat", + "mya": "Burmese", + "cad": "Caddo", + "cat": "카탈로니아어", + "ceb": "Cebuano", + "chg": "Chagatai", + "cha": "Chamorro", + "che": "Chechen", + "chr": "체로키 문자", + "chy": "Cheyenne", + "chb": "Chibcha", + "zho": "중국어", + "chn": "Chinook jargon", + "chp": "Chipewyan", + "cho": "Choctaw", + "cht": "Cholón", + "chk": "Chuukese", + "chv": "Chuvash", + "cop": "콥트어", + "cor": "Cornish", + "cos": "Corsican", + "cre": "Cree", + "mus": "Creek", + "hrv": "크로아티아어", + "ces": "체크어", + "dak": "Dakota", + "dan": "덴마크어", + "dar": "Dargwa", + "del": "Delaware", + "div": "Dhivehi", + "din": "Dinka", + "doi": "Dogri (macrolanguage)", + "dgr": "Dogrib", + "dua": "Duala", + "nld": "네덜란드어", + "dse": "Dutch Sign Language", + "dyu": "Dyula", + "dzo": "Dzongkha", + "efi": "Efik", + "egy": "Egyptian (Ancient)", + "eka": "Ekajuk", + "elx": "Elamite", + "eng": "영어", + "enu": "Enu", + "myv": "Erzya", + "epo": "에스페란토어", + "est": "에스토니아어", + "ewe": "Ewe", + "ewo": "Ewondo", + "fan": "Fang (Equatorial Guinea)", + "fat": "Fanti", + "fao": "페로스어", + "fij": "Fijian", + "fil": "Filipino", + "fin": "핀란드어", + "fon": "Fon", + "fra": "프랑스어", + "fur": "Friulian", + "ful": "Fulah", + "gaa": "Ga", + "glg": "Galician", + "lug": "Ganda", + "gay": "Gayo", + "gba": "Gbaya (Central African Republic)", + "hmj": "Ge", + "gez": "Geez", + "kat": "그루지야어", + "deu": "독일어", + "gil": "Gilbertese", + "gon": "Gondi", + "gor": "Gorontalo", + "got": "고트어", + "grb": "Grebo", + "grn": "Guarani", + "guj": "구자라트 문자", + "gwi": "Gwichʼin", + "hai": "Haida", + "hau": "Hausa", + "haw": "Hawaiian", + "heb": "헤브루어", + "her": "Herero", + "hil": "Hiligaynon", + "hin": "Hindi", + "hmo": "Hiri Motu", + "hit": "Hittite", + "hmn": "Hmong", + "hun": "헝가리어", + "hup": "Hupa", + "iba": "Iban", + "isl": "아이슬란드어", + "ido": "Ido", + "ibo": "Igbo", + "ilo": "Iloko", + "ind": "인도네시아어", + "inh": "Ingush", + "ina": "Interlingua (International Auxiliary Language Association)", + "ile": "Interlingue", + "iku": "Inuktitut", + "ipk": "Inupiaq", + "gle": "아일랜드어", + "ita": "이탈리아어", + "jpn": "일본어", + "jav": "Javanese", + "jrb": "Judeo-Arabic", + "jpr": "Judeo-Persian", + "kbd": "Kabardian", + "kab": "Kabyle", + "kac": "Kachin", + "kal": "Kalaallisut", + "xal": "Kalmyk", + "kam": "Kamba (Kenya)", + "kan": " 칸나다 문자", + "kau": "Kanuri", + "kaa": "Kara-Kalpak", + "krc": "Karachay-Balkar", + "krl": "Karelian", + "kas": "Kashmiri", + "csb": "Kashubian", + "kaw": "Kawi", + "kaz": "Kazakh", + "kha": "Khasi", + "kho": "Khotanese", + "kik": "Kikuyu", + "kmb": "Kimbundu", + "kin": "Kinyarwanda", + "kir": "Kirghiz", + "tlh": "Klingon", + "kom": "Komi", + "kon": "Kongo", + "kok": "Konkani (macrolanguage)", + "kor": "한국어", + "kos": "Kosraean", + "kpe": "Kpelle", + "kua": "Kuanyama", + "kum": "Kumyk", + "kur": "Kurdish", + "kru": "Kurukh", + "kut": "Kutenai", + "lad": "Ladino", + "lah": "Lahnda", + "lam": "Lamba", + "lao": "라오 문자", + "lat": "Latin", + "lav": "라트비아어", + "lez": "Lezghian", + "lim": "Limburgan", + "lin": "Lingala", + "lit": "리투아니아어", + "jbo": "Lojban", + "loz": "Lozi", + "lub": "Luba-Katanga", + "lua": "Luba-Lulua", + "lui": "Luiseno", + "smj": "Lule Sami", + "lun": "Lunda", + "luo": "Luo (Kenya and Tanzania)", + "lus": "Lushai", + "ltz": "Luxembourgish", + "mkd": "마케도니아어", + "mad": "Madurese", + "mag": "Magahi", + "mai": "Maithili", + "mak": "Makasar", + "mlg": "Malagasy", + "msa": "Malay (macrolanguage)", + "mal": "말라얄람 문자", + "mlt": "Maltese", + "mnc": "Manchu", + "mdr": "Mandar", + "man": "Mandingo", + "mni": "Manipuri", + "glv": "Manx", + "mri": "Maori", + "arn": "Mapudungun", + "mar": "Marathi", + "chm": "Mari (Russia)", + "mah": "Marshallese", + "mwr": "Marwari", + "mas": "Masai", + "men": "Mende (Sierra Leone)", + "mic": "Mi'kmaq", + "min": "Minangkabau", + "mwl": "Mirandese", + "moh": "Mohawk", + "mdf": "Moksha", + "lol": "Mongo", + "mon": "몽골 문자", + "mos": "Mossi", + "mul": "Multiple languages", + "nqo": "응코 문자", + "nau": "나우루어", + "nav": "나바호어", + "ndo": "Ndonga", + "nap": "Neapolitan", + "nia": "Nias", + "niu": "Niuean", + "zxx": "No linguistic content", + "nog": "Nogai", + "nor": "노르웨이어", + "nob": "Norwegian Bokmål", + "nno": "Norwegian Nynorsk", + "nym": "Nyamwezi", + "nya": "Nyanja", + "nyn": "Nyankole", + "nyo": "Nyoro", + "nzi": "Nzima", + "oci": "Occitan (post 1500)", + "oji": "Ojibwa", + "orm": "Oromo", + "osa": "Osage", + "oss": "Ossetian", + "pal": "Pahlavi", + "pau": "Palauan", + "pli": "Pali", + "pam": "Pampanga", + "pag": "Pangasinan", + "pan": "Panjabi", + "pap": "Papiamento", + "fas": "Persian", + "phn": " 페니키아 문자", + "pon": "Pohnpeian", + "pol": "폴란드어", + "por": "포르투갈어", + "pus": "Pashto", + "que": "Quechua", + "raj": "Rajasthani", + "rap": "Rapanui", + "ron": "루마니아어", + "roh": "Romansh", + "rom": "Romany", + "run": "Rundi", + "rus": "러시아어", + "smo": "Samoan", + "sad": "Sandawe", + "sag": "Sango", + "san": "Sanskrit", + "sat": "Santali", + "srd": "Sardinian", + "sas": "Sasak", + "sco": "Scots", + "sel": "Selkup", + "srp": "세르비아어", + "srr": "Serer", + "shn": "Shan", + "sna": "Shona", + "scn": "Sicilian", + "sid": "Sidamo", + "bla": "Siksika", + "snd": "Sindhi", + "sin": "싱할라 문자", + "den": "Slave (Athapascan)", + "slk": "슬로바키아어", + "slv": "슬로베니아어", + "sog": "Sogdian", + "som": "Somali", + "snk": "Soninke", + "spa": "스페인어", + "srn": "Sranan Tongo", + "suk": "Sukuma", + "sux": "Sumerian", + "sun": "Sundanese", + "sus": "Susu", + "swa": "Swahili (macrolanguage)", + "ssw": "Swati", + "swe": "스웨덴어", + "syr": "시리아 문자", + "tgl": "타갈로그 문자", + "tah": "Tahitian", + "tgk": "Tajik", + "tmh": "Tamashek", + "tam": "타밀 문자", + "tat": "Tatar", + "tel": "텔루구 문자", + "ter": "Tereno", + "tet": "Tetum", + "tha": "태국어", + "bod": "티베트 문자", + "tig": "Tigre", + "tir": "Tigrinya", + "tem": "Timne", + "tiv": "Tiv", + "tli": "Tlingit", + "tpi": "Tok Pisin", + "tkl": "Tokelau", + "tog": "Tonga (Nyasa)", + "ton": "Tonga (Tonga Islands)", + "tsi": "Tsimshian", + "tso": "Tsonga", + "tsn": "Tswana", + "tum": "Tumbuka", + "tur": "터키어", + "tuk": "Turkmen", + "tvl": "Tuvalu", + "tyv": "Tuvinian", + "twi": "Twi", + "udm": "Udmurt", + "uga": "우가리트 문자", + "uig": "Uighur", + "ukr": "Ukrainian", + "umb": "Umbundu", + "mis": "Uncoded languages", + "und": "Undetermined", + "urd": "Urdu", + "uzb": "Uzbek", + "vai": "Vai", + "ven": "Venda", + "vie": "베트남어", + "vol": "Volapük", + "vot": "Votic", + "wln": "Walloon", + "war": "Waray (Philippines)", + "was": "Washo", + "cym": "Welsh", + "wal": "Wolaytta", + "wol": "Wolof", + "xho": "Xhosa", + "sah": "Yakut", + "yao": "Yao", + "yap": "Yapese", + "yid": "Yiddish", + "yor": "Yoruba", + "zap": "Zapotec", + "zza": "Zaza", + "zen": "Zenaga", + "zha": "Zhuang", + "zul": "Zulu", + "zun": "Zuni" + }, "nl": { "aar": "Afar; Hamitisch", "abk": "Abchazisch", @@ -4220,6 +5394,7 @@ LANGUAGE_NAMES = { "bik": "Bikol", "bin": "Bini; Edo", "bis": "Bislama", + "bit": "Berinomo", "bla": "Siksika", "bod": "Tibetaans", "bos": "Bosnisch", @@ -4266,6 +5441,7 @@ LANGUAGE_NAMES = { "div": "Divehi", "doi": "Dogri", "dsb": "Sorbisch; lager", + "dse": "Nederlandse gebarentaal", "dua": "Duala", "dum": "Nederlands; middel (ca. 1050-1350)", "dyu": "Dyula", @@ -4277,6 +5453,7 @@ LANGUAGE_NAMES = { "elx": "Elamitisch", "eng": "Engels", "enm": "Engels; middel (1100-1500)", + "enu": "Enu", "epo": "Esperanto", "est": "Estlands", "eus": "Baskisch", @@ -4327,6 +5504,7 @@ LANGUAGE_NAMES = { "hil": "Hiligainoons", "hin": "Hindi", "hit": "Hittitisch", + "hmj": "Ge", "hmn": "Hmong", "hmo": "Hiri Motu", "hrv": "Kroatisch", @@ -4598,6 +5776,384 @@ LANGUAGE_NAMES = { "zxx": "Geen linguïstische inhoud", "zza": "Zaza" }, + "no": { + "abk": "Abkhazian", + "ace": "Achinese", + "ach": "Acoli", + "ada": "Adangme", + "ady": "Adyghe", + "aar": "Afar", + "afh": "Afrihili", + "afr": "Afrikansk", + "ain": "Ainu (Japan)", + "aka": "Akan", + "akk": "Akkadian", + "sqi": "Albansk", + "ale": "Aleut", + "amh": "Amharic", + "anp": "Angika", + "ara": "Arabisk", + "arg": "Aragonsk", + "arp": "Arapaho", + "arw": "Arawak", + "hye": "Armensk", + "asm": "assamisk", + "ast": "Asturian", + "ava": "Avaric", + "ave": "Avestisk", + "awa": "Awadhi", + "aym": "Aymara", + "aze": "Aserbadjansk", + "ban": "Balinese", + "bal": "Baluchi", + "bam": "Bambara", + "bas": "Basa (Cameroon)", + "bak": "Basjkirsk", + "eus": "Baskisk", + "bej": "Beja", + "bel": "Hviterussisk", + "bem": "Bemba (Zambia)", + "ben": "Bengali", + "bit": "Berinomo", + "bho": "Bhojpuri", + "bik": "Bikol", + "byn": "Bilin", + "bin": "Bini", + "bis": "Bislama", + "zbl": "Blissymbols", + "bos": "Bosnian", + "bra": "Braj", + "bre": "Breton", + "bug": "Buginese", + "bul": "Bulgarsk", + "bua": "Buriat", + "mya": "burmesisk", + "cad": "Caddo", + "cat": "Katalan", + "ceb": "Cebuano", + "chg": "Chagatai", + "cha": "chamorro", + "che": "Chechen", + "chr": "cherokee", + "chy": "Cheyenne", + "chb": "Chibcha", + "zho": "Kinesisk", + "chn": "Chinook jargon", + "chp": "Chipewyan", + "cho": "Choctaw", + "cht": "Cholón", + "chk": "Chuukese", + "chv": "tsjuvansk", + "cop": "Koptisk", + "cor": "Cornish", + "cos": "Corsican", + "cre": "Cree", + "mus": "Creek", + "hrv": "Kroatsisk", + "ces": "Tjekkisk", + "dak": "Dakota", + "dan": "Dansk", + "dar": "Dargwa", + "del": "Delaware", + "div": "Dhivehi", + "din": "Dinka", + "doi": "Dogri (macrolanguage)", + "dgr": "Dogrib", + "dua": "Duala", + "nld": "Nederlandsk", + "dse": "Dutch Sign Language", + "dyu": "Dyula", + "dzo": "dzongkha", + "efi": "Efik", + "egy": "Egyptian (Ancient)", + "eka": "Ekajuk", + "elx": "Elamite", + "eng": "Engelsk", + "enu": "Enu", + "myv": "Erzya", + "epo": "Esperanto", + "est": "Estonsk", + "ewe": "ewe", + "ewo": "Ewondo", + "fan": "Fang (Equatorial Guinea)", + "fat": "Fanti", + "fao": "færøysk", + "fij": "fijiansk", + "fil": "Filipino", + "fin": "Finsk", + "fon": "Fon", + "fra": "Fransk", + "fur": "Friulian", + "ful": "fulani", + "gaa": "Ga", + "glg": "Galician", + "lug": "Ganda", + "gay": "Gayo", + "gba": "Gbaya (Central African Republic)", + "hmj": "Ge", + "gez": "Geez", + "kat": "Georgisk", + "deu": "Tysk", + "gil": "Gilbertese", + "gon": "Gondi", + "gor": "Gorontalo", + "got": "Gotisk", + "grb": "Grebo", + "grn": "Guarani", + "guj": "gujarati", + "gwi": "Gwichʼin", + "hai": "Haida", + "hau": "Hausa", + "haw": "hawaiisk", + "heb": "Hebraisk", + "her": "Herero", + "hil": "Hiligaynon", + "hin": "hindi", + "hmo": "Hiri Motu", + "hit": "Hittite", + "hmn": "Hmong", + "hun": "Ungarsk", + "hup": "Hupa", + "iba": "Iban", + "isl": "Islandsk", + "ido": "ido", + "ibo": "ibo", + "ilo": "Iloko", + "ind": "Indonesisk", + "inh": "Ingush", + "ina": "Interlingua (International Auxiliary Language Association)", + "ile": "interlingue", + "iku": "inuktitut", + "ipk": "unupiak", + "gle": "Irsk", + "ita": "Italiensk", + "jpn": "Japansk", + "jav": "Javanesisk", + "jrb": "Judeo-Arabic", + "jpr": "Judeo-Persian", + "kbd": "Kabardian", + "kab": "Kabyle", + "kac": "Kachin", + "kal": "Grønlandsk", + "xal": "Kalmyk", + "kam": "Kamba (Kenya)", + "kan": "kannada", + "kau": "Kanuri", + "kaa": "Kara-Kalpak", + "krc": "Karachay-Balkar", + "krl": "Karelisk", + "kas": "kasjmiri", + "csb": "Kashubian", + "kaw": "Kawi", + "kaz": "kasakhisk", + "kha": "Khasi", + "kho": "Khotanese", + "kik": "kikuyu", + "kmb": "Kimbundu", + "kin": "kinjarwanda", + "kir": "kirgisisk", + "tlh": "Klingon", + "kom": "komi", + "kon": "Kongo", + "kok": "Konkani (macrolanguage)", + "kor": "Koreansk", + "kos": "Kosraean", + "kpe": "Kpelle", + "kua": "kuanyama", + "kum": "Kumyk", + "kur": "Kurdisk", + "kru": "Kurukh", + "kut": "Kutenai", + "lad": "Ladino", + "lah": "Lahnda", + "lam": "Lamba", + "lao": "laotisk", + "lat": "Latin", + "lav": "Latvisk", + "lez": "Lezghian", + "lim": "Limburgan", + "lin": "lingala", + "lit": "Lituaisk", + "jbo": "Lojban", + "loz": "Lozi", + "lub": "luba-katanga", + "lua": "Luba-Lulua", + "lui": "Luiseno", + "smj": "Lulesamisk", + "lun": "Lunda", + "luo": "Luo (Kenya and Tanzania)", + "lus": "Lushai", + "ltz": "Luxemburgisk", + "mkd": "Makedonsk", + "mad": "Madurese", + "mag": "Magahi", + "mai": "Maithili", + "mak": "Makasar", + "mlg": "madagassisk", + "msa": "Malay (macrolanguage)", + "mal": "malayalam", + "mlt": "Maltisk", + "mnc": "Manchu", + "mdr": "Mandar", + "man": "Mandingo", + "mni": "Manipuri", + "glv": "manx", + "mri": "Maori", + "arn": "Mapudungun", + "mar": "Marathi", + "chm": "Mari (Russland)", + "mah": "Marshallese", + "mwr": "Marwari", + "mas": "Masai", + "men": "Mende (Sierra Leone)", + "mic": "Mi'kmaq", + "min": "Minangkabau", + "mwl": "Mirandese", + "moh": "Mohawk", + "mdf": "Moksha", + "lol": "Mongo", + "mon": "Mongolsk", + "mos": "Mossi", + "mul": "Flere språk", + "nqo": "N'Ko", + "nau": "nauru", + "nav": "Navajo", + "ndo": "Ndonga", + "nap": "Napolitansk", + "nia": "Nias", + "niu": "Niuean", + "zxx": "Inget språklig innhold", + "nog": "Nogai", + "nor": "Norsk", + "nob": "Norsk bokmål", + "nno": "Norsk nynorsk", + "nym": "Nyamwezi", + "nya": "Nyanja", + "nyn": "Nyankole", + "nyo": "Nyoro", + "nzi": "Nzima", + "oci": "Occitan (post 1500)", + "oji": "Ojibwa", + "orm": "oromo", + "osa": "Osage", + "oss": "Ossetian", + "pal": "Pahlavi", + "pau": "Palauan", + "pli": "Pali", + "pam": "Pampanga", + "pag": "Pangasinan", + "pan": "Panjabi", + "pap": "Papiamento", + "fas": "Persisk", + "phn": "Phoenician", + "pon": "Pohnpeian", + "pol": "Polsk", + "por": "Portugisisk", + "pus": "Pashto", + "que": "Quechua", + "raj": "Rajasthani", + "rap": "Rapanui", + "ron": "Rumensk", + "roh": "Retoromansk", + "rom": "Romany", + "run": "rundi", + "rus": "Russisk", + "smo": "samoansk", + "sad": "Sandawe", + "sag": "Sango", + "san": "sanskrit", + "sat": "Santali", + "srd": "Sardinsk", + "sas": "Sasak", + "sco": "Scots", + "sel": "Selkup", + "srp": "Serbisk", + "srr": "Serer", + "shn": "Shan", + "sna": "Shona", + "scn": "Siciliansk", + "sid": "sidamo", + "bla": "Siksika", + "snd": "sindhi", + "sin": "Sinhala", + "den": "Slave (Athapascan)", + "slk": "Slovakisk", + "slv": "Slovensk", + "sog": "Sogdian", + "som": "somalisk", + "snk": "Soninke", + "spa": "Spansk", + "srn": "Sranan Tongo", + "suk": "Sukuma", + "sux": "Sumerian", + "sun": "sundanesisk", + "sus": "Susu", + "swa": "Swahili (macrolanguage)", + "ssw": "swati", + "swe": "Svensk", + "syr": "Syriac", + "tgl": "tagalog", + "tah": "Tahitian", + "tgk": "Tajik", + "tmh": "Tamashek", + "tam": "Tamilsk", + "tat": "tatarisk", + "tel": "Telugu", + "ter": "Tereno", + "tet": "Tetum", + "tha": "Thai", + "bod": "tibetansk", + "tig": "Tigre", + "tir": "Tigrinya", + "tem": "Timne", + "tiv": "Tiv", + "tli": "Tlingit", + "tpi": "Tok Pisin", + "tkl": "Tokelau", + "tog": "Tonga (Nyasa)", + "ton": "tonga (Tonga-øyene)", + "tsi": "Tsimshian", + "tso": "tsonga", + "tsn": "tswana", + "tum": "Tumbuka", + "tur": "Tyrkisk", + "tuk": "turkmensk", + "tvl": "Tuvalu", + "tyv": "Tuvinian", + "twi": "twi", + "udm": "Udmurt", + "uga": "Ugaritic", + "uig": "uigurisk", + "ukr": "Ukrainsk", + "umb": "Umbundu", + "mis": "Uncoded languages", + "und": "Undetermined", + "urd": "urdu", + "uzb": "usbekisk", + "vai": "Vai", + "ven": "venda", + "vie": "Vietnamesisk", + "vol": "Volapük", + "vot": "Votic", + "wln": "Walloon", + "war": "Waray (Philippines)", + "was": "Washo", + "cym": "Walisisk", + "wal": "Wolaytta", + "wol": "wolof", + "xho": "Xhosa", + "sah": "Yakut", + "yao": "Yao", + "yap": "Yapese", + "yid": "jiddisk", + "yor": "joruba", + "zap": "Zapotec", + "zza": "Zaza", + "zen": "Zenaga", + "zha": "Zhuang", + "zul": "Zulu", + "zun": "Zuni" + }, "pl": { "aar": "afarski", "abk": "abchaski", @@ -4641,6 +6197,7 @@ LANGUAGE_NAMES = { "bik": "bikol", "bin": "edo", "bis": "bislama", + "bit": "Berinomo", "bla": "siksika", "bod": "tybetański", "bos": "bośniacki", @@ -4687,6 +6244,7 @@ LANGUAGE_NAMES = { "div": "malediwski; divehi", "doi": "dogri (makrojęzyk)", "dsb": "dolnołużycki", + "dse": "holenderski język migowy", "dua": "duala", "dum": "holenderski średniowieczny (ok. 1050-1350)", "dyu": "diula", @@ -4698,6 +6256,7 @@ LANGUAGE_NAMES = { "elx": "elamicki", "eng": "Angielski", "enm": "angielski średniowieczny (1100-1500)", + "enu": "Enu", "epo": "esperanto", "est": "estoński", "eus": "baskijski", @@ -4748,6 +6307,7 @@ LANGUAGE_NAMES = { "hil": "hiligajnon", "hin": "hindi", "hit": "hetycki", + "hmj": "Ge", "hmn": "hmong", "hmo": "hiri motu", "hrv": "chorwacki", @@ -5057,6 +6617,7 @@ LANGUAGE_NAMES = { "bel": "Belarusian", "bem": "Bemba (Zambia)", "ben": "Bengali", + "bit": "Berinomo", "bho": "Bhojpuri", "bik": "Bikol", "byn": "Bilin", @@ -5103,6 +6664,7 @@ LANGUAGE_NAMES = { "dgr": "Dogrib", "dua": "Duala", "nld": "Holandês", + "dse": "Língua gestual holandesa", "dyu": "Dyula", "dzo": "Dzongkha", "efi": "Efik", @@ -5110,6 +6672,7 @@ LANGUAGE_NAMES = { "eka": "Ekajuk", "elx": "Elamite", "eng": "Inglês", + "enu": "Enu", "myv": "Erzya", "epo": "Esperanto", "est": "Estónio", @@ -5130,6 +6693,7 @@ LANGUAGE_NAMES = { "lug": "Ganda", "gay": "Gayo", "gba": "Gbaya (Central African Republic)", + "hmj": "Ge", "gez": "Geez", "kat": "Georgiano", "deu": "Alemão", @@ -5436,6 +7000,7 @@ LANGUAGE_NAMES = { "bik": "Бикольский", "bin": "Бини", "bis": "Бислама", + "bit": "Berinomo", "bla": "Сиксика", "bod": "Тибетский", "bos": "Боснийский", @@ -5482,6 +7047,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (macrolanguage)", "dsb": "Sorbian; Lower", + "dse": "Dutch Sign Language", "dua": "Дуала", "dum": "Dutch; Middle (ca. 1050-1350)", "dyu": "Диула (Дьюла)", @@ -5493,6 +7059,7 @@ LANGUAGE_NAMES = { "elx": "Эламский", "eng": "Английский", "enm": "Среднеанглийский (1100-1500)", + "enu": "Enu", "epo": "Эсперанто", "est": "Эстонский", "eus": "Баскский", @@ -5543,6 +7110,7 @@ LANGUAGE_NAMES = { "hil": "Хилигайнон", "hin": "Хинди", "hit": "Хиттит", + "hmj": "Ge", "hmn": "Хмонг", "hmo": "Хири Моту", "hrv": "Хорватский", @@ -5857,6 +7425,7 @@ LANGUAGE_NAMES = { "bik": "Bikol", "bin": "Edo (bini)", "bis": "Bislama", + "bit": "Berinomo", "bla": "Siksika (svartfotindianernas språk)", "bod": "Tibetanska", "bos": "Bosniska", @@ -5903,6 +7472,7 @@ LANGUAGE_NAMES = { "div": "Divehi", "doi": "Dogri (macrolanguage)", "dsb": "Sorbian; nedre", + "dse": "Nederländskt teckenspråk", "dua": "Duala", "dum": "Hollänska; medeltida (ca. 1050-1350)", "dyu": "Dyula", @@ -5914,6 +7484,7 @@ LANGUAGE_NAMES = { "elx": "Elamitiska", "eng": "Engelska", "enm": "Medelengelska (1100-1500)", + "enu": "Enu", "epo": "Esperanto", "est": "Estniska", "eus": "Baskiska", @@ -5964,6 +7535,7 @@ LANGUAGE_NAMES = { "hil": "Hiligaynon", "hin": "Hindi", "hit": "Hettitiska språk", + "hmj": "Ge", "hmn": "Hmong", "hmo": "Hiri Motu", "hrv": "Kroatiska", @@ -6273,6 +7845,7 @@ LANGUAGE_NAMES = { "bel": "Beyaz Rusça", "bem": "Bemba (Zambia)", "ben": "Bengalce", + "bit": "Berinomo", "bho": "Bhojpuri (Hindistan)", "bik": "Bikol (Filipinler)", "byn": "Bilin", @@ -6319,6 +7892,7 @@ LANGUAGE_NAMES = { "dgr": "Dogrib (Kanada)", "dua": "Duala (Afrika)", "nld": "Flâmanca (Hollanda dili)", + "dse": "Hollandalı İşaret Dili", "dyu": "Dyula (Burkina Faso; Mali)", "dzo": "Dzongkha (Butan)", "efi": "Efik (Afrika)", @@ -6326,6 +7900,7 @@ LANGUAGE_NAMES = { "eka": "Ekajuk (Afrika)", "elx": "Elamca", "eng": "İngilizce", + "enu": "Enu", "myv": "Erzya dili", "epo": "Esperanto", "est": "Estonca", @@ -6346,6 +7921,7 @@ LANGUAGE_NAMES = { "lug": "Ganda Dili", "gay": "Gayo (Sumatra)", "gba": "Gbaya (Orta Afrika Cumhuriyeti)", + "hmj": "Ge", "gez": "Geez (Etiyopya)", "kat": "Gürcüce", "deu": "Almanca", @@ -6652,6 +8228,7 @@ LANGUAGE_NAMES = { "bik": "бікольська", "bin": "біні", "bis": "біслама", + "bit": "беріномо", "bla": "сісіка", "bod": "тибетська", "bos": "боснійська", @@ -6698,6 +8275,7 @@ LANGUAGE_NAMES = { "div": "мальдивська", "doi": "догрі (макромова)", "dsb": "нижньолужицька", + "dse": "голландська мова жестів", "dua": "дуала", "dum": "середньовічна голландська (бл. 1050-1350)", "dyu": "діула", @@ -6709,6 +8287,7 @@ LANGUAGE_NAMES = { "elx": "еламська", "eng": "англійська", "enm": "середньоанглійська (1100-1500)", + "enu": "ену", "epo": "есперанто", "est": "естонська", "eus": "баскська", @@ -6759,6 +8338,7 @@ LANGUAGE_NAMES = { "hil": "хілігайнон", "hin": "хінді", "hit": "хетська", + "hmj": "ге", "hmn": "хмонг", "hmo": "хірімоту", "hrv": "хорватська", @@ -7030,6 +8610,384 @@ LANGUAGE_NAMES = { "zxx": "немає мовних даних", "zza": "заза" }, + "vi": { + "abk": "Abkhazian", + "ace": "Tiếng A-chinh", + "ach": "Tiếng A-co-li", + "ada": "Tiếng A-đang-me", + "ady": "Adyghe", + "aar": "Afar", + "afh": "Tiếng A-phi-li", + "afr": "Tiếng Hà Lan-Nam Phi", + "ain": "Ainu (Japan)", + "aka": "Akan", + "akk": "Tiếng A-ca-đi", + "sqi": "Tiếng An-ba-ni", + "ale": "Tiếng A-le-uth", + "amh": "Tiếng Am-ha-ri", + "anp": "Tiếng An-gi-ca", + "ara": "Tiếng A-rập", + "arg": "Tiếng A-ra-got", + "arp": "Tiếng A-ra-bô", + "arw": "Tiếng A-ra-ouac", + "hye": "Tiếng Ác-mê-ni", + "asm": "Tiếng A-xam", + "ast": "Asturian", + "ava": "Tiếng A-va-ri", + "ave": "Tiếng A-ve-x-tan", + "awa": "Tiếng A-oua-đi", + "aym": "Aymara", + "aze": "Tiếng Agiecbaigiăng", + "ban": "Tiếng Ba-li", + "bal": "Tiếng Ba-lu-khi", + "bam": "Bambara", + "bas": "Basa (Cameroon)", + "bak": "Tiếng Ba-s-kic", + "eus": "Tiếng Baxcơ", + "bej": "Tiếng Be-gia", + "bel": "Tiếng Be-la-ruxợ", + "bem": "Bemba (Zambia)", + "ben": "Tiếng Băng Gan", + "bit": "Berinomo", + "bho": "Tiếng Bo-giơ-pu-ri", + "bik": "Tiếng Bi-cot", + "byn": "Bilin", + "bin": "Tiếng Bi-ni", + "bis": "Tiếng Bix-la-ma", + "zbl": "Blissymbols", + "bos": "Tiếng Bô-xni-a", + "bra": "Tiếng Boua-giơ", + "bre": "Tiếng Boue-ton (Pháp)", + "bug": "Tiếng Bu-gin", + "bul": "Tiếng Bảo Gai Lơi", + "bua": "Tiếng Bu-ri-at", + "mya": "Tiếng Miến Điện", + "cad": "Tiếng Ca-đô", + "cat": "Tiếng Catalăng", + "ceb": "Tiếng Xe-bu-a-nô", + "chg": "Chagatai", + "cha": "Tiếng Cha-mo-ro", + "che": "Tiếng Che-chẹnh", + "chr": "Tiếng Che-rô-ki", + "chy": "Tiếng Chê-iênh", + "chb": "Tiếng Chic-cha", + "zho": "Tiếng Trung Hoa", + "chn": "Biệt ngữ Chi-nukh", + "chp": "Tiếng Chi-pu-i-a", + "cho": "Tiếng Choc-toa", + "cht": "Cholón", + "chk": "Tiếng Chu-ki", + "chv": "Tiếng Chu-vaxơ", + "cop": "Ngôn ngữ phổ biến trong Giáo hội Ai Cập", + "cor": "Tiếng Khonh-uoă", + "cos": "Tiếng Kho-si-ca", + "cre": "Tiếng Kh-ri", + "mus": "Tiếng C-ric", + "hrv": "Tiếng Crô-át", + "ces": "Tiếng Séc", + "dak": "Tiếng Đa-cô-ta", + "dan": "Tiếng Đan Mạch", + "dar": "Tiếng Đac-oua", + "del": "Tiếng Đe-la-oue", + "div": "Dhivehi", + "din": "Dinka", + "doi": "Dogri (macrolanguage)", + "dgr": "Tiếng Đoc-ric", + "dua": "Tiếng Đu-a-la", + "nld": "Tiếng Hòa Lan", + "dse": "Dutch Sign Language", + "dyu": "Tiếng Đi-u-la", + "dzo": "Tiếng Đxong-kha", + "efi": "Tiếng E-phic", + "egy": "Tiếng Ai Cập (cổ)", + "eka": "Tiếng E-ca-giuc", + "elx": "Tiếng E-la-mi", + "eng": "Tiếng Anh", + "enu": "Enu", + "myv": "Tiếng Ơ-dia", + "epo": "Tiếng Etpêrantô", + "est": "Tiếng Phổ Cổ", + "ewe": "Tiếng E-oue", + "ewo": "Tiếng E-ouon-đô", + "fan": "Fang (Equatorial Guinea)", + "fat": "Tiếng Phan-ti", + "fao": "Tiếng Pha-rô", + "fij": "Tiếng Phi-gi", + "fil": "Filipino", + "fin": "Tiếng Phần Lan", + "fon": "Tiếng Phonh", + "fra": "Tiếng Pháp", + "fur": "Tiếng Ph-riu-li", + "ful": "Tiếng Phu-la", + "gaa": "Tiếng Ga", + "glg": "Galician", + "lug": "Ganda", + "gay": "Tiếng Gay-ô", + "gba": "Gbaya (Central African Republic)", + "hmj": "Ge", + "gez": "Tiếng Gi-d", + "kat": "Tiếng Gi-oa-gi-a", + "deu": "Tiếng Đức", + "gil": "Tiếng Gil-bơt", + "gon": "Tiếng Gon-đi", + "gor": "Tiếng Go-ron-ta-lô", + "got": "Tiếng Gô-tích", + "grb": "Tiếng Goue-bô", + "grn": "Tiếng Gua-ra-ni", + "guj": "Tiếng Gu-gia-ra-ti", + "gwi": "Gwichʼin", + "hai": "Tiếng Hai-đa", + "hau": "Tiếng Hau-xa", + "haw": "Tiếng Ha-uoai-i", + "heb": "Tiếng Do Thái", + "her": "Tiếng He-re-rô", + "hil": "Tiếng Hi-li-gay-non", + "hin": "Tiếng Hin-đi", + "hmo": "Tiếng Mo-tu", + "hit": "Tiếng Hic-tic", + "hmn": "Tiếng Miêu", + "hun": "Tiếng Hung Gia Lợi", + "hup": "Tiếng Hu-pa", + "iba": "Iban", + "isl": "Tiếng Băng đảo", + "ido": "Tiếng I-đô", + "ibo": "Tiếng Ic-bô", + "ilo": "Tiếng I-lô-cô", + "ind": "Tiếng Nam Dương", + "inh": "Tiếng In-gut", + "ina": "Ngôn ngữ lẫn nhau In-tơ-lin-gua (Liên Hiệp Ngôn Ngữ Bổ Trợ Quốc Tế)", + "ile": "Ngôn ngữ lẫn nhau In-tơ-ling", + "iku": "Tiếng I-nuc-ti-tuc", + "ipk": "Tiếng In-u-bơ-lac", + "gle": "Tiếng Ái Nhĩ Lan", + "ita": "Tiếng Ý", + "jpn": "Tiếng Nhật", + "jav": "Tiếng Gia-va", + "jrb": "Do thái - A-rập", + "jpr": "Do thái - Ba tư", + "kbd": "Tiếng Ca-bat", + "kab": "Tiếng Ca-bai", + "kac": "Tiếng Ca-chin", + "kal": "Kalaallisut", + "xal": "Kalmyk", + "kam": "Kamba (Kenya)", + "kan": "Tiếng Kan-na-đa", + "kau": "Tiếng Ca-nu-ri", + "kaa": "Tiếng Ca-ra-Cac-pac", + "krc": "Tiếng Ca-ra-chay-Boa-ca", + "krl": "Tiếng Ca-re-ni", + "kas": "Tiếng Ca-s-mi-ri", + "csb": "Tiếng Ca-su-bi", + "kaw": "Tiếng Ca-oui", + "kaz": "Tiếng Ca-dakh", + "kha": "Khasi", + "kho": "Tiếng Kho-tan", + "kik": "Tiếng Khi-ku-iu", + "kmb": "Tiếng Kim-bun-đu", + "kin": "Tiếng Kin-ia-ouanh-đa", + "kir": "Tiếng Kit-ki-dơ", + "tlh": "Klingon", + "kom": "Tiếng Cô-mi", + "kon": "Kongo", + "kok": "Konkani (macrolanguage)", + "kor": "Tiếng Hàn Quốc", + "kos": "Tiếng Co-x-rai", + "kpe": "Tiếng C-pe-le", + "kua": "Tiếng Cu-an-i-am-a", + "kum": "Tiếng Cu-mic", + "kur": "Tiếng người Kurd", + "kru": "Tiếng Cu-ruc", + "kut": "Tiếng Cu-ten-ai", + "lad": "Tiếng La-đi-nô", + "lah": "Tiếng Lan-đa", + "lam": "Tiếng Lam-ba", + "lao": "Tiếng Lào", + "lat": "Tiếng La-tinh", + "lav": "Tiếng Lát-vi-a", + "lez": "Tiếng Le-d-khi-an", + "lim": "Limburgan", + "lin": "Tiếng Lin-ga-la", + "lit": "Tiếng Li-tu-a-ni", + "jbo": "Tiếng Loc-ba", + "loz": "Tiếng Lo-di", + "lub": "Tiếng Lu-ba-Ca-tan-ga", + "lua": "Tiếng Lu-ba-Lu-lu-a", + "lui": "Tiếng Lui-xen-ô", + "smj": "Tiếng Sa-mi Lu-le", + "lun": "Tiếng Lun-đa", + "luo": "Tiếng Luo (Ken-i-a và Than-dê-ni-a)", + "lus": "Tiếng Lu-sai", + "ltz": "Luxembourgish", + "mkd": "Tiếng Maxêđôni", + "mad": "Tiếng Ma-đu-ri", + "mag": "Tiếng Mu-ga-hi", + "mai": "Tiếng Mai-ti-li", + "mak": "Makasar", + "mlg": "Tiếng Ma-la-ga-si", + "msa": "Malay (macrolanguage)", + "mal": "Tiếng Ma-lay-am", + "mlt": "Tiếng Mantơ", + "mnc": "Tiếng Man-chu (Trung Hoa)", + "mdr": "Tiếng Man-đa", + "man": "Tiếng Man-đin-gô", + "mni": "Tiếng Ma-ni-pu-ri", + "glv": "Tiếng Man-khơx", + "mri": "Tiếng Maori", + "arn": "Mapudungun", + "mar": "Tiếng Ma-ra-ti", + "chm": "Mari (Russia)", + "mah": "Marshallese", + "mwr": "Tiếng Ma-oua-ri", + "mas": "Tiếng Ma-sai", + "men": "Mende (Sierra Leone)", + "mic": "Mi'kmaq", + "min": "Tiếng Mi-nang-ca-bau", + "mwl": "Tiếng Mi-ran-đi", + "moh": "Tiếng Mô-hoakh", + "mdf": "Tiếng Moc-sa", + "lol": "Tiếng Mon-gô", + "mon": "Tiếng Mông Cổ", + "mos": "Tiếng Mo-xi", + "mul": "Đa ngôn ngữ", + "nqo": "N'Ko", + "nau": "Tiếng Nau-ru", + "nav": "Navajo", + "ndo": "Tiếng N-đon-ga", + "nap": "Tiếng Na-po-li (Ý)", + "nia": "Tiếng Ni-at", + "niu": "Tiếng Niu-i", + "zxx": "Không có nội dung kiểu ngôn ngữ", + "nog": "Tiếng No-gai", + "nor": "Tiếng Na-uy", + "nob": "Norwegian Bokmål", + "nno": "Tiếng Na-uy (Nynorsk)", + "nym": "Tiếng Nai-am-oue-di", + "nya": "Nyanja", + "nyn": "Tiếng Nai-an-co-le", + "nyo": "Nyoro", + "nzi": "Tiếng N-di-ma", + "oci": "Occitan (post 1500)", + "oji": "Ojibwa", + "orm": "Tiếng O-ro-mô", + "osa": "Tiếng O-sa-ge", + "oss": "Ossetian", + "pal": "Tiếng Pa-la-vi", + "pau": "Tiếng Pa-lau-a", + "pli": "Pali", + "pam": "Tiếng Pam-pan-ga", + "pag": "Tiếng Pan-ga-sin", + "pan": "Panjabi", + "pap": "Tiếng Pa-pi-a-men-tô", + "fas": "Tiếng Ba Tư", + "phn": "Tiếng Phê-ni-xi", + "pon": "Tiếng Pon-pê-i-a", + "pol": "Tiếng Ba Lan", + "por": "Tiếng Bồ Đào Nha", + "pus": "Tiếng Pu-s-tô", + "que": "Quechua", + "raj": "Tiếng Ra-gia-x-tni", + "rap": "Tiếng Ra-pa-nui", + "ron": "Tiếng Lỗ Má Ni", + "roh": "Romansh", + "rom": "Tiếng Gipxi", + "run": "Tiếng Run-đi", + "rus": "Tiếng Nga", + "smo": "Tiếng Xa-mô-a", + "sad": "Tiếng San-đa-ouê", + "sag": "Sango", + "san": "Tiếng Phạn", + "sat": "Tiếng San-ta-li", + "srd": "Tiếng Xa-đi-ni-a (Ý)", + "sas": "Sasak", + "sco": "Tiếng Ê-cốt", + "sel": "Tiếng Xe-cuc", + "srp": "Tiếng Xéc bi", + "srr": "Serer", + "shn": "Tiếng San", + "sna": "Tiếng Sô-na", + "scn": "Tiếng Xi-xi-li", + "sid": "Tiếng Xi-đa-mô", + "bla": "Tiếng Xich-xich-a", + "snd": "Tiếng Sin-đi", + "sin": "Sinhala", + "den": "Tiếng A-ta-pax-ca", + "slk": "Tiếng Xlô-vác", + "slv": "Tiếng Xlô-ven", + "sog": "Tiếng Xoc-đi-a", + "som": "Tiếng Xô-ma-li", + "snk": "Tiếng Xo-nin-khe", + "spa": "Tiếng Tây Ban Nha", + "srn": "Sranan Tongo", + "suk": "Tiếng Xu-ku-ma", + "sux": "Tiếng Xu-me", + "sun": "Tiếng Xunh-đan", + "sus": "Tiếng xu-xu", + "swa": "Swahili (macrolanguage)", + "ssw": "Tiếng Xôa-thi", + "swe": "Tiếng Thuỵ Điển", + "syr": "Tiếng Xi-ri", + "tgl": "Tiếng Ta-ga-lọc", + "tah": "Tiếng Ta-hi-ti", + "tgk": "Tiếng Ta-gic", + "tmh": "Tamashek", + "tam": "Tiếng Ta-mil", + "tat": "Tiếng Tác-ta", + "tel": "Telugu", + "ter": "Tiếng Te-re-no", + "tet": "Tiếng Te-tum", + "tha": "Tiếng Thái Lan", + "bod": "Tiếng Tây Tạng", + "tig": "Tiếng Thi-gơ-rơ", + "tir": "Tiếng Thi-gơ-rin-ya", + "tem": "Tiếng Tim-ne", + "tiv": "Tiếng Ti-ph", + "tli": "Tiếng Tợ-lin-git", + "tpi": "Tiếng Tok Pi-sin", + "tkl": "Tiếng To-ke-lau", + "tog": "Tiếng Ton-ga (Nai-a-sa)", + "ton": "Tiếng Ton-ga (Quần đảo Ton-ga)", + "tsi": "Tiếng T-xim-si-an", + "tso": "Tiếng Xông-ga", + "tsn": "Tiếng T-xoua-na", + "tum": "Tiếng Tum-bu-ka", + "tur": "Tiếng Thổ Nhĩ Kỳ", + "tuk": "Tiếng Tuơkh-men", + "tvl": "Tiếng Tu-va-lu", + "tyv": "Tiếng Tu-vi-ni", + "twi": "Tiếng Toui", + "udm": "Tiếng Ud-mợt", + "uga": "Tiếng U-ga-ri", + "uig": "Tiếng Ui-guơ", + "ukr": "Tiếng Ukraina", + "umb": "Tiếng Um-bun-đu", + "mis": "Uncoded languages", + "und": "Chưa quyết định", + "urd": "Tiếng Uơ-đu", + "uzb": "Tiếng U-dơ-bếch", + "vai": "Tiếng Vai", + "ven": "Tiếng Ven-đa", + "vie": "Tiếng Việt", + "vol": "Tiếng Vo-la-puk", + "vot": "Tiếng Vo-tic", + "wln": "Tiếng Oua-lon", + "war": "Waray (Philippines)", + "was": "Tiếng Oua-sô", + "cym": "Tiếng Oue-l-s", + "wal": "Wolaytta", + "wol": "Tiếng Ou-o-loc", + "xho": "Tiếng X-hô-da", + "sah": "Tiếng Ia-cut", + "yao": "Tiếng Yao", + "yap": "Tiếng Yat", + "yid": "Tiếng Y-đit", + "yor": "Tiếng Yo-ru-ba", + "zap": "Zapotec", + "zza": "Zaza", + "zen": "Tiếng De-na-ga", + "zha": "Zhuang", + "zul": "Tiếng Du-lu", + "zun": "Tiếng Du-ni" + }, "zh_Hans_CN": { "aar": "阿法尔语", "abk": "阿布哈兹语", @@ -7073,6 +9031,7 @@ LANGUAGE_NAMES = { "bik": "比科尔语", "bin": "比尼语", "bis": "比斯拉马语", + "bit": "Berinomo", "bla": "西克西卡语", "bod": "藏语", "bos": "波斯尼亚语", @@ -7119,6 +9078,7 @@ LANGUAGE_NAMES = { "div": "迪维希语", "doi": "多格拉语", "dsb": "索布语(下)", + "dse": "荷兰手语", "dua": "杜亚拉语", "dum": "荷兰语(中古,约 1050-1350)", "dyu": "迪尤拉语", @@ -7130,6 +9090,7 @@ LANGUAGE_NAMES = { "elx": "埃兰语", "eng": "英语", "enm": "英语(中古,1100-1500)", + "enu": "Enu", "epo": "世界语", "est": "爱沙尼亚语", "eus": "巴斯克语", @@ -7180,6 +9141,7 @@ LANGUAGE_NAMES = { "hil": "希利盖农语", "hin": "印地语", "hit": "赫梯语", + "hmj": "亻革家语、重安江苗语", "hmn": "苗语", "hmo": "希里莫图语", "hrv": "克罗地亚语", @@ -7489,6 +9451,7 @@ LANGUAGE_NAMES = { "bel": "白俄羅斯文", "bem": "Bemba (Zambia)", "ben": "Bengali", + "bit": "Berinomo", "bho": "Bhojpuri", "bik": "Bikol", "byn": "Bilin", @@ -7535,6 +9498,7 @@ LANGUAGE_NAMES = { "dgr": "Dogrib", "dua": "Duala", "nld": "荷蘭文", + "dse": "Dutch Sign Language", "dyu": "Dyula", "dzo": "Dzongkha", "efi": "Efik", @@ -7542,6 +9506,7 @@ LANGUAGE_NAMES = { "eka": "Ekajuk", "elx": "Elamite", "eng": "英文", + "enu": "Enu", "myv": "Erzya", "epo": "世界語", "est": "愛沙尼亞文", @@ -7562,6 +9527,7 @@ LANGUAGE_NAMES = { "lug": "Ganda", "gay": "Gayo", "gba": "Gbaya (Central African Republic)", + "hmj": "Ge", "gez": "Geez", "kat": "Georgian", "deu": "德文", @@ -7868,6 +9834,7 @@ LANGUAGE_NAMES = { "bik": "Bikol", "bin": "Bini", "bis": "Bislama", + "bit": "Berinomo", "bla": "Siksika", "bod": "Tibetan", "bos": "Bosnian", @@ -7902,6 +9869,7 @@ LANGUAGE_NAMES = { "cre": "Cree", "crh": "Turkish; Crimean", "csb": "Kashubian", + "csl": "Chinese Sign Language", "cym": "Welsh", "dak": "Dakota", "dan": "Danish", @@ -7914,6 +9882,7 @@ LANGUAGE_NAMES = { "div": "Dhivehi", "doi": "Dogri (macrolanguage)", "dsb": "Sorbian; Lower", + "dse": "Dutch Sign Language", "dua": "Duala", "dum": "Dutch; Middle (ca. 1050-1350)", "dyu": "Dyula", @@ -7925,6 +9894,7 @@ LANGUAGE_NAMES = { "elx": "Elamite", "eng": "English", "enm": "English; Middle (1100-1500)", + "enu": "Enu", "epo": "Esperanto", "est": "Estonian", "eus": "Basque", @@ -7975,6 +9945,7 @@ LANGUAGE_NAMES = { "hil": "Hiligaynon", "hin": "Hindi", "hit": "Hittite", + "hmj": "Ge", "hmn": "Hmong", "hmo": "Hiri Motu", "hrv": "Croatian", diff --git a/cps/jinjia.py b/cps/jinjia.py index 06e99141e..e42c650c5 100644 --- a/cps/jinjia.py +++ b/cps/jinjia.py @@ -22,17 +22,17 @@ # custom jinja filters +from markupsafe import escape import datetime import mimetypes from uuid import uuid4 -from babel.dates import format_date +# from babel.dates import format_date from flask import Blueprint, request, url_for -from flask_babel import get_locale +from flask_babel import format_date from flask_login import current_user -from markupsafe import escape -from . import logger +from . import constants, logger jinjia = Blueprint('jinjia', __name__) log = logger.create() @@ -77,7 +77,7 @@ def mimetype_filter(val): @jinjia.app_template_filter('formatdate') def formatdate_filter(val): try: - return format_date(val, format='medium', locale=get_locale()) + return format_date(val, format='medium') except AttributeError as e: log.error('Babel error: %s, Current user locale: %s, Current User: %s', e, current_user.locale, @@ -128,12 +128,55 @@ def formatseriesindex_filter(series_index): return series_index return 0 + @jinjia.app_template_filter('escapedlink') def escapedlink_filter(url, text): return "{}".format(url, escape(text)) + @jinjia.app_template_filter('uuidfilter') def uuidfilter(var): return uuid4() +@jinjia.app_template_filter('cache_timestamp') +def cache_timestamp(rolling_period='month'): + if rolling_period == 'day': + return str(int(datetime.datetime.today().replace(hour=1, minute=1).timestamp())) + elif rolling_period == 'year': + return str(int(datetime.datetime.today().replace(day=1).timestamp())) + else: + return str(int(datetime.datetime.today().replace(month=1, day=1).timestamp())) + + +@jinjia.app_template_filter('last_modified') +def book_last_modified(book): + return str(int(book.last_modified.timestamp())) + + +@jinjia.app_template_filter('get_cover_srcset') +def get_cover_srcset(book): + srcset = list() + resolutions = { + constants.COVER_THUMBNAIL_SMALL: 'sm', + constants.COVER_THUMBNAIL_MEDIUM: 'md', + constants.COVER_THUMBNAIL_LARGE: 'lg' + } + for resolution, shortname in resolutions.items(): + url = url_for('web.get_cover', book_id=book.id, resolution=shortname, c=book_last_modified(book)) + srcset.append(f'{url} {resolution}x') + return ', '.join(srcset) + + +@jinjia.app_template_filter('get_series_srcset') +def get_cover_srcset(series): + srcset = list() + resolutions = { + constants.COVER_THUMBNAIL_SMALL: 'sm', + constants.COVER_THUMBNAIL_MEDIUM: 'md', + constants.COVER_THUMBNAIL_LARGE: 'lg' + } + for resolution, shortname in resolutions.items(): + url = url_for('web.get_series_cover', series_id=series.id, resolution=shortname, c=cache_timestamp()) + srcset.append(f'{url} {resolution}x') + return ', '.join(srcset) diff --git a/cps/kobo.py b/cps/kobo.py index 8a395821a..9df1acbc8 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -22,11 +22,8 @@ import datetime import os import uuid from time import gmtime, strftime - -try: - from urllib import unquote -except ImportError: - from urllib.parse import unquote +import json +from urllib.parse import unquote from flask import ( Blueprint, @@ -48,7 +45,8 @@ import requests from . import config, logger, kobo_auth, db, calibre_db, helper, shelf as shelf_lib, ub, csrf, kobo_sync_status -from .constants import sqlalchemy_version2 +from . import isoLanguages +from .constants import sqlalchemy_version2, COVER_THUMBNAIL_SMALL from .helper import get_download_link from .services import SyncToken as SyncToken from .web import download_required @@ -102,6 +100,8 @@ def make_request_to_kobo_store(sync_token=None): allow_redirects=False, timeout=(2, 10) ) + log.debug("Content: " + str(store_response.content)) + log.debug("StatusCode: " + str(store_response.status_code)) return store_response @@ -110,7 +110,8 @@ def redirect_or_proxy_request(): if request.method == "GET": return redirect(get_store_url_for_current_request(), 307) else: - # The Kobo device turns other request types into GET requests on redirects, so we instead proxy to the Kobo store ourselves. + # The Kobo device turns other request types into GET requests on redirects, + # so we instead proxy to the Kobo store ourselves. store_response = make_request_to_kobo_store() response_headers = store_response.headers @@ -129,7 +130,7 @@ def convert_to_kobo_timestamp_string(timestamp): return timestamp.strftime("%Y-%m-%dT%H:%M:%SZ") except AttributeError as exc: log.debug("Timestamp not valid: {}".format(exc)) - return datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ") + return datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") @kobo.route("/v1/library/sync") @@ -142,16 +143,20 @@ def HandleSyncRequest(): if not current_app.wsgi_app.is_proxied: log.debug('Kobo: Received unproxied request, changed request port to external server port') - # TODO: Limit the number of books return per sync call, and rely on the sync-continuatation header - # instead so that the device triggers another sync. + # if no books synced don't respect sync_token + if not ub.session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.user_id == current_user.id).count(): + sync_token.books_last_modified = datetime.datetime.min + sync_token.books_last_created = datetime.datetime.min + sync_token.reading_state_last_modified = datetime.datetime.min - new_books_last_modified = sync_token.books_last_modified - new_books_last_created = sync_token.books_last_created + new_books_last_modified = sync_token.books_last_modified # needed for sync selected shelfs only + new_books_last_created = sync_token.books_last_created # needed to distinguish between new and changed entitlement new_reading_state_last_modified = sync_token.reading_state_last_modified + new_archived_last_modified = datetime.datetime.min sync_results = [] - # We reload the book database so that the user get's a fresh view of the library + # We reload the book database so that the user gets a fresh view of the library # in case of external changes (e.g: adding a book through Calibre). calibre_db.reconnect_db(config, ub.app_DB_path) @@ -169,21 +174,20 @@ def HandleSyncRequest(): ub.BookShelf.date_added, ub.ArchivedBook.is_archived) changed_entries = (changed_entries - .join(db.Data).outerjoin(ub.ArchivedBook, db.Books.id == ub.ArchivedBook.book_id) - .join(ub.KoboSyncedBooks, ub.KoboSyncedBooks.book_id == db.Books.id, isouter=True) - .filter(or_(ub.KoboSyncedBooks.user_id != current_user.id, - ub.KoboSyncedBooks.book_id == None)) - .filter(ub.BookShelf.date_added > sync_token.books_last_modified) - .filter(db.Data.format.in_(KOBO_FORMATS)) - .filter(calibre_db.common_filters(allow_show_archived=True)) - .order_by(db.Books.id) - .order_by(ub.ArchivedBook.last_modified) - .join(ub.BookShelf, db.Books.id == ub.BookShelf.book_id) - .join(ub.Shelf) - .filter(ub.Shelf.user_id == current_user.id) - .filter(ub.Shelf.kobo_sync) - .distinct() - ) + .join(db.Data).outerjoin(ub.ArchivedBook, and_(db.Books.id == ub.ArchivedBook.book_id, + ub.ArchivedBook.user_id == current_user.id)) + .filter(db.Books.id.notin_(calibre_db.session.query(ub.KoboSyncedBooks.book_id) + .filter(ub.KoboSyncedBooks.user_id == current_user.id))) + .filter(ub.BookShelf.date_added > sync_token.books_last_modified) + .filter(db.Data.format.in_(KOBO_FORMATS)) + .filter(calibre_db.common_filters(allow_show_archived=True)) + .order_by(db.Books.id) + .order_by(ub.ArchivedBook.last_modified) + .join(ub.BookShelf, db.Books.id == ub.BookShelf.book_id) + .join(ub.Shelf) + .filter(ub.Shelf.user_id == current_user.id) + .filter(ub.Shelf.kobo_sync) + .distinct()) else: if sqlalchemy_version2: changed_entries = select(db.Books, ub.ArchivedBook.last_modified, ub.ArchivedBook.is_archived) @@ -192,26 +196,24 @@ def HandleSyncRequest(): ub.ArchivedBook.last_modified, ub.ArchivedBook.is_archived) changed_entries = (changed_entries - .join(db.Data).outerjoin(ub.ArchivedBook, db.Books.id == ub.ArchivedBook.book_id) - .join(ub.KoboSyncedBooks, ub.KoboSyncedBooks.book_id == db.Books.id, isouter=True) - .filter(or_(ub.KoboSyncedBooks.user_id != current_user.id, - ub.KoboSyncedBooks.book_id == None)) - .filter(calibre_db.common_filters()) - .filter(db.Data.format.in_(KOBO_FORMATS)) - .order_by(db.Books.last_modified) - .order_by(db.Books.id) - ) - + .join(db.Data).outerjoin(ub.ArchivedBook, and_(db.Books.id == ub.ArchivedBook.book_id, + ub.ArchivedBook.user_id == current_user.id)) + .filter(db.Books.id.notin_(calibre_db.session.query(ub.KoboSyncedBooks.book_id) + .filter(ub.KoboSyncedBooks.user_id == current_user.id))) + .filter(calibre_db.common_filters(allow_show_archived=True)) + .filter(db.Data.format.in_(KOBO_FORMATS)) + .order_by(db.Books.last_modified) + .order_by(db.Books.id)) reading_states_in_new_entitlements = [] if sqlalchemy_version2: books = calibre_db.session.execute(changed_entries.limit(SYNC_ITEM_LIMIT)) else: books = changed_entries.limit(SYNC_ITEM_LIMIT) + log.debug("Books to Sync: {}".format(len(books.all()))) for book in books: - kobo_sync_status.add_synced_books(book.Books.id) formats = [data.format for data in book.Books.data] - if not 'KEPUB' in formats and config.config_kepubifypath and 'EPUB' in formats: + if 'KEPUB' not in formats and config.config_kepubifypath and 'EPUB' in formats: helper.convert_book_format(book.Books.id, config.config_calibre_dir, 'EPUB', 'KEPUB', current_user.name) kobo_reading_state = get_or_create_reading_state(book.Books.id) @@ -248,14 +250,17 @@ def HandleSyncRequest(): pass new_books_last_created = max(ts_created, new_books_last_created) + kobo_sync_status.add_synced_books(book.Books.id) if sqlalchemy_version2: max_change = calibre_db.session.execute(changed_entries .filter(ub.ArchivedBook.is_archived) + .filter(ub.ArchivedBook.user_id == current_user.id) .order_by(func.datetime(ub.ArchivedBook.last_modified).desc()))\ .columns(db.Books).first() else: - max_change = changed_entries.from_self().filter(ub.ArchivedBook.is_archived) \ + max_change = changed_entries.from_self().filter(ub.ArchivedBook.is_archived)\ + .filter(ub.ArchivedBook.user_id == current_user.id) \ .order_by(func.datetime(ub.ArchivedBook.last_modified).desc()).first() max_change = max_change.last_modified if max_change else new_archived_last_modified @@ -290,7 +295,8 @@ def HandleSyncRequest(): changed_reading_states = changed_reading_states.filter( and_(ub.KoboReadingState.user_id == current_user.id, - ub.KoboReadingState.book_id.notin_(reading_states_in_new_entitlements))) + ub.KoboReadingState.book_id.notin_(reading_states_in_new_entitlements)))\ + .order_by(ub.KoboReadingState.last_modified) cont_sync |= bool(changed_reading_states.count() > SYNC_ITEM_LIMIT) for kobo_reading_state in changed_reading_states.limit(SYNC_ITEM_LIMIT).all(): book = calibre_db.session.query(db.Books).filter(db.Books.id == kobo_reading_state.book_id).one_or_none() @@ -304,18 +310,19 @@ def HandleSyncRequest(): sync_shelves(sync_token, sync_results, only_kobo_shelves) - sync_token.books_last_created = new_books_last_created + # update last created timestamp to distinguish between new and changed entitlements + if not cont_sync: + sync_token.books_last_created = new_books_last_created sync_token.books_last_modified = new_books_last_modified sync_token.archive_last_modified = new_archived_last_modified sync_token.reading_state_last_modified = new_reading_state_last_modified - # sync_token.books_last_id = books_last_id return generate_sync_response(sync_token, sync_results, cont_sync) def generate_sync_response(sync_token, sync_results, set_cont=False): extra_headers = {} - if config.config_kobo_proxy: + if config.config_kobo_proxy and not set_cont: # Merge in sync results from the official Kobo store. try: store_response = make_request_to_kobo_store(sync_token) @@ -334,8 +341,9 @@ def generate_sync_response(sync_token, sync_results, set_cont=False): sync_token.to_headers(extra_headers) # log.debug("Kobo Sync Content: {}".format(sync_results)) - response = make_response(jsonify(sync_results), extra_headers) - + # jsonify decodes the unicode string different to what kobo expects + response = make_response(json.dumps(sync_results), extra_headers) + response.headers["Content-Type"] = "application/json; charset=utf-8" return response @@ -348,11 +356,13 @@ def HandleMetadataRequest(book_uuid): log.info("Kobo library metadata request received for book %s" % book_uuid) book = calibre_db.get_book_by_uuid(book_uuid) if not book or not book.data: - log.info(u"Book %s not found in database", book_uuid) + log.info("Book %s not found in database", book_uuid) return redirect_or_proxy_request() metadata = get_metadata(book) - return jsonify([metadata]) + response = make_response(json.dumps([metadata], ensure_ascii=False)) + response.headers["Content-Type"] = "application/json; charset=utf-8" + return response def get_download_url_for_book(book, book_format): @@ -380,10 +390,10 @@ def get_download_url_for_book(book, book_format): def create_book_entitlement(book, archived): - book_uuid = book.uuid + book_uuid = str(book.uuid) return { "Accessibility": "Full", - "ActivePeriod": {"From": convert_to_kobo_timestamp_string(datetime.datetime.now())}, + "ActivePeriod": {"From": convert_to_kobo_timestamp_string(datetime.datetime.utcnow())}, "Created": convert_to_kobo_timestamp_string(book.timestamp), "CrossRevisionId": book_uuid, "Id": book_uuid, @@ -407,18 +417,15 @@ def get_description(book): return book.comments[0].text -# TODO handle multiple authors def get_author(book): if not book.authors: return {"Contributors": None} - if len(book.authors) > 1: - author_list = [] - autor_roles = [] - for author in book.authors: - autor_roles.append({"Name":author.name, "Role":"Author"}) - author_list.append(author.name) - return {"ContributorRoles": autor_roles, "Contributors":author_list} - return {"ContributorRoles": [{"Name":book.authors[0].name, "Role":"Author"}], "Contributors": book.authors[0].name} + author_list = [] + autor_roles = [] + for author in book.authors: + autor_roles.append({"Name": author.name}) + author_list.append(author.name) + return {"ContributorRoles": autor_roles, "Contributors": author_list} def get_publisher(book): @@ -432,10 +439,17 @@ def get_series(book): return None return book.series[0].name + def get_seriesindex(book): return book.series_index or 1 +def get_language(book): + if not book.languages: + return 'en' + return isoLanguages.get(part3=book.languages[0].lang_code).part1 + + def get_metadata(book): download_urls = [] kepub = [data for data in book.data if data.format == 'KEPUB'] @@ -473,12 +487,10 @@ def get_metadata(book): "IsInternetArchive": False, "IsPreOrder": False, "IsSocialEnabled": True, - "Language": "en", + "Language": get_language(book), "PhoneticPronunciations": {}, - # TODO: Fix book.pubdate to return a datetime object so that we can easily - # convert it to the format Kobo devices expect. - "PublicationDate": book.pubdate, - "Publisher": {"Imprint": "", "Name": get_publisher(book),}, + "PublicationDate": convert_to_kobo_timestamp_string(book.pubdate), + "Publisher": {"Imprint": "", "Name": get_publisher(book), }, "RevisionId": book_uuid, "Title": book.title, "WorkId": book_uuid, @@ -492,17 +504,18 @@ def get_metadata(book): "Number": get_seriesindex(book), # ToDo Check int() ? "NumberFloat": float(get_seriesindex(book)), # Get a deterministic id based on the series name. - "Id": uuid.uuid3(uuid.NAMESPACE_DNS, name), + "Id": str(uuid.uuid3(uuid.NAMESPACE_DNS, name)), } return metadata + @csrf.exempt @kobo.route("/v1/library/tags", methods=["POST", "DELETE"]) @requires_kobo_auth # Creates a Shelf with the given items, and returns the shelf's uuid. def HandleTagCreate(): - # catch delete requests, otherwise the are handeld in the book delete handler + # catch delete requests, otherwise the are handled in the book delete handler if request.method == "DELETE": abort(405) name, items = None, None @@ -545,11 +558,9 @@ def HandleTagUpdate(tag_id): else: abort(404, description="Collection isn't known to CalibreWeb") - if not shelf_lib.check_shelf_edit_permissions(shelf): - abort(401, description="User is unauthaurized to edit shelf.") - if request.method == "DELETE": - shelf_lib.delete_shelf_helper(shelf) + if not shelf_lib.delete_shelf_helper(shelf): + abort(401, description="Error deleting Shelf") else: name = None try: @@ -667,11 +678,8 @@ def HandleTagRemoveItem(tag_id): # Note: Public shelves that aren't owned by the user aren't supported. def sync_shelves(sync_token, sync_results, only_kobo_shelves=False): new_tags_last_modified = sync_token.tags_last_modified - - for shelf in ub.session.query(ub.ShelfArchive).filter( - func.datetime(ub.ShelfArchive.last_modified) > sync_token.tags_last_modified, - ub.ShelfArchive.user_id == current_user.id - ): + # transmit all archived shelfs independent of last sync (why should this matter?) + for shelf in ub.session.query(ub.ShelfArchive).filter(ub.ShelfArchive.user_id == current_user.id): new_tags_last_modified = max(shelf.last_modified, new_tags_last_modified) sync_results.append({ "DeletedTag": { @@ -684,7 +692,6 @@ def sync_shelves(sync_token, sync_results, only_kobo_shelves=False): ub.session.delete(shelf) ub.session_commit() - extra_filters = [] if only_kobo_shelves: for shelf in ub.session.query(ub.Shelf).filter( @@ -717,7 +724,6 @@ def sync_shelves(sync_token, sync_results, only_kobo_shelves=False): *extra_filters ).distinct().order_by(func.datetime(ub.Shelf.last_modified).asc()) - for shelf in shelflist: if not shelf_lib.check_shelf_view_permissions(shelf): continue @@ -753,7 +759,7 @@ def create_kobo_tag(shelf): for book_shelf in shelf.books: book = calibre_db.get_book(book_shelf.book_id) if not book: - log.info(u"Book (id: %s) in BookShelf (id: %s) not found in book database", book_shelf.book_id, shelf.id) + log.info("Book (id: %s) in BookShelf (id: %s) not found in book database", book_shelf.book_id, shelf.id) continue tag["Items"].append( { @@ -763,13 +769,14 @@ def create_kobo_tag(shelf): ) return {"Tag": tag} + @csrf.exempt @kobo.route("/v1/library//state", methods=["GET", "PUT"]) @requires_kobo_auth def HandleStateRequest(book_uuid): book = calibre_db.get_book_by_uuid(book_uuid) if not book or not book.data: - log.info(u"Book %s not found in database", book_uuid) + log.info("Book %s not found in database", book_uuid) return redirect_or_proxy_request() kobo_reading_state = get_or_create_reading_state(book.id) @@ -807,7 +814,7 @@ def HandleStateRequest(book_uuid): book_read = kobo_reading_state.book_read_link new_book_read_status = get_ub_read_status(request_status_info["Status"]) if new_book_read_status == ub.ReadBook.STATUS_IN_PROGRESS \ - and new_book_read_status != book_read.read_status: + and new_book_read_status != book_read.read_status: book_read.times_started_reading += 1 book_read.last_time_started_reading = datetime.datetime.utcnow() book_read.read_status = new_book_read_status @@ -847,7 +854,7 @@ def get_ub_read_status(kobo_read_status): def get_or_create_reading_state(book_id): book_read = ub.session.query(ub.ReadBook).filter(ub.ReadBook.book_id == book_id, - ub.ReadBook.user_id == current_user.id).one_or_none() + ub.ReadBook.user_id == int(current_user.id)).one_or_none() if not book_read: book_read = ub.ReadBook(user_id=current_user.id, book_id=book_id) if not book_read.kobo_reading_state: @@ -911,13 +918,12 @@ def get_current_bookmark_response(current_bookmark): } return resp + @kobo.route("/////image.jpg", defaults={'Quality': ""}) @kobo.route("//////image.jpg") @requires_kobo_auth -def HandleCoverImageRequest(book_uuid, width, height,Quality, isGreyscale): - book_cover = helper.get_book_cover_with_uuid( - book_uuid, use_generic_cover_on_failure=False - ) +def HandleCoverImageRequest(book_uuid, width, height, Quality, isGreyscale): + book_cover = helper.get_book_cover_with_uuid(book_uuid, resolution=COVER_THUMBNAIL_SMALL) if not book_cover: if config.config_kobo_proxy: log.debug("Cover for unknown book: %s proxied to kobo" % book_uuid) @@ -942,25 +948,16 @@ def TopLevelEndpoint(): @kobo.route("/v1/library/", methods=["DELETE"]) @requires_kobo_auth def HandleBookDeletionRequest(book_uuid): - log.info("Kobo book deletion request received for book %s" % book_uuid) + log.info("Kobo book delete request received for book %s" % book_uuid) book = calibre_db.get_book_by_uuid(book_uuid) if not book: - log.info(u"Book %s not found in database", book_uuid) + log.info("Book %s not found in database", book_uuid) return redirect_or_proxy_request() book_id = book.id - archived_book = ( - ub.session.query(ub.ArchivedBook) - .filter(ub.ArchivedBook.book_id == book_id) - .first() - ) - if not archived_book: - archived_book = ub.ArchivedBook(user_id=current_user.id, book_id=book_id) - archived_book.is_archived = True - archived_book.last_modified = datetime.datetime.utcnow() - - ub.session.merge(archived_book) - ub.session_commit() + is_archived = kobo_sync_status.change_archived_books(book_id, True) + if is_archived: + kobo_sync_status.remove_synced_book(book_id) return "", 204 @@ -968,7 +965,7 @@ def HandleBookDeletionRequest(book_uuid): @csrf.exempt @kobo.route("/v1/library/", methods=["DELETE", "GET"]) def HandleUnimplementedRequest(dummy=None): - log.debug("Unimplemented Library Request received: %s", request.base_url) + log.debug("Unimplemented Library Request received: %s (request is forwarded to kobo if configured)", request.base_url) return redirect_or_proxy_request() @@ -980,22 +977,47 @@ def HandleUnimplementedRequest(dummy=None): @kobo.route("/v1/user/recommendations", methods=["GET", "POST"]) @kobo.route("/v1/analytics/", methods=["GET", "POST"]) def HandleUserRequest(dummy=None): - log.debug("Unimplemented User Request received: %s", request.base_url) + log.debug("Unimplemented User Request received: %s (request is forwarded to kobo if configured)", request.base_url) return redirect_or_proxy_request() +@csrf.exempt +@kobo.route("/v1/user/loyalty/benefits", methods=["GET"]) +def handle_benefits(): + if config.config_kobo_proxy: + return redirect_or_proxy_request() + else: + return make_response(jsonify({"Benefits": {}})) + + +@csrf.exempt +@kobo.route("/v1/analytics/gettests", methods=["GET", "POST"]) +def handle_getests(): + if config.config_kobo_proxy: + return redirect_or_proxy_request() + else: + testkey = request.headers.get("X-Kobo-userkey", "") + return make_response(jsonify({"Result": "Success", "TestKey": testkey, "Tests": {}})) + + @csrf.exempt @kobo.route("/v1/products//prices", methods=["GET", "POST"]) @kobo.route("/v1/products//recommendations", methods=["GET", "POST"]) @kobo.route("/v1/products//nextread", methods=["GET", "POST"]) @kobo.route("/v1/products//reviews", methods=["GET", "POST"]) +@kobo.route("/v1/products/featured/", methods=["GET", "POST"]) +@kobo.route("/v1/products/featured/", methods=["GET", "POST"]) @kobo.route("/v1/products/books/external/", methods=["GET", "POST"]) @kobo.route("/v1/products/books/series/", methods=["GET", "POST"]) @kobo.route("/v1/products/books/", methods=["GET", "POST"]) +@kobo.route("/v1/products/books//", methods=["GET", "POST"]) @kobo.route("/v1/products/dailydeal", methods=["GET", "POST"]) +@kobo.route("/v1/products/deals", methods=["GET", "POST"]) @kobo.route("/v1/products", methods=["GET", "POST"]) +@kobo.route("/v1/affiliate", methods=["GET", "POST"]) +@kobo.route("/v1/deals", methods=["GET", "POST"]) def HandleProductsRequest(dummy=None): - log.debug("Unimplemented Products Request received: %s", request.base_url) + log.debug("Unimplemented Products Request received: %s (request is forwarded to kobo if configured)", request.base_url) return redirect_or_proxy_request() @@ -1005,7 +1027,7 @@ def make_calibre_web_auth_response(): content = request.get_json() AccessToken = base64.b64encode(os.urandom(24)).decode('utf-8') RefreshToken = base64.b64encode(os.urandom(24)).decode('utf-8') - return make_response( + return make_response( jsonify( { "AccessToken": AccessToken, @@ -1143,14 +1165,16 @@ def NATIVE_KOBO_RESOURCES(): "eula_page": "https://www.kobo.com/termsofuse?style=onestore", "exchange_auth": "https://storeapi.kobo.com/v1/auth/exchange", "external_book": "https://storeapi.kobo.com/v1/products/books/external/{Ids}", - "facebook_sso_page": "https://authorize.kobo.com/signin/provider/Facebook/login?returnUrl=http://store.kobobooks.com/", + "facebook_sso_page": + "https://authorize.kobo.com/signin/provider/Facebook/login?returnUrl=http://store.kobobooks.com/", "featured_list": "https://storeapi.kobo.com/v1/products/featured/{FeaturedListId}", "featured_lists": "https://storeapi.kobo.com/v1/products/featured", "free_books_page": { "EN": "https://www.kobo.com/{region}/{language}/p/free-ebooks", "FR": "https://www.kobo.com/{region}/{language}/p/livres-gratuits", "IT": "https://www.kobo.com/{region}/{language}/p/libri-gratuiti", - "NL": "https://www.kobo.com/{region}/{language}/List/bekijk-het-overzicht-van-gratis-ebooks/QpkkVWnUw8sxmgjSlCbJRg", + "NL": "https://www.kobo.com/{region}/{language}/" + "List/bekijk-het-overzicht-van-gratis-ebooks/QpkkVWnUw8sxmgjSlCbJRg", "PT": "https://www.kobo.com/{region}/{language}/p/livros-gratis", }, "fte_feedback": "https://storeapi.kobo.com/v1/products/ftefeedback", @@ -1175,7 +1199,8 @@ def NATIVE_KOBO_RESOURCES(): "library_stack": "https://storeapi.kobo.com/v1/user/library/stacks/{LibraryItemId}", "library_sync": "https://storeapi.kobo.com/v1/library/sync", "love_dashboard_page": "https://store.kobobooks.com/{culture}/kobosuperpoints", - "love_points_redemption_page": "https://store.kobobooks.com/{culture}/KoboSuperPointsRedemption?productId={ProductId}", + "love_points_redemption_page": + "https://store.kobobooks.com/{culture}/KoboSuperPointsRedemption?productId={ProductId}", "magazine_landing_page": "https://store.kobobooks.com/emagazines", "notifications_registration_issue": "https://storeapi.kobo.com/v1/notifications/registration", "oauth_host": "https://oauth.kobo.com", @@ -1191,7 +1216,8 @@ def NATIVE_KOBO_RESOURCES(): "product_recommendations": "https://storeapi.kobo.com/v1/products/{ProductId}/recommendations", "product_reviews": "https://storeapi.kobo.com/v1/products/{ProductIds}/reviews", "products": "https://storeapi.kobo.com/v1/products", - "provider_external_sign_in_page": "https://authorize.kobo.com/ExternalSignIn/{providerName}?returnUrl=http://store.kobobooks.com/", + "provider_external_sign_in_page": + "https://authorize.kobo.com/ExternalSignIn/{providerName}?returnUrl=http://store.kobobooks.com/", "purchase_buy": "https://www.kobo.com/checkout/createpurchase/", "purchase_buy_templated": "https://www.kobo.com/{culture}/checkout/createpurchase/{ProductId}", "quickbuy_checkout": "https://storeapi.kobo.com/v1/store/quickbuy/{PurchaseId}/checkout", diff --git a/cps/kobo_auth.py b/cps/kobo_auth.py index a51095c8d..82c140ff3 100644 --- a/cps/kobo_auth.py +++ b/cps/kobo_auth.py @@ -62,6 +62,7 @@ particular calls to non-Kobo specific endpoints such as the CalibreWeb book down from binascii import hexlify from datetime import datetime from os import urandom +from functools import wraps from flask import g, Blueprint, url_for, abort, request from flask_login import login_user, current_user, login_required @@ -70,20 +71,61 @@ from flask_babel import gettext as _ from . import logger, config, calibre_db, db, helper, ub, lm from .render_template import render_title_template -try: - from functools import wraps -except ImportError: - pass # We're not using Python 3 - - log = logger.create() +kobo_auth = Blueprint("kobo_auth", __name__, url_prefix="/kobo_auth") -def register_url_value_preprocessor(kobo): - @kobo.url_value_preprocessor - # pylint: disable=unused-variable - def pop_auth_token(__, values): - g.auth_token = values.pop("auth_token") + +@kobo_auth.route("/generate_auth_token/") +@login_required +def generate_auth_token(user_id): + warning = False + host_list = request.host.rsplit(':') + if len(host_list) == 1: + host = ':'.join(host_list) + else: + host = ':'.join(host_list[0:-1]) + if host.startswith('127.') or host.lower() == 'localhost' or host.startswith('[::ffff:7f') or host == "[::1]": + warning = _('Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device') + + # Generate auth token if none is existing for this user + auth_token = ub.session.query(ub.RemoteAuthToken).filter( + ub.RemoteAuthToken.user_id == user_id + ).filter(ub.RemoteAuthToken.token_type==1).first() + + if not auth_token: + auth_token = ub.RemoteAuthToken() + auth_token.user_id = user_id + auth_token.expiration = datetime.max + auth_token.auth_token = (hexlify(urandom(16))).decode("utf-8") + auth_token.token_type = 1 + + ub.session.add(auth_token) + ub.session_commit() + + books = calibre_db.session.query(db.Books).join(db.Data).all() + + for book in books: + formats = [data.format for data in book.data] + if 'KEPUB' not in formats and config.config_kepubifypath and 'EPUB' in formats: + helper.convert_book_format(book.id, config.config_calibre_dir, 'EPUB', 'KEPUB', current_user.name) + + return render_title_template( + "generate_kobo_auth_url.html", + title=_("Kobo Setup"), + auth_token=auth_token.auth_token, + warning = warning + ) + + +@kobo_auth.route("/deleteauthtoken/", methods=["POST"]) +@login_required +def delete_auth_token(user_id): + # Invalidate any previously generated Kobo Auth token for this user + ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.user_id == user_id)\ + .filter(ub.RemoteAuthToken.token_type==1).delete() + + return ub.session_commit() def disable_failed_auth_redirect_for_blueprint(bp): @@ -97,6 +139,13 @@ def get_auth_token(): return None +def register_url_value_preprocessor(kobo): + @kobo.url_value_preprocessor + # pylint: disable=unused-variable + def pop_auth_token(__, values): + g.auth_token = values.pop("auth_token") + + def requires_kobo_auth(f): @wraps(f) def inner(*args, **kwargs): @@ -114,64 +163,3 @@ def requires_kobo_auth(f): log.debug("Received Kobo request without a recognizable auth token.") return abort(401) return inner - - -kobo_auth = Blueprint("kobo_auth", __name__, url_prefix="/kobo_auth") - - -@kobo_auth.route("/generate_auth_token/") -@login_required -def generate_auth_token(user_id): - host_list = request.host.rsplit(':') - if len(host_list) == 1: - host = ':'.join(host_list) - else: - host = ':'.join(host_list[0:-1]) - if host.startswith('127.') or host.lower() == 'localhost' or host.startswith('[::ffff:7f'): - warning = _('PLease access calibre-web from non localhost to get valid api_endpoint for kobo device') - return render_title_template( - "generate_kobo_auth_url.html", - title=_(u"Kobo Setup"), - warning = warning - ) - else: - # Invalidate any prevously generated Kobo Auth token for this user. - auth_token = ub.session.query(ub.RemoteAuthToken).filter( - ub.RemoteAuthToken.user_id == user_id - ).filter(ub.RemoteAuthToken.token_type==1).first() - - if not auth_token: - auth_token = ub.RemoteAuthToken() - auth_token.user_id = user_id - auth_token.expiration = datetime.max - auth_token.auth_token = (hexlify(urandom(16))).decode("utf-8") - auth_token.token_type = 1 - - ub.session.add(auth_token) - ub.session_commit() - - books = calibre_db.session.query(db.Books).join(db.Data).all() - - for book in books: - formats = [data.format for data in book.data] - if not 'KEPUB' in formats and config.config_kepubifypath and 'EPUB' in formats: - helper.convert_book_format(book.id, config.config_calibre_dir, 'EPUB', 'KEPUB', current_user.name) - - return render_title_template( - "generate_kobo_auth_url.html", - title=_(u"Kobo Setup"), - kobo_auth_url=url_for( - "kobo.TopLevelEndpoint", auth_token=auth_token.auth_token, _external=True - ), - warning = False - ) - - -@kobo_auth.route("/deleteauthtoken/") -@login_required -def delete_auth_token(user_id): - # Invalidate any prevously generated Kobo Auth token for this user. - ub.session.query(ub.RemoteAuthToken).filter(ub.RemoteAuthToken.user_id == user_id)\ - .filter(ub.RemoteAuthToken.token_type==1).delete() - - return ub.session_commit() diff --git a/cps/kobo_sync_status.py b/cps/kobo_sync_status.py index f4a666048..7a2018612 100644 --- a/cps/kobo_sync_status.py +++ b/cps/kobo_sync_status.py @@ -20,52 +20,69 @@ from flask_login import current_user from . import ub import datetime -from sqlalchemy.sql.expression import or_ - +from sqlalchemy.sql.expression import or_, and_, true +from sqlalchemy import exc +# Add the current book id to kobo_synced_books table for current user, if entry is already present, +# do nothing (safety precaution) def add_synced_books(book_id): - synced_book = ub.KoboSyncedBooks() - synced_book.user_id = current_user.id - synced_book.book_id = book_id - ub.session.add(synced_book) - ub.session_commit() + is_present = ub.session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.book_id == book_id)\ + .filter(ub.KoboSyncedBooks.user_id == current_user.id).count() + if not is_present: + synced_book = ub.KoboSyncedBooks() + synced_book.user_id = current_user.id + synced_book.book_id = book_id + ub.session.add(synced_book) + ub.session_commit() -def remove_synced_book(book_id): - ub.session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.book_id == book_id).delete() - ub.session_commit() +# Select all entries of current book in kobo_synced_books table, which are from current user and delete them +def remove_synced_book(book_id, all=False, session=None): + if not all: + user = ub.KoboSyncedBooks.user_id == current_user.id + else: + user = true() + if not session: + ub.session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.book_id == book_id).filter(user).delete() + ub.session_commit() + else: + session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.book_id == book_id).filter(user).delete() + ub.session_commit(_session=session) -def add_archived_books(book_id): - archived_book = ( - ub.session.query(ub.ArchivedBook) - .filter(ub.ArchivedBook.book_id == book_id) - .first() - ) + + +def change_archived_books(book_id, state=None, message=None): + archived_book = ub.session.query(ub.ArchivedBook).filter(and_(ub.ArchivedBook.user_id == int(current_user.id), + ub.ArchivedBook.book_id == book_id)).first() if not archived_book: archived_book = ub.ArchivedBook(user_id=current_user.id, book_id=book_id) - archived_book.is_archived = True - archived_book.last_modified = datetime.datetime.utcnow() + + archived_book.is_archived = state if state else not archived_book.is_archived + archived_book.last_modified = datetime.datetime.utcnow() # toDo. Check utc timestamp ub.session.merge(archived_book) - ub.session_commit() + ub.session_commit(message) + return archived_book.is_archived +# select all books which are synced by the current user and do not belong to a synced shelf and set them to archive +# select all shelves from current user which are synced and do not belong to the "only sync" shelves +def update_on_sync_shelfs(user_id): + books_to_archive = (ub.session.query(ub.KoboSyncedBooks) + .join(ub.BookShelf, ub.KoboSyncedBooks.book_id == ub.BookShelf.book_id, isouter=True) + .join(ub.Shelf, ub.Shelf.user_id == user_id, isouter=True) + .filter(or_(ub.Shelf.kobo_sync == 0, ub.Shelf.kobo_sync == None)) + .filter(ub.KoboSyncedBooks.user_id == user_id).all()) + for b in books_to_archive: + change_archived_books(b.book_id, True) + ub.session.query(ub.KoboSyncedBooks) \ + .filter(ub.KoboSyncedBooks.book_id == b.book_id) \ + .filter(ub.KoboSyncedBooks.user_id == user_id).delete() + ub.session_commit() -# select all books which are synced by the current user and do not belong to a synced shelf and them to archive -# select all shelfs from current user which are synced and do not belong to the "only sync" shelfs -def update_on_sync_shelfs(content_id): - books_to_archive = (ub.session.query(ub.KoboSyncedBooks) - .join(ub.BookShelf, ub.KoboSyncedBooks.book_id == ub.BookShelf.book_id, isouter=True) - .join(ub.Shelf, ub.Shelf.user_id == content_id, isouter=True) - .filter(or_(ub.Shelf.kobo_sync == 0, ub.Shelf.kobo_sync == None)) - .filter(ub.KoboSyncedBooks.user_id == content_id).all()) - for b in books_to_archive: - add_archived_books(b.book_id) - ub.session.query(ub.KoboSyncedBooks).filter(ub.KoboSyncedBooks.book_id == b.book_id).filter(ub.KoboSyncedBooks.user_id == content_id).delete() - ub.session_commit() - - shelfs_to_archive = ub.session.query(ub.Shelf).filter(ub.Shelf.user_id == content_id).filter( - ub.Shelf.kobo_sync == 0).all() - for a in shelfs_to_archive: - ub.session.add(ub.ShelfArchive(uuid=a.uuid, user_id=content_id)) - ub.session_commit() + # Search all shelf which are currently not synced + shelves_to_archive = ub.session.query(ub.Shelf).filter(ub.Shelf.user_id == user_id).filter( + ub.Shelf.kobo_sync == 0).all() + for a in shelves_to_archive: + ub.session.add(ub.ShelfArchive(uuid=a.uuid, user_id=user_id)) + ub.session_commit() diff --git a/cps/logger.py b/cps/logger.py index 5847188bb..13535efba 100644 --- a/cps/logger.py +++ b/cps/logger.py @@ -42,23 +42,17 @@ logging.addLevelName(logging.CRITICAL, "CRIT") class _Logger(logging.Logger): - def debug_or_exception(self, message, *args, **kwargs): + def error_or_exception(self, message, stacklevel=2, *args, **kwargs): if sys.version_info > (3, 7): if is_debug_enabled(): - self.exception(message, stacklevel=2, *args, **kwargs) + self.exception(message, stacklevel=stacklevel, *args, **kwargs) else: - self.error(message, stacklevel=2, *args, **kwargs) - elif sys.version_info > (3, 0): + self.error(message, stacklevel=stacklevel, *args, **kwargs) + else: if is_debug_enabled(): self.exception(message, stack_info=True, *args, **kwargs) else: self.error(message, *args, **kwargs) - else: - if is_debug_enabled(): - self.exception(message, *args, **kwargs) - else: - self.error(message, *args, **kwargs) - def debug_no_auth(self, message, *args, **kwargs): message = message.strip("\r\n") @@ -71,6 +65,7 @@ class _Logger(logging.Logger): def get(name=None): return logging.getLogger(name) + def create(): parent_frame = inspect.stack(0)[1] if hasattr(parent_frame, 'frame'): @@ -80,9 +75,11 @@ def create(): parent_module = inspect.getmodule(parent_frame) return get(parent_module.__name__) + def is_debug_enabled(): return logging.root.level <= logging.DEBUG + def is_info_enabled(logger): return logging.getLogger(logger).level <= logging.INFO @@ -119,10 +116,10 @@ def get_accesslogfile(log_file): def setup(log_file, log_level=None): - ''' + """ Configure the logging output. May be called multiple times. - ''' + """ log_level = log_level or DEFAULT_LOG_LEVEL logging.setLoggerClass(_Logger) logging.getLogger(__package__).setLevel(log_level) @@ -132,7 +129,7 @@ def setup(log_file, log_level=None): # avoid spamming the log with debug messages from libraries r.setLevel(log_level) - # Otherwise name get's destroyed on windows + # Otherwise, name gets destroyed on Windows if log_file != LOG_TO_STDERR and log_file != LOG_TO_STDOUT: log_file = _absolute_log_file(log_file, DEFAULT_LOG_FILE) @@ -164,13 +161,14 @@ def setup(log_file, log_level=None): r.removeHandler(h) h.close() r.addHandler(file_handler) + logging.captureWarnings(True) return "" if log_file == DEFAULT_LOG_FILE else log_file def create_access_log(log_file, log_name, formatter): - ''' + """ One-time configuration for the web server's access log. - ''' + """ log_file = _absolute_log_file(log_file, DEFAULT_ACCESS_LOG) logging.debug("access log: %s", log_file) @@ -187,8 +185,7 @@ def create_access_log(log_file, log_name, formatter): file_handler.setFormatter(formatter) access_log.addHandler(file_handler) - return access_log, \ - "" if _absolute_log_file(log_file, DEFAULT_ACCESS_LOG) == DEFAULT_ACCESS_LOG else log_file + return access_log, "" if _absolute_log_file(log_file, DEFAULT_ACCESS_LOG) == DEFAULT_ACCESS_LOG else log_file # Enable logging of smtp lib debug output diff --git a/cps/main.py b/cps/main.py new file mode 100644 index 000000000..d3591c064 --- /dev/null +++ b/cps/main.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2012-2022 OzzieIsaacs +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import sys + +from . import create_app +from .jinjia import jinjia +from .remotelogin import remotelogin + +def main(): + app = create_app() + + from .web import web + from .opds import opds + from .admin import admi + from .gdrive import gdrive + from .editbooks import editbook + from .about import about + from .search import search + from .search_metadata import meta + from .shelf import shelf + from .tasks_status import tasks + from .error_handler import init_errorhandler + try: + from .kobo import kobo, get_kobo_activated + from .kobo_auth import kobo_auth + kobo_available = get_kobo_activated() + except (ImportError, AttributeError): # Catch also error for not installed flask-WTF (missing csrf decorator) + kobo_available = False + + try: + from .oauth_bb import oauth + oauth_available = True + except ImportError: + oauth_available = False + + from . import web_server + init_errorhandler() + + app.register_blueprint(search) + app.register_blueprint(tasks) + app.register_blueprint(web) + app.register_blueprint(opds) + app.register_blueprint(jinjia) + app.register_blueprint(about) + app.register_blueprint(shelf) + app.register_blueprint(admi) + app.register_blueprint(remotelogin) + app.register_blueprint(meta) + app.register_blueprint(gdrive) + app.register_blueprint(editbook) + if kobo_available: + app.register_blueprint(kobo) + app.register_blueprint(kobo_auth) + if oauth_available: + app.register_blueprint(oauth) + success = web_server.start() + sys.exit(0 if success else 1) diff --git a/cps/metadata_provider/amazon.py b/cps/metadata_provider/amazon.py new file mode 100644 index 000000000..a83747e6e --- /dev/null +++ b/cps/metadata_provider/amazon.py @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2022 quarz12 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import concurrent.futures +import requests +from bs4 import BeautifulSoup as BS # requirement +from typing import List, Optional + +try: + import cchardet #optional for better speed +except ImportError: + pass +from cps import logger +from cps.services.Metadata import MetaRecord, MetaSourceInfo, Metadata +import cps.logger as logger + +#from time import time +from operator import itemgetter +log = logger.create() + +log = logger.create() + + +class Amazon(Metadata): + __name__ = "Amazon" + __id__ = "amazon" + headers = {'upgrade-insecure-requests': '1', + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36', + 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', + 'sec-gpc': '1', + 'sec-fetch-site': 'none', + 'sec-fetch-mode': 'navigate', + 'sec-fetch-user': '?1', + 'sec-fetch-dest': 'document', + 'accept-encoding': 'gzip, deflate, br', + 'accept-language': 'en-US,en;q=0.9'} + session = requests.Session() + session.headers=headers + + def search( + self, query: str, generic_cover: str = "", locale: str = "en" + ) -> Optional[List[MetaRecord]]: + #timer=time() + def inner(link, index) -> [dict, int]: + with self.session as session: + try: + r = session.get(f"https://www.amazon.com/{link}") + r.raise_for_status() + except Exception as ex: + log.warning(ex) + return None + long_soup = BS(r.text, "lxml") #~4sec :/ + soup2 = long_soup.find("div", attrs={"cel_widget_id": "dpx-books-ppd_csm_instrumentation_wrapper"}) + if soup2 is None: + return None + try: + match = MetaRecord( + title = "", + authors = "", + source=MetaSourceInfo( + id=self.__id__, + description="Amazon Books", + link="https://amazon.com/" + ), + url = f"https://www.amazon.com{link}", + #the more searches the slower, these are too hard to find in reasonable time or might not even exist + publisher= "", # very unreliable + publishedDate= "", # very unreliable + id = None, # ? + tags = [] # dont exist on amazon + ) + + try: + match.description = "\n".join( + soup2.find("div", attrs={"data-feature-name": "bookDescription"}).stripped_strings)\ + .replace("\xa0"," ")[:-9].strip().strip("\n") + except (AttributeError, TypeError): + return None # if there is no description it is not a book and therefore should be ignored + try: + match.title = soup2.find("span", attrs={"id": "productTitle"}).text + except (AttributeError, TypeError): + match.title = "" + try: + match.authors = [next( + filter(lambda i: i != " " and i != "\n" and not i.startswith("{"), + x.findAll(text=True))).strip() + for x in soup2.findAll("span", attrs={"class": "author"})] + except (AttributeError, TypeError, StopIteration): + match.authors = "" + try: + match.rating = int( + soup2.find("span", class_="a-icon-alt").text.split(" ")[0].split(".")[ + 0]) # first number in string + except (AttributeError, ValueError): + match.rating = 0 + try: + match.cover = soup2.find("img", attrs={"class": "a-dynamic-image frontImage"})["src"] + except (AttributeError, TypeError): + match.cover = "" + return match, index + except Exception as e: + log.error_or_exception(e) + return None + + val = list() + if self.active: + try: + results = self.session.get( + f"https://www.amazon.com/s?k={query.replace(' ', '+')}&i=digital-text&sprefix={query.replace(' ', '+')}" + f"%2Cdigital-text&ref=nb_sb_noss", + headers=self.headers) + results.raise_for_status() + except requests.exceptions.HTTPError as e: + log.error_or_exception(e) + return [] + except Exception as e: + log.warning(e) + return [] + soup = BS(results.text, 'html.parser') + links_list = [next(filter(lambda i: "digital-text" in i["href"], x.findAll("a")))["href"] for x in + soup.findAll("div", attrs={"data-component-type": "s-search-result"})] + with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: + fut = {executor.submit(inner, link, index) for index, link in enumerate(links_list[:5])} + val = list(map(lambda x : x.result() ,concurrent.futures.as_completed(fut))) + result = list(filter(lambda x: x, val)) + return [x[0] for x in sorted(result, key=itemgetter(1))] #sort by amazons listing order for best relevance diff --git a/cps/metadata_provider/comicvine.py b/cps/metadata_provider/comicvine.py index 8f496608c..b4d8d34ce 100644 --- a/cps/metadata_provider/comicvine.py +++ b/cps/metadata_provider/comicvine.py @@ -17,49 +17,76 @@ # along with this program. If not, see . # ComicVine api document: https://comicvine.gamespot.com/api/documentation +from typing import Dict, List, Optional +from urllib.parse import quote import requests -from cps.services.Metadata import Metadata +from cps import logger +from cps.services.Metadata import MetaRecord, MetaSourceInfo, Metadata + +log = logger.create() class ComicVine(Metadata): __name__ = "ComicVine" __id__ = "comicvine" + DESCRIPTION = "ComicVine Books" + META_URL = "https://comicvine.gamespot.com/" + API_KEY = "57558043c53943d5d1e96a9ad425b0eb85532ee6" + BASE_URL = ( + f"https://comicvine.gamespot.com/api/search?api_key={API_KEY}" + f"&resources=issue&query=" + ) + QUERY_PARAMS = "&sort=name:desc&format=json" + HEADERS = {"User-Agent": "Not Evil Browser"} - def search(self, query, __): + def search( + self, query: str, generic_cover: str = "", locale: str = "en" + ) -> Optional[List[MetaRecord]]: val = list() - apikey = "57558043c53943d5d1e96a9ad425b0eb85532ee6" if self.active: - headers = { - 'User-Agent': 'Not Evil Browser' - } - - result = requests.get("https://comicvine.gamespot.com/api/search?api_key=" - + apikey + "&resources=issue&query=" + query + "&sort=name:desc&format=json", headers=headers) - for r in result.json()['results']: - seriesTitle = r['volume'].get('name', "") - if r.get('store_date'): - dateFomers = r.get('store_date') - else: - dateFomers = r.get('date_added') - v = dict() - v['id'] = r['id'] - v['title'] = seriesTitle + " #" + r.get('issue_number', "0") + " - " + ( r.get('name', "") or "") - v['authors'] = r.get('authors', []) - v['description'] = r.get('description', "") - v['publisher'] = "" - v['publishedDate'] = dateFomers - v['tags'] = ["Comics", seriesTitle] - v['rating'] = 0 - v['series'] = seriesTitle - v['cover'] = r['image'].get('original_url') - v['source'] = { - "id": self.__id__, - "description": "ComicVine Books", - "link": "https://comicvine.gamespot.com/" - } - v['url'] = r.get('site_detail_url', "") - val.append(v) + title_tokens = list(self.get_title_tokens(query, strip_joiners=False)) + if title_tokens: + tokens = [quote(t.encode("utf-8")) for t in title_tokens] + query = "%20".join(tokens) + try: + result = requests.get( + f"{ComicVine.BASE_URL}{query}{ComicVine.QUERY_PARAMS}", + headers=ComicVine.HEADERS, + ) + result.raise_for_status() + except Exception as e: + log.warning(e) + return None + for result in result.json()["results"]: + match = self._parse_search_result( + result=result, generic_cover=generic_cover, locale=locale + ) + val.append(match) return val - + def _parse_search_result( + self, result: Dict, generic_cover: str, locale: str + ) -> MetaRecord: + series = result["volume"].get("name", "") + series_index = result.get("issue_number", 0) + issue_name = result.get("name", "") + match = MetaRecord( + id=result["id"], + title=f"{series}#{series_index} - {issue_name}", + authors=result.get("authors", []), + url=result.get("site_detail_url", ""), + source=MetaSourceInfo( + id=self.__id__, + description=ComicVine.DESCRIPTION, + link=ComicVine.META_URL, + ), + series=series, + ) + match.cover = result["image"].get("original_url", generic_cover) + match.description = result.get("description", "") + match.publishedDate = result.get("store_date", result.get("date_added")) + match.series_index = series_index + match.tags = ["Comics", series] + match.identifiers = {"comicvine": match.id} + return match diff --git a/cps/metadata_provider/douban.py b/cps/metadata_provider/douban.py new file mode 100644 index 000000000..8e27e82e8 --- /dev/null +++ b/cps/metadata_provider/douban.py @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2022 xlivevil +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import re +from concurrent import futures +from typing import List, Optional + +import requests +from html2text import HTML2Text +from lxml import etree + +from cps import logger +from cps.services.Metadata import Metadata, MetaRecord, MetaSourceInfo + +log = logger.create() + + +def html2text(html: str) -> str: + + h2t = HTML2Text() + h2t.body_width = 0 + h2t.single_line_break = True + h2t.emphasis_mark = "*" + return h2t.handle(html) + + +class Douban(Metadata): + __name__ = "豆瓣" + __id__ = "douban" + DESCRIPTION = "豆瓣" + META_URL = "https://book.douban.com/" + SEARCH_JSON_URL = "https://www.douban.com/j/search" + SEARCH_URL = "https://www.douban.com/search" + + ID_PATTERN = re.compile(r"sid: (?P\d+),") + AUTHORS_PATTERN = re.compile(r"作者|译者") + PUBLISHER_PATTERN = re.compile(r"出版社") + SUBTITLE_PATTERN = re.compile(r"副标题") + PUBLISHED_DATE_PATTERN = re.compile(r"出版年") + SERIES_PATTERN = re.compile(r"丛书") + IDENTIFIERS_PATTERN = re.compile(r"ISBN|统一书号") + CRITERIA_PATTERN = re.compile("criteria = '(.+)'") + + TITTLE_XPATH = "//span[@property='v:itemreviewed']" + COVER_XPATH = "//a[@class='nbg']" + INFO_XPATH = "//*[@id='info']//span[@class='pl']" + TAGS_XPATH = "//a[contains(@class, 'tag')]" + DESCRIPTION_XPATH = "//div[@id='link-report']//div[@class='intro']" + RATING_XPATH = "//div[@class='rating_self clearfix']/strong" + + session = requests.Session() + session.headers = { + 'user-agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 Edg/98.0.1108.56', + } + + def search(self, + query: str, + generic_cover: str = "", + locale: str = "en") -> List[MetaRecord]: + val = [] + if self.active: + log.debug(f"start searching {query} on douban") + if title_tokens := list( + self.get_title_tokens(query, strip_joiners=False)): + query = "+".join(title_tokens) + + book_id_list = self._get_book_id_list_from_html(query) + + if not book_id_list: + log.debug("No search results in Douban") + return [] + + with futures.ThreadPoolExecutor( + max_workers=5, thread_name_prefix='douban') as executor: + + fut = [ + executor.submit(self._parse_single_book, book_id, + generic_cover) for book_id in book_id_list + ] + + val = [ + future.result() for future in futures.as_completed(fut) + if future.result() + ] + + return val + + def _get_book_id_list_from_html(self, query: str) -> List[str]: + try: + r = self.session.get(self.SEARCH_URL, + params={ + "cat": 1001, + "q": query + }) + r.raise_for_status() + + except Exception as e: + log.warning(e) + return [] + + html = etree.HTML(r.content.decode("utf8")) + result_list = html.xpath(self.COVER_XPATH) + + return [ + self.ID_PATTERN.search(item.get("onclick")).group("id") + for item in result_list[:10] + if self.ID_PATTERN.search(item.get("onclick")) + ] + + def _get_book_id_list_from_json(self, query: str) -> List[str]: + try: + r = self.session.get(self.SEARCH_JSON_URL, + params={ + "cat": 1001, + "q": query + }) + r.raise_for_status() + + except Exception as e: + log.warning(e) + return [] + + results = r.json() + if results["total"] == 0: + return [] + + return [ + self.ID_PATTERN.search(item).group("id") + for item in results["items"][:10] if self.ID_PATTERN.search(item) + ] + + def _parse_single_book(self, + id: str, + generic_cover: str = "") -> Optional[MetaRecord]: + url = f"https://book.douban.com/subject/{id}/" + log.debug(f"start parsing {url}") + + try: + r = self.session.get(url) + r.raise_for_status() + except Exception as e: + log.warning(e) + return None + + match = MetaRecord( + id=id, + title="", + authors=[], + url=url, + source=MetaSourceInfo( + id=self.__id__, + description=self.DESCRIPTION, + link=self.META_URL, + ), + ) + + html = etree.HTML(r.content.decode("utf8")) + + match.title = html.xpath(self.TITTLE_XPATH)[0].text + match.cover = html.xpath( + self.COVER_XPATH)[0].attrib["href"] or generic_cover + try: + rating_num = float(html.xpath(self.RATING_XPATH)[0].text.strip()) + except Exception: + rating_num = 0 + match.rating = int(-1 * rating_num // 2 * -1) if rating_num else 0 + + tag_elements = html.xpath(self.TAGS_XPATH) + if len(tag_elements): + match.tags = [tag_element.text for tag_element in tag_elements] + else: + match.tags = self._get_tags(html.text) + + description_element = html.xpath(self.DESCRIPTION_XPATH) + if len(description_element): + match.description = html2text( + etree.tostring(description_element[-1]).decode("utf8")) + + info = html.xpath(self.INFO_XPATH) + + for element in info: + text = element.text + if self.AUTHORS_PATTERN.search(text): + next_element = element.getnext() + while next_element is not None and next_element.tag != "br": + match.authors.append(next_element.text) + next_element = next_element.getnext() + elif self.PUBLISHER_PATTERN.search(text): + if publisher := element.tail.strip(): + match.publisher = publisher + else: + match.publisher = element.getnext().text + elif self.SUBTITLE_PATTERN.search(text): + match.title = f'{match.title}:{element.tail.strip()}' + elif self.PUBLISHED_DATE_PATTERN.search(text): + match.publishedDate = self._clean_date(element.tail.strip()) + elif self.SERIES_PATTERN.search(text): + match.series = element.getnext().text + elif i_type := self.IDENTIFIERS_PATTERN.search(text): + match.identifiers[i_type.group()] = element.tail.strip() + + return match + + def _clean_date(self, date: str) -> str: + """ + Clean up the date string to be in the format YYYY-MM-DD + + Examples of possible patterns: + '2014-7-16', '1988年4月', '1995-04', '2021-8', '2020-12-1', '1996年', + '1972', '2004/11/01', '1959年3月北京第1版第1印' + """ + year = date[:4] + moon = "01" + day = "01" + + if len(date) > 5: + digit = [] + ls = [] + for i in range(5, len(date)): + if date[i].isdigit(): + digit.append(date[i]) + elif digit: + ls.append("".join(digit) if len(digit) == + 2 else f"0{digit[0]}") + digit = [] + if digit: + ls.append("".join(digit) if len(digit) == + 2 else f"0{digit[0]}") + + moon = ls[0] + if len(ls) > 1: + day = ls[1] + + return f"{year}-{moon}-{day}" + + def _get_tags(self, text: str) -> List[str]: + tags = [] + if criteria := self.CRITERIA_PATTERN.search(text): + tags.extend( + item.replace('7:', '') for item in criteria.group().split('|') + if item.startswith('7:')) + + return tags diff --git a/cps/metadata_provider/google.py b/cps/metadata_provider/google.py index f3d02d8e8..ba7e10af1 100644 --- a/cps/metadata_provider/google.py +++ b/cps/metadata_provider/google.py @@ -17,39 +17,113 @@ # along with this program. If not, see . # Google Books api document: https://developers.google.com/books/docs/v1/using - +from typing import Dict, List, Optional +from urllib.parse import quote +from datetime import datetime import requests -from cps.services.Metadata import Metadata + +from cps import logger +from cps.isoLanguages import get_lang3, get_language_name +from cps.services.Metadata import MetaRecord, MetaSourceInfo, Metadata + +log = logger.create() + class Google(Metadata): __name__ = "Google" __id__ = "google" + DESCRIPTION = "Google Books" + META_URL = "https://books.google.com/" + BOOK_URL = "https://books.google.com/books?id=" + SEARCH_URL = "https://www.googleapis.com/books/v1/volumes?q=" + ISBN_TYPE = "ISBN_13" - def search(self, query, __): + def search( + self, query: str, generic_cover: str = "", locale: str = "en" + ) -> Optional[List[MetaRecord]]: + val = list() if self.active: - val = list() - result = requests.get("https://www.googleapis.com/books/v1/volumes?q="+query.replace(" ","+")) - for r in result.json()['items']: - v = dict() - v['id'] = r['id'] - v['title'] = r['volumeInfo']['title'] - v['authors'] = r['volumeInfo'].get('authors', []) - v['description'] = r['volumeInfo'].get('description', "") - v['publisher'] = r['volumeInfo'].get('publisher', "") - v['publishedDate'] = r['volumeInfo'].get('publishedDate', "") - v['tags'] = r['volumeInfo'].get('categories', []) - v['rating'] = r['volumeInfo'].get('averageRating', 0) - if r['volumeInfo'].get('imageLinks'): - v['cover'] = r['volumeInfo']['imageLinks']['thumbnail'].replace("http://", "https://") - else: - v['cover'] = "/../../../static/generic_cover.jpg" - v['source'] = { - "id": self.__id__, - "description": "Google Books", - "link": "https://books.google.com/"} - v['url'] = "https://books.google.com/books?id=" + r['id'] - val.append(v) - return val + title_tokens = list(self.get_title_tokens(query, strip_joiners=False)) + if title_tokens: + tokens = [quote(t.encode("utf-8")) for t in title_tokens] + query = "+".join(tokens) + try: + results = requests.get(Google.SEARCH_URL + query) + results.raise_for_status() + except Exception as e: + log.warning(e) + return None + for result in results.json().get("items", []): + val.append( + self._parse_search_result( + result=result, generic_cover=generic_cover, locale=locale + ) + ) + return val + def _parse_search_result( + self, result: Dict, generic_cover: str, locale: str + ) -> MetaRecord: + match = MetaRecord( + id=result["id"], + title=result["volumeInfo"]["title"], + authors=result["volumeInfo"].get("authors", []), + url=Google.BOOK_URL + result["id"], + source=MetaSourceInfo( + id=self.__id__, + description=Google.DESCRIPTION, + link=Google.META_URL, + ), + ) + + match.cover = self._parse_cover(result=result, generic_cover=generic_cover) + match.description = result["volumeInfo"].get("description", "") + match.languages = self._parse_languages(result=result, locale=locale) + match.publisher = result["volumeInfo"].get("publisher", "") + try: + datetime.strptime(result["volumeInfo"].get("publishedDate", ""), "%Y-%m-%d") + match.publishedDate = result["volumeInfo"].get("publishedDate", "") + except ValueError: + match.publishedDate = "" + match.rating = result["volumeInfo"].get("averageRating", 0) + match.series, match.series_index = "", 1 + match.tags = result["volumeInfo"].get("categories", []) + + match.identifiers = {"google": match.id} + match = self._parse_isbn(result=result, match=match) + return match + + @staticmethod + def _parse_isbn(result: Dict, match: MetaRecord) -> MetaRecord: + identifiers = result["volumeInfo"].get("industryIdentifiers", []) + for identifier in identifiers: + if identifier.get("type") == Google.ISBN_TYPE: + match.identifiers["isbn"] = identifier.get("identifier") + break + return match + + @staticmethod + def _parse_cover(result: Dict, generic_cover: str) -> str: + if result["volumeInfo"].get("imageLinks"): + cover_url = result["volumeInfo"]["imageLinks"]["thumbnail"] + + # strip curl in cover + cover_url = cover_url.replace("&edge=curl", "") + + # request 800x900 cover image (higher resolution) + cover_url += "&fife=w800-h900" + + return cover_url.replace("http://", "https://") + return generic_cover + + @staticmethod + def _parse_languages(result: Dict, locale: str) -> List[str]: + language_iso2 = result["volumeInfo"].get("language", "") + languages = ( + [get_language_name(locale, get_lang3(language_iso2))] + if language_iso2 + else [] + ) + return languages diff --git a/cps/metadata_provider/lubimyczytac.py b/cps/metadata_provider/lubimyczytac.py new file mode 100644 index 000000000..e4abe9dbc --- /dev/null +++ b/cps/metadata_provider/lubimyczytac.py @@ -0,0 +1,350 @@ +# -*- coding: utf-8 -*- +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2021 OzzieIsaacs +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import datetime +import json +import re +from multiprocessing.pool import ThreadPool +from typing import List, Optional, Tuple, Union +from urllib.parse import quote + +import requests +from dateutil import parser +from html2text import HTML2Text +from lxml.html import HtmlElement, fromstring, tostring +from markdown2 import Markdown + +from cps import logger +from cps.isoLanguages import get_language_name +from cps.services.Metadata import MetaRecord, MetaSourceInfo, Metadata + +log = logger.create() + +SYMBOLS_TO_TRANSLATE = ( + "öÖüÜóÓőŐúÚéÉáÁűŰíÍąĄćĆęĘłŁńŃóÓśŚźŹżŻ", + "oOuUoOoOuUeEaAuUiIaAcCeElLnNoOsSzZzZ", +) +SYMBOL_TRANSLATION_MAP = dict( + [(ord(a), ord(b)) for (a, b) in zip(*SYMBOLS_TO_TRANSLATE)] +) + + +def get_int_or_float(value: str) -> Union[int, float]: + number_as_float = float(value) + number_as_int = int(number_as_float) + return number_as_int if number_as_float == number_as_int else number_as_float + + +def strip_accents(s: Optional[str]) -> Optional[str]: + return s.translate(SYMBOL_TRANSLATION_MAP) if s is not None else s + + +def sanitize_comments_html(html: str) -> str: + text = html2text(html) + md = Markdown() + html = md.convert(text) + return html + + +def html2text(html: str) -> str: + # replace tags with as becomes emphasis in html2text + if isinstance(html, bytes): + html = html.decode("utf-8") + html = re.sub( + r"<\s*(?P/?)\s*[uU]\b(?P[^>]*)>", + r"<\gspan\g>", + html, + ) + h2t = HTML2Text() + h2t.body_width = 0 + h2t.single_line_break = True + h2t.emphasis_mark = "*" + return h2t.handle(html) + + +class LubimyCzytac(Metadata): + __name__ = "LubimyCzytac.pl" + __id__ = "lubimyczytac" + + BASE_URL = "https://lubimyczytac.pl" + + BOOK_SEARCH_RESULT_XPATH = ( + "*//div[@class='listSearch']//div[@class='authorAllBooks__single']" + ) + SINGLE_BOOK_RESULT_XPATH = ".//div[contains(@class,'authorAllBooks__singleText')]" + TITLE_PATH = "/div/a[contains(@class,'authorAllBooks__singleTextTitle')]" + TITLE_TEXT_PATH = f"{TITLE_PATH}//text()" + URL_PATH = f"{TITLE_PATH}/@href" + AUTHORS_PATH = "/div/a[contains(@href,'autor')]//text()" + + SIBLINGS = "/following-sibling::dd" + + CONTAINER = "//section[@class='container book']" + PUBLISHER = f"{CONTAINER}//dt[contains(text(),'Wydawnictwo:')]{SIBLINGS}/a/text()" + LANGUAGES = f"{CONTAINER}//dt[contains(text(),'Język:')]{SIBLINGS}/text()" + DESCRIPTION = f"{CONTAINER}//div[@class='collapse-content']" + SERIES = f"{CONTAINER}//span/a[contains(@href,'/cykl/')]/text()" + + DETAILS = "//div[@id='book-details']" + PUBLISH_DATE = "//dt[contains(@title,'Data pierwszego wydania" + FIRST_PUBLISH_DATE = f"{DETAILS}{PUBLISH_DATE} oryginalnego')]{SIBLINGS}[1]/text()" + FIRST_PUBLISH_DATE_PL = f"{DETAILS}{PUBLISH_DATE} polskiego')]{SIBLINGS}[1]/text()" + TAGS = "//nav[@aria-label='breadcrumb']//a[contains(@href,'/ksiazki/k/')]/text()" + + RATING = "//meta[@property='books:rating:value']/@content" + COVER = "//meta[@property='og:image']/@content" + ISBN = "//meta[@property='books:isbn']/@content" + META_TITLE = "//meta[@property='og:description']/@content" + + SUMMARY = "//script[@type='application/ld+json']//text()" + + def search( + self, query: str, generic_cover: str = "", locale: str = "en" + ) -> Optional[List[MetaRecord]]: + if self.active: + try: + result = requests.get(self._prepare_query(title=query)) + result.raise_for_status() + except Exception as e: + log.warning(e) + return None + root = fromstring(result.text) + lc_parser = LubimyCzytacParser(root=root, metadata=self) + matches = lc_parser.parse_search_results() + if matches: + with ThreadPool(processes=10) as pool: + final_matches = pool.starmap( + lc_parser.parse_single_book, + [(match, generic_cover, locale) for match in matches], + ) + return final_matches + return matches + + def _prepare_query(self, title: str) -> str: + query = "" + characters_to_remove = "\?()\/" + pattern = "[" + characters_to_remove + "]" + title = re.sub(pattern, "", title) + title = title.replace("_", " ") + if '"' in title or ",," in title: + title = title.split('"')[0].split(",,")[0] + + if "/" in title: + title_tokens = [ + token for token in title.lower().split(" ") if len(token) > 1 + ] + else: + title_tokens = list(self.get_title_tokens(title, strip_joiners=False)) + if title_tokens: + tokens = [quote(t.encode("utf-8")) for t in title_tokens] + query = query + "%20".join(tokens) + if not query: + return "" + return f"{LubimyCzytac.BASE_URL}/szukaj/ksiazki?phrase={query}" + + +class LubimyCzytacParser: + PAGES_TEMPLATE = "

Książka ma {0} stron(y).

" + PUBLISH_DATE_TEMPLATE = "

Data pierwszego wydania: {0}

" + PUBLISH_DATE_PL_TEMPLATE = ( + "

Data pierwszego wydania w Polsce: {0}

" + ) + + def __init__(self, root: HtmlElement, metadata: Metadata) -> None: + self.root = root + self.metadata = metadata + + def parse_search_results(self) -> List[MetaRecord]: + matches = [] + results = self.root.xpath(LubimyCzytac.BOOK_SEARCH_RESULT_XPATH) + for result in results: + title = self._parse_xpath_node( + root=result, + xpath=f"{LubimyCzytac.SINGLE_BOOK_RESULT_XPATH}" + f"{LubimyCzytac.TITLE_TEXT_PATH}", + ) + + book_url = self._parse_xpath_node( + root=result, + xpath=f"{LubimyCzytac.SINGLE_BOOK_RESULT_XPATH}" + f"{LubimyCzytac.URL_PATH}", + ) + authors = self._parse_xpath_node( + root=result, + xpath=f"{LubimyCzytac.SINGLE_BOOK_RESULT_XPATH}" + f"{LubimyCzytac.AUTHORS_PATH}", + take_first=False, + ) + if not all([title, book_url, authors]): + continue + matches.append( + MetaRecord( + id=book_url.replace(f"/ksiazka/", "").split("/")[0], + title=title, + authors=[strip_accents(author) for author in authors], + url=LubimyCzytac.BASE_URL + book_url, + source=MetaSourceInfo( + id=self.metadata.__id__, + description=self.metadata.__name__, + link=LubimyCzytac.BASE_URL, + ), + ) + ) + return matches + + def parse_single_book( + self, match: MetaRecord, generic_cover: str, locale: str + ) -> MetaRecord: + try: + response = requests.get(match.url) + response.raise_for_status() + except Exception as e: + log.warning(e) + return None + self.root = fromstring(response.text) + match.cover = self._parse_cover(generic_cover=generic_cover) + match.description = self._parse_description() + match.languages = self._parse_languages(locale=locale) + match.publisher = self._parse_publisher() + match.publishedDate = self._parse_from_summary(attribute_name="datePublished") + match.rating = self._parse_rating() + match.series, match.series_index = self._parse_series() + match.tags = self._parse_tags() + match.identifiers = { + "isbn": self._parse_isbn(), + "lubimyczytac": match.id, + } + return match + + def _parse_xpath_node( + self, + xpath: str, + root: HtmlElement = None, + take_first: bool = True, + strip_element: bool = True, + ) -> Optional[Union[str, List[str]]]: + root = root if root is not None else self.root + node = root.xpath(xpath) + if not node: + return None + return ( + (node[0].strip() if strip_element else node[0]) + if take_first + else [x.strip() for x in node] + ) + + def _parse_cover(self, generic_cover) -> Optional[str]: + return ( + self._parse_xpath_node(xpath=LubimyCzytac.COVER, take_first=True) + or generic_cover + ) + + def _parse_publisher(self) -> Optional[str]: + return self._parse_xpath_node(xpath=LubimyCzytac.PUBLISHER, take_first=True) + + def _parse_languages(self, locale: str) -> List[str]: + languages = list() + lang = self._parse_xpath_node(xpath=LubimyCzytac.LANGUAGES, take_first=True) + if lang: + if "polski" in lang: + languages.append("pol") + if "angielski" in lang: + languages.append("eng") + return [get_language_name(locale, language) for language in languages] + + def _parse_series(self) -> Tuple[Optional[str], Optional[Union[float, int]]]: + series_index = 0 + series = self._parse_xpath_node(xpath=LubimyCzytac.SERIES, take_first=True) + if series: + if "tom " in series: + series_name, series_info = series.split(" (tom ", 1) + series_info = series_info.replace(" ", "").replace(")", "") + # Check if book is not a bundle, i.e. chapter 1-3 + if "-" in series_info: + series_info = series_info.split("-", 1)[0] + if series_info.replace(".", "").isdigit() is True: + series_index = get_int_or_float(series_info) + return series_name, series_index + return None, None + + def _parse_tags(self) -> List[str]: + tags = self._parse_xpath_node(xpath=LubimyCzytac.TAGS, take_first=False) + return [ + strip_accents(w.replace(", itd.", " itd.")) + for w in tags + if isinstance(w, str) + ] + + def _parse_from_summary(self, attribute_name: str) -> Optional[str]: + value = None + summary_text = self._parse_xpath_node(xpath=LubimyCzytac.SUMMARY) + if summary_text: + data = json.loads(summary_text) + value = data.get(attribute_name) + return value.strip() if value is not None else value + + def _parse_rating(self) -> Optional[str]: + rating = self._parse_xpath_node(xpath=LubimyCzytac.RATING) + return round(float(rating.replace(",", ".")) / 2) if rating else rating + + def _parse_date(self, xpath="first_publish") -> Optional[datetime.datetime]: + options = { + "first_publish": LubimyCzytac.FIRST_PUBLISH_DATE, + "first_publish_pl": LubimyCzytac.FIRST_PUBLISH_DATE_PL, + } + date = self._parse_xpath_node(xpath=options.get(xpath)) + return parser.parse(date) if date else None + + def _parse_isbn(self) -> Optional[str]: + return self._parse_xpath_node(xpath=LubimyCzytac.ISBN) + + def _parse_description(self) -> str: + description = "" + description_node = self._parse_xpath_node( + xpath=LubimyCzytac.DESCRIPTION, strip_element=False + ) + if description_node is not None: + for source in self.root.xpath('//p[@class="source"]'): + source.getparent().remove(source) + description = tostring(description_node, method="html") + description = sanitize_comments_html(description) + + else: + description_node = self._parse_xpath_node(xpath=LubimyCzytac.META_TITLE) + if description_node is not None: + description = description_node + description = sanitize_comments_html(description) + description = self._add_extra_info_to_description(description=description) + return description + + def _add_extra_info_to_description(self, description: str) -> str: + pages = self._parse_from_summary(attribute_name="numberOfPages") + if pages: + description += LubimyCzytacParser.PAGES_TEMPLATE.format(pages) + + first_publish_date = self._parse_date() + if first_publish_date: + description += LubimyCzytacParser.PUBLISH_DATE_TEMPLATE.format( + first_publish_date.strftime("%d.%m.%Y") + ) + + first_publish_date_pl = self._parse_date(xpath="first_publish_pl") + if first_publish_date_pl: + description += LubimyCzytacParser.PUBLISH_DATE_PL_TEMPLATE.format( + first_publish_date_pl.strftime("%d.%m.%Y") + ) + + return description diff --git a/cps/metadata_provider/scholar.py b/cps/metadata_provider/scholar.py index 6e13c7689..5f6323430 100644 --- a/cps/metadata_provider/scholar.py +++ b/cps/metadata_provider/scholar.py @@ -15,47 +15,69 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import itertools +from typing import Dict, List, Optional +from urllib.parse import quote, unquote -from scholarly import scholarly +try: + from fake_useragent.errors import FakeUserAgentError +except (ImportError): + FakeUserAgentError = BaseException +try: + from scholarly import scholarly +except FakeUserAgentError: + raise ImportError("No module named 'scholarly'") -from cps.services.Metadata import Metadata +from cps import logger +from cps.services.Metadata import MetaRecord, MetaSourceInfo, Metadata + +log = logger.create() class scholar(Metadata): __name__ = "Google Scholar" __id__ = "googlescholar" + META_URL = "https://scholar.google.com/" - def search(self, query, generic_cover=""): + def search( + self, query: str, generic_cover: str = "", locale: str = "en" + ) -> Optional[List[MetaRecord]]: val = list() if self.active: - scholar_gen = scholarly.search_pubs(' '.join(query.split('+'))) - i = 0 - for publication in scholar_gen: - v = dict() - v['id'] = "1234" # publication['bib'].get('title') - v['title'] = publication['bib'].get('title') - v['authors'] = publication['bib'].get('author', []) - v['description'] = publication['bib'].get('abstract', "") - v['publisher'] = publication['bib'].get('venue', "") - if publication['bib'].get('pub_year'): - v['publishedDate'] = publication['bib'].get('pub_year')+"-01-01" - else: - v['publishedDate'] = "" - v['tags'] = "" - v['ratings'] = 0 - v['series'] = "" - v['cover'] = generic_cover - v['url'] = publication.get('pub_url') or publication.get('eprint_url') or "", - v['source'] = { - "id": self.__id__, - "description": "Google Scholar", - "link": "https://scholar.google.com/" - } - val.append(v) - i += 1 - if (i >= 10): - break + title_tokens = list(self.get_title_tokens(query, strip_joiners=False)) + if title_tokens: + tokens = [quote(t.encode("utf-8")) for t in title_tokens] + query = " ".join(tokens) + try: + scholarly.set_timeout(20) + scholarly.set_retries(2) + scholar_gen = itertools.islice(scholarly.search_pubs(query), 10) + except Exception as e: + log.warning(e) + return list() + for result in scholar_gen: + match = self._parse_search_result( + result=result, generic_cover="", locale=locale + ) + val.append(match) return val + def _parse_search_result( + self, result: Dict, generic_cover: str, locale: str + ) -> MetaRecord: + match = MetaRecord( + id=result.get("pub_url", result.get("eprint_url", "")), + title=result["bib"].get("title"), + authors=result["bib"].get("author", []), + url=result.get("pub_url", result.get("eprint_url", "")), + source=MetaSourceInfo( + id=self.__id__, description=self.__name__, link=scholar.META_URL + ), + ) - + match.cover = result.get("image", {}).get("original_url", generic_cover) + match.description = unquote(result["bib"].get("abstract", "")) + match.publisher = result["bib"].get("venue", "") + match.publishedDate = result["bib"].get("pub_year") + "-01-01" + match.identifiers = {"scholar": match.id} + return match diff --git a/cps/oauth.py b/cps/oauth.py index f8e5c1fd3..0caa61ec5 100644 --- a/cps/oauth.py +++ b/cps/oauth.py @@ -19,18 +19,12 @@ from flask import session try: - from flask_dance.consumer.backend.sqla import SQLAlchemyBackend, first, _get_real_user + from flask_dance.consumer.storage.sqla import SQLAlchemyStorage as SQLAlchemyBackend + from flask_dance.consumer.storage.sqla import first, _get_real_user from sqlalchemy.orm.exc import NoResultFound - backend_resultcode = False # prevent storing values with this resultcode + backend_resultcode = True # prevent storing values with this resultcode except ImportError: - # fails on flask-dance >1.3, due to renaming - try: - from flask_dance.consumer.storage.sqla import SQLAlchemyStorage as SQLAlchemyBackend - from flask_dance.consumer.storage.sqla import first, _get_real_user - from sqlalchemy.orm.exc import NoResultFound - backend_resultcode = True # prevent storing values with this resultcode - except ImportError: - pass + pass class OAuthBackend(SQLAlchemyBackend): diff --git a/cps/oauth_bb.py b/cps/oauth_bb.py index d9efd41e4..ec400f716 100644 --- a/cps/oauth_bb.py +++ b/cps/oauth_bb.py @@ -74,7 +74,7 @@ def register_user_with_oauth(user=None): if len(all_oauth.keys()) == 0: return if user is None: - flash(_(u"Register with %(provider)s", provider=", ".join(list(all_oauth.values()))), category="success") + flash(_("Register with %(provider)s", provider=", ".join(list(all_oauth.values()))), category="success") else: for oauth_key in all_oauth.keys(): # Find this OAuth token in the database, or create it @@ -134,8 +134,8 @@ def bind_oauth_or_register(provider_id, provider_user_id, redirect_url, provider # already bind with user, just login if oauth_entry.user: login_user(oauth_entry.user) - log.debug(u"You are now logged in as: '%s'", oauth_entry.user.name) - flash(_(u"you are now logged in as: '%(nickname)s'", nickname= oauth_entry.user.name), + log.debug("You are now logged in as: '%s'", oauth_entry.user.name) + flash(_("Success! You are now logged in as: %(nickname)s", nickname= oauth_entry.user.name), category="success") return redirect(url_for('web.index')) else: @@ -145,21 +145,21 @@ def bind_oauth_or_register(provider_id, provider_user_id, redirect_url, provider try: ub.session.add(oauth_entry) ub.session.commit() - flash(_(u"Link to %(oauth)s Succeeded", oauth=provider_name), category="success") + flash(_("Link to %(oauth)s Succeeded", oauth=provider_name), category="success") log.info("Link to {} Succeeded".format(provider_name)) return redirect(url_for('web.profile')) except Exception as ex: - log.debug_or_exception(ex) + log.error_or_exception(ex) ub.session.rollback() else: - flash(_(u"Login failed, No User Linked With OAuth Account"), category="error") + flash(_("Login failed, No User Linked With OAuth Account"), category="error") log.info('Login failed, No User Linked With OAuth Account') return redirect(url_for('web.login')) # return redirect(url_for('web.login')) # if config.config_public_reg: # return redirect(url_for('web.register')) # else: - # flash(_(u"Public registration is not enabled"), category="error") + # flash(_("Public registration is not enabled"), category="error") # return redirect(url_for(redirect_url)) except (NoResultFound, AttributeError): return redirect(url_for(redirect_url)) @@ -194,15 +194,15 @@ def unlink_oauth(provider): ub.session.delete(oauth_entry) ub.session.commit() logout_oauth_user() - flash(_(u"Unlink to %(oauth)s Succeeded", oauth=oauth_check[provider]), category="success") + flash(_("Unlink to %(oauth)s Succeeded", oauth=oauth_check[provider]), category="success") log.info("Unlink to {} Succeeded".format(oauth_check[provider])) except Exception as ex: - log.debug_or_exception(ex) + log.error_or_exception(ex) ub.session.rollback() - flash(_(u"Unlink to %(oauth)s Failed", oauth=oauth_check[provider]), category="error") + flash(_("Unlink to %(oauth)s Failed", oauth=oauth_check[provider]), category="error") except NoResultFound: log.warning("oauth %s for user %d not found", provider, current_user.id) - flash(_(u"Not Linked to %(oauth)s", oauth=provider), category="error") + flash(_("Not Linked to %(oauth)s", oauth=provider), category="error") return redirect(url_for('web.profile')) def generate_oauth_blueprints(): @@ -258,13 +258,13 @@ if ub.oauth_support: @oauth_authorized.connect_via(oauthblueprints[0]['blueprint']) def github_logged_in(blueprint, token): if not token: - flash(_(u"Failed to log in with GitHub."), category="error") + flash(_("Failed to log in with GitHub."), category="error") log.error("Failed to log in with GitHub") return False resp = blueprint.session.get("/user") if not resp.ok: - flash(_(u"Failed to fetch user info from GitHub."), category="error") + flash(_("Failed to fetch user info from GitHub."), category="error") log.error("Failed to fetch user info from GitHub") return False @@ -276,13 +276,13 @@ if ub.oauth_support: @oauth_authorized.connect_via(oauthblueprints[1]['blueprint']) def google_logged_in(blueprint, token): if not token: - flash(_(u"Failed to log in with Google."), category="error") + flash(_("Failed to log in with Google."), category="error") log.error("Failed to log in with Google") return False resp = blueprint.session.get("/oauth2/v2/userinfo") if not resp.ok: - flash(_(u"Failed to fetch user info from Google."), category="error") + flash(_("Failed to fetch user info from Google."), category="error") log.error("Failed to fetch user info from Google") return False @@ -295,8 +295,8 @@ if ub.oauth_support: @oauth_error.connect_via(oauthblueprints[0]['blueprint']) def github_error(blueprint, error, error_description=None, error_uri=None): msg = ( - u"OAuth error from {name}! " - u"error={error} description={description} uri={uri}" + "OAuth error from {name}! " + "error={error} description={description} uri={uri}" ).format( name=blueprint.name, error=error, @@ -308,8 +308,8 @@ if ub.oauth_support: @oauth_error.connect_via(oauthblueprints[1]['blueprint']) def google_error(blueprint, error, error_description=None, error_uri=None): msg = ( - u"OAuth error from {name}! " - u"error={error} description={description} uri={uri}" + "OAuth error from {name}! " + "error={error} description={description} uri={uri}" ).format( name=blueprint.name, error=error, @@ -329,10 +329,10 @@ def github_login(): if account_info.ok: account_info_json = account_info.json() return bind_oauth_or_register(oauthblueprints[0]['id'], account_info_json['id'], 'github.login', 'github') - flash(_(u"GitHub Oauth error, please retry later."), category="error") + flash(_("GitHub Oauth error, please retry later."), category="error") log.error("GitHub Oauth error, please retry later") except (InvalidGrantError, TokenExpiredError) as e: - flash(_(u"GitHub Oauth error: {}").format(e), category="error") + flash(_("GitHub Oauth error: {}").format(e), category="error") log.error(e) return redirect(url_for('web.login')) @@ -353,10 +353,10 @@ def google_login(): if resp.ok: account_info_json = resp.json() return bind_oauth_or_register(oauthblueprints[1]['id'], account_info_json['id'], 'google.login', 'google') - flash(_(u"Google Oauth error, please retry later."), category="error") + flash(_("Google Oauth error, please retry later."), category="error") log.error("Google Oauth error, please retry later") except (InvalidGrantError, TokenExpiredError) as e: - flash(_(u"Google Oauth error: {}").format(e), category="error") + flash(_("Google Oauth error: {}").format(e), category="error") log.error(e) return redirect(url_for('web.login')) diff --git a/cps/opds.py b/cps/opds.py index 92c51d1ba..6b09a84d4 100644 --- a/cps/opds.py +++ b/cps/opds.py @@ -20,56 +20,28 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys import datetime -from functools import wraps +from urllib.parse import unquote_plus -from flask import Blueprint, request, render_template, Response, g, make_response, abort +from flask import Blueprint, request, render_template, make_response, abort from flask_login import current_user +from flask_babel import get_locale +from flask_babel import gettext as _ from sqlalchemy.sql.expression import func, text, or_, and_, true -from werkzeug.security import check_password_hash +from sqlalchemy.exc import InvalidRequestError, OperationalError -from . import constants, logger, config, db, calibre_db, ub, services, get_locale, isoLanguages +from . import logger, config, db, calibre_db, ub, isoLanguages +from .usermanagement import requires_basic_auth_if_no_ano from .helper import get_download_link, get_book_cover from .pagination import Pagination from .web import render_read_books -from .usermanagement import load_user_from_request -from flask_babel import gettext as _ -from babel import Locale as LC -from babel.core import UnknownLocaleError + opds = Blueprint('opds', __name__) log = logger.create() -def requires_basic_auth_if_no_ano(f): - @wraps(f) - def decorated(*args, **kwargs): - auth = request.authorization - if config.config_anonbrowse != 1: - if not auth or auth.type != 'basic' or not check_auth(auth.username, auth.password): - return authenticate() - return f(*args, **kwargs) - if config.config_login_type == constants.LOGIN_LDAP and services.ldap and config.config_anonbrowse != 1: - return services.ldap.basic_auth_required(f) - return decorated - - -class FeedObject: - def __init__(self, rating_id, rating_name): - self.rating_id = rating_id - self.rating_name = rating_name - - @property - def id(self): - return self.rating_id - - @property - def name(self): - return self.rating_name - - @opds.route("/opds/") @opds.route("/opds") @requires_basic_auth_if_no_ano @@ -84,10 +56,12 @@ def feed_osd(): @opds.route("/opds/search", defaults={'query': ""}) -@opds.route("/opds/search/") +@opds.route("/opds/search/") @requires_basic_auth_if_no_ano def feed_cc_search(query): - return feed_search(query.strip()) + # Handle strange query from Libera Reader with + instead of spaces + plus_query = unquote_plus(request.environ['RAW_URI'].split('/opds/search/')[1]).strip() + return feed_search(plus_query) @opds.route("/opds/search", methods=["GET"]) @@ -99,26 +73,7 @@ def feed_normal_search(): @opds.route("/opds/books") @requires_basic_auth_if_no_ano def feed_booksindex(): - shift = 0 - off = int(request.args.get("offset") or 0) - entries = calibre_db.session.query(func.upper(func.substr(db.Books.sort, 1, 1)).label('id'))\ - .filter(calibre_db.common_filters()).group_by(func.upper(func.substr(db.Books.sort, 1, 1))).all() - - elements = [] - if off == 0: - elements.append({'id': "00", 'name':_("All")}) - shift = 1 - for entry in entries[ - off + shift - 1: - int(off + int(config.config_books_per_page) - shift)]: - elements.append({'id': entry.id, 'name': entry.id}) - - pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, - len(entries) + 1) - return render_xml_template('feed.xml', - letterelements=elements, - folder='opds.feed_letter_books', - pagination=pagination) + return render_element_index(db.Books.sort, None, 'opds.feed_letter_books') @opds.route("/opds/books/letter/") @@ -129,7 +84,8 @@ def feed_letter_books(book_id): entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, db.Books, letter, - [db.Books.sort]) + [db.Books.sort], + True, config.config_read_column) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @@ -139,15 +95,16 @@ def feed_letter_books(book_id): def feed_new(): off = request.args.get("offset") or 0 entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, - db.Books, True, [db.Books.timestamp.desc()]) + db.Books, True, [db.Books.timestamp.desc()], + True, config.config_read_column) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @opds.route("/opds/discover") @requires_basic_auth_if_no_ano def feed_discover(): - entries = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()).order_by(func.random())\ - .limit(config.config_books_per_page) + query = calibre_db.generate_linked_query(config.config_read_column, db.Books) + entries = query.filter(calibre_db.common_filters()).order_by(func.random()).limit(config.config_books_per_page) pagination = Pagination(1, config.config_books_per_page, int(config.config_books_per_page)) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @@ -158,7 +115,8 @@ def feed_best_rated(): off = request.args.get("offset") or 0 entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, db.Books, db.Books.ratings.any(db.Ratings.rating > 9), - [db.Books.timestamp.desc()]) + [db.Books.timestamp.desc()], + True, config.config_read_column) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @@ -171,43 +129,23 @@ def feed_hot(): hot_books = all_books.offset(off).limit(config.config_books_per_page) entries = list() for book in hot_books: - downloadBook = calibre_db.get_book(book.Downloads.book_id) - if downloadBook: - entries.append( - calibre_db.get_filtered_book(book.Downloads.book_id) - ) + query = calibre_db.generate_linked_query(config.config_read_column, db.Books) + download_book = query.filter(calibre_db.common_filters()).filter( + book.Downloads.book_id == db.Books.id).first() + if download_book: + entries.append(download_book) else: ub.delete_download(book.Downloads.book_id) - numBooks = entries.__len__() + num_books = entries.__len__() pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), - config.config_books_per_page, numBooks) + config.config_books_per_page, num_books) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @opds.route("/opds/author") @requires_basic_auth_if_no_ano def feed_authorindex(): - shift = 0 - off = int(request.args.get("offset") or 0) - entries = calibre_db.session.query(func.upper(func.substr(db.Authors.sort, 1, 1)).label('id'))\ - .join(db.books_authors_link).join(db.Books).filter(calibre_db.common_filters())\ - .group_by(func.upper(func.substr(db.Authors.sort, 1, 1))).all() - - elements = [] - if off == 0: - elements.append({'id': "00", 'name':_("All")}) - shift = 1 - for entry in entries[ - off + shift - 1: - int(off + int(config.config_books_per_page) - shift)]: - elements.append({'id': entry.id, 'name': entry.id}) - - pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, - len(entries) + 1) - return render_xml_template('feed.xml', - letterelements=elements, - folder='opds.feed_letter_author', - pagination=pagination) + return render_element_index(db.Authors.sort, db.books_authors_link, 'opds.feed_letter_author') @opds.route("/opds/author/letter/") @@ -228,12 +166,7 @@ def feed_letter_author(book_id): @opds.route("/opds/author/") @requires_basic_auth_if_no_ano def feed_author(book_id): - off = request.args.get("offset") or 0 - entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, - db.Books, - db.Books.authors.any(db.Authors.id == book_id), - [db.Books.timestamp.desc()]) - return render_xml_template('feed.xml', entries=entries, pagination=pagination) + return render_xml_dataset(db.Authors, book_id) @opds.route("/opds/publisher") @@ -254,37 +187,14 @@ def feed_publisherindex(): @opds.route("/opds/publisher/") @requires_basic_auth_if_no_ano def feed_publisher(book_id): - off = request.args.get("offset") or 0 - entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, - db.Books, - db.Books.publishers.any(db.Publishers.id == book_id), - [db.Books.timestamp.desc()]) - return render_xml_template('feed.xml', entries=entries, pagination=pagination) + return render_xml_dataset(db.Publishers, book_id) @opds.route("/opds/category") @requires_basic_auth_if_no_ano def feed_categoryindex(): - shift = 0 - off = int(request.args.get("offset") or 0) - entries = calibre_db.session.query(func.upper(func.substr(db.Tags.name, 1, 1)).label('id'))\ - .join(db.books_tags_link).join(db.Books).filter(calibre_db.common_filters())\ - .group_by(func.upper(func.substr(db.Tags.name, 1, 1))).all() - elements = [] - if off == 0: - elements.append({'id': "00", 'name':_("All")}) - shift = 1 - for entry in entries[ - off + shift - 1: - int(off + int(config.config_books_per_page) - shift)]: - elements.append({'id': entry.id, 'name': entry.id}) + return render_element_index(db.Tags.name, db.books_tags_link, 'opds.feed_letter_category') - pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, - len(entries) + 1) - return render_xml_template('feed.xml', - letterelements=elements, - folder='opds.feed_letter_category', - pagination=pagination) @opds.route("/opds/category/letter/") @requires_basic_auth_if_no_ano @@ -306,36 +216,14 @@ def feed_letter_category(book_id): @opds.route("/opds/category/") @requires_basic_auth_if_no_ano def feed_category(book_id): - off = request.args.get("offset") or 0 - entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, - db.Books, - db.Books.tags.any(db.Tags.id == book_id), - [db.Books.timestamp.desc()]) - return render_xml_template('feed.xml', entries=entries, pagination=pagination) + return render_xml_dataset(db.Tags, book_id) @opds.route("/opds/series") @requires_basic_auth_if_no_ano def feed_seriesindex(): - shift = 0 - off = int(request.args.get("offset") or 0) - entries = calibre_db.session.query(func.upper(func.substr(db.Series.sort, 1, 1)).label('id'))\ - .join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters())\ - .group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all() - elements = [] - if off == 0: - elements.append({'id': "00", 'name':_("All")}) - shift = 1 - for entry in entries[ - off + shift - 1: - int(off + int(config.config_books_per_page) - shift)]: - elements.append({'id': entry.id, 'name': entry.id}) - pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, - len(entries) + 1) - return render_xml_template('feed.xml', - letterelements=elements, - folder='opds.feed_letter_series', - pagination=pagination) + return render_element_index(db.Series.sort, db.books_series_link, 'opds.feed_letter_series') + @opds.route("/opds/series/letter/") @requires_basic_auth_if_no_ano @@ -361,7 +249,8 @@ def feed_series(book_id): entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, db.Books, db.Books.series.any(db.Series.id == book_id), - [db.Books.series_index]) + [db.Books.series_index], + True, config.config_read_column) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @@ -370,7 +259,7 @@ def feed_series(book_id): def feed_ratingindex(): off = request.args.get("offset") or 0 entries = calibre_db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'), - (db.Ratings.rating / 2).label('name')) \ + (db.Ratings.rating / 2).label('name')) \ .join(db.books_ratings_link)\ .join(db.Books)\ .filter(calibre_db.common_filters()) \ @@ -388,12 +277,7 @@ def feed_ratingindex(): @opds.route("/opds/ratings/") @requires_basic_auth_if_no_ano def feed_ratings(book_id): - off = request.args.get("offset") or 0 - entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, - db.Books, - db.Books.ratings.any(db.Ratings.id == book_id), - [db.Books.timestamp.desc()]) - return render_xml_template('feed.xml', entries=entries, pagination=pagination) + return render_xml_dataset(db.Ratings, book_id) @opds.route("/opds/formats") @@ -420,7 +304,8 @@ def feed_format(book_id): entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, db.Books, db.Books.data.any(db.Data.format == book_id.upper()), - [db.Books.timestamp.desc()]) + [db.Books.timestamp.desc()], + True, config.config_read_column) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @@ -429,20 +314,12 @@ def feed_format(book_id): @requires_basic_auth_if_no_ano def feed_languagesindex(): off = request.args.get("offset") or 0 - if current_user.filter_language() == u"all": + if current_user.filter_language() == "all": languages = calibre_db.speaking_language() else: - #try: - # cur_l = LC.parse(current_user.filter_language()) - #except UnknownLocaleError: - # cur_l = None languages = calibre_db.session.query(db.Languages).filter( db.Languages.lang_code == current_user.filter_language()).all() languages[0].name = isoLanguages.get_language_name(get_locale(), languages[0].lang_code) - #if cur_l: - # languages[0].name = cur_l.get_language_name(get_locale()) - #else: - # languages[0].name = _(isoLanguages.get(part3=languages[0].lang_code).name) pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, len(languages)) return render_xml_template('feed.xml', listelements=languages, folder='opds.feed_languages', pagination=pagination) @@ -455,7 +332,8 @@ def feed_languages(book_id): entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, db.Books, db.Books.languages.any(db.Languages.id == book_id), - [db.Books.timestamp.desc()]) + [db.Books.timestamp.desc()], + True, config.config_read_column) return render_xml_template('feed.xml', entries=entries, pagination=pagination) @@ -463,7 +341,8 @@ def feed_languages(book_id): @requires_basic_auth_if_no_ano def feed_shelfindex(): off = request.args.get("offset") or 0 - shelf = g.shelves_access + shelf = ub.session.query(ub.Shelf).filter( + or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == current_user.id)).order_by(ub.Shelf.name).all() number = len(shelf) pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, number) @@ -485,24 +364,32 @@ def feed_shelf(book_id): result = list() # user is allowed to access shelf if shelf: - books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == book_id).order_by( - ub.BookShelf.order.asc()).all() - for book in books_in_shelf: - cur_book = calibre_db.get_book(book.book_id) - result.append(cur_book) - pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, - len(result)) + result, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), + config.config_books_per_page, + db.Books, + ub.BookShelf.shelf == shelf.id, + [ub.BookShelf.order.asc()], + True, config.config_read_column, + ub.BookShelf, ub.BookShelf.book_id == db.Books.id) + # delete shelf entries where book is not existent anymore, can happen if book is deleted outside calibre-web + wrong_entries = calibre_db.session.query(ub.BookShelf) \ + .join(db.Books, ub.BookShelf.book_id == db.Books.id, isouter=True) \ + .filter(db.Books.id == None).all() + for entry in wrong_entries: + log.info('Not existing book {} in {} deleted'.format(entry.book_id, shelf)) + try: + ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == entry.book_id).delete() + ub.session.commit() + except (OperationalError, InvalidRequestError) as e: + ub.session.rollback() + log.error_or_exception("Settings Database error: {}".format(e)) return render_xml_template('feed.xml', entries=result, pagination=pagination) @opds.route("/opds/download///") @requires_basic_auth_if_no_ano def opds_download_link(book_id, book_format): - # I gave up with this: With enabled ldap login, the user doesn't get logged in, therefore it's always guest - # workaround, loading the user from the request and checking it's download rights here - # in case of anonymous browsing user is None - user = load_user_from_request(request) or current_user - if not user.role_download(): + if not current_user.role_download(): return abort(403) if "Kobo" in request.headers.get('User-Agent'): client = "kobo" @@ -525,47 +412,6 @@ def get_metadata_calibre_companion(uuid, library): return "" -def feed_search(term): - if term: - entries, __, ___ = calibre_db.get_search_results(term) - entriescount = len(entries) if len(entries) > 0 else 1 - pagination = Pagination(1, entriescount, entriescount) - return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination) - else: - return render_xml_template('feed.xml', searchterm="") - - -def check_auth(username, password): - try: - username = username.encode('windows-1252') - except UnicodeEncodeError: - username = username.encode('utf-8') - user = ub.session.query(ub.User).filter(func.lower(ub.User.name) == - username.decode('utf-8').lower()).first() - if bool(user and check_password_hash(str(user.password), password)): - return True - else: - ip_Address = request.headers.get('X-Forwarded-For', request.remote_addr) - log.warning('OPDS Login failed for user "%s" IP-address: %s', username.decode('utf-8'), ip_Address) - return False - - -def authenticate(): - return Response( - 'Could not verify your access level for that URL.\n' - 'You have to login with proper credentials', 401, - {'WWW-Authenticate': 'Basic realm="Login Required"'}) - - -def render_xml_template(*args, **kwargs): - # ToDo: return time in current timezone similar to %z - currtime = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S+00:00") - xml = render_template(current_time=currtime, instance=config.config_calibre_web_title, *args, **kwargs) - response = make_response(xml) - response.headers["Content-Type"] = "application/atom+xml; charset=utf-8" - return response - - @opds.route("/opds/thumb_240_240/") @opds.route("/opds/cover_240_240/") @opds.route("/opds/cover_90_90/") @@ -589,3 +435,71 @@ def feed_unread_books(): off = request.args.get("offset") or 0 result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True) return render_xml_template('feed.xml', entries=result, pagination=pagination) + + +class FeedObject: + def __init__(self, rating_id, rating_name): + self.rating_id = rating_id + self.rating_name = rating_name + + @property + def id(self): + return self.rating_id + + @property + def name(self): + return self.rating_name + + +def feed_search(term): + if term: + entries, __, ___ = calibre_db.get_search_results(term, config=config) + entries_count = len(entries) if len(entries) > 0 else 1 + pagination = Pagination(1, entries_count, entries_count) + return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination) + else: + return render_xml_template('feed.xml', searchterm="") + + + +def render_xml_template(*args, **kwargs): + # ToDo: return time in current timezone similar to %z + currtime = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S+00:00") + xml = render_template(current_time=currtime, instance=config.config_calibre_web_title, *args, **kwargs) + response = make_response(xml) + response.headers["Content-Type"] = "application/atom+xml; charset=utf-8" + return response + + +def render_xml_dataset(data_table, book_id): + off = request.args.get("offset") or 0 + entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0, + db.Books, + getattr(db.Books, data_table.__tablename__).any(data_table.id == book_id), + [db.Books.timestamp.desc()], + True, config.config_read_column) + return render_xml_template('feed.xml', entries=entries, pagination=pagination) + + +def render_element_index(database_column, linked_table, folder): + shift = 0 + off = int(request.args.get("offset") or 0) + entries = calibre_db.session.query(func.upper(func.substr(database_column, 1, 1)).label('id'), None, None) + # query = calibre_db.generate_linked_query(config.config_read_column, db.Books) + if linked_table is not None: + entries = entries.join(linked_table).join(db.Books) + entries = entries.filter(calibre_db.common_filters()).group_by(func.upper(func.substr(database_column, 1, 1))).all() + elements = [] + if off == 0: + elements.append({'id': "00", 'name': _("All")}) + shift = 1 + for entry in entries[ + off + shift - 1: + int(off + int(config.config_books_per_page) - shift)]: + elements.append({'id': entry.id, 'name': entry.id}) + pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, + len(entries) + 1) + return render_xml_template('feed.xml', + letterelements=elements, + folder=folder, + pagination=pagination) diff --git a/cps/pagination.py b/cps/pagination.py index 7a9bfb702..bda9f4c8c 100644 --- a/cps/pagination.py +++ b/cps/pagination.py @@ -57,10 +57,10 @@ class Pagination(object): def has_next(self): return self.page < self.pages - # right_edge: last right_edges count of all pages are shown as number, means, if 10 pages are paginated -> 9,10 shwn - # left_edge: first left_edges count of all pages are shown as number -> 1,2 shwn - # left_current: left_current count below current page are shown as number, means if current page 5 -> 3,4 shwn - # left_current: right_current count above current page are shown as number, means if current page 5 -> 6,7 shwn + # right_edge: last right_edges count of all pages are shown as number, means, if 10 pages are paginated -> 9,10 shown + # left_edge: first left_edges count of all pages are shown as number -> 1,2 shown + # left_current: left_current count below current page are shown as number, means if current page 5 -> 3,4 shown + # left_current: right_current count above current page are shown as number, means if current page 5 -> 6,7 shown def iter_pages(self, left_edge=2, left_current=2, right_current=4, right_edge=2): last = 0 diff --git a/cps/redirect.py b/cps/redirect.py index d491b353f..09b3101f8 100644 --- a/cps/redirect.py +++ b/cps/redirect.py @@ -25,12 +25,9 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# http://flask.pocoo.org/snippets/62/ +# https://web.archive.org/web/20120517003641/http://flask.pocoo.org/snippets/62/ -try: - from urllib.parse import urlparse, urljoin -except ImportError: - from urlparse import urlparse, urljoin +from urllib.parse import urlparse, urljoin from flask import request, url_for, redirect diff --git a/cps/remotelogin.py b/cps/remotelogin.py index a9994f09e..ee4346702 100644 --- a/cps/remotelogin.py +++ b/cps/remotelogin.py @@ -22,6 +22,7 @@ import json from datetime import datetime +from functools import wraps from flask import Blueprint, request, make_response, abort, url_for, flash, redirect from flask_login import login_required, current_user, login_user @@ -31,10 +32,6 @@ from sqlalchemy.sql.expression import true from . import config, logger, ub from .render_template import render_title_template -try: - from functools import wraps -except ImportError: - pass # We're not using Python 3 remotelogin = Blueprint('remotelogin', __name__) log = logger.create() @@ -61,8 +58,8 @@ def remote_login(): ub.session.add(auth_token) ub.session_commit() verify_url = url_for('remotelogin.verify_token', token=auth_token.auth_token, _external=true) - log.debug(u"Remot Login request with token: %s", auth_token.auth_token) - return render_title_template('remote_login.html', title=_(u"Login"), token=auth_token.auth_token, + log.debug("Remot Login request with token: %s", auth_token.auth_token) + return render_title_template('remote_login.html', title=_("Login"), token=auth_token.auth_token, verify_url=verify_url, page="remotelogin") @@ -74,8 +71,8 @@ def verify_token(token): # Token not found if auth_token is None: - flash(_(u"Token not found"), category="error") - log.error(u"Remote Login token not found") + flash(_("Token not found"), category="error") + log.error("Remote Login token not found") return redirect(url_for('web.index')) # Token expired @@ -83,8 +80,8 @@ def verify_token(token): ub.session.delete(auth_token) ub.session_commit() - flash(_(u"Token has expired"), category="error") - log.error(u"Remote Login token expired") + flash(_("Token has expired"), category="error") + log.error("Remote Login token expired") return redirect(url_for('web.index')) # Update token with user information @@ -92,8 +89,8 @@ def verify_token(token): auth_token.verified = True ub.session_commit() - flash(_(u"Success! Please return to your device"), category="success") - log.debug(u"Remote Login token for userid %s verified", auth_token.user_id) + flash(_("Success! Please return to your device"), category="success") + log.debug("Remote Login token for userid %s verified", auth_token.user_id) return redirect(url_for('web.index')) @@ -108,7 +105,7 @@ def token_verified(): # Token not found if auth_token is None: data['status'] = 'error' - data['message'] = _(u"Token not found") + data['message'] = _("Token not found") # Token expired elif datetime.now() > auth_token.expiration: @@ -116,7 +113,7 @@ def token_verified(): ub.session_commit() data['status'] = 'error' - data['message'] = _(u"Token has expired") + data['message'] = _("Token has expired") elif not auth_token.verified: data['status'] = 'not_verified' @@ -129,8 +126,8 @@ def token_verified(): ub.session_commit("User {} logged in via remotelogin, token deleted".format(user.name)) data['status'] = 'success' - log.debug(u"Remote Login for userid %s succeded", user.id) - flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.name), category="success") + log.debug("Remote Login for userid %s succeeded", user.id) + flash(_("Success! You are now logged in as: %(nickname)s", nickname=user.name), category="success") response = make_response(json.dumps(data, ensure_ascii=False)) response.headers["Content-Type"] = "application/json; charset=utf-8" diff --git a/cps/render_template.py b/cps/render_template.py index 7cd341ea0..68b464593 100644 --- a/cps/render_template.py +++ b/cps/render_template.py @@ -16,20 +16,23 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from flask import render_template +from flask import render_template, g, abort, request from flask_babel import gettext as _ -from flask import g from werkzeug.local import LocalProxy from flask_login import current_user +from sqlalchemy.sql.expression import or_ -from . import config, constants, ub, logger, db, calibre_db +from . import config, constants, logger, ub from .ub import User + log = logger.create() def get_sidebar_config(kwargs=None): kwargs = kwargs or [] + simple = bool([e for e in ['kindle', 'tolino', "kobo", "bookeen"] + if (e in request.headers.get('User-Agent', "").lower())]) if 'content' in kwargs: content = kwargs['content'] content = isinstance(content, (User, LocalProxy)) and not content.role_anonymous() @@ -44,12 +47,12 @@ def get_sidebar_config(kwargs=None): "show_text": _('Show Hot Books'), "config_show": True}) if current_user.role_admin(): sidebar.append({"glyph": "glyphicon-download", "text": _('Downloaded Books'), "link": 'web.download_list', - "id": "download", "visibility": constants.SIDEBAR_DOWNLOAD, 'public': (not g.user.is_anonymous), + "id": "download", "visibility": constants.SIDEBAR_DOWNLOAD, 'public': (not current_user.is_anonymous), "page": "download", "show_text": _('Show Downloaded Books'), "config_show": content}) else: sidebar.append({"glyph": "glyphicon-download", "text": _('Downloaded Books'), "link": 'web.books_list', - "id": "download", "visibility": constants.SIDEBAR_DOWNLOAD, 'public': (not g.user.is_anonymous), + "id": "download", "visibility": constants.SIDEBAR_DOWNLOAD, 'public': (not current_user.is_anonymous), "page": "download", "show_text": _('Show Downloaded Books'), "config_show": content}) sidebar.append( @@ -57,66 +60,60 @@ def get_sidebar_config(kwargs=None): "visibility": constants.SIDEBAR_BEST_RATED, 'public': True, "page": "rated", "show_text": _('Show Top Rated Books'), "config_show": True}) sidebar.append({"glyph": "glyphicon-eye-open", "text": _('Read Books'), "link": 'web.books_list', "id": "read", - "visibility": constants.SIDEBAR_READ_AND_UNREAD, 'public': (not g.user.is_anonymous), - "page": "read", "show_text": _('Show read and unread'), "config_show": content}) + "visibility": constants.SIDEBAR_READ_AND_UNREAD, 'public': (not current_user.is_anonymous), + "page": "read", "show_text": _('Show Read and Unread'), "config_show": content}) sidebar.append( {"glyph": "glyphicon-eye-close", "text": _('Unread Books'), "link": 'web.books_list', "id": "unread", - "visibility": constants.SIDEBAR_READ_AND_UNREAD, 'public': (not g.user.is_anonymous), "page": "unread", + "visibility": constants.SIDEBAR_READ_AND_UNREAD, 'public': (not current_user.is_anonymous), "page": "unread", "show_text": _('Show unread'), "config_show": False}) sidebar.append({"glyph": "glyphicon-random", "text": _('Discover'), "link": 'web.books_list', "id": "rand", "visibility": constants.SIDEBAR_RANDOM, 'public': True, "page": "discover", "show_text": _('Show Random Books'), "config_show": True}) sidebar.append({"glyph": "glyphicon-inbox", "text": _('Categories'), "link": 'web.category_list', "id": "cat", "visibility": constants.SIDEBAR_CATEGORY, 'public': True, "page": "category", - "show_text": _('Show category selection'), "config_show": True}) + "show_text": _('Show Category Section'), "config_show": True}) sidebar.append({"glyph": "glyphicon-bookmark", "text": _('Series'), "link": 'web.series_list', "id": "serie", "visibility": constants.SIDEBAR_SERIES, 'public': True, "page": "series", - "show_text": _('Show series selection'), "config_show": True}) + "show_text": _('Show Series Section'), "config_show": True}) sidebar.append({"glyph": "glyphicon-user", "text": _('Authors'), "link": 'web.author_list', "id": "author", "visibility": constants.SIDEBAR_AUTHOR, 'public': True, "page": "author", - "show_text": _('Show author selection'), "config_show": True}) + "show_text": _('Show Author Section'), "config_show": True}) sidebar.append( {"glyph": "glyphicon-text-size", "text": _('Publishers'), "link": 'web.publisher_list', "id": "publisher", "visibility": constants.SIDEBAR_PUBLISHER, 'public': True, "page": "publisher", - "show_text": _('Show publisher selection'), "config_show":True}) + "show_text": _('Show Publisher Section'), "config_show":True}) sidebar.append({"glyph": "glyphicon-flag", "text": _('Languages'), "link": 'web.language_overview', "id": "lang", - "visibility": constants.SIDEBAR_LANGUAGE, 'public': (g.user.filter_language() == 'all'), + "visibility": constants.SIDEBAR_LANGUAGE, 'public': (current_user.filter_language() == 'all'), "page": "language", - "show_text": _('Show language selection'), "config_show": True}) + "show_text": _('Show Language Section'), "config_show": True}) sidebar.append({"glyph": "glyphicon-star-empty", "text": _('Ratings'), "link": 'web.ratings_list', "id": "rate", "visibility": constants.SIDEBAR_RATING, 'public': True, - "page": "rating", "show_text": _('Show ratings selection'), "config_show": True}) + "page": "rating", "show_text": _('Show Ratings Section'), "config_show": True}) sidebar.append({"glyph": "glyphicon-file", "text": _('File formats'), "link": 'web.formats_list', "id": "format", "visibility": constants.SIDEBAR_FORMAT, 'public': True, - "page": "format", "show_text": _('Show file formats selection'), "config_show": True}) + "page": "format", "show_text": _('Show File Formats Section'), "config_show": True}) sidebar.append( {"glyph": "glyphicon-trash", "text": _('Archived Books'), "link": 'web.books_list', "id": "archived", - "visibility": constants.SIDEBAR_ARCHIVED, 'public': (not g.user.is_anonymous), "page": "archived", - "show_text": _('Show archived books'), "config_show": content}) - sidebar.append( - {"glyph": "glyphicon-th-list", "text": _('Books List'), "link": 'web.books_table', "id": "list", - "visibility": constants.SIDEBAR_LIST, 'public': (not g.user.is_anonymous), "page": "list", - "show_text": _('Show Books List'), "config_show": content}) + "visibility": constants.SIDEBAR_ARCHIVED, 'public': (not current_user.is_anonymous), "page": "archived", + "show_text": _('Show Archived Books'), "config_show": content}) + if not simple: + sidebar.append( + {"glyph": "glyphicon-th-list", "text": _('Books List'), "link": 'web.books_table', "id": "list", + "visibility": constants.SIDEBAR_LIST, 'public': (not current_user.is_anonymous), "page": "list", + "show_text": _('Show Books List'), "config_show": content}) + g.shelves_access = ub.session.query(ub.Shelf).filter( + or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == current_user.id)).order_by(ub.Shelf.name).all() - return sidebar + return sidebar, simple -def get_readbooks_ids(): - if not config.config_read_column: - readBooks = ub.session.query(ub.ReadBook).filter(ub.ReadBook.user_id == int(current_user.id))\ - .filter(ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED).all() - return frozenset([x.book_id for x in readBooks]) - else: - try: - readBooks = calibre_db.session.query(db.cc_classes[config.config_read_column])\ - .filter(db.cc_classes[config.config_read_column].value == True).all() - return frozenset([x.book for x in readBooks]) - except (KeyError, AttributeError): - log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column) - return [] # Returns the template for rendering and includes the instance name def render_title_template(*args, **kwargs): - sidebar = get_sidebar_config(kwargs) - return render_template(instance=config.config_calibre_web_title, sidebar=sidebar, - accept=constants.EXTENSIONS_UPLOAD, read_book_ids=get_readbooks_ids(), - *args, **kwargs) + sidebar, simple = get_sidebar_config(kwargs) + try: + return render_template(instance=config.config_calibre_web_title, sidebar=sidebar, simple=simple, + accept=constants.EXTENSIONS_UPLOAD, + *args, **kwargs) + except PermissionError: + log.error("No permission to access {} file.".format(args[0])) + abort(403) diff --git a/cps/schedule.py b/cps/schedule.py new file mode 100644 index 000000000..707e9bb3c --- /dev/null +++ b/cps/schedule.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2020 mmonkey +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import datetime + +from . import config, constants +from .services.background_scheduler import BackgroundScheduler, CronTrigger, use_APScheduler +from .tasks.database import TaskReconnectDatabase +from .tasks.thumbnail import TaskGenerateCoverThumbnails, TaskGenerateSeriesThumbnails, TaskClearCoverThumbnailCache +from .services.worker import WorkerThread +from .tasks.metadata_backup import TaskBackupMetadata + +def get_scheduled_tasks(reconnect=True): + tasks = list() + # config.schedule_reconnect or + # Reconnect Calibre database (metadata.db) + if reconnect: + tasks.append([lambda: TaskReconnectDatabase(), 'reconnect', False]) + + # ToDo make configurable. Generate metadata.opf file for each changed book + if False: + tasks.append([lambda: TaskBackupMetadata("en"), 'backup metadata', False]) + + # Generate all missing book cover thumbnails + if config.schedule_generate_book_covers: + tasks.append([lambda: TaskClearCoverThumbnailCache(0), 'delete superfluous book covers', True]) + tasks.append([lambda: TaskGenerateCoverThumbnails(), 'generate book covers', False]) + + # Generate all missing series thumbnails + if config.schedule_generate_series_covers: + tasks.append([lambda: TaskGenerateSeriesThumbnails(), 'generate book covers', False]) + + return tasks + + +def end_scheduled_tasks(): + worker = WorkerThread.get_instance() + for __, __, __, task, __ in worker.tasks: + if task.scheduled and task.is_cancellable: + worker.end_task(task.id) + + +def register_scheduled_tasks(reconnect=True): + scheduler = BackgroundScheduler() + + if scheduler: + # Remove all existing jobs + scheduler.remove_all_jobs() + + start = config.schedule_start_time + duration = config.schedule_duration + + # Register scheduled tasks + scheduler.schedule_tasks(tasks=get_scheduled_tasks(reconnect), trigger=CronTrigger(hour=start)) + end_time = calclulate_end_time(start, duration) + scheduler.schedule(func=end_scheduled_tasks, trigger=CronTrigger(hour=end_time.hour, minute=end_time.minute), + name="end scheduled task") + + # Kick-off tasks, if they should currently be running + if should_task_be_running(start, duration): + scheduler.schedule_tasks_immediately(tasks=get_scheduled_tasks(reconnect)) + + +def register_startup_tasks(): + scheduler = BackgroundScheduler() + + if scheduler: + start = config.schedule_start_time + duration = config.schedule_duration + + # Run scheduled tasks immediately for development and testing + # Ignore tasks that should currently be running, as these will be added when registering scheduled tasks + if constants.APP_MODE in ['development', 'test'] and not should_task_be_running(start, duration): + scheduler.schedule_tasks_immediately(tasks=get_scheduled_tasks(False)) + + +def should_task_be_running(start, duration): + now = datetime.datetime.now() + start_time = datetime.datetime.now().replace(hour=start, minute=0, second=0, microsecond=0) + end_time = start_time + datetime.timedelta(hours=duration // 60, minutes=duration % 60) + return start_time < now < end_time + + +def calclulate_end_time(start, duration): + start_time = datetime.datetime.now().replace(hour=start, minute=0) + return start_time + datetime.timedelta(hours=duration // 60, minutes=duration % 60) + diff --git a/cps/search.py b/cps/search.py new file mode 100644 index 000000000..96f21d62c --- /dev/null +++ b/cps/search.py @@ -0,0 +1,397 @@ +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2022 OzzieIsaacs +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import json +from datetime import datetime + +from flask import Blueprint, request, redirect, url_for, flash +from flask import session as flask_session +from flask_login import current_user +from flask_babel import format_date +from flask_babel import gettext as _ +from sqlalchemy.sql.expression import func, not_, and_, or_, text, true +from sqlalchemy.sql.functions import coalesce + +from . import logger, db, calibre_db, config, ub +from .usermanagement import login_required_if_no_ano +from .render_template import render_title_template +from .pagination import Pagination + +search = Blueprint('search', __name__) + +log = logger.create() + + +@search.route("/search", methods=["POST"]) +@login_required_if_no_ano +def simple_search(): + term = dict(request.form).get("query") + if term: + flask_session['query'] = json.dumps(term.strip()) + return redirect(url_for('web.books_list', data="search", sort_param='stored', query="")) # term.strip() + else: + return render_title_template('search.html', + searchterm="", + result_count=0, + title=_("Search"), + page="search") + + +@search.route("/advsearch", methods=['POST']) +@login_required_if_no_ano +def advanced_search(): + values = dict(request.form) + params = ['include_tag', 'exclude_tag', 'include_serie', 'exclude_serie', 'include_shelf', 'exclude_shelf', + 'include_language', 'exclude_language', 'include_extension', 'exclude_extension'] + for param in params: + values[param] = list(request.form.getlist(param)) + flask_session['query'] = json.dumps(values) + return redirect(url_for('web.books_list', data="advsearch", sort_param='stored', query="")) + + +@search.route("/advsearch", methods=['GET']) +@login_required_if_no_ano +def advanced_search_form(): + # Build custom columns names + cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True) + return render_prepare_search_form(cc) + + +def adv_search_custom_columns(cc, term, q): + for c in cc: + if c.datatype == "datetime": + custom_start = term.get('custom_column_' + str(c.id) + '_start') + custom_end = term.get('custom_column_' + str(c.id) + '_end') + if custom_start: + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + func.datetime(db.cc_classes[c.id].value) >= func.datetime(custom_start))) + if custom_end: + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + func.datetime(db.cc_classes[c.id].value) <= func.datetime(custom_end))) + else: + custom_query = term.get('custom_column_' + str(c.id)) + if custom_query != '' and custom_query is not None: + if c.datatype == 'bool': + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + db.cc_classes[c.id].value == (custom_query == "True"))) + elif c.datatype == 'int' or c.datatype == 'float': + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + db.cc_classes[c.id].value == custom_query)) + elif c.datatype == 'rating': + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + db.cc_classes[c.id].value == int(float(custom_query) * 2))) + else: + q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( + func.lower(db.cc_classes[c.id].value).ilike("%" + custom_query + "%"))) + return q + + +def adv_search_language(q, include_languages_inputs, exclude_languages_inputs): + if current_user.filter_language() != "all": + q = q.filter(db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())) + else: + for language in include_languages_inputs: + q = q.filter(db.Books.languages.any(db.Languages.id == language)) + for language in exclude_languages_inputs: + q = q.filter(not_(db.Books.series.any(db.Languages.id == language))) + return q + + +def adv_search_ratings(q, rating_high, rating_low): + if rating_high: + rating_high = int(rating_high) * 2 + q = q.filter(db.Books.ratings.any(db.Ratings.rating <= rating_high)) + if rating_low: + rating_low = int(rating_low) * 2 + q = q.filter(db.Books.ratings.any(db.Ratings.rating >= rating_low)) + return q + + +def adv_search_read_status(read_status): + if not config.config_read_column: + if read_status == "True": + db_filter = and_(ub.ReadBook.user_id == int(current_user.id), + ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED) + else: + db_filter = coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED + else: + try: + if read_status == "True": + db_filter = db.cc_classes[config.config_read_column].value == True + else: + db_filter = coalesce(db.cc_classes[config.config_read_column].value, False) != True + except (KeyError, AttributeError, IndexError): + log.error("Custom Column No.{} does not exist in calibre database".format(config.config_read_column)) + flash(_("Custom Column No.%(column)d does not exist in calibre database", + column=config.config_read_column), + category="error") + return true() + return db_filter + + +def adv_search_extension(q, include_extension_inputs, exclude_extension_inputs): + for extension in include_extension_inputs: + q = q.filter(db.Books.data.any(db.Data.format == extension)) + for extension in exclude_extension_inputs: + q = q.filter(not_(db.Books.data.any(db.Data.format == extension))) + return q + + +def adv_search_tag(q, include_tag_inputs, exclude_tag_inputs): + for tag in include_tag_inputs: + q = q.filter(db.Books.tags.any(db.Tags.id == tag)) + for tag in exclude_tag_inputs: + q = q.filter(not_(db.Books.tags.any(db.Tags.id == tag))) + return q + + +def adv_search_serie(q, include_series_inputs, exclude_series_inputs): + for serie in include_series_inputs: + q = q.filter(db.Books.series.any(db.Series.id == serie)) + for serie in exclude_series_inputs: + q = q.filter(not_(db.Books.series.any(db.Series.id == serie))) + return q + +def adv_search_shelf(q, include_shelf_inputs, exclude_shelf_inputs): + q = q.outerjoin(ub.BookShelf, db.Books.id == ub.BookShelf.book_id)\ + .filter(or_(ub.BookShelf.shelf == None, ub.BookShelf.shelf.notin_(exclude_shelf_inputs))) + if len(include_shelf_inputs) > 0: + q = q.filter(ub.BookShelf.shelf.in_(include_shelf_inputs)) + return q + +def extend_search_term(searchterm, + author_name, + book_title, + publisher, + pub_start, + pub_end, + tags, + rating_high, + rating_low, + read_status, + ): + searchterm.extend((author_name.replace('|', ','), book_title, publisher)) + if pub_start: + try: + searchterm.extend([_("Published after ") + + format_date(datetime.strptime(pub_start, "%Y-%m-%d"), + format='medium')]) + except ValueError: + pub_start = "" + if pub_end: + try: + searchterm.extend([_("Published before ") + + format_date(datetime.strptime(pub_end, "%Y-%m-%d"), + format='medium')]) + except ValueError: + pub_end = "" + elements = {'tag': db.Tags, 'serie':db.Series, 'shelf':ub.Shelf} + for key, db_element in elements.items(): + tag_names = calibre_db.session.query(db_element).filter(db_element.id.in_(tags['include_' + key])).all() + searchterm.extend(tag.name for tag in tag_names) + tag_names = calibre_db.session.query(db_element).filter(db_element.id.in_(tags['exclude_' + key])).all() + searchterm.extend(tag.name for tag in tag_names) + language_names = calibre_db.session.query(db.Languages). \ + filter(db.Languages.id.in_(tags['include_language'])).all() + if language_names: + language_names = calibre_db.speaking_language(language_names) + searchterm.extend(language.name for language in language_names) + language_names = calibre_db.session.query(db.Languages). \ + filter(db.Languages.id.in_(tags['exclude_language'])).all() + if language_names: + language_names = calibre_db.speaking_language(language_names) + searchterm.extend(language.name for language in language_names) + if rating_high: + searchterm.extend([_("Rating <= %(rating)s", rating=rating_high)]) + if rating_low: + searchterm.extend([_("Rating >= %(rating)s", rating=rating_low)]) + if read_status: + searchterm.extend([_("Read Status = %(status)s", status=read_status)]) + searchterm.extend(ext for ext in tags['include_extension']) + searchterm.extend(ext for ext in tags['exclude_extension']) + # handle custom columns + searchterm = " + ".join(filter(None, searchterm)) + return searchterm, pub_start, pub_end + + +def render_adv_search_results(term, offset=None, order=None, limit=None): + sort = order[0] if order else [db.Books.sort] + pagination = None + + cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True) + calibre_db.session.connection().connection.connection.create_function("lower", 1, db.lcase) + query = calibre_db.generate_linked_query(config.config_read_column, db.Books) + q = query.outerjoin(db.books_series_link, db.Books.id == db.books_series_link.c.book)\ + .outerjoin(db.Series)\ + .filter(calibre_db.common_filters(True)) + + # parse multi selects to a complete dict + tags = dict() + elements = ['tag', 'serie', 'shelf', 'language', 'extension'] + for element in elements: + tags['include_' + element] = term.get('include_' + element) + tags['exclude_' + element] = term.get('exclude_' + element) + + author_name = term.get("author_name") + book_title = term.get("book_title") + publisher = term.get("publisher") + pub_start = term.get("publishstart") + pub_end = term.get("publishend") + rating_low = term.get("ratinghigh") + rating_high = term.get("ratinglow") + description = term.get("comment") + read_status = term.get("read_status") + if author_name: + author_name = author_name.strip().lower().replace(',', '|') + if book_title: + book_title = book_title.strip().lower() + if publisher: + publisher = publisher.strip().lower() + + search_term = [] + cc_present = False + for c in cc: + if c.datatype == "datetime": + column_start = term.get('custom_column_' + str(c.id) + '_start') + column_end = term.get('custom_column_' + str(c.id) + '_end') + if column_start: + search_term.extend(["{} >= {}".format(c.name, + format_date(datetime.strptime(column_start, "%Y-%m-%d").date(), + format='medium') + )]) + cc_present = True + if column_end: + search_term.extend(["{} <= {}".format(c.name, + format_date(datetime.strptime(column_end, "%Y-%m-%d").date(), + format='medium') + )]) + cc_present = True + elif term.get('custom_column_' + str(c.id)): + search_term.extend([("{}: {}".format(c.name, term.get('custom_column_' + str(c.id))))]) + cc_present = True + + if any(tags.values()) or author_name or book_title or publisher or pub_start or pub_end or rating_low \ + or rating_high or description or cc_present or read_status: + search_term, pub_start, pub_end = extend_search_term(search_term, + author_name, + book_title, + publisher, + pub_start, + pub_end, + tags, + rating_high, + rating_low, + read_status) + if author_name: + q = q.filter(db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + author_name + "%"))) + if book_title: + q = q.filter(func.lower(db.Books.title).ilike("%" + book_title + "%")) + if pub_start: + q = q.filter(func.datetime(db.Books.pubdate) > func.datetime(pub_start)) + if pub_end: + q = q.filter(func.datetime(db.Books.pubdate) < func.datetime(pub_end)) + q = q.filter(adv_search_read_status(read_status)) + if publisher: + q = q.filter(db.Books.publishers.any(func.lower(db.Publishers.name).ilike("%" + publisher + "%"))) + q = adv_search_tag(q, tags['include_tag'], tags['exclude_tag']) + q = adv_search_serie(q, tags['include_serie'], tags['exclude_serie']) + q = adv_search_shelf(q, tags['include_shelf'], tags['exclude_shelf']) + q = adv_search_extension(q, tags['include_extension'], tags['exclude_extension']) + q = adv_search_language(q, tags['include_language'], tags['exclude_language']) + q = adv_search_ratings(q, rating_high, rating_low) + + if description: + q = q.filter(db.Books.comments.any(func.lower(db.Comments.text).ilike("%" + description + "%"))) + + # search custom columns + try: + q = adv_search_custom_columns(cc, term, q) + except AttributeError as ex: + log.debug_or_exception(ex) + flash(_("Error on search for custom columns, please restart Calibre-Web"), category="error") + + q = q.order_by(*sort).all() + flask_session['query'] = json.dumps(term) + ub.store_combo_ids(q) + result_count = len(q) + if offset is not None and limit is not None: + offset = int(offset) + limit_all = offset + int(limit) + pagination = Pagination((offset / (int(limit)) + 1), limit, result_count) + else: + offset = 0 + limit_all = result_count + entries = calibre_db.order_authors(q[offset:limit_all], list_return=True, combined=True) + return render_title_template('search.html', + adv_searchterm=search_term, + pagination=pagination, + entries=entries, + result_count=result_count, + title=_("Advanced Search"), page="advsearch", + order=order[1]) + + +def render_prepare_search_form(cc): + # prepare data for search-form + tags = calibre_db.session.query(db.Tags)\ + .join(db.books_tags_link)\ + .join(db.Books)\ + .filter(calibre_db.common_filters()) \ + .group_by(text('books_tags_link.tag'))\ + .order_by(db.Tags.name).all() + series = calibre_db.session.query(db.Series)\ + .join(db.books_series_link)\ + .join(db.Books)\ + .filter(calibre_db.common_filters()) \ + .group_by(text('books_series_link.series'))\ + .order_by(db.Series.name)\ + .filter(calibre_db.common_filters()).all() + shelves = ub.session.query(ub.Shelf)\ + .filter(or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == int(current_user.id)))\ + .order_by(ub.Shelf.name).all() + extensions = calibre_db.session.query(db.Data)\ + .join(db.Books)\ + .filter(calibre_db.common_filters()) \ + .group_by(db.Data.format)\ + .order_by(db.Data.format).all() + if current_user.filter_language() == "all": + languages = calibre_db.speaking_language() + else: + languages = None + return render_title_template('search_form.html', tags=tags, languages=languages, extensions=extensions, + series=series,shelves=shelves, title=_("Advanced Search"), cc=cc, page="advsearch") + + +def render_search_results(term, offset=None, order=None, limit=None): + join = db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series + entries, result_count, pagination = calibre_db.get_search_results(term, + config, + offset, + order, + limit, + *join) + return render_title_template('search.html', + searchterm=term, + pagination=pagination, + query=term, + adv_searchterm=term, + entries=entries, + result_count=result_count, + title=_("Search"), + page="search", + order=order[1]) + + diff --git a/cps/search_metadata.py b/cps/search_metadata.py index e837fe21a..e018da326 100644 --- a/cps/search_metadata.py +++ b/cps/search_metadata.py @@ -16,69 +16,91 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import os -import json -import importlib -import sys -import inspect -import datetime import concurrent.futures +import importlib +import inspect +import json +import os +import sys -from flask import Blueprint, request, Response, url_for +from flask import Blueprint, Response, request, url_for from flask_login import current_user from flask_login import login_required +from flask_babel import get_locale +from sqlalchemy.exc import InvalidRequestError, OperationalError from sqlalchemy.orm.attributes import flag_modified -from sqlalchemy.exc import OperationalError, InvalidRequestError -from . import constants, logger, ub from cps.services.Metadata import Metadata +from . import constants, logger, ub, web_server +# current_milli_time = lambda: int(round(time() * 1000)) -meta = Blueprint('metadata', __name__) +meta = Blueprint("metadata", __name__) log = logger.create() +try: + from dataclasses import asdict +except ImportError: + log.info('*** "dataclasses" is needed for calibre-web to run. Please install it using pip: "pip install dataclasses" ***') + print('*** "dataclasses" is needed for calibre-web to run. Please install it using pip: "pip install dataclasses" ***') + web_server.stop(True) + sys.exit(6) + new_list = list() meta_dir = os.path.join(constants.BASE_DIR, "cps", "metadata_provider") modules = os.listdir(os.path.join(constants.BASE_DIR, "cps", "metadata_provider")) for f in modules: - if os.path.isfile(os.path.join(meta_dir, f)) and not f.endswith('__init__.py'): + if os.path.isfile(os.path.join(meta_dir, f)) and not f.endswith("__init__.py"): a = os.path.basename(f)[:-3] try: importlib.import_module("cps.metadata_provider." + a) new_list.append(a) - except ImportError: - log.error("Import error for metadata source: {}".format(a)) - pass + except (IndentationError, SyntaxError) as e: + log.error("Syntax error for metadata source: {} - {}".format(a, e)) + except ImportError as e: + log.debug("Import error for metadata source: {} - {}".format(a, e)) + def list_classes(provider_list): classes = list() for element in provider_list: - for name, obj in inspect.getmembers(sys.modules["cps.metadata_provider." + element]): - if inspect.isclass(obj) and name != "Metadata" and issubclass(obj, Metadata): + for name, obj in inspect.getmembers( + sys.modules["cps.metadata_provider." + element] + ): + if ( + inspect.isclass(obj) + and name != "Metadata" + and issubclass(obj, Metadata) + ): classes.append(obj()) return classes + cl = list_classes(new_list) + @meta.route("/metadata/provider") @login_required def metadata_provider(): - active = current_user.view_settings.get('metadata', {}) + active = current_user.view_settings.get("metadata", {}) provider = list() for c in cl: ac = active.get(c.__id__, True) - provider.append({"name": c.__name__, "active": ac, "initial": ac, "id": c.__id__}) - return Response(json.dumps(provider), mimetype='application/json') + provider.append( + {"name": c.__name__, "active": ac, "initial": ac, "id": c.__id__} + ) + return Response(json.dumps(provider), mimetype="application/json") -@meta.route("/metadata/provider", methods=['POST']) -@meta.route("/metadata/provider/", methods=['POST']) + +@meta.route("/metadata/provider", methods=["POST"]) +@meta.route("/metadata/provider/", methods=["POST"]) @login_required def metadata_change_active_provider(prov_name): new_state = request.get_json() - active = current_user.view_settings.get('metadata', {}) - active[new_state['id']] = new_state['value'] - current_user.view_settings['metadata'] = active + active = current_user.view_settings.get("metadata", {}) + active[new_state["id"]] = new_state["value"] + current_user.view_settings["metadata"] = active try: try: flag_modified(current_user, "view_settings") @@ -89,29 +111,33 @@ def metadata_change_active_provider(prov_name): log.error("Invalid request received: {}".format(request)) return "Invalid request", 400 if "initial" in new_state and prov_name: - for c in cl: - if c.__id__ == prov_name: - data = c.search(new_state.get('query', "")) - break - return Response(json.dumps(data), mimetype='application/json') + data = [] + provider = next((c for c in cl if c.__id__ == prov_name), None) + if provider is not None: + data = provider.search(new_state.get("query", "")) + return Response( + json.dumps([asdict(x) for x in data]), mimetype="application/json" + ) return "" -@meta.route("/metadata/search", methods=['POST']) + +@meta.route("/metadata/search", methods=["POST"]) @login_required def metadata_search(): - query = request.form.to_dict().get('query') + query = request.form.to_dict().get("query") data = list() - active = current_user.view_settings.get('metadata', {}) + active = current_user.view_settings.get("metadata", {}) + locale = get_locale() if query: - static_cover = url_for('static', filename='generic_cover.jpg') + static_cover = url_for("static", filename="generic_cover.jpg") + # start = current_milli_time() with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: - meta = {executor.submit(c.search, query, static_cover): c for c in cl if active.get(c.__id__, True)} + meta = { + executor.submit(c.search, query, static_cover, locale): c + for c in cl + if active.get(c.__id__, True) + } for future in concurrent.futures.as_completed(meta): - data.extend(future.result()) - return Response(json.dumps(data), mimetype='application/json') - - - - - - + data.extend([asdict(x) for x in future.result() if x]) + # log.info({'Time elapsed {}'.format(current_milli_time()-start)}) + return Response(json.dumps(data), mimetype="application/json") diff --git a/cps/server.py b/cps/server.py index e261c50a2..6b5ac7610 100644 --- a/cps/server.py +++ b/cps/server.py @@ -22,9 +22,11 @@ import errno import signal import socket import subprocess # nosec +from .services.background_scheduler import BackgroundScheduler try: from gevent.pywsgi import WSGIServer + from .gevent_wsgi import MyWSGIHandler from gevent.pool import Pool from gevent import __version__ as _version from greenlet import GreenletExit @@ -32,7 +34,7 @@ try: VERSION = 'Gevent ' + _version _GEVENT = True except ImportError: - from tornado.wsgi import WSGIContainer + from .tornado_wsgi import MyWSGIContainer from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop from tornado import version as _version @@ -202,7 +204,9 @@ class WebServer(object): if output is None: output = _readable_listen_address(self.listen_address, self.listen_port) log.info('Starting Gevent server on %s', output) - self.wsgiserver = WSGIServer(sock, self.app, log=self.access_logger, spawn=Pool(), **ssl_args) + self.wsgiserver = WSGIServer(sock, self.app, log=self.access_logger, handler_class=MyWSGIHandler, + error_log=log, + spawn=Pool(), **ssl_args) if ssl_args: wrap_socket = self.wsgiserver.wrap_socket def my_wrap_socket(*args, **kwargs): @@ -225,8 +229,8 @@ class WebServer(object): asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) log.info('Starting Tornado server on %s', _readable_listen_address(self.listen_address, self.listen_port)) - # Max Buffersize set to 200MB ) - http_server = HTTPServer(WSGIContainer(self.app), + # Max Buffersize set to 200MB + http_server = HTTPServer(MyWSGIContainer(self.app), max_buffer_size=209700000, ssl_options=self.ssl_args) http_server.listen(self.listen_port, self.listen_address) @@ -262,6 +266,12 @@ class WebServer(object): subprocess.call(args, close_fds=True) # nosec return True + @staticmethod + def shutdown_scheduler(): + scheduler = BackgroundScheduler() + if scheduler: + scheduler.scheduler.shutdown() + def _killServer(self, __, ___): self.stop() @@ -270,6 +280,7 @@ class WebServer(object): updater_thread.stop() log.info("webserver stop (restart=%s)", restart) + self.shutdown_scheduler() self.restart = restart if self.wsgiserver: if _GEVENT: diff --git a/cps/services/Metadata.py b/cps/services/Metadata.py index d6e4e7d53..ab4fd4823 100644 --- a/cps/services/Metadata.py +++ b/cps/services/Metadata.py @@ -15,13 +15,97 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import abc +import dataclasses +import os +import re +from typing import Dict, Generator, List, Optional, Union + +from cps import constants -class Metadata(): +@dataclasses.dataclass +class MetaSourceInfo: + id: str + description: str + link: str + + +@dataclasses.dataclass +class MetaRecord: + id: Union[str, int] + title: str + authors: List[str] + url: str + source: MetaSourceInfo + cover: str = os.path.join(constants.STATIC_DIR, 'generic_cover.jpg') + description: Optional[str] = "" + series: Optional[str] = None + series_index: Optional[Union[int, float]] = 0 + identifiers: Dict[str, Union[str, int]] = dataclasses.field(default_factory=dict) + publisher: Optional[str] = None + publishedDate: Optional[str] = None + rating: Optional[int] = 0 + languages: Optional[List[str]] = dataclasses.field(default_factory=list) + tags: Optional[List[str]] = dataclasses.field(default_factory=list) + + +class Metadata: __name__ = "Generic" + __id__ = "generic" def __init__(self): self.active = True def set_status(self, state): self.active = state + + @abc.abstractmethod + def search( + self, query: str, generic_cover: str = "", locale: str = "en" + ) -> Optional[List[MetaRecord]]: + pass + + @staticmethod + def get_title_tokens( + title: str, strip_joiners: bool = True + ) -> Generator[str, None, None]: + """ + Taken from calibre source code + It's a simplified (cut out what is unnecessary) version of + https://github.com/kovidgoyal/calibre/blob/99d85b97918625d172227c8ffb7e0c71794966c0/ + src/calibre/ebooks/metadata/sources/base.py#L363-L367 + (src/calibre/ebooks/metadata/sources/base.py - lines 363-398) + """ + title_patterns = [ + (re.compile(pat, re.IGNORECASE), repl) + for pat, repl in [ + # Remove things like: (2010) (Omnibus) etc. + ( + r"(?i)[({\[](\d{4}|omnibus|anthology|hardcover|" + r"audiobook|audio\scd|paperback|turtleback|" + r"mass\s*market|edition|ed\.)[\])}]", + "", + ), + # Remove any strings that contain the substring edition inside + # parentheses + (r"(?i)[({\[].*?(edition|ed.).*?[\]})]", ""), + # Remove commas used a separators in numbers + (r"(\d+),(\d+)", r"\1\2"), + # Remove hyphens only if they have whitespace before them + (r"(\s-)", " "), + # Replace other special chars with a space + (r"""[:,;!@$%^&*(){}.`~"\s\[\]/]《》「」“”""", " "), + ] + ] + + for pat, repl in title_patterns: + title = pat.sub(repl, title) + + tokens = title.split() + for token in tokens: + token = token.strip().strip('"').strip("'") + if token and ( + not strip_joiners or token.lower() not in ("a", "and", "the", "&") + ): + yield token diff --git a/cps/services/SyncToken.py b/cps/services/SyncToken.py index 692aaa240..a53d7a99b 100644 --- a/cps/services/SyncToken.py +++ b/cps/services/SyncToken.py @@ -21,11 +21,8 @@ import sys from base64 import b64decode, b64encode from jsonschema import validate, exceptions, __version__ from datetime import datetime -try: - # pylint: disable=unused-import - from urllib import unquote -except ImportError: - from urllib.parse import unquote + +from urllib.parse import unquote from flask import json from .. import logger @@ -138,12 +135,9 @@ class SyncToken: archive_last_modified = get_datetime_from_json(data_json, "archive_last_modified") reading_state_last_modified = get_datetime_from_json(data_json, "reading_state_last_modified") tags_last_modified = get_datetime_from_json(data_json, "tags_last_modified") - # books_last_id = data_json["books_last_id"] except TypeError: log.error("SyncToken timestamps don't parse to a datetime.") return SyncToken(raw_kobo_store_token=raw_kobo_store_token) - #except KeyError: - # books_last_id = -1 return SyncToken( raw_kobo_store_token=raw_kobo_store_token, @@ -152,7 +146,6 @@ class SyncToken: archive_last_modified=archive_last_modified, reading_state_last_modified=reading_state_last_modified, tags_last_modified=tags_last_modified, - #books_last_id=books_last_id ) def set_kobo_store_header(self, store_headers): @@ -176,16 +169,14 @@ class SyncToken: "archive_last_modified": to_epoch_timestamp(self.archive_last_modified), "reading_state_last_modified": to_epoch_timestamp(self.reading_state_last_modified), "tags_last_modified": to_epoch_timestamp(self.tags_last_modified), - #"books_last_id":self.books_last_id }, } return b64encode_json(token) def __str__(self): - return "{},{},{},{},{},{}".format(self.raw_kobo_store_token, - self.books_last_created, + return "{},{},{},{},{},{}".format(self.books_last_created, self.books_last_modified, self.archive_last_modified, self.reading_state_last_modified, - self.tags_last_modified) - #self.books_last_id) + self.tags_last_modified, + self.raw_kobo_store_token) diff --git a/cps/services/__init__.py b/cps/services/__init__.py index 32a9d485d..f93eca340 100644 --- a/cps/services/__init__.py +++ b/cps/services/__init__.py @@ -18,11 +18,10 @@ from .. import logger - log = logger.create() - -try: from . import goodreads_support +try: + from . import goodreads_support except ImportError as err: log.debug("Cannot import goodreads, showing authors-metadata will not work: %s", err) goodreads_support = None diff --git a/cps/services/background_scheduler.py b/cps/services/background_scheduler.py new file mode 100644 index 000000000..729915597 --- /dev/null +++ b/cps/services/background_scheduler.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2020 mmonkey +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import atexit + +from .. import logger +from .worker import WorkerThread + +try: + from apscheduler.schedulers.background import BackgroundScheduler as BScheduler + from apscheduler.triggers.cron import CronTrigger + from apscheduler.triggers.date import DateTrigger + use_APScheduler = True +except (ImportError, RuntimeError) as e: + use_APScheduler = False + log = logger.create() + log.info('APScheduler not found. Unable to schedule tasks.') + + +class BackgroundScheduler: + _instance = None + + def __new__(cls): + if not use_APScheduler: + return False + + if cls._instance is None: + cls._instance = super(BackgroundScheduler, cls).__new__(cls) + cls.log = logger.create() + cls.scheduler = BScheduler() + cls.scheduler.start() + + return cls._instance + + def schedule(self, func, trigger, name=None): + if use_APScheduler: + return self.scheduler.add_job(func=func, trigger=trigger, name=name) + + # Expects a lambda expression for the task + def schedule_task(self, task, user=None, name=None, hidden=False, trigger=None): + if use_APScheduler: + def scheduled_task(): + worker_task = task() + worker_task.scheduled = True + WorkerThread.add(user, worker_task, hidden=hidden) + return self.schedule(func=scheduled_task, trigger=trigger, name=name) + + # Expects a list of lambda expressions for the tasks + def schedule_tasks(self, tasks, user=None, trigger=None): + if use_APScheduler: + for task in tasks: + self.schedule_task(task[0], user=user, trigger=trigger, name=task[1], hidden=task[2]) + + # Expects a lambda expression for the task + def schedule_task_immediately(self, task, user=None, name=None, hidden=False): + if use_APScheduler: + def immediate_task(): + WorkerThread.add(user, task(), hidden) + return self.schedule(func=immediate_task, trigger=DateTrigger(), name=name) + + # Expects a list of lambda expressions for the tasks + def schedule_tasks_immediately(self, tasks, user=None): + if use_APScheduler: + for task in tasks: + self.schedule_task_immediately(task[0], user, name="immediately " + task[1], hidden=task[2]) + + # Remove all jobs + def remove_all_jobs(self): + self.scheduler.remove_all_jobs() diff --git a/cps/services/gmail.py b/cps/services/gmail.py index ff36b3084..3a4eab7f9 100644 --- a/cps/services/gmail.py +++ b/cps/services/gmail.py @@ -25,7 +25,7 @@ from google.oauth2.credentials import Credentials from datetime import datetime import base64 from flask_babel import gettext as _ -from ..constants import BASE_DIR +from ..constants import CONFIG_DIR from .. import logger @@ -53,11 +53,11 @@ def setup_gmail(token): if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: - cred_file = os.path.join(BASE_DIR, 'gmail.json') + cred_file = os.path.join(CONFIG_DIR, 'gmail.json') if not os.path.exists(cred_file): raise Exception(_("Found no valid gmail.json file with OAuth information")) flow = InstalledAppFlow.from_client_secrets_file( - os.path.join(BASE_DIR, 'gmail.json'), SCOPES) + os.path.join(CONFIG_DIR, 'gmail.json'), SCOPES) creds = flow.run_local_server(port=0) user_info = get_user_info(creds) return { diff --git a/cps/services/worker.py b/cps/services/worker.py index 5952c7057..63d83bfb3 100644 --- a/cps/services/worker.py +++ b/cps/services/worker.py @@ -37,11 +37,13 @@ STAT_WAITING = 0 STAT_FAIL = 1 STAT_STARTED = 2 STAT_FINISH_SUCCESS = 3 +STAT_ENDED = 4 +STAT_CANCELLED = 5 # Only retain this many tasks in dequeued list TASK_CLEANUP_TRIGGER = 20 -QueuedTask = namedtuple('QueuedTask', 'num, user, added, task') +QueuedTask = namedtuple('QueuedTask', 'num, user, added, task, hidden') def _get_main_thread(): @@ -51,7 +53,6 @@ def _get_main_thread(): raise Exception("main thread not found?!") - class ImprovedQueue(queue.Queue): def to_list(self): """ @@ -61,12 +62,13 @@ class ImprovedQueue(queue.Queue): with self.mutex: return list(self.queue) + # Class for all worker tasks in the background class WorkerThread(threading.Thread): _instance = None @classmethod - def getInstance(cls): + def get_instance(cls): if cls._instance is None: cls._instance = WorkerThread() return cls._instance @@ -82,15 +84,17 @@ class WorkerThread(threading.Thread): self.start() @classmethod - def add(cls, user, task): - ins = cls.getInstance() + def add(cls, user, task, hidden=False): + ins = cls.get_instance() ins.num += 1 - log.debug("Add Task for user: {}: {}".format(user, task)) + username = user if user is not None else 'System' + log.debug("Add Task for user: {} - {}".format(username, task)) ins.queue.put(QueuedTask( num=ins.num, - user=user, + user=username, added=datetime.now(), task=task, + hidden=hidden )) @property @@ -111,10 +115,10 @@ class WorkerThread(threading.Thread): if delta > TASK_CLEANUP_TRIGGER: ret = alive else: - # otherwise, lop off the oldest dead tasks until we hit the target trigger - ret = sorted(dead, key=lambda x: x.task.end_time)[-TASK_CLEANUP_TRIGGER:] + alive + # otherwise, loop off the oldest dead tasks until we hit the target trigger + ret = sorted(dead, key=lambda y: y.task.end_time)[-TASK_CLEANUP_TRIGGER:] + alive - self.dequeued = sorted(ret, key=lambda x: x.num) + self.dequeued = sorted(ret, key=lambda y: y.num) # Main thread loop starting the different tasks def run(self): @@ -141,11 +145,21 @@ class WorkerThread(threading.Thread): # sometimes tasks (like Upload) don't actually have work to do and are created as already finished if item.task.stat is STAT_WAITING: - # CalibreTask.start() should wrap all exceptions in it's own error handling + # CalibreTask.start() should wrap all exceptions in its own error handling item.task.start(self) + # remove self_cleanup tasks and hidden "System Tasks" from list + if item.task.self_cleanup or item.hidden: + self.dequeued.remove(item) + self.queue.task_done() + def end_task(self, task_id): + ins = self.get_instance() + for __, __, __, task, __ in ins.tasks: + if str(task.id) == str(task_id) and task.is_cancellable: + task.stat = STAT_CANCELLED if task.stat == STAT_WAITING else STAT_ENDED + class CalibreTask: __metaclass__ = abc.ABCMeta @@ -158,10 +172,12 @@ class CalibreTask: self.end_time = None self.message = message self.id = uuid.uuid4() + self.self_cleanup = False + self._scheduled = False @abc.abstractmethod def run(self, worker_thread): - """Provides the caller some human-readable name for this class""" + """The main entry-point for this task""" raise NotImplementedError @abc.abstractmethod @@ -169,6 +185,11 @@ class CalibreTask: """Provides the caller some human-readable name for this class""" raise NotImplementedError + @abc.abstractmethod + def is_cancellable(self): + """Does this task gracefully handle being cancelled (STAT_ENDED, STAT_CANCELLED)?""" + raise NotImplementedError + def start(self, *args): self.start_time = datetime.now() self.stat = STAT_STARTED @@ -178,7 +199,7 @@ class CalibreTask: self.run(*args) except Exception as ex: self._handleError(str(ex)) - log.debug_or_exception(ex) + log.error_or_exception(ex) self.end_time = datetime.now() @@ -219,15 +240,23 @@ class CalibreTask: We have a separate dictating this because there may be certain tasks that want to override this """ # By default, we're good to clean a task if it's "Done" - return self.stat in (STAT_FINISH_SUCCESS, STAT_FAIL) + return self.stat in (STAT_FINISH_SUCCESS, STAT_FAIL, STAT_ENDED, STAT_CANCELLED) - '''@progress.setter - def progress(self, x): - if x > 1: - x = 1 - if x < 0: - x = 0 - self._progress = x''' + @property + def self_cleanup(self): + return self._self_cleanup + + @self_cleanup.setter + def self_cleanup(self, is_self_cleanup): + self._self_cleanup = is_self_cleanup + + @property + def scheduled(self): + return self._scheduled + + @scheduled.setter + def scheduled(self, is_scheduled): + self._scheduled = is_scheduled def _handleError(self, error_message): self.stat = STAT_FAIL diff --git a/cps/shelf.py b/cps/shelf.py index 97147a716..04f7a6a69 100644 --- a/cps/shelf.py +++ b/cps/shelf.py @@ -23,7 +23,7 @@ import sys from datetime import datetime -from flask import Blueprint, flash, redirect, request, url_for +from flask import Blueprint, flash, redirect, request, url_for, abort from flask_babel import gettext as _ from flask_login import current_user, login_required from sqlalchemy.exc import InvalidRequestError, OperationalError @@ -33,30 +33,12 @@ from . import calibre_db, config, db, logger, ub from .render_template import render_title_template from .usermanagement import login_required_if_no_ano -shelf = Blueprint('shelf', __name__) log = logger.create() - -def check_shelf_edit_permissions(cur_shelf): - if not cur_shelf.is_public and not cur_shelf.user_id == int(current_user.id): - log.error("User %s not allowed to edit shelf %s", current_user, cur_shelf) - return False - if cur_shelf.is_public and not current_user.role_edit_shelfs(): - log.info("User %s not allowed to edit public shelves", current_user) - return False - return True +shelf = Blueprint('shelf', __name__) -def check_shelf_view_permissions(cur_shelf): - if cur_shelf.is_public: - return True - if current_user.is_anonymous or cur_shelf.user_id != current_user.id: - log.error("User is unauthorized to view non-public shelf: %s", cur_shelf) - return False - return True - - -@shelf.route("/shelf/add//") +@shelf.route("/shelf/add//", methods=["POST"]) @login_required def add_to_shelf(shelf_id, book_id): xhr = request.headers.get('X-Requested-With') == 'XMLHttpRequest' @@ -64,13 +46,13 @@ def add_to_shelf(shelf_id, book_id): if shelf is None: log.error("Invalid shelf specified: %s", shelf_id) if not xhr: - flash(_(u"Invalid shelf specified"), category="error") + flash(_("Invalid shelf specified"), category="error") return redirect(url_for('web.index')) return "Invalid shelf specified", 400 if not check_shelf_edit_permissions(shelf): if not xhr: - flash(_(u"Sorry you are not allowed to add a book to that shelf"), category="error") + flash(_("Sorry you are not allowed to add a book to that shelf"), category="error") return redirect(url_for('web.index')) return "Sorry you are not allowed to add a book to the that shelf", 403 @@ -79,7 +61,7 @@ def add_to_shelf(shelf_id, book_id): if book_in_shelf: log.error("Book %s is already part of %s", book_id, shelf) if not xhr: - flash(_(u"Book is already part of the shelf: %(shelfname)s", shelfname=shelf.name), category="error") + flash(_("Book is already part of the shelf: %(shelfname)s", shelfname=shelf.name), category="error") return redirect(url_for('web.index')) return "Book is already part of the shelf: %s" % shelf.name, 400 @@ -94,17 +76,17 @@ def add_to_shelf(shelf_id, book_id): try: ub.session.merge(shelf) ub.session.commit() - except (OperationalError, InvalidRequestError): + except (OperationalError, InvalidRequestError) as e: ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_(u"Settings DB is not Writeable"), category="error") + log.error_or_exception("Settings Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") if "HTTP_REFERER" in request.environ: return redirect(request.environ["HTTP_REFERER"]) else: return redirect(url_for('web.index')) if not xhr: log.debug("Book has been added to shelf: {}".format(shelf.name)) - flash(_(u"Book has been added to shelf: %(sname)s", sname=shelf.name), category="success") + flash(_("Book has been added to shelf: %(sname)s", sname=shelf.name), category="success") if "HTTP_REFERER" in request.environ: return redirect(request.environ["HTTP_REFERER"]) else: @@ -112,18 +94,18 @@ def add_to_shelf(shelf_id, book_id): return "", 204 -@shelf.route("/shelf/massadd/") +@shelf.route("/shelf/massadd/", methods=["POST"]) @login_required def search_to_shelf(shelf_id): shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() if shelf is None: - log.error("Invalid shelf specified: %s", shelf_id) - flash(_(u"Invalid shelf specified"), category="error") + log.error("Invalid shelf specified: {}".format(shelf_id)) + flash(_("Invalid shelf specified"), category="error") return redirect(url_for('web.index')) if not check_shelf_edit_permissions(shelf): log.warning("You are not allowed to add a book to the shelf".format(shelf.name)) - flash(_(u"You are not allowed to add a book to the shelf"), category="error") + flash(_("You are not allowed to add a book to the shelf"), category="error") return redirect(url_for('web.index')) if current_user.id in ub.searched_ids and ub.searched_ids[current_user.id]: @@ -141,7 +123,7 @@ def search_to_shelf(shelf_id): if not books_for_shelf: log.error("Books are already part of {}".format(shelf.name)) - flash(_(u"Books are already part of the shelf: %(name)s", name=shelf.name), category="error") + flash(_("Books are already part of the shelf: %(name)s", name=shelf.name), category="error") return redirect(url_for('web.index')) maxOrder = ub.session.query(func.max(ub.BookShelf.order)).filter(ub.BookShelf.shelf == shelf_id).first()[0] or 0 @@ -153,18 +135,18 @@ def search_to_shelf(shelf_id): try: ub.session.merge(shelf) ub.session.commit() - flash(_(u"Books have been added to shelf: %(sname)s", sname=shelf.name), category="success") - except (OperationalError, InvalidRequestError): + flash(_("Books have been added to shelf: %(sname)s", sname=shelf.name), category="success") + except (OperationalError, InvalidRequestError) as e: ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") + log.error_or_exception("Settings Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") else: log.error("Could not add books to shelf: {}".format(shelf.name)) - flash(_(u"Could not add books to shelf: %(sname)s", sname=shelf.name), category="error") + flash(_("Could not add books to shelf: %(sname)s", sname=shelf.name), category="error") return redirect(url_for('web.index')) -@shelf.route("/shelf/remove//") +@shelf.route("/shelf/remove//", methods=["POST"]) @login_required def remove_from_shelf(shelf_id, book_id): xhr = request.headers.get('X-Requested-With') == 'XMLHttpRequest' @@ -197,16 +179,16 @@ def remove_from_shelf(shelf_id, book_id): ub.session.delete(book_shelf) shelf.last_modified = datetime.utcnow() ub.session.commit() - except (OperationalError, InvalidRequestError): + except (OperationalError, InvalidRequestError) as e: ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") + log.error_or_exception("Settings Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") if "HTTP_REFERER" in request.environ: return redirect(request.environ["HTTP_REFERER"]) else: return redirect(url_for('web.index')) if not xhr: - flash(_(u"Book has been removed from shelf: %(sname)s", sname=shelf.name), category="success") + flash(_("Book has been removed from shelf: %(sname)s", sname=shelf.name), category="success") if "HTTP_REFERER" in request.environ: return redirect(request.environ["HTTP_REFERER"]) else: @@ -215,7 +197,7 @@ def remove_from_shelf(shelf_id, book_id): else: if not xhr: log.warning("You are not allowed to remove a book from shelf: {}".format(shelf.name)) - flash(_(u"Sorry you are not allowed to remove a book from this shelf"), + flash(_("Sorry you are not allowed to remove a book from this shelf"), category="error") return redirect(url_for('web.index')) return "Sorry you are not allowed to remove a book from this shelf", 403 @@ -224,13 +206,8 @@ def remove_from_shelf(shelf_id, book_id): @shelf.route("/shelf/create", methods=["GET", "POST"]) @login_required def create_shelf(): - if not current_user.role_edit_shelfs() and request.method == 'POST': - flash(_(u"Sorry you are not allowed to create a public shelf"), category="error") - return redirect(url_for('web.index')) - else: - shelf = ub.Shelf() - return create_edit_shelf(shelf, page_title=_(u"Create a Shelf"), page="shelfcreate") - + shelf = ub.Shelf() + return create_edit_shelf(shelf, page_title=_("Create a Shelf"), page="shelfcreate") @shelf.route("/shelf/edit/", methods=["GET", "POST"]) @@ -238,102 +215,24 @@ def create_shelf(): def edit_shelf(shelf_id): shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() if not check_shelf_edit_permissions(shelf): - flash(_(u"Sorry you are not allowed to edit this shelf"), category="error") + flash(_("Sorry you are not allowed to edit this shelf"), category="error") return redirect(url_for('web.index')) - return create_edit_shelf(shelf, page_title=_(u"Edit a shelf"), page="shelfedit", shelf_id=shelf_id) + return create_edit_shelf(shelf, page_title=_("Edit a shelf"), page="shelfedit", shelf_id=shelf_id) -# if shelf ID is set, we are editing a shelf -def create_edit_shelf(shelf, page_title, page, shelf_id=False): - sync_only_selected_shelves = current_user.kobo_only_shelves_sync - # calibre_db.session.query(ub.Shelf).filter(ub.Shelf.user_id == current_user.id).filter(ub.Shelf.kobo_sync).count() - if request.method == "POST": - to_save = request.form.to_dict() - shelf.is_public = 1 if to_save.get("is_public") else 0 - if config.config_kobo_sync: - shelf.kobo_sync = True if to_save.get("kobo_sync") else False - shelf_title = to_save.get("title", "") - if check_shelf_is_unique(shelf, shelf_title, shelf_id): - shelf.name = shelf_title - if not shelf_id: - shelf.user_id = int(current_user.id) - ub.session.add(shelf) - shelf_action = "created" - flash_text = _(u"Shelf %(title)s created", title=shelf_title) - else: - shelf_action = "changed" - flash_text = _(u"Shelf %(title)s changed", title=shelf_title) - try: - ub.session.commit() - log.info(u"Shelf {} {}".format(shelf_title, shelf_action)) - flash(flash_text, category="success") - return redirect(url_for('shelf.show_shelf', shelf_id=shelf.id)) - except (OperationalError, InvalidRequestError) as ex: - ub.session.rollback() - log.debug_or_exception(ex) - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") - except Exception as ex: - ub.session.rollback() - log.debug_or_exception(ex) - flash(_(u"There was an error"), category="error") - return render_title_template('shelf_edit.html', - shelf=shelf, - title=page_title, - page=page, - kobo_sync_enabled=config.config_kobo_sync, - sync_only_selected_shelves=sync_only_selected_shelves) - - -def check_shelf_is_unique(shelf, title, shelf_id=False): - if shelf_id: - ident = ub.Shelf.id != shelf_id - else: - ident = true() - if shelf.is_public == 1: - is_shelf_name_unique = ub.session.query(ub.Shelf) \ - .filter((ub.Shelf.name == title) & (ub.Shelf.is_public == 1)) \ - .filter(ident) \ - .first() is None - - if not is_shelf_name_unique: - log.error("A public shelf with the name '{}' already exists.".format(title)) - flash(_(u"A public shelf with the name '%(title)s' already exists.", title=title), - category="error") - else: - is_shelf_name_unique = ub.session.query(ub.Shelf) \ - .filter((ub.Shelf.name == title) & (ub.Shelf.is_public == 0) & - (ub.Shelf.user_id == int(current_user.id))) \ - .filter(ident) \ - .first() is None - - if not is_shelf_name_unique: - log.error("A private shelf with the name '{}' already exists.".format(title)) - flash(_(u"A private shelf with the name '%(title)s' already exists.", title=title), - category="error") - return is_shelf_name_unique - - -def delete_shelf_helper(cur_shelf): - if not cur_shelf or not check_shelf_edit_permissions(cur_shelf): - return - shelf_id = cur_shelf.id - ub.session.delete(cur_shelf) - ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).delete() - ub.session.add(ub.ShelfArchive(uuid=cur_shelf.uuid, user_id=cur_shelf.user_id)) - ub.session_commit("successfully deleted Shelf {}".format(cur_shelf.name)) - - -@shelf.route("/shelf/delete/") +@shelf.route("/shelf/delete/", methods=["POST"]) @login_required def delete_shelf(shelf_id): cur_shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() try: - delete_shelf_helper(cur_shelf) - except InvalidRequestError: + if not delete_shelf_helper(cur_shelf): + flash(_("Error deleting Shelf"), category="error") + else: + flash(_("Shelf successfully deleted"), category="success") + except InvalidRequestError as e: ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") + log.error_or_exception("Settings Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") return redirect(url_for('web.index')) @@ -354,32 +253,144 @@ def show_shelf(shelf_id, sort_param, page): @shelf.route("/shelf/order/", methods=["GET", "POST"]) @login_required def order_shelf(shelf_id): + shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() + if shelf and check_shelf_view_permissions(shelf): + if request.method == "POST": + to_save = request.form.to_dict() + books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).order_by( + ub.BookShelf.order.asc()).all() + counter = 0 + for book in books_in_shelf: + setattr(book, 'order', to_save[str(book.book_id)]) + counter += 1 + # if order different from before -> shelf.last_modified = datetime.utcnow() + try: + ub.session.commit() + except (OperationalError, InvalidRequestError) as e: + ub.session.rollback() + log.error_or_exception("Settings Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") + + result = list() + if shelf: + result = calibre_db.session.query(db.Books) \ + .join(ub.BookShelf, ub.BookShelf.book_id == db.Books.id, isouter=True) \ + .add_columns(calibre_db.common_filters().label("visible")) \ + .filter(ub.BookShelf.shelf == shelf_id).order_by(ub.BookShelf.order.asc()).all() + return render_title_template('shelf_order.html', entries=result, + title=_("Change order of Shelf: '%(name)s'", name=shelf.name), + shelf=shelf, page="shelforder") + else: + abort(404) + + +def check_shelf_edit_permissions(cur_shelf): + if not cur_shelf.is_public and not cur_shelf.user_id == int(current_user.id): + log.error("User {} not allowed to edit shelf: {}".format(current_user.id, cur_shelf.name)) + return False + if cur_shelf.is_public and not current_user.role_edit_shelfs(): + log.info("User {} not allowed to edit public shelves".format(current_user.id)) + return False + return True + + +def check_shelf_view_permissions(cur_shelf): + if cur_shelf.is_public: + return True + if current_user.is_anonymous or cur_shelf.user_id != current_user.id: + log.error("User is unauthorized to view non-public shelf: {}".format(cur_shelf.name)) + return False + return True + + +# if shelf ID is set, we are editing a shelf +def create_edit_shelf(shelf, page_title, page, shelf_id=False): + sync_only_selected_shelves = current_user.kobo_only_shelves_sync + # calibre_db.session.query(ub.Shelf).filter(ub.Shelf.user_id == current_user.id).filter(ub.Shelf.kobo_sync).count() if request.method == "POST": to_save = request.form.to_dict() - books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).order_by( - ub.BookShelf.order.asc()).all() - counter = 0 - for book in books_in_shelf: - setattr(book, 'order', to_save[str(book.book_id)]) - counter += 1 - # if order diffrent from before -> shelf.last_modified = datetime.utcnow() - try: - ub.session.commit() - except (OperationalError, InvalidRequestError): - ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") + if not current_user.role_edit_shelfs() and to_save.get("is_public") == "on": + flash(_("Sorry you are not allowed to create a public shelf"), category="error") + return redirect(url_for('web.index')) + is_public = 1 if to_save.get("is_public") == "on" else 0 + if config.config_kobo_sync: + shelf.kobo_sync = True if to_save.get("kobo_sync") else False + if shelf.kobo_sync: + ub.session.query(ub.ShelfArchive).filter(ub.ShelfArchive.user_id == current_user.id).filter( + ub.ShelfArchive.uuid == shelf.uuid).delete() + ub.session_commit() + shelf_title = to_save.get("title", "") + if check_shelf_is_unique(shelf_title, is_public, shelf_id): + shelf.name = shelf_title + shelf.is_public = is_public + if not shelf_id: + shelf.user_id = int(current_user.id) + ub.session.add(shelf) + shelf_action = "created" + flash_text = _("Shelf %(title)s created", title=shelf_title) + else: + shelf_action = "changed" + flash_text = _("Shelf %(title)s changed", title=shelf_title) + try: + ub.session.commit() + log.info("Shelf {} {}".format(shelf_title, shelf_action)) + flash(flash_text, category="success") + return redirect(url_for('shelf.show_shelf', shelf_id=shelf.id)) + except (OperationalError, InvalidRequestError) as ex: + ub.session.rollback() + log.error_or_exception(ex) + log.error_or_exception("Settings Database error: {}".format(ex)) + flash(_("Oops! Database Error: %(error)s.", error=ex.orig), category="error") + except Exception as ex: + ub.session.rollback() + log.error_or_exception(ex) + flash(_("There was an error"), category="error") + return render_title_template('shelf_edit.html', + shelf=shelf, + title=page_title, + page=page, + kobo_sync_enabled=config.config_kobo_sync, + sync_only_selected_shelves=sync_only_selected_shelves) - shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() - result = list() - if shelf and check_shelf_view_permissions(shelf): - result = calibre_db.session.query(db.Books) \ - .join(ub.BookShelf, ub.BookShelf.book_id == db.Books.id, isouter=True) \ - .add_columns(calibre_db.common_filters().label("visible")) \ - .filter(ub.BookShelf.shelf == shelf_id).order_by(ub.BookShelf.order.asc()).all() - return render_title_template('shelf_order.html', entries=result, - title=_(u"Change order of Shelf: '%(name)s'", name=shelf.name), - shelf=shelf, page="shelforder") + +def check_shelf_is_unique(title, is_public, shelf_id=False): + if shelf_id: + ident = ub.Shelf.id != shelf_id + else: + ident = true() + if is_public == 1: + is_shelf_name_unique = ub.session.query(ub.Shelf) \ + .filter((ub.Shelf.name == title) & (ub.Shelf.is_public == 1)) \ + .filter(ident) \ + .first() is None + + if not is_shelf_name_unique: + log.error("A public shelf with the name '{}' already exists.".format(title)) + flash(_("A public shelf with the name '%(title)s' already exists.", title=title), + category="error") + else: + is_shelf_name_unique = ub.session.query(ub.Shelf) \ + .filter((ub.Shelf.name == title) & (ub.Shelf.is_public == 0) & + (ub.Shelf.user_id == int(current_user.id))) \ + .filter(ident) \ + .first() is None + + if not is_shelf_name_unique: + log.error("A private shelf with the name '{}' already exists.".format(title)) + flash(_("A private shelf with the name '%(title)s' already exists.", title=title), + category="error") + return is_shelf_name_unique + + +def delete_shelf_helper(cur_shelf): + if not cur_shelf or not check_shelf_edit_permissions(cur_shelf): + return False + shelf_id = cur_shelf.id + ub.session.delete(cur_shelf) + ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).delete() + ub.session.add(ub.ShelfArchive(uuid=cur_shelf.uuid, user_id=cur_shelf.user_id)) + ub.session_commit("successfully deleted Shelf {}".format(cur_shelf.name)) + return True def change_shelf_order(shelf_id, order): @@ -399,7 +410,6 @@ def render_show_shelf(shelf_type, shelf_id, page_no, sort_param): # check user is allowed to access shelf if shelf and check_shelf_view_permissions(shelf): - if shelf_type == 1: # order = [ub.BookShelf.order.asc()] if sort_param == 'pubnew': @@ -430,6 +440,7 @@ def render_show_shelf(shelf_type, shelf_id, page_no, sort_param): db.Books, ub.BookShelf.shelf == shelf_id, [ub.BookShelf.order.asc()], + True, config.config_read_column, ub.BookShelf, ub.BookShelf.book_id == db.Books.id) # delete chelf entries where book is not existent anymore, can happen if book is deleted outside calibre-web wrong_entries = calibre_db.session.query(ub.BookShelf) \ @@ -440,17 +451,17 @@ def render_show_shelf(shelf_type, shelf_id, page_no, sort_param): try: ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == entry.book_id).delete() ub.session.commit() - except (OperationalError, InvalidRequestError): + except (OperationalError, InvalidRequestError) as e: ub.session.rollback() - log.error("Settings DB is not Writeable") - flash(_("Settings DB is not Writeable"), category="error") + log.error_or_exception("Settings Database error: {}".format(e)) + flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error") return render_title_template(page, entries=result, pagination=pagination, - title=_(u"Shelf: '%(name)s'", name=shelf.name), + title=_("Shelf: '%(name)s'", name=shelf.name), shelf=shelf, page="shelf") else: - flash(_(u"Error opening shelf. Shelf does not exist or is not accessible"), category="error") + flash(_("Error opening shelf. Shelf does not exist or is not accessible"), category="error") return redirect(url_for("web.index")) diff --git a/cps/static/css/caliBlur.css b/cps/static/css/caliBlur.css index 3a9801808..dbbea88ea 100644 --- a/cps/static/css/caliBlur.css +++ b/cps/static/css/caliBlur.css @@ -3290,9 +3290,11 @@ div.btn-group[role=group][aria-label="Download, send to Kindle, reading"] .dropd -ms-transform-origin: center top; transform-origin: center top; border: 0; - left: 0 !important; overflow-y: auto; } +.dropdown-menu:not(.datepicker-dropdown):not(.profileDropli) { + left: 0 !important; +} #add-to-shelves { max-height: calc(100% - 120px); overflow-y: auto; @@ -4423,38 +4425,6 @@ body.advanced_search > div.container-fluid > div.row-fluid > div.col-sm-10 > div left: 49px; margin-top: 5px } - - body:not(.blur) > .navbar > .container-fluid > .navbar-header:after, body:not(.blur) > .navbar > .container-fluid > .navbar-header:before { - color: hsla(0, 0%, 100%, .7); - cursor: pointer; - display: block; - font-family: plex-icons-new, serif; - font-size: 20px; - font-stretch: 100%; - font-style: normal; - font-variant-caps: normal; - font-variant-east-asian: normal; - font-variant-numeric: normal; - font-weight: 400; - height: 60px; - letter-spacing: normal; - line-height: 60px; - position: absolute - } - - body:not(.blur) > .navbar > .container-fluid > .navbar-header:before { - content: "\EA30"; - -webkit-font-variant-ligatures: normal; - font-variant-ligatures: normal; - left: 20px - } - - body:not(.blur) > .navbar > .container-fluid > .navbar-header:after { - content: "\EA2F"; - -webkit-font-variant-ligatures: normal; - font-variant-ligatures: normal; - left: 60px - } } body.admin > div.container-fluid > div > div.col-sm-10 > div.container-fluid > div.row:first-of-type > div.col > h2:before, body.admin > div.container-fluid > div > div.col-sm-10 > div.discover > h2:first-of-type:before, body.edituser.admin > div.container-fluid > div.row-fluid > div.col-sm-10 > div.discover > h1:before, body.newuser.admin > div.container-fluid > div.row-fluid > div.col-sm-10 > div.discover > h1:before { @@ -5150,7 +5120,7 @@ body.login > div.navbar.navbar-default.navbar-static-top > div > div.navbar-head pointer-events: none } -#DeleteDomain:hover:before, #RestartDialog:hover:before, #ShutdownDialog:hover:before, #StatusDialog:hover:before, #deleteButton, #deleteModal:hover:before, body.mailset > div.container-fluid > div > div.col-sm-10 > div.discover td > a:hover { +#DeleteDomain:hover:before, #RestartDialog:hover:before, #ShutdownDialog:hover:before, #StatusDialog:hover:before, #deleteButton, #deleteModal:hover:before, #cancelTaskModal:hover:before, body.mailset > div.container-fluid > div > div.col-sm-10 > div.discover td > a:hover { cursor: pointer } @@ -5237,7 +5207,11 @@ body.admin > div.container-fluid > div > div.col-sm-10 > div.container-fluid > d margin-bottom: 20px } -body.admin:not(.modal-open) .btn-default { +body.admin > div.container-fluid div.scheduled_tasks_details { + margin-bottom: 20px +} + +body.admin .btn-default { margin-bottom: 10px } @@ -5468,7 +5442,7 @@ body.admin.modal-open .navbar { z-index: 0 !important } -#RestartDialog, #ShutdownDialog, #StatusDialog, #deleteModal { +#RestartDialog, #ShutdownDialog, #StatusDialog, #deleteModal, #cancelTaskModal { top: 0; overflow: hidden; padding-top: 70px; @@ -5478,7 +5452,7 @@ body.admin.modal-open .navbar { background: rgba(0, 0, 0, .5) } -#RestartDialog:before, #ShutdownDialog:before, #StatusDialog:before, #deleteModal:before { +#RestartDialog:before, #ShutdownDialog:before, #StatusDialog:before, #deleteModal:before, #cancelTaskModal:before { content: "\E208"; padding-right: 10px; display: block; @@ -5500,18 +5474,18 @@ body.admin.modal-open .navbar { z-index: 99 } -#RestartDialog.in:before, #ShutdownDialog.in:before, #StatusDialog.in:before, #deleteModal.in:before { +#RestartDialog.in:before, #ShutdownDialog.in:before, #StatusDialog.in:before, #deleteModal.in:before, #cancelTaskModal.in:before { -webkit-transform: translate(0, 0); -ms-transform: translate(0, 0); transform: translate(0, 0) } -#RestartDialog > .modal-dialog, #ShutdownDialog > .modal-dialog, #StatusDialog > .modal-dialog, #deleteModal > .modal-dialog { +#RestartDialog > .modal-dialog, #ShutdownDialog > .modal-dialog, #StatusDialog > .modal-dialog, #deleteModal > .modal-dialog, #cancelTaskModal > .modal-dialog { width: 450px; margin: auto } -#RestartDialog > .modal-dialog > .modal-content, #ShutdownDialog > .modal-dialog > .modal-content, #StatusDialog > .modal-dialog > .modal-content, #deleteModal > .modal-dialog > .modal-content { +#RestartDialog > .modal-dialog > .modal-content, #ShutdownDialog > .modal-dialog > .modal-content, #StatusDialog > .modal-dialog > .modal-content, #deleteModal > .modal-dialog > .modal-content, #cancelTaskModal > .modal-dialog > .modal-content { max-height: calc(100% - 90px); -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); box-shadow: 0 5px 15px rgba(0, 0, 0, .5); @@ -5522,7 +5496,7 @@ body.admin.modal-open .navbar { width: 450px } -#RestartDialog > .modal-dialog > .modal-content > .modal-header, #ShutdownDialog > .modal-dialog > .modal-content > .modal-header, #StatusDialog > .modal-dialog > .modal-content > .modal-header, #deleteModal > .modal-dialog > .modal-content > .modal-header { +#RestartDialog > .modal-dialog > .modal-content > .modal-header, #ShutdownDialog > .modal-dialog > .modal-content > .modal-header, #StatusDialog > .modal-dialog > .modal-content > .modal-header, #deleteModal > .modal-dialog > .modal-content > .modal-header, #cancelTaskModal > .modal-dialog > .modal-content > .modal-header { padding: 15px 20px; border-radius: 3px 3px 0 0; line-height: 1.71428571; @@ -5535,7 +5509,7 @@ body.admin.modal-open .navbar { text-align: left } -#RestartDialog > .modal-dialog > .modal-content > .modal-header:before, #ShutdownDialog > .modal-dialog > .modal-content > .modal-header:before, #StatusDialog > .modal-dialog > .modal-content > .modal-header:before, #deleteModal > .modal-dialog > .modal-content > .modal-header:before { +#RestartDialog > .modal-dialog > .modal-content > .modal-header:before, #ShutdownDialog > .modal-dialog > .modal-content > .modal-header:before, #StatusDialog > .modal-dialog > .modal-content > .modal-header:before, #deleteModal > .modal-dialog > .modal-content > .modal-header:before, #cancelTaskModal > .modal-dialog > .modal-content > .modal-header:before { padding-right: 10px; font-size: 18px; color: #999; @@ -5564,6 +5538,11 @@ body.admin.modal-open .navbar { font-family: plex-icons-new, serif } +#cancelTaskModal > .modal-dialog > .modal-content > .modal-header:before { + content: "\EA6D"; + font-family: plex-icons-new, serif +} + #RestartDialog > .modal-dialog > .modal-content > .modal-header:after { content: "Restart Calibre-Web"; display: inline-block; @@ -5588,7 +5567,13 @@ body.admin.modal-open .navbar { font-size: 20px } -#StatusDialog > .modal-dialog > .modal-content > .modal-header > span, #deleteModal > .modal-dialog > .modal-content > .modal-header > span, #loader > center > img, .rating-mobile { +#cancelTaskModal > .modal-dialog > .modal-content > .modal-header:after { + content: "Delete Book"; + display: inline-block; + font-size: 20px +} + +#StatusDialog > .modal-dialog > .modal-content > .modal-header > span, #deleteModal > .modal-dialog > .modal-content > .modal-header > span, #cancelTaskModal > .modal-dialog > .modal-content > .modal-header > span, #loader > center > img, .rating-mobile { display: none } @@ -5602,7 +5587,7 @@ body.admin.modal-open .navbar { text-align: left } -#ShutdownDialog > .modal-dialog > .modal-content > .modal-body, #StatusDialog > .modal-dialog > .modal-content > .modal-body, #deleteModal > .modal-dialog > .modal-content > .modal-body { +#ShutdownDialog > .modal-dialog > .modal-content > .modal-body, #StatusDialog > .modal-dialog > .modal-content > .modal-body, #deleteModal > .modal-dialog > .modal-content > .modal-body, #cancelTaskModal > .modal-dialog > .modal-content > .modal-body { padding: 20px 20px 40px; font-size: 16px; line-height: 1.6em; @@ -5612,7 +5597,7 @@ body.admin.modal-open .navbar { text-align: left } -#RestartDialog > .modal-dialog > .modal-content > .modal-body > p, #ShutdownDialog > .modal-dialog > .modal-content > .modal-body > p, #StatusDialog > .modal-dialog > .modal-content > .modal-body > p, #deleteModal > .modal-dialog > .modal-content > .modal-body > p { +#RestartDialog > .modal-dialog > .modal-content > .modal-body > p, #ShutdownDialog > .modal-dialog > .modal-content > .modal-body > p, #StatusDialog > .modal-dialog > .modal-content > .modal-body > p, #deleteModal > .modal-dialog > .modal-content > .modal-body > p, #cancelTaskModal > .modal-dialog > .modal-content > .modal-body > p { padding: 20px 20px 0 0; font-size: 16px; line-height: 1.6em; @@ -5621,7 +5606,7 @@ body.admin.modal-open .navbar { background: #282828 } -#RestartDialog > .modal-dialog > .modal-content > .modal-body > .btn-default:not(#restart), #ShutdownDialog > .modal-dialog > .modal-content > .modal-body > .btn-default:not(#shutdown), #deleteModal > .modal-dialog > .modal-content > .modal-footer > .btn-default { +#RestartDialog > .modal-dialog > .modal-content > .modal-body > .btn-default:not(#restart), #ShutdownDialog > .modal-dialog > .modal-content > .modal-body > .btn-default:not(#shutdown), #deleteModal > .modal-dialog > .modal-content > .modal-footer > .btn-default, #cancelTaskModal > .modal-dialog > .modal-content > .modal-footer > .btn-default { float: right; z-index: 9; position: relative; @@ -5669,6 +5654,18 @@ body.admin.modal-open .navbar { border-radius: 3px } +#cancelTaskModal > .modal-dialog > .modal-content > .modal-footer > .btn-danger { + float: right; + z-index: 9; + position: relative; + margin: 0 0 0 10px; + min-width: 80px; + padding: 10px 18px; + font-size: 16px; + line-height: 1.33; + border-radius: 3px +} + #RestartDialog > .modal-dialog > .modal-content > .modal-body > .btn-default:not(#restart) { margin: 25px 0 0 10px } @@ -5681,7 +5678,11 @@ body.admin.modal-open .navbar { margin: 0 0 0 10px } -#RestartDialog > .modal-dialog > .modal-content > .modal-body > .btn-default:not(#restart):hover, #ShutdownDialog > .modal-dialog > .modal-content > .modal-body > .btn-default:not(#shutdown):hover, #deleteModal > .modal-dialog > .modal-content > .modal-footer > .btn-default:hover { +#cancelTaskModal > .modal-dialog > .modal-content > .modal-footer > .btn-default { + margin: 0 0 0 10px +} + +#RestartDialog > .modal-dialog > .modal-content > .modal-body > .btn-default:not(#restart):hover, #ShutdownDialog > .modal-dialog > .modal-content > .modal-body > .btn-default:not(#shutdown):hover, #deleteModal > .modal-dialog > .modal-content > .modal-footer > .btn-default:hover, #cancelTaskModal > .modal-dialog > .modal-content > .modal-footer > .btn-default:hover { background-color: hsla(0, 0%, 100%, .3) } @@ -7303,11 +7304,11 @@ body.edituser.admin > div.container-fluid > div.row-fluid > div.col-sm-10 > div. background-color: transparent !important } - #RestartDialog > .modal-dialog, #ShutdownDialog > .modal-dialog, #StatusDialog > .modal-dialog, #deleteModal > .modal-dialog { + #RestartDialog > .modal-dialog, #ShutdownDialog > .modal-dialog, #StatusDialog > .modal-dialog, #deleteModal > .modal-dialog, #cancelTaskModal > .modal-dialog { max-width: calc(100vw - 40px) } - #RestartDialog > .modal-dialog > .modal-content, #ShutdownDialog > .modal-dialog > .modal-content, #StatusDialog > .modal-dialog > .modal-content, #deleteModal > .modal-dialog > .modal-content { + #RestartDialog > .modal-dialog > .modal-content, #ShutdownDialog > .modal-dialog > .modal-content, #StatusDialog > .modal-dialog > .modal-content, #deleteModal > .modal-dialog > .modal-content, #cancelTaskModal > .modal-dialog > .modal-content { max-width: calc(100vw - 40px); left: 0 } @@ -7457,7 +7458,7 @@ body.edituser.admin > div.container-fluid > div.row-fluid > div.col-sm-10 > div. padding: 30px 15px } - #RestartDialog.in:before, #ShutdownDialog.in:before, #StatusDialog.in:before, #deleteModal.in:before { + #RestartDialog.in:before, #ShutdownDialog.in:before, #StatusDialog.in:before, #deleteModal.in:before, #cancelTaskModal.in:before { left: auto; right: 34px } diff --git a/cps/static/css/caliBlur_override.css b/cps/static/css/caliBlur_override.css index 4c8b6cb07..29fd7e298 100644 --- a/cps/static/css/caliBlur_override.css +++ b/cps/static/css/caliBlur_override.css @@ -22,3 +22,7 @@ body.serieslist.grid-view div.container-fluid > div > div.col-sm-10::before { padding: 0 0; line-height: 15px; } + +input.datepicker {color: transparent} +input.datepicker:focus {color: transparent} +input.datepicker:focus + input {color: #555} diff --git a/cps/static/css/epub_themes.css b/cps/static/css/epub_themes.css new file mode 100644 index 000000000..16c27805d --- /dev/null +++ b/cps/static/css/epub_themes.css @@ -0,0 +1,19 @@ +.lightTheme { + background: #fff; + color: #000; +} + +.darkTheme { + background: #202124; + color: #fff +} + +.sepiaTheme { + background: #ece1ca; + color: #000; +} + +.blackTheme { + background: #000; + color: #fff +} \ No newline at end of file diff --git a/cps/static/css/libs/images/findbarButton-next-dark.svg b/cps/static/css/libs/images/findbarButton-next-dark.svg deleted file mode 100644 index 80df70bc1..000000000 --- a/cps/static/css/libs/images/findbarButton-next-dark.svg +++ /dev/null @@ -1,6 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/findbarButton-previous-dark.svg b/cps/static/css/libs/images/findbarButton-previous-dark.svg deleted file mode 100644 index d304a9b8c..000000000 --- a/cps/static/css/libs/images/findbarButton-previous-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/grab.cur b/cps/static/css/libs/images/grab.cur deleted file mode 100644 index db7ad5aed..000000000 Binary files a/cps/static/css/libs/images/grab.cur and /dev/null differ diff --git a/cps/static/css/libs/images/grabbing.cur b/cps/static/css/libs/images/grabbing.cur deleted file mode 100644 index e0dfd04e4..000000000 Binary files a/cps/static/css/libs/images/grabbing.cur and /dev/null differ diff --git a/cps/static/css/libs/images/secondaryToolbarButton-documentProperties-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-documentProperties-dark.svg deleted file mode 100644 index 306e628d7..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-documentProperties-dark.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-firstPage-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-firstPage-dark.svg deleted file mode 100644 index c13ff8671..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-firstPage-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-handTool-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-handTool-dark.svg deleted file mode 100644 index 834d8b0da..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-handTool-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-lastPage-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-lastPage-dark.svg deleted file mode 100644 index 8633e420a..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-lastPage-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-rotateCcw-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-rotateCcw-dark.svg deleted file mode 100644 index 1a92f802c..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-rotateCcw-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-rotateCw-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-rotateCw-dark.svg deleted file mode 100644 index 2a4ef7385..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-rotateCw-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-scrollHorizontal-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-scrollHorizontal-dark.svg deleted file mode 100644 index 337f85ef4..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-scrollHorizontal-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-scrollPage.svg b/cps/static/css/libs/images/secondaryToolbarButton-scrollPage.svg new file mode 100644 index 000000000..bea2f0d67 --- /dev/null +++ b/cps/static/css/libs/images/secondaryToolbarButton-scrollPage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-scrollVertical-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-scrollVertical-dark.svg deleted file mode 100644 index 41bdd8f14..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-scrollVertical-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-scrollWrapped-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-scrollWrapped-dark.svg deleted file mode 100644 index cd50526ff..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-scrollWrapped-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-selectTool-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-selectTool-dark.svg deleted file mode 100644 index 7a95098af..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-selectTool-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-spreadEven-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-spreadEven-dark.svg deleted file mode 100644 index 0c9586ed8..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-spreadEven-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-spreadNone-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-spreadNone-dark.svg deleted file mode 100644 index 75e1b985d..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-spreadNone-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/secondaryToolbarButton-spreadOdd-dark.svg b/cps/static/css/libs/images/secondaryToolbarButton-spreadOdd-dark.svg deleted file mode 100644 index 8dff9598e..000000000 --- a/cps/static/css/libs/images/secondaryToolbarButton-spreadOdd-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-bookmark-dark.svg b/cps/static/css/libs/images/toolbarButton-bookmark-dark.svg deleted file mode 100644 index 7bf332972..000000000 --- a/cps/static/css/libs/images/toolbarButton-bookmark-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-currentOutlineItem.svg b/cps/static/css/libs/images/toolbarButton-currentOutlineItem.svg new file mode 100644 index 000000000..c1c72b208 --- /dev/null +++ b/cps/static/css/libs/images/toolbarButton-currentOutlineItem.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-download-dark.svg b/cps/static/css/libs/images/toolbarButton-download-dark.svg deleted file mode 100644 index d2a92e5d4..000000000 --- a/cps/static/css/libs/images/toolbarButton-download-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-editorFreeText.svg b/cps/static/css/libs/images/toolbarButton-editorFreeText.svg new file mode 100644 index 000000000..f0f11b47c --- /dev/null +++ b/cps/static/css/libs/images/toolbarButton-editorFreeText.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/cps/static/css/libs/images/toolbarButton-editorInk.svg b/cps/static/css/libs/images/toolbarButton-editorInk.svg new file mode 100644 index 000000000..2b37e85f3 --- /dev/null +++ b/cps/static/css/libs/images/toolbarButton-editorInk.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/cps/static/css/libs/images/toolbarButton-menuArrow-dark.svg b/cps/static/css/libs/images/toolbarButton-menuArrow-dark.svg deleted file mode 100644 index eb7f50e6d..000000000 --- a/cps/static/css/libs/images/toolbarButton-menuArrow-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-openFile-dark.svg b/cps/static/css/libs/images/toolbarButton-openFile-dark.svg deleted file mode 100644 index 0bd612f0e..000000000 --- a/cps/static/css/libs/images/toolbarButton-openFile-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-pageDown-dark.svg b/cps/static/css/libs/images/toolbarButton-pageDown-dark.svg deleted file mode 100644 index c2ca60c8f..000000000 --- a/cps/static/css/libs/images/toolbarButton-pageDown-dark.svg +++ /dev/null @@ -1,8 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-pageUp-dark.svg b/cps/static/css/libs/images/toolbarButton-pageUp-dark.svg deleted file mode 100644 index dddc4ab26..000000000 --- a/cps/static/css/libs/images/toolbarButton-pageUp-dark.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-presentationMode-dark.svg b/cps/static/css/libs/images/toolbarButton-presentationMode-dark.svg deleted file mode 100644 index 13fa9dc7c..000000000 --- a/cps/static/css/libs/images/toolbarButton-presentationMode-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-print-dark.svg b/cps/static/css/libs/images/toolbarButton-print-dark.svg deleted file mode 100644 index ad37022f0..000000000 --- a/cps/static/css/libs/images/toolbarButton-print-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-search-dark.svg b/cps/static/css/libs/images/toolbarButton-search-dark.svg deleted file mode 100644 index cec8a4206..000000000 --- a/cps/static/css/libs/images/toolbarButton-search-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-secondaryToolbarToggle-dark.svg b/cps/static/css/libs/images/toolbarButton-secondaryToolbarToggle-dark.svg deleted file mode 100644 index 0160c07cd..000000000 --- a/cps/static/css/libs/images/toolbarButton-secondaryToolbarToggle-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-sidebarToggle-dark.svg b/cps/static/css/libs/images/toolbarButton-sidebarToggle-dark.svg deleted file mode 100644 index 0118e41a8..000000000 --- a/cps/static/css/libs/images/toolbarButton-sidebarToggle-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-viewAttachments-dark.svg b/cps/static/css/libs/images/toolbarButton-viewAttachments-dark.svg deleted file mode 100644 index c9714fdea..000000000 --- a/cps/static/css/libs/images/toolbarButton-viewAttachments-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-viewLayers-dark.svg b/cps/static/css/libs/images/toolbarButton-viewLayers-dark.svg deleted file mode 100644 index 76b042a95..000000000 --- a/cps/static/css/libs/images/toolbarButton-viewLayers-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-viewOutline-dark.svg b/cps/static/css/libs/images/toolbarButton-viewOutline-dark.svg deleted file mode 100644 index 1704d961a..000000000 --- a/cps/static/css/libs/images/toolbarButton-viewOutline-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-viewThumbnail-dark.svg b/cps/static/css/libs/images/toolbarButton-viewThumbnail-dark.svg deleted file mode 100644 index 17c55f7b8..000000000 --- a/cps/static/css/libs/images/toolbarButton-viewThumbnail-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-zoomIn-dark.svg b/cps/static/css/libs/images/toolbarButton-zoomIn-dark.svg deleted file mode 100644 index 9b615541e..000000000 --- a/cps/static/css/libs/images/toolbarButton-zoomIn-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/toolbarButton-zoomOut-dark.svg b/cps/static/css/libs/images/toolbarButton-zoomOut-dark.svg deleted file mode 100644 index 0fb3594d1..000000000 --- a/cps/static/css/libs/images/toolbarButton-zoomOut-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cps/static/css/libs/images/treeitem-collapsed-dark.svg b/cps/static/css/libs/images/treeitem-collapsed-dark.svg deleted file mode 100644 index 1fb655162..000000000 --- a/cps/static/css/libs/images/treeitem-collapsed-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/images/treeitem-expanded-dark.svg b/cps/static/css/libs/images/treeitem-expanded-dark.svg deleted file mode 100644 index 695b0aa61..000000000 --- a/cps/static/css/libs/images/treeitem-expanded-dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/cps/static/css/libs/viewer.css b/cps/static/css/libs/viewer.css index cd4781bf4..c357a9fde 100644 --- a/cps/static/css/libs/viewer.css +++ b/cps/static/css/libs/viewer.css @@ -15,6 +15,7 @@ .textLayer { position: absolute; + text-align: initial; left: 0; top: 0; right: 0; @@ -22,9 +23,14 @@ overflow: hidden; opacity: 0.2; line-height: 1; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + text-size-adjust: none; + forced-color-adjust: none; } -.textLayer > span { +.textLayer span, +.textLayer br { color: transparent; position: absolute; white-space: pre; @@ -32,6 +38,13 @@ transform-origin: 0% 0%; } +/* Only necessary in Google Chrome, see issue 14205, and most unfortunately + * the problem doesn't show up in "text" reference tests. */ +.textLayer span.markedContent { + top: 0; + height: 0; +} + .textLayer .highlight { margin: -1px; padding: 1px; @@ -39,16 +52,20 @@ border-radius: 4px; } +.textLayer .highlight.appended { + position: initial; +} + .textLayer .highlight.begin { - border-radius: 4px 0px 0px 4px; + border-radius: 4px 0 0 4px; } .textLayer .highlight.end { - border-radius: 0px 4px 4px 0px; + border-radius: 0 4px 4px 0; } .textLayer .highlight.middle { - border-radius: 0px; + border-radius: 0; } .textLayer .highlight.selected { @@ -63,28 +80,61 @@ background: rgba(0, 0, 255, 1); } +/* Avoids https://github.com/mozilla/pdf.js/issues/13840 in Chrome */ +.textLayer br::-moz-selection { + background: transparent; +} +.textLayer br::selection { + background: transparent; +} + .textLayer .endOfContent { display: block; position: absolute; - left: 0px; + left: 0; top: 100%; - right: 0px; - bottom: 0px; + right: 0; + bottom: 0; z-index: -1; cursor: default; -webkit-user-select: none; -moz-user-select: none; - -ms-user-select: none; user-select: none; } .textLayer .endOfContent.active { - top: 0px; + top: 0; } +:root { + --annotation-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,"); +} + +@media (forced-colors: active) { + .annotationLayer .textWidgetAnnotation input:required, + .annotationLayer .textWidgetAnnotation textarea:required, + .annotationLayer .choiceWidgetAnnotation select:required, + .annotationLayer .buttonWidgetAnnotation.checkBox input:required, + .annotationLayer .buttonWidgetAnnotation.radioButton input:required { + outline: 1.5px solid selectedItem; + } +} + +.annotationLayer { + position: absolute; + top: 0; + left: 0; + pointer-events: none; + transform-origin: 0 0; +} + .annotationLayer section { position: absolute; + text-align: initial; + pointer-events: auto; + box-sizing: border-box; + transform-origin: 0 0; } .annotationLayer .linkAnnotation > a, @@ -97,16 +147,23 @@ height: 100%; } +.annotationLayer .buttonWidgetAnnotation.pushButton > canvas { + width: 100%; + height: 100%; +} + .annotationLayer .linkAnnotation > a:hover, .annotationLayer .buttonWidgetAnnotation.pushButton > a:hover { opacity: 0.2; background: rgba(255, 255, 0, 1); - box-shadow: 0px 2px 10px rgba(255, 255, 0, 1); + box-shadow: 0 2px 10px rgba(255, 255, 0, 1); } .annotationLayer .textAnnotation img { position: absolute; cursor: pointer; + width: 100%; + height: 100%; } .annotationLayer .textWidgetAnnotation input, @@ -114,17 +171,24 @@ .annotationLayer .choiceWidgetAnnotation select, .annotationLayer .buttonWidgetAnnotation.checkBox input, .annotationLayer .buttonWidgetAnnotation.radioButton input { - background-color: rgba(0, 54, 255, 0.13); + background-image: var(--annotation-unfocused-field-background); border: 1px solid transparent; box-sizing: border-box; - font-size: 9px; + font: calc(9px * var(--scale-factor)) sans-serif; height: 100%; margin: 0; - padding: 0 3px; vertical-align: top; width: 100%; } +.annotationLayer .textWidgetAnnotation input:required, +.annotationLayer .textWidgetAnnotation textarea:required, +.annotationLayer .choiceWidgetAnnotation select:required, +.annotationLayer .buttonWidgetAnnotation.checkBox input:required, +.annotationLayer .buttonWidgetAnnotation.radioButton input:required { + outline: 1.5px solid red; +} + .annotationLayer .choiceWidgetAnnotation select option { padding: 0; } @@ -134,8 +198,6 @@ } .annotationLayer .textWidgetAnnotation textarea { - font: message-box; - font-size: 9px; resize: none; } @@ -164,10 +226,20 @@ border: 1px solid transparent; } +.annotationLayer .textWidgetAnnotation input :focus, +.annotationLayer .textWidgetAnnotation textarea :focus, +.annotationLayer .choiceWidgetAnnotation select :focus, +.annotationLayer .buttonWidgetAnnotation.checkBox :focus, +.annotationLayer .buttonWidgetAnnotation.radioButton :focus { + background-image: none; + background-color: transparent; + outline: auto; +} + .annotationLayer .buttonWidgetAnnotation.checkBox input:checked:before, .annotationLayer .buttonWidgetAnnotation.checkBox input:checked:after, .annotationLayer .buttonWidgetAnnotation.radioButton input:checked:before { - background-color: rgba(0, 0, 0, 1); + background-color: CanvasText; content: ""; display: block; position: absolute; @@ -209,7 +281,7 @@ * area, causing horizontal scrolling. We avoid this by extending the width * when the element has focus and revert this when it loses focus. */ - width: 115%; + width: 103%; } .annotationLayer .buttonWidgetAnnotation.checkBox input, @@ -217,46 +289,59 @@ -webkit-appearance: none; -moz-appearance: none; appearance: none; - padding: 0; +} + +.annotationLayer .popupTriggerArea { + height: 100%; + width: 100%; } .annotationLayer .popupWrapper { position: absolute; - width: 20em; + font-size: calc(9px * var(--scale-factor)); + width: 100%; + min-width: calc(180px * var(--scale-factor)); + pointer-events: none; } .annotationLayer .popup { position: absolute; - z-index: 200; - max-width: 20em; + max-width: calc(180px * var(--scale-factor)); background-color: rgba(255, 255, 153, 1); - box-shadow: 0px 2px 5px rgba(136, 136, 136, 1); - border-radius: 2px; - padding: 6px; - margin-left: 5px; + box-shadow: 0 calc(2px * var(--scale-factor)) calc(5px * var(--scale-factor)) + rgba(136, 136, 136, 1); + border-radius: calc(2px * var(--scale-factor)); + padding: calc(6px * var(--scale-factor)); + margin-left: calc(5px * var(--scale-factor)); cursor: pointer; font: message-box; - font-size: 9px; + white-space: normal; word-wrap: break-word; + pointer-events: auto; } .annotationLayer .popup > * { - font-size: 9px; + font-size: calc(9px * var(--scale-factor)); } .annotationLayer .popup h1 { display: inline-block; } -.annotationLayer .popup span { +.annotationLayer .popupDate { display: inline-block; - margin-left: 5px; + margin-left: calc(5px * var(--scale-factor)); } -.annotationLayer .popup p { +.annotationLayer .popupContent { border-top: 1px solid rgba(51, 51, 51, 1); - margin-top: 2px; - padding-top: 2px; + margin-top: calc(2px * var(--scale-factor)); + padding-top: calc(2px * var(--scale-factor)); +} + +.annotationLayer .richText > * { + white-space: pre-wrap; + font-size: calc(9px * var(--scale-factor)); } .annotationLayer .highlightAnnotation, @@ -276,6 +361,527 @@ cursor: pointer; } +.annotationLayer section svg { + position: absolute; + width: 100%; + height: 100%; +} + +.annotationLayer .annotationTextContent { + position: absolute; + width: 100%; + height: 100%; + opacity: 0; + color: transparent; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + pointer-events: none; +} + +.annotationLayer .annotationTextContent span { + width: 100%; + display: inline-block; +} + + +:root { + --xfa-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,"); +} + +@media (forced-colors: active) { + .xfaLayer *:required { + outline: 1.5px solid selectedItem; + } +} + +.xfaLayer .highlight { + margin: -1px; + padding: 1px; + background-color: rgba(239, 203, 237, 1); + border-radius: 4px; +} + +.xfaLayer .highlight.appended { + position: initial; +} + +.xfaLayer .highlight.begin { + border-radius: 4px 0 0 4px; +} + +.xfaLayer .highlight.end { + border-radius: 0 4px 4px 0; +} + +.xfaLayer .highlight.middle { + border-radius: 0; +} + +.xfaLayer .highlight.selected { + background-color: rgba(203, 223, 203, 1); +} + +.xfaLayer ::-moz-selection { + background: rgba(0, 0, 255, 1); +} + +.xfaLayer ::selection { + background: rgba(0, 0, 255, 1); +} + +.xfaPage { + overflow: hidden; + position: relative; +} + +.xfaContentarea { + position: absolute; +} + +.xfaPrintOnly { + display: none; +} + +.xfaLayer { + position: absolute; + text-align: initial; + top: 0; + left: 0; + transform-origin: 0 0; + line-height: 1.2; +} + +.xfaLayer * { + color: inherit; + font: inherit; + font-style: inherit; + font-weight: inherit; + font-kerning: inherit; + letter-spacing: -0.01px; + text-align: inherit; + text-decoration: inherit; + box-sizing: border-box; + background-color: transparent; + padding: 0; + margin: 0; + pointer-events: auto; + line-height: inherit; +} + +.xfaLayer *:required { + outline: 1.5px solid red; +} + +.xfaLayer div { + pointer-events: none; +} + +.xfaLayer svg { + pointer-events: none; +} + +.xfaLayer svg * { + pointer-events: none; +} + +.xfaLayer a { + color: blue; +} + +.xfaRich li { + margin-left: 3em; +} + +.xfaFont { + color: black; + font-weight: normal; + font-kerning: none; + font-size: 10px; + font-style: normal; + letter-spacing: 0; + text-decoration: none; + vertical-align: 0; +} + +.xfaCaption { + overflow: hidden; + flex: 0 0 auto; +} + +.xfaCaptionForCheckButton { + overflow: hidden; + flex: 1 1 auto; +} + +.xfaLabel { + height: 100%; + width: 100%; +} + +.xfaLeft { + display: flex; + flex-direction: row; + align-items: center; +} + +.xfaRight { + display: flex; + flex-direction: row-reverse; + align-items: center; +} + +.xfaLeft > .xfaCaption, +.xfaLeft > .xfaCaptionForCheckButton, +.xfaRight > .xfaCaption, +.xfaRight > .xfaCaptionForCheckButton { + max-height: 100%; +} + +.xfaTop { + display: flex; + flex-direction: column; + align-items: flex-start; +} + +.xfaBottom { + display: flex; + flex-direction: column-reverse; + align-items: flex-start; +} + +.xfaTop > .xfaCaption, +.xfaTop > .xfaCaptionForCheckButton, +.xfaBottom > .xfaCaption, +.xfaBottom > .xfaCaptionForCheckButton { + width: 100%; +} + +.xfaBorder { + background-color: transparent; + position: absolute; + pointer-events: none; +} + +.xfaWrapped { + width: 100%; + height: 100%; +} + +.xfaTextfield:focus, +.xfaSelect:focus { + background-image: none; + background-color: transparent; + outline: auto; + outline-offset: -1px; +} + +.xfaCheckbox:focus, +.xfaRadio:focus { + outline: auto; +} + +.xfaTextfield, +.xfaSelect { + height: 100%; + width: 100%; + flex: 1 1 auto; + border: none; + resize: none; + background-image: var(--xfa-unfocused-field-background); +} + +.xfaTop > .xfaTextfield, +.xfaTop > .xfaSelect, +.xfaBottom > .xfaTextfield, +.xfaBottom > .xfaSelect { + flex: 0 1 auto; +} + +.xfaButton { + cursor: pointer; + width: 100%; + height: 100%; + border: none; + text-align: center; +} + +.xfaLink { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; +} + +.xfaCheckbox, +.xfaRadio { + width: 100%; + height: 100%; + flex: 0 0 auto; + border: none; +} + +.xfaRich { + white-space: pre-wrap; + width: 100%; + height: 100%; +} + +.xfaImage { + -o-object-position: left top; + object-position: left top; + -o-object-fit: contain; + object-fit: contain; + width: 100%; + height: 100%; +} + +.xfaLrTb, +.xfaRlTb, +.xfaTb { + display: flex; + flex-direction: column; + align-items: stretch; +} + +.xfaLr { + display: flex; + flex-direction: row; + align-items: stretch; +} + +.xfaRl { + display: flex; + flex-direction: row-reverse; + align-items: stretch; +} + +.xfaTb > div { + justify-content: left; +} + +.xfaPosition { + position: relative; +} + +.xfaArea { + position: relative; +} + +.xfaValignMiddle { + display: flex; + align-items: center; +} + +.xfaTable { + display: flex; + flex-direction: column; + align-items: stretch; +} + +.xfaTable .xfaRow { + display: flex; + flex-direction: row; + align-items: stretch; +} + +.xfaTable .xfaRlRow { + display: flex; + flex-direction: row-reverse; + align-items: stretch; + flex: 1; +} + +.xfaTable .xfaRlRow > div { + flex: 1; +} + +.xfaNonInteractive input, +.xfaNonInteractive textarea, +.xfaDisabled input, +.xfaDisabled textarea, +.xfaReadOnly input, +.xfaReadOnly textarea { + background: initial; +} + +@media print { + .xfaTextfield, + .xfaSelect { + background: transparent; + } + + .xfaSelect { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + text-indent: 1px; + text-overflow: ""; + } +} + + +:root { + --focus-outline: solid 2px blue; + --hover-outline: dashed 2px blue; + --freetext-line-height: 1.35; + --freetext-padding: 2px; + --editorInk-editing-cursor: url(images/toolbarButton-editorInk.svg) 0 16; +} + +@media (forced-colors: active) { + :root { + --focus-outline: solid 3px ButtonText; + --hover-outline: dashed 3px ButtonText; + } +} + +[data-editor-rotation="90"] { + transform: rotate(90deg); +} +[data-editor-rotation="180"] { + transform: rotate(180deg); +} +[data-editor-rotation="270"] { + transform: rotate(270deg); +} + +.annotationEditorLayer { + background: transparent; + position: absolute; + top: 0; + left: 0; + font-size: calc(100px * var(--scale-factor)); + transform-origin: 0 0; +} + +.annotationEditorLayer .selectedEditor { + outline: var(--focus-outline); + resize: none; +} + +.annotationEditorLayer .freeTextEditor { + position: absolute; + background: transparent; + border-radius: 3px; + padding: calc(var(--freetext-padding) * var(--scale-factor)); + resize: none; + width: auto; + height: auto; + z-index: 1; + transform-origin: 0 0; + touch-action: none; +} + +.annotationEditorLayer .freeTextEditor .internal { + background: transparent; + border: none; + top: 0; + left: 0; + overflow: visible; + white-space: nowrap; + resize: none; + font: 10px sans-serif; + line-height: var(--freetext-line-height); +} + +.annotationEditorLayer .freeTextEditor .overlay { + position: absolute; + display: none; + background: transparent; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.annotationEditorLayer .freeTextEditor .overlay.enabled { + display: block; +} + +.annotationEditorLayer .freeTextEditor .internal:empty::before { + content: attr(default-content); + color: gray; +} + +.annotationEditorLayer .freeTextEditor .internal:focus { + outline: none; +} + +.annotationEditorLayer .inkEditor.disabled { + resize: none; +} + +.annotationEditorLayer .inkEditor.disabled.selectedEditor { + resize: horizontal; +} + +.annotationEditorLayer .freeTextEditor:hover:not(.selectedEditor), +.annotationEditorLayer .inkEditor:hover:not(.selectedEditor) { + outline: var(--hover-outline); +} + +.annotationEditorLayer .inkEditor { + position: absolute; + background: transparent; + border-radius: 3px; + overflow: auto; + width: 100%; + height: 100%; + z-index: 1; + transform-origin: 0 0; + cursor: auto; +} + +.annotationEditorLayer .inkEditor.editing { + resize: none; + cursor: var(--editorInk-editing-cursor), pointer; +} + +.annotationEditorLayer .inkEditor .inkEditorCanvas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + touch-action: none; +} + +:root { + --viewer-container-height: 0; + --pdfViewer-padding-bottom: 0; + --page-margin: 1px auto -8px; + --page-border: 9px solid transparent; + --page-border-image: url(images/shadow.png) 9 9 repeat; + --spreadHorizontalWrapped-margin-LR: -3.5px; + --scale-factor: 1; +} + +@media screen and (forced-colors: active) { + :root { + --pdfViewer-padding-bottom: 9px; + --page-margin: 8px auto -1px; + --page-border: 1px solid CanvasText; + --page-border-image: none; + --spreadHorizontalWrapped-margin-LR: 3.5px; + } +} + +[data-main-rotation="90"] { + transform: rotate(90deg) translateY(-100%); +} +[data-main-rotation="180"] { + transform: rotate(180deg) translate(-100%, -100%); +} +[data-main-rotation="270"] { + transform: rotate(270deg) translateX(-100%); +} + +.pdfViewer { + padding-bottom: var(--pdfViewer-padding-bottom); +} + .pdfViewer .canvasWrapper { overflow: hidden; } @@ -284,18 +890,24 @@ direction: ltr; width: 816px; height: 1056px; - margin: 1px auto -8px auto; + margin: var(--page-margin); position: relative; overflow: visible; - border: 9px solid transparent; + border: var(--page-border); + -o-border-image: var(--page-border-image); + border-image: var(--page-border-image); background-clip: content-box; - -o-border-image: url(images/shadow.png) 9 9 repeat; - border-image: url(images/shadow.png) 9 9 repeat; background-color: rgba(255, 255, 255, 1); } +.pdfViewer .dummyPage { + position: relative; + width: 0; + height: var(--viewer-container-height); +} + .pdfViewer.removePageBorders .page { - margin: 0px auto 10px auto; + margin: 0 auto 10px; border: none; } @@ -329,6 +941,7 @@ } .spread .page, +.spread .dummyPage, .pdfViewer.scrollHorizontal .page, .pdfViewer.scrollWrapped .page, .pdfViewer.scrollHorizontal .spread, @@ -340,8 +953,8 @@ .spread .page, .pdfViewer.scrollHorizontal .page, .pdfViewer.scrollWrapped .page { - margin-left: -3.5px; - margin-right: -3.5px; + margin-left: var(--spreadHorizontalWrapped-margin-LR); + margin-right: var(--spreadHorizontalWrapped-margin-LR); } .pdfViewer.removePageBorders .spread .page, @@ -369,85 +982,86 @@ bottom: 0; background: url("images/loading-icon.gif") center no-repeat; } +.pdfViewer .page .loadingIcon.notVisible { + background: none; +} + +.pdfViewer.enablePermissions .textLayer span { + -webkit-user-select: none !important; + -moz-user-select: none !important; + user-select: none !important; + cursor: not-allowed; +} .pdfPresentationMode .pdfViewer { - margin-left: 0; - margin-right: 0; + padding-bottom: 0; } -.pdfPresentationMode .pdfViewer .page, -.pdfPresentationMode .pdfViewer .spread { - display: block; +.pdfPresentationMode .spread { + margin: 0; } -.pdfPresentationMode .pdfViewer .page, -.pdfPresentationMode .pdfViewer.removePageBorders .page { - margin-left: auto; - margin-right: auto; -} - -.pdfPresentationMode:-ms-fullscreen .pdfViewer .page { - margin-bottom: 100% !important; -} - -.pdfPresentationMode:-webkit-full-screen .pdfViewer .page { - margin-bottom: 100%; - border: 0; -} - -.pdfPresentationMode:-moz-full-screen .pdfViewer .page { - margin-bottom: 100%; - border: 0; -} - -.pdfPresentationMode:fullscreen .pdfViewer .page { - margin-bottom: 100%; - border: 0; +.pdfPresentationMode .pdfViewer .page { + margin: 0 auto; + border: 2px solid transparent; } :root { + --dir-factor: 1; --sidebar-width: 200px; --sidebar-transition-duration: 200ms; --sidebar-transition-timing-function: ease; + --scale-select-container-width: 140px; + --scale-select-overflow: 22px; --toolbar-icon-opacity: 0.7; --doorhanger-icon-opacity: 0.9; --main-color: rgba(12, 12, 13, 1); --body-bg-color: rgba(237, 237, 240, 1); - --errorWrapper-bg-color: rgba(255, 74, 74, 1); + --errorWrapper-bg-color: rgba(255, 110, 110, 1); + --progressBar-percent: 0%; + --progressBar-end-offset: 0; --progressBar-color: rgba(10, 132, 255, 1); --progressBar-indeterminate-bg-color: rgba(221, 221, 222, 1); --progressBar-indeterminate-blend-color: rgba(116, 177, 239, 1); --scrollbar-color: auto; --scrollbar-bg-color: auto; + --toolbar-icon-bg-color: rgba(0, 0, 0, 1); + --toolbar-icon-hover-bg-color: rgba(0, 0, 0, 1); - --sidebar-bg-color: rgba(245, 246, 247, 1); + --sidebar-narrow-bg-color: rgba(237, 237, 240, 0.9); + --sidebar-toolbar-bg-color: rgba(245, 246, 247, 1); --toolbar-bg-color: rgba(249, 249, 250, 1); --toolbar-border-color: rgba(204, 204, 204, 1); --button-hover-color: rgba(221, 222, 223, 1); + --toggled-btn-color: rgba(0, 0, 0, 1); --toggled-btn-bg-color: rgba(0, 0, 0, 0.3); + --toggled-hover-active-btn-color: rgba(0, 0, 0, 0.4); --dropdown-btn-bg-color: rgba(215, 215, 219, 1); --separator-color: rgba(0, 0, 0, 0.3); --field-color: rgba(6, 6, 6, 1); --field-bg-color: rgba(255, 255, 255, 1); --field-border-color: rgba(187, 187, 188, 1); - --findbar-nextprevious-btn-bg-color: rgba(227, 228, 230, 1); - --outline-color: rgba(0, 0, 0, 0.8); - --outline-hover-color: rgba(0, 0, 0, 0.9); - --outline-active-color: rgba(0, 0, 0, 0.08); - --outline-active-bg-color: rgba(0, 0, 0, 1); + --treeitem-color: rgba(0, 0, 0, 0.8); + --treeitem-hover-color: rgba(0, 0, 0, 0.9); + --treeitem-selected-color: rgba(0, 0, 0, 0.9); + --treeitem-selected-bg-color: rgba(0, 0, 0, 0.25); --sidebaritem-bg-color: rgba(0, 0, 0, 0.15); --doorhanger-bg-color: rgba(255, 255, 255, 1); --doorhanger-border-color: rgba(12, 12, 13, 0.2); - --doorhanger-hover-color: rgba(237, 237, 237, 1); + --doorhanger-hover-color: rgba(12, 12, 13, 1); + --doorhanger-hover-bg-color: rgba(237, 237, 237, 1); --doorhanger-separator-color: rgba(222, 222, 222, 1); - --overlay-button-bg-color: rgba(12, 12, 13, 0.1); - --overlay-button-hover-color: rgba(12, 12, 13, 0.3); + --dialog-button-border: 0 none; + --dialog-button-bg-color: rgba(12, 12, 13, 0.1); + --dialog-button-hover-bg-color: rgba(12, 12, 13, 0.3); - /*--loading-icon: url(images/loading.svg); + --loading-icon: url(images/loading.svg); --treeitem-expanded-icon: url(images/treeitem-expanded.svg); --treeitem-collapsed-icon: url(images/treeitem-collapsed.svg); + --toolbarButton-editorFreeText-icon: url(images/toolbarButton-editorFreeText.svg); + --toolbarButton-editorInk-icon: url(images/toolbarButton-editorInk.svg); --toolbarButton-menuArrow-icon: url(images/toolbarButton-menuArrow.svg); --toolbarButton-sidebarToggle-icon: url(images/toolbarButton-sidebarToggle.svg); --toolbarButton-secondaryToolbarToggle-icon: url(images/toolbarButton-secondaryToolbarToggle.svg); @@ -464,6 +1078,7 @@ --toolbarButton-viewOutline-icon: url(images/toolbarButton-viewOutline.svg); --toolbarButton-viewAttachments-icon: url(images/toolbarButton-viewAttachments.svg); --toolbarButton-viewLayers-icon: url(images/toolbarButton-viewLayers.svg); + --toolbarButton-currentOutlineItem-icon: url(images/toolbarButton-currentOutlineItem.svg); --toolbarButton-search-icon: url(images/toolbarButton-search.svg); --findbarButton-previous-icon: url(images/findbarButton-previous.svg); --findbarButton-next-icon: url(images/findbarButton-next.svg); @@ -473,48 +1088,82 @@ --secondaryToolbarButton-rotateCw-icon: url(images/secondaryToolbarButton-rotateCw.svg); --secondaryToolbarButton-selectTool-icon: url(images/secondaryToolbarButton-selectTool.svg); --secondaryToolbarButton-handTool-icon: url(images/secondaryToolbarButton-handTool.svg); + --secondaryToolbarButton-scrollPage-icon: url(images/secondaryToolbarButton-scrollPage.svg); --secondaryToolbarButton-scrollVertical-icon: url(images/secondaryToolbarButton-scrollVertical.svg); --secondaryToolbarButton-scrollHorizontal-icon: url(images/secondaryToolbarButton-scrollHorizontal.svg); --secondaryToolbarButton-scrollWrapped-icon: url(images/secondaryToolbarButton-scrollWrapped.svg); --secondaryToolbarButton-spreadNone-icon: url(images/secondaryToolbarButton-spreadNone.svg); --secondaryToolbarButton-spreadOdd-icon: url(images/secondaryToolbarButton-spreadOdd.svg); --secondaryToolbarButton-spreadEven-icon: url(images/secondaryToolbarButton-spreadEven.svg); - --secondaryToolbarButton-documentProperties-icon: url(images/secondaryToolbarButton-documentProperties.svg);*/ + --secondaryToolbarButton-documentProperties-icon: url(images/secondaryToolbarButton-documentProperties.svg); +} + +[dir="rtl"]:root { + --dir-factor: -1; } @media (prefers-color-scheme: dark) { :root { --main-color: rgba(249, 249, 250, 1); --body-bg-color: rgba(42, 42, 46, 1); - --errorWrapper-bg-color: rgba(199, 17, 17, 1); + --errorWrapper-bg-color: rgba(169, 14, 14, 1); --progressBar-color: rgba(0, 96, 223, 1); --progressBar-indeterminate-bg-color: rgba(40, 40, 43, 1); --progressBar-indeterminate-blend-color: rgba(20, 68, 133, 1); --scrollbar-color: rgba(121, 121, 123, 1); --scrollbar-bg-color: rgba(35, 35, 39, 1); + --toolbar-icon-bg-color: rgba(255, 255, 255, 1); + --toolbar-icon-hover-bg-color: rgba(255, 255, 255, 1); - --sidebar-bg-color: rgba(50, 50, 52, 1); + --sidebar-narrow-bg-color: rgba(42, 42, 46, 0.9); + --sidebar-toolbar-bg-color: rgba(50, 50, 52, 1); --toolbar-bg-color: rgba(56, 56, 61, 1); --toolbar-border-color: rgba(12, 12, 13, 1); --button-hover-color: rgba(102, 102, 103, 1); + --toggled-btn-color: rgba(255, 255, 255, 1); --toggled-btn-bg-color: rgba(0, 0, 0, 0.3); + --toggled-hover-active-btn-color: rgba(0, 0, 0, 0.4); --dropdown-btn-bg-color: rgba(74, 74, 79, 1); --separator-color: rgba(0, 0, 0, 0.3); --field-color: rgba(250, 250, 250, 1); --field-bg-color: rgba(64, 64, 68, 1); --field-border-color: rgba(115, 115, 115, 1); - --findbar-nextprevious-btn-bg-color: rgba(89, 89, 89, 1); - --outline-color: rgba(255, 255, 255, 0.8); - --outline-hover-color: rgba(255, 255, 255, 0.9); - --outline-active-color: rgba(255, 255, 255, 0.08); - --outline-active-bg-color: rgba(255, 255, 255, 1); + --treeitem-color: rgba(255, 255, 255, 0.8); + --treeitem-hover-color: rgba(255, 255, 255, 0.9); + --treeitem-selected-color: rgba(255, 255, 255, 0.9); + --treeitem-selected-bg-color: rgba(255, 255, 255, 0.25); --sidebaritem-bg-color: rgba(255, 255, 255, 0.15); --doorhanger-bg-color: rgba(74, 74, 79, 1); --doorhanger-border-color: rgba(39, 39, 43, 1); - --doorhanger-hover-color: rgba(93, 94, 98, 1); + --doorhanger-hover-color: rgba(249, 249, 250, 1); + --doorhanger-hover-bg-color: rgba(93, 94, 98, 1); --doorhanger-separator-color: rgba(92, 92, 97, 1); - --overlay-button-bg-color: rgba(92, 92, 97, 1); - --overlay-button-hover-color: rgba(115, 115, 115, 1); + --dialog-button-bg-color: rgba(92, 92, 97, 1); + --dialog-button-hover-bg-color: rgba(115, 115, 115, 1); + + /* This image is used in elements, which unfortunately means that + * the `mask-image` approach used with all of the other images doesn't work + * here; hence why we still have two versions of this particular image. */ + --loading-icon: url(images/loading-dark.svg); + } +} + +@media screen and (forced-colors: active) { + :root { + --button-hover-color: Highlight; + --doorhanger-hover-bg-color: Highlight; + --toolbar-icon-opacity: 1; + --toolbar-icon-bg-color: ButtonText; + --toolbar-icon-hover-bg-color: ButtonFace; + --toggled-btn-color: HighlightText; + --toggled-btn-bg-color: LinkText; + --doorhanger-hover-color: ButtonFace; + --doorhanger-border-color-whcm: 1px solid ButtonText; + --doorhanger-triangle-opacity-whcm: 0; + --dialog-button-border: 1px solid Highlight; + --dialog-button-hover-bg-color: Highlight; + --dialog-button-hover-color: ButtonFace; + --field-border-color: ButtonText; } } @@ -523,211 +1172,32 @@ margin: 0; } -html { - height: 100%; - width: 100%; - /* Font size is needed to make the activity bar the correct size. */ - font-size: 10px; -} - +html, body { height: 100%; width: 100%; - background-color: rgba(237, 237, 240, 1); - background-color: var(--body-bg-color); -} - -@media (prefers-color-scheme: dark) { - - body { - background-color: rgba(42, 42, 46, 1); - background-color: var(--body-bg-color); - } } body { - font: message-box; - outline: none; - scrollbar-color: auto auto; - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); -} - -@media (prefers-color-scheme: dark) { - - body { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - body { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - body { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - body { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -input { - font: message-box; - outline: none; - scrollbar-color: auto auto; - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); -} - -@media (prefers-color-scheme: dark) { - - input { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - input { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - input { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - input { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -button { - font: message-box; - outline: none; - scrollbar-color: auto auto; - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); -} - -@media (prefers-color-scheme: dark) { - - button { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - button { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - button { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - button { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } + background-color: var(--body-bg-color); } +body, +input, +button, select { font: message-box; outline: none; - scrollbar-color: auto auto; scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); } -@media (prefers-color-scheme: dark) { - - select { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - select { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - select { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - select { - scrollbar-color: rgba(121, 121, 123, 1) rgba(35, 35, 39, 1); - scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); - } -} - -.hidden { - display: none !important; -} +.hidden, [hidden] { display: none !important; } -.pdfViewer.enablePermissions .textLayer > span { - -webkit-user-select: none !important; - -moz-user-select: none !important; - -ms-user-select: none !important; - user-select: none !important; - cursor: not-allowed; -} - -#viewerContainer.pdfPresentationMode:-ms-fullscreen { - top: 0px !important; - overflow: hidden !important; -} - -#viewerContainer.pdfPresentationMode:-ms-fullscreen::-ms-backdrop { - background-color: rgba(0, 0, 0, 1); -} - #viewerContainer.pdfPresentationMode:-webkit-full-screen { - top: 0px; - border-top: 2px solid rgba(0, 0, 0, 0); + top: 0; background-color: rgba(0, 0, 0, 1); width: 100%; height: 100%; @@ -737,33 +1207,8 @@ select { user-select: none; } -#viewerContainer.pdfPresentationMode:-moz-full-screen { - top: 0px; - border-top: 2px solid rgba(0, 0, 0, 0); - background-color: rgba(0, 0, 0, 1); - width: 100%; - height: 100%; - overflow: hidden; - cursor: none; - -moz-user-select: none; - user-select: none; -} - -#viewerContainer.pdfPresentationMode:-ms-fullscreen { - top: 0px; - border-top: 2px solid rgba(0, 0, 0, 0); - background-color: rgba(0, 0, 0, 1); - width: 100%; - height: 100%; - overflow: hidden; - cursor: none; - -ms-user-select: none; - user-select: none; -} - #viewerContainer.pdfPresentationMode:fullscreen { - top: 0px; - border-top: 2px solid rgba(0, 0, 0, 0); + top: 0; background-color: rgba(0, 0, 0, 1); width: 100%; height: 100%; @@ -771,7 +1216,6 @@ select { cursor: none; -webkit-user-select: none; -moz-user-select: none; - -ms-user-select: none; user-select: none; } @@ -779,36 +1223,20 @@ select { display: none; } -.pdfPresentationMode:-moz-full-screen a:not(.internalLink) { - display: none; -} - -.pdfPresentationMode:-ms-fullscreen a:not(.internalLink) { - display: none; -} - .pdfPresentationMode:fullscreen a:not(.internalLink) { display: none; } -.pdfPresentationMode:-webkit-full-screen .textLayer > span { +.pdfPresentationMode:-webkit-full-screen .textLayer span { cursor: none; } -.pdfPresentationMode:-moz-full-screen .textLayer > span { - cursor: none; -} - -.pdfPresentationMode:-ms-fullscreen .textLayer > span { - cursor: none; -} - -.pdfPresentationMode:fullscreen .textLayer > span { +.pdfPresentationMode:fullscreen .textLayer span { cursor: none; } .pdfPresentationMode.pdfPresentationModeControls > *, -.pdfPresentationMode.pdfPresentationModeControls .textLayer > span { +.pdfPresentationMode.pdfPresentationModeControls .textLayer span { cursor: default; } @@ -818,54 +1246,58 @@ select { position: relative; } +[dir="ltr"] #sidebarContainer { + left: calc(-1 * var(--sidebar-width)); +} + +[dir="rtl"] #sidebarContainer { + right: calc(-1 * var(--sidebar-width)); +} + +[dir="ltr"] #sidebarContainer { + border-right: var(--doorhanger-border-color-whcm); +} + +[dir="rtl"] #sidebarContainer { + border-left: var(--doorhanger-border-color-whcm); +} + +[dir="ltr"] #sidebarContainer { + transition-property: left; +} + +[dir="rtl"] #sidebarContainer { + transition-property: right; +} + #sidebarContainer { position: absolute; top: 32px; bottom: 0; - width: 200px; + inset-inline-start: calc(-1 * var(--sidebar-width)); width: var(--sidebar-width); visibility: hidden; z-index: 100; border-top: 1px solid rgba(51, 51, 51, 1); - transition-duration: 200ms; + -webkit-border-end: var(--doorhanger-border-color-whcm); + border-inline-end: var(--doorhanger-border-color-whcm); + transition-property: inset-inline-start; transition-duration: var(--sidebar-transition-duration); - transition-timing-function: ease; transition-timing-function: var(--sidebar-transition-timing-function); } -html[dir="ltr"] #sidebarContainer { - transition-property: left; - left: -200px; - left: calc(0px - var(--sidebar-width)); -} -html[dir="rtl"] #sidebarContainer { - transition-property: right; - right: -200px; - right: calc(0px - var(--sidebar-width)); -} - -.loadingInProgress #sidebarContainer { - top: 36px; -} - -#outerContainer.sidebarResizing #sidebarContainer { - /* Improve responsiveness and avoid visual glitches when the sidebar is resized. */ - transition-duration: 0s; - /* Prevent e.g. the thumbnails being selected when the sidebar is resized. */ - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} #outerContainer.sidebarMoving #sidebarContainer, #outerContainer.sidebarOpen #sidebarContainer { visibility: visible; } -html[dir="ltr"] #outerContainer.sidebarOpen #sidebarContainer { - left: 0px; +[dir="ltr"] #outerContainer.sidebarOpen #sidebarContainer { + left: 0; } -html[dir="rtl"] #outerContainer.sidebarOpen #sidebarContainer { - right: 0px; +[dir="rtl"] #outerContainer.sidebarOpen #sidebarContainer { + right: 0; +} +#outerContainer.sidebarOpen #sidebarContainer { + inset-inline-start: 0; } #mainContainer { @@ -874,30 +1306,30 @@ html[dir="rtl"] #outerContainer.sidebarOpen #sidebarContainer { right: 0; bottom: 0; left: 0; - min-width: 320px; + min-width: 350px; +} + +[dir="ltr"] #sidebarContent { + left: 0; +} + +[dir="rtl"] #sidebarContent { + right: 0; } #sidebarContent { top: 32px; bottom: 0; + inset-inline-start: 0; overflow: auto; - -webkit-overflow-scrolling: touch; position: absolute; width: 100%; background-color: rgba(0, 0, 0, 0.1); -} -html[dir="ltr"] #sidebarContent { - left: 0; - box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.25); -} -html[dir="rtl"] #sidebarContent { - right: 0; - box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.25); + box-shadow: inset calc(-1px * var(--dir-factor)) 0 0 rgba(0, 0, 0, 0.25); } #viewerContainer { overflow: auto; - -webkit-overflow-scrolling: touch; position: absolute; top: 32px; right: 0; @@ -906,32 +1338,31 @@ html[dir="rtl"] #sidebarContent { outline: none; } #viewerContainer:not(.pdfPresentationMode) { - transition-duration: 200ms; transition-duration: var(--sidebar-transition-duration); - transition-timing-function: ease; transition-timing-function: var(--sidebar-transition-timing-function); } -#outerContainer.sidebarResizing #viewerContainer { - /* Improve responsiveness and avoid visual glitches when the sidebar is resized. */ - transition-duration: 0s; -} - -html[dir="ltr"] - #outerContainer.sidebarOpen - #viewerContainer:not(.pdfPresentationMode) { - transition-property: left; - left: 200px; +[dir="ltr"] #outerContainer.sidebarOpen #viewerContainer:not(.pdfPresentationMode) { left: var(--sidebar-width); } -html[dir="rtl"] - #outerContainer.sidebarOpen - #viewerContainer:not(.pdfPresentationMode) { - transition-property: right; - right: 200px; + +[dir="rtl"] #outerContainer.sidebarOpen #viewerContainer:not(.pdfPresentationMode) { right: var(--sidebar-width); } +[dir="ltr"] #outerContainer.sidebarOpen #viewerContainer:not(.pdfPresentationMode) { + transition-property: left; +} + +[dir="rtl"] #outerContainer.sidebarOpen #viewerContainer:not(.pdfPresentationMode) { + transition-property: right; +} + +#outerContainer.sidebarOpen #viewerContainer:not(.pdfPresentationMode) { + inset-inline-start: var(--sidebar-width); + transition-property: inset-inline-start; +} + .toolbar { position: relative; left: 0; @@ -947,256 +1378,127 @@ html[dir="rtl"] #toolbarSidebar { width: 100%; height: 32px; - background-color: rgba(245, 246, 247, 1); - background-color: var(--sidebar-bg-color); + background-color: var(--sidebar-toolbar-bg-color); + box-shadow: inset calc(-1px * var(--dir-factor)) 0 0 rgba(0, 0, 0, 0.25), + 0 1px 0 rgba(0, 0, 0, 0.15), 0 0 1px rgba(0, 0, 0, 0.1); } -@media (prefers-color-scheme: dark) { - - #toolbarSidebar { - background-color: rgba(50, 50, 52, 1); - background-color: var(--sidebar-bg-color); - } -} -html[dir="ltr"] #toolbarSidebar { - box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(0, 0, 0, 0.15), - 0 0 1px rgba(0, 0, 0, 0.1); -} -html[dir="rtl"] #toolbarSidebar { - box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(0, 0, 0, 0.15), - 0 0 1px rgba(0, 0, 0, 0.1); +[dir="ltr"] #sidebarResizer { + right: -6px; } -html[dir="ltr"] #toolbarSidebar .toolbarButton { - margin-right: 2px !important; -} -html[dir="rtl"] #toolbarSidebar .toolbarButton { - margin-left: 2px !important; +[dir="rtl"] #sidebarResizer { + left: -6px; } #sidebarResizer { position: absolute; top: 0; bottom: 0; + inset-inline-end: -6px; width: 6px; z-index: 200; cursor: ew-resize; } -html[dir="ltr"] #sidebarResizer { - right: -6px; -} -html[dir="rtl"] #sidebarResizer { - left: -6px; -} -#toolbarContainer { +#toolbarContainer, +.findbar, +.secondaryToolbar, +.editorParamsToolbar { position: relative; height: 32px; - background-color: rgba(249, 249, 250, 1); background-color: var(--toolbar-bg-color); -} - -@media (prefers-color-scheme: dark) { - - #toolbarContainer { - background-color: rgba(56, 56, 61, 1); - background-color: var(--toolbar-bg-color); - } -} - -.findbar { - position: relative; - height: 32px; - background-color: rgba(249, 249, 250, 1); - background-color: var(--toolbar-bg-color); -} - -@media (prefers-color-scheme: dark) { - - .findbar { - background-color: rgba(56, 56, 61, 1); - background-color: var(--toolbar-bg-color); - } -} - -.secondaryToolbar { - position: relative; - height: 32px; - background-color: rgba(249, 249, 250, 1); - background-color: var(--toolbar-bg-color); -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbar { - background-color: rgba(56, 56, 61, 1); - background-color: var(--toolbar-bg-color); - } -} -html[dir="ltr"] #toolbarContainer { - box-shadow: 0 1px 0 rgba(204, 204, 204, 1); box-shadow: 0 1px 0 var(--toolbar-border-color); } -@media (prefers-color-scheme: dark) { - - html[dir="ltr"] #toolbarContainer { - box-shadow: 0 1px 0 rgba(12, 12, 13, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); - } -} -.findbar { - box-shadow: 0 1px 0 rgba(204, 204, 204, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); -} -@media (prefers-color-scheme: dark) { - - .findbar { - box-shadow: 0 1px 0 rgba(12, 12, 13, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); - } -} -.secondaryToolbar { - box-shadow: 0 1px 0 rgba(204, 204, 204, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); -} -@media (prefers-color-scheme: dark) { - - .secondaryToolbar { - box-shadow: 0 1px 0 rgba(12, 12, 13, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); - } -} -html[dir="rtl"] #toolbarContainer { - box-shadow: 0 1px 0 rgba(204, 204, 204, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); -} -@media (prefers-color-scheme: dark) { - - html[dir="rtl"] #toolbarContainer { - box-shadow: 0 1px 0 rgba(12, 12, 13, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); - } -} -.findbar { - box-shadow: 0 1px 0 rgba(204, 204, 204, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); -} -@media (prefers-color-scheme: dark) { - - .findbar { - box-shadow: 0 1px 0 rgba(12, 12, 13, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); - } -} -.secondaryToolbar { - box-shadow: 0 1px 0 rgba(204, 204, 204, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); -} -@media (prefers-color-scheme: dark) { - - .secondaryToolbar { - box-shadow: 0 1px 0 rgba(12, 12, 13, 1); - box-shadow: 0 1px 0 var(--toolbar-border-color); - } -} #toolbarViewer { height: 32px; } +[dir="ltr"] #loadingBar { + left: 0; + right: var(--progressBar-end-offset); +} + +[dir="rtl"] #loadingBar { + right: 0; + left: var(--progressBar-end-offset); +} + +[dir="ltr"] #loadingBar { + transition-property: left; +} + +[dir="rtl"] #loadingBar { + transition-property: right; +} + #loadingBar { - position: relative; - width: 100%; + position: absolute; + inset-inline: 0 var(--progressBar-end-offset); height: 4px; - background-color: rgba(237, 237, 240, 1); background-color: var(--body-bg-color); - border-bottom: 1px solid rgba(204, 204, 204, 1); border-bottom: 1px solid var(--toolbar-border-color); + transition-property: inset-inline-start; + transition-duration: var(--sidebar-transition-duration); + transition-timing-function: var(--sidebar-transition-timing-function); } -@media (prefers-color-scheme: dark) { - - #loadingBar { - border-bottom: 1px solid rgba(12, 12, 13, 1); - border-bottom: 1px solid var(--toolbar-border-color); - } +[dir="ltr"] #outerContainer.sidebarOpen #loadingBar { + left: var(--sidebar-width); } -@media (prefers-color-scheme: dark) { +[dir="rtl"] #outerContainer.sidebarOpen #loadingBar { + right: var(--sidebar-width); +} - #loadingBar { - background-color: rgba(42, 42, 46, 1); - background-color: var(--body-bg-color); - } +#outerContainer.sidebarOpen #loadingBar { + inset-inline-start: var(--sidebar-width); } #loadingBar .progress { position: absolute; top: 0; left: 0; - width: 0%; + width: 100%; + transform: scaleX(var(--progressBar-percent)); + transform-origin: 0 0; height: 100%; - background-color: rgba(10, 132, 255, 1); background-color: var(--progressBar-color); overflow: hidden; - transition: width 200ms; -} - -@media (prefers-color-scheme: dark) { - - #loadingBar .progress { - background-color: rgba(0, 96, 223, 1); - background-color: var(--progressBar-color); - } + transition: transform 200ms; } @-webkit-keyframes progressIndeterminate { 0% { - left: -142px; + transform: translateX(-142px); } 100% { - left: 0; + transform: translateX(0); } } @keyframes progressIndeterminate { 0% { - left: -142px; + transform: translateX(-142px); } 100% { - left: 0; + transform: translateX(0); } } -#loadingBar .progress.indeterminate { - background-color: rgba(221, 221, 222, 1); +#loadingBar.indeterminate .progress { + transform: none; background-color: var(--progressBar-indeterminate-bg-color); transition: none; } -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate { - background-color: rgba(40, 40, 43, 1); - background-color: var(--progressBar-indeterminate-bg-color); - } -} - -#loadingBar .progress.indeterminate .glimmer { +#loadingBar.indeterminate .progress .glimmer { position: absolute; top: 0; left: 0; height: 100%; width: calc(100% + 150px); - background: repeating-linear-gradient( - 135deg, - rgba(116, 177, 239, 1) 0, - rgba(221, 221, 222, 1) 5px, - rgba(221, 221, 222, 1) 45px, - rgba(10, 132, 255, 1) 55px, - rgba(10, 132, 255, 1) 95px, - rgba(116, 177, 239, 1) 100px - ); background: repeating-linear-gradient( 135deg, var(--progressBar-indeterminate-blend-color) 0, @@ -1210,365 +1512,61 @@ html[dir="rtl"] #toolbarContainer { animation: progressIndeterminate 1s linear infinite; } -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate .glimmer { - background: repeating-linear-gradient( - 135deg, - rgba(20, 68, 133, 1) 0, - rgba(40, 40, 43, 1) 5px, - rgba(40, 40, 43, 1) 45px, - rgba(0, 96, 223, 1) 55px, - rgba(0, 96, 223, 1) 95px, - rgba(20, 68, 133, 1) 100px - ); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-indeterminate-blend-color) 0, - var(--progressBar-indeterminate-bg-color) 5px, - var(--progressBar-indeterminate-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-indeterminate-blend-color) 100px - ); - } -} - -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate .glimmer { - background: repeating-linear-gradient( - 135deg, - rgba(20, 68, 133, 1) 0, - rgba(40, 40, 43, 1) 5px, - rgba(40, 40, 43, 1) 45px, - rgba(0, 96, 223, 1) 55px, - rgba(0, 96, 223, 1) 95px, - rgba(20, 68, 133, 1) 100px - ); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-indeterminate-blend-color) 0, - var(--progressBar-indeterminate-bg-color) 5px, - var(--progressBar-indeterminate-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-indeterminate-blend-color) 100px - ); - } -} - -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate .glimmer { - background: repeating-linear-gradient( - 135deg, - rgba(20, 68, 133, 1) 0, - rgba(40, 40, 43, 1) 5px, - rgba(40, 40, 43, 1) 45px, - rgba(0, 96, 223, 1) 55px, - rgba(0, 96, 223, 1) 95px, - rgba(20, 68, 133, 1) 100px - ); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-indeterminate-blend-color) 0, - var(--progressBar-indeterminate-bg-color) 5px, - var(--progressBar-indeterminate-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-indeterminate-blend-color) 100px - ); - } -} - -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate .glimmer { - background: repeating-linear-gradient( - 135deg, - rgba(20, 68, 133, 1) 0, - rgba(40, 40, 43, 1) 5px, - rgba(40, 40, 43, 1) 45px, - rgba(0, 96, 223, 1) 55px, - rgba(0, 96, 223, 1) 95px, - rgba(20, 68, 133, 1) 100px - ); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-indeterminate-blend-color) 0, - var(--progressBar-indeterminate-bg-color) 5px, - var(--progressBar-indeterminate-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-indeterminate-blend-color) 100px - ); - } -} - -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate .glimmer { - background: repeating-linear-gradient( - 135deg, - rgba(20, 68, 133, 1) 0, - rgba(40, 40, 43, 1) 5px, - rgba(40, 40, 43, 1) 45px, - rgba(0, 96, 223, 1) 55px, - rgba(0, 96, 223, 1) 95px, - rgba(20, 68, 133, 1) 100px - ); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-indeterminate-blend-color) 0, - var(--progressBar-indeterminate-bg-color) 5px, - var(--progressBar-indeterminate-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-indeterminate-blend-color) 100px - ); - } -} - -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate .glimmer { - background: repeating-linear-gradient( - 135deg, - rgba(20, 68, 133, 1) 0, - rgba(40, 40, 43, 1) 5px, - rgba(40, 40, 43, 1) 45px, - rgba(0, 96, 223, 1) 55px, - rgba(0, 96, 223, 1) 95px, - rgba(20, 68, 133, 1) 100px - ); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-indeterminate-blend-color) 0, - var(--progressBar-indeterminate-bg-color) 5px, - var(--progressBar-indeterminate-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-indeterminate-blend-color) 100px - ); - } -} - -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate .glimmer { - background: repeating-linear-gradient( - 135deg, - rgba(20, 68, 133, 1) 0, - rgba(40, 40, 43, 1) 5px, - rgba(40, 40, 43, 1) 45px, - rgba(0, 96, 223, 1) 55px, - rgba(0, 96, 223, 1) 95px, - rgba(20, 68, 133, 1) 100px - ); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-indeterminate-blend-color) 0, - var(--progressBar-indeterminate-bg-color) 5px, - var(--progressBar-indeterminate-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-indeterminate-blend-color) 100px - ); - } -} - -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate .glimmer { - background: repeating-linear-gradient( - 135deg, - rgba(20, 68, 133, 1) 0, - rgba(40, 40, 43, 1) 5px, - rgba(40, 40, 43, 1) 45px, - rgba(0, 96, 223, 1) 55px, - rgba(0, 96, 223, 1) 95px, - rgba(20, 68, 133, 1) 100px - ); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-indeterminate-blend-color) 0, - var(--progressBar-indeterminate-bg-color) 5px, - var(--progressBar-indeterminate-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-indeterminate-blend-color) 100px - ); - } -} - -@media (prefers-color-scheme: dark) { - - #loadingBar .progress.indeterminate .glimmer { - background: repeating-linear-gradient( - 135deg, - rgba(20, 68, 133, 1) 0, - rgba(40, 40, 43, 1) 5px, - rgba(40, 40, 43, 1) 45px, - rgba(0, 96, 223, 1) 55px, - rgba(0, 96, 223, 1) 95px, - rgba(20, 68, 133, 1) 100px - ); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-indeterminate-blend-color) 0, - var(--progressBar-indeterminate-bg-color) 5px, - var(--progressBar-indeterminate-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-indeterminate-blend-color) 100px - ); - } +#outerContainer.sidebarResizing #sidebarContainer, +#outerContainer.sidebarResizing #viewerContainer, +#outerContainer.sidebarResizing #loadingBar { + /* Improve responsiveness and avoid visual glitches when the sidebar is resized. */ + transition-duration: 0s; } .findbar, -.secondaryToolbar { +.secondaryToolbar, +.editorParamsToolbar { top: 32px; position: absolute; z-index: 10000; height: auto; - min-width: 16px; - padding: 0px 4px 0px 4px; - margin: 4px 2px 4px 2px; - color: rgba(217, 217, 217, 1); + padding: 0 4px; + margin: 4px 2px; font-size: 12px; line-height: 14px; text-align: left; cursor: default; } -.findbar { - min-width: 300px; - background-color: rgba(249, 249, 250, 1); - background-color: var(--toolbar-bg-color); +[dir="ltr"] .findbar { + left: 64px; } -@media (prefers-color-scheme: dark) { +[dir="rtl"] .findbar { + right: 64px; +} - .findbar { - background-color: rgba(56, 56, 61, 1); +.findbar { + inset-inline-start: 64px; + min-width: 300px; background-color: var(--toolbar-bg-color); - } } .findbar > div { height: 32px; } -.findbar.wrapContainers > div { +[dir="ltr"] .findbar > div#findbarInputContainer { + margin-right: 4px; +} +[dir="rtl"] .findbar > div#findbarInputContainer { + margin-left: 4px; +} +.findbar > div#findbarInputContainer { + -webkit-margin-end: 4px; + margin-inline-end: 4px; +} +.findbar.wrapContainers > div, +.findbar.wrapContainers > div#findbarMessageContainer > * { clear: both; } .findbar.wrapContainers > div#findbarMessageContainer { height: auto; } -html[dir="ltr"] .findbar { - left: 64px; -} -html[dir="rtl"] .findbar { - right: 64px; -} - -html[dir="ltr"] .findbar .splitToolbarButton { - margin-left: 0px; - margin-top: 3px; -} - -html[dir="rtl"] .findbar .splitToolbarButton { - margin-right: 0px; - margin-top: 3px; -} - -.findbar .splitToolbarButton .findNext { - width: 29px; -} - -html[dir="ltr"] .findbar .splitToolbarButton .findNext { - border-right: 1px solid rgba(187, 187, 188, 1); - border-right: 1px solid var(--field-border-color); -} - -@media (prefers-color-scheme: dark) { - - html[dir="ltr"] .findbar .splitToolbarButton .findNext { - border-right: 1px solid rgba(115, 115, 115, 1); - border-right: 1px solid var(--field-border-color); - } -} - -html[dir="rtl"] .findbar .splitToolbarButton .findNext { - border-left: 1px solid rgba(187, 187, 188, 1); - border-left: 1px solid var(--field-border-color); -} - -@media (prefers-color-scheme: dark) { - - html[dir="rtl"] .findbar .splitToolbarButton .findNext { - border-left: 1px solid rgba(115, 115, 115, 1); - border-left: 1px solid var(--field-border-color); - } -} - -.findbar .splitToolbarButton .toolbarButton { - background-color: rgba(227, 228, 230, 1); - background-color: var(--findbar-nextprevious-btn-bg-color); - border-radius: 0px; - height: 26px; - border-top: 1px solid rgba(187, 187, 188, 1); - border-top: 1px solid var(--field-border-color); - border-bottom: 1px solid rgba(187, 187, 188, 1); - border-bottom: 1px solid var(--field-border-color); -} - -@media (prefers-color-scheme: dark) { - - .findbar .splitToolbarButton .toolbarButton { - border-bottom: 1px solid rgba(115, 115, 115, 1); - border-bottom: 1px solid var(--field-border-color); - } -} - -@media (prefers-color-scheme: dark) { - - .findbar .splitToolbarButton .toolbarButton { - border-top: 1px solid rgba(115, 115, 115, 1); - border-top: 1px solid var(--field-border-color); - } -} - -@media (prefers-color-scheme: dark) { - - .findbar .splitToolbarButton .toolbarButton { - background-color: rgba(89, 89, 89, 1); - background-color: var(--findbar-nextprevious-btn-bg-color); - } -} - -.findbar .splitToolbarButton .toolbarButton::before { - top: 5px; -} - -html[dir="ltr"] .findbar .splitToolbarButton > .findPrevious { - border-radius: 0; -} -html[dir="ltr"] .findbar .splitToolbarButton > .findNext { - border-bottom-left-radius: 0; - border-bottom-right-radius: 2px; - border-top-left-radius: 0; - border-top-right-radius: 2px; -} - -html[dir="rtl"] .findbar .splitToolbarButton > .findPrevious { - border-radius: 0; -} -html[dir="rtl"] .findbar .splitToolbarButton > .findNext { - border-bottom-left-radius: 2px; - border-bottom-right-radius: 0; - border-top-left-radius: 2px; - border-top-right-radius: 0; -} .findbar input[type="checkbox"] { pointer-events: none; @@ -1577,360 +1575,385 @@ html[dir="rtl"] .findbar .splitToolbarButton > .findNext { .findbar label { -webkit-user-select: none; -moz-user-select: none; - -ms-user-select: none; user-select: none; } -.findbar label:hover { - background-color: rgba(221, 222, 223, 1); +.findbar label:hover, +.findbar input:focus-visible + label { + color: var(--toggled-btn-color); background-color: var(--button-hover-color); } -@media (prefers-color-scheme: dark) { - - .findbar label:hover { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} - -.findbar input:focus + label { - background-color: rgba(221, 222, 223, 1); - background-color: var(--button-hover-color); -} - -@media (prefers-color-scheme: dark) { - - .findbar input:focus + label { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} - -html[dir="ltr"] #findInput { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -html[dir="rtl"] #findInput { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - .findbar .toolbarField[type="checkbox"]:checked + .toolbarLabel { - background-color: rgba(0, 0, 0, 0.3) !important; background-color: var(--toggled-btn-bg-color) !important; -} - -@media (prefers-color-scheme: dark) { - - .findbar .toolbarField[type="checkbox"]:checked + .toolbarLabel { - background-color: rgba(0, 0, 0, 0.3) !important; - background-color: var(--toggled-btn-bg-color) !important; - } + color: var(--toggled-btn-color); } #findInput { width: 200px; } -#findInput::-webkit-input-placeholder { - color: rgba(191, 191, 191, 1); -} #findInput::-moz-placeholder { font-style: normal; } -#findInput:-ms-input-placeholder { - font-style: normal; -} -#findInput::-ms-input-placeholder { - font-style: normal; -} #findInput::placeholder { font-style: normal; } #findInput[data-status="pending"] { - background-image: url(images/loading.svg); - /*background-image: var(--loading-icon);*/ + background-image: var(--loading-icon); background-repeat: no-repeat; - background-position: 98%; + background-position: calc(50% + 48% * var(--dir-factor)); } -@media (prefers-color-scheme: dark) { - - #findInput[data-status="pending"] { - background-image: url(images/loading-dark.svg); - /*background-image: var(--loading-icon);*/ - } -} -html[dir="rtl"] #findInput[data-status="pending"] { - background-position: 3px; +#findInput[data-status="notFound"] { + background-color: rgba(255, 102, 102, 1); } -.secondaryToolbar { - padding: 6px 0 10px 0; - height: auto; - z-index: 30000; - background-color: rgba(255, 255, 255, 1); - background-color: var(--doorhanger-bg-color); -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbar { - background-color: rgba(74, 74, 79, 1); - background-color: var(--doorhanger-bg-color); - } -} -html[dir="ltr"] .secondaryToolbar { +[dir="ltr"] .secondaryToolbar,[dir="ltr"] +.editorParamsToolbar { right: 4px; } -html[dir="rtl"] .secondaryToolbar { + +[dir="rtl"] .secondaryToolbar,[dir="rtl"] +.editorParamsToolbar { left: 4px; } +.secondaryToolbar, +.editorParamsToolbar { + padding: 6px 0 10px; + inset-inline-end: 4px; + height: auto; + z-index: 30000; + background-color: var(--doorhanger-bg-color); +} + +.editorParamsToolbarContainer { + width: 220px; + margin-bottom: -4px; +} + +.editorParamsToolbarContainer > .editorParamsSetter { + min-height: 26px; + display: flex; + align-items: center; + justify-content: space-between; + padding-left: 10px; + padding-right: 10px; + padding-inline: 10px; +} + +[dir="ltr"] .editorParamsToolbarContainer .editorParamsLabel { + padding-right: 10px; +} + +[dir="rtl"] .editorParamsToolbarContainer .editorParamsLabel { + padding-left: 10px; +} + +.editorParamsToolbarContainer .editorParamsLabel { + -webkit-padding-end: 10px; + padding-inline-end: 10px; + flex: none; + color: var(--main-color); +} + +.editorParamsToolbarContainer .editorParamsColor { + width: 32px; + height: 32px; + flex: none; +} + +.editorParamsToolbarContainer .editorParamsSlider { + background-color: transparent; + width: 90px; + flex: 0 1 0; +} + +.editorParamsToolbarContainer .editorParamsSlider::-moz-range-progress { + background-color: black; +} + +.editorParamsToolbarContainer .editorParamsSlider::-webkit-slider-runnable-track, +.editorParamsToolbarContainer .editorParamsSlider::-moz-range-track { + background-color: black; +} + +.editorParamsToolbarContainer .editorParamsSlider::-webkit-slider-thumb, +.editorParamsToolbarContainer .editorParamsSlider::-moz-range-thumb { + background-color: white; +} + #secondaryToolbarButtonContainer { max-width: 220px; - max-height: 400px; + min-height: 26px; + max-height: calc(var(--viewer-container-height) - 40px); overflow-y: auto; - -webkit-overflow-scrolling: touch; margin-bottom: -4px; } -#secondaryToolbarButtonContainer.hiddenScrollModeButtons > .scrollModeButtons, -#secondaryToolbarButtonContainer.hiddenSpreadModeButtons > .spreadModeButtons { - display: none !important; +[dir="ltr"] #editorInkParamsToolbar { + right: 40px; } -.doorHanger { - border-radius: 2px; - box-shadow: 0 1px 5px rgba(12, 12, 13, 0.2), - 0 0 0 1px rgba(12, 12, 13, 0.2); - box-shadow: 0 1px 5px var(--doorhanger-border-color), - 0 0 0 1px var(--doorhanger-border-color); +[dir="rtl"] #editorInkParamsToolbar { + left: 40px; } -@media (prefers-color-scheme: dark) { - - .doorHanger { - box-shadow: 0 1px 5px rgba(39, 39, 43, 1), - 0 0 0 1px rgba(39, 39, 43, 1); - box-shadow: 0 1px 5px var(--doorhanger-border-color), - 0 0 0 1px var(--doorhanger-border-color); - } +#editorInkParamsToolbar { + inset-inline-end: 40px; + background-color: var(--toolbar-bg-color); } +[dir="ltr"] #editorFreeTextParamsToolbar { + right: 68px; +} + +[dir="rtl"] #editorFreeTextParamsToolbar { + left: 68px; +} + +#editorFreeTextParamsToolbar { + inset-inline-end: 68px; + background-color: var(--toolbar-bg-color); +} + +.doorHanger, .doorHangerRight { border-radius: 2px; - box-shadow: 0 1px 5px rgba(12, 12, 13, 0.2), - 0 0 0 1px rgba(12, 12, 13, 0.2); box-shadow: 0 1px 5px var(--doorhanger-border-color), 0 0 0 1px var(--doorhanger-border-color); -} - -@media (prefers-color-scheme: dark) { - - .doorHangerRight { - box-shadow: 0 1px 5px rgba(39, 39, 43, 1), - 0 0 0 1px rgba(39, 39, 43, 1); - box-shadow: 0 1px 5px var(--doorhanger-border-color), - 0 0 0 1px var(--doorhanger-border-color); - } + border: var(--doorhanger-border-color-whcm); } .doorHanger:after, .doorHanger:before, .doorHangerRight:after, .doorHangerRight:before { bottom: 100%; - border: solid rgba(0, 0, 0, 0); + border: 8px solid rgba(0, 0, 0, 0); content: " "; height: 0; width: 0; position: absolute; pointer-events: none; + opacity: var(--doorhanger-triangle-opacity-whcm); } -.doorHanger:after, -.doorHangerRight:after { - border-width: 8px; -} -.doorHanger:after { - border-bottom-color: rgba(249, 249, 250, 1); - border-bottom-color: var(--toolbar-bg-color); -} -@media (prefers-color-scheme: dark) { - - .doorHanger:after { - border-bottom-color: rgba(56, 56, 61, 1); - border-bottom-color: var(--toolbar-bg-color); - } -} -.doorHangerRight:after { - border-bottom-color: rgba(255, 255, 255, 1); - border-bottom-color: var(--doorhanger-bg-color); -} -@media (prefers-color-scheme: dark) { - - .doorHangerRight:after { - border-bottom-color: rgba(74, 74, 79, 1); - border-bottom-color: var(--doorhanger-bg-color); - } -} -.doorHanger:before { - border-bottom-color: rgba(12, 12, 13, 0.2); - border-bottom-color: var(--doorhanger-border-color); - border-width: 9px; -} -@media (prefers-color-scheme: dark) { - - .doorHanger:before { - border-bottom-color: rgba(39, 39, 43, 1); - border-bottom-color: var(--doorhanger-border-color); - } -} -.doorHangerRight:before { - border-bottom-color: rgba(12, 12, 13, 0.2); - border-bottom-color: var(--doorhanger-border-color); - border-width: 9px; -} -@media (prefers-color-scheme: dark) { - - .doorHangerRight:before { - border-bottom-color: rgba(39, 39, 43, 1); - border-bottom-color: var(--doorhanger-border-color); - } -} - -html[dir="ltr"] .doorHanger:after, -html[dir="rtl"] .doorHangerRight:after { +[dir="ltr"] .doorHanger:after { left: 10px; +} +[dir="rtl"] .doorHanger:after { + right: 10px; +} +[dir="ltr"] .doorHanger:after { margin-left: -8px; } - -html[dir="ltr"] .doorHanger:before, -html[dir="rtl"] .doorHangerRight:before { - left: 10px; - margin-left: -9px; -} - -html[dir="rtl"] .doorHanger:after, -html[dir="ltr"] .doorHangerRight:after { - right: 10px; +[dir="rtl"] .doorHanger:after { margin-right: -8px; } - -html[dir="rtl"] .doorHanger:before, -html[dir="ltr"] .doorHangerRight:before { +.doorHanger:after { + inset-inline-start: 10px; + -webkit-margin-start: -8px; + margin-inline-start: -8px; + border-bottom-color: var(--toolbar-bg-color); +} +[dir="ltr"] .doorHangerRight:after { right: 10px; +} +[dir="rtl"] .doorHangerRight:after { + left: 10px; +} +[dir="ltr"] .doorHangerRight:after { + margin-right: -8px; +} +[dir="rtl"] .doorHangerRight:after { + margin-left: -8px; +} +.doorHangerRight:after { + inset-inline-end: 10px; + -webkit-margin-end: -8px; + margin-inline-end: -8px; + border-bottom-color: var(--doorhanger-bg-color); +} +.doorHanger:before, +.doorHangerRight:before { + border-bottom-color: var(--doorhanger-border-color); + border-width: 9px; +} +[dir="ltr"] .doorHanger:before { + left: 10px; +} +[dir="rtl"] .doorHanger:before { + right: 10px; +} +[dir="ltr"] .doorHanger:before { + margin-left: -9px; +} +[dir="rtl"] .doorHanger:before { margin-right: -9px; } +.doorHanger:before { + inset-inline-start: 10px; + -webkit-margin-start: -9px; + margin-inline-start: -9px; +} +[dir="ltr"] .doorHangerRight:before { + right: 10px; +} +[dir="rtl"] .doorHangerRight:before { + left: 10px; +} +[dir="ltr"] .doorHangerRight:before { + margin-right: -9px; +} +[dir="rtl"] .doorHangerRight:before { + margin-left: -9px; +} +.doorHangerRight:before { + inset-inline-end: 10px; + -webkit-margin-end: -9px; + margin-inline-end: -9px; +} #findResultsCount { background-color: rgba(217, 217, 217, 1); color: rgba(82, 82, 82, 1); text-align: center; - padding: 3px 4px; + padding: 4px 5px; margin: 5px; } #findMsg { color: rgba(251, 0, 0, 1); } + +#findResultsCount:empty, #findMsg:empty { display: none; } -#findInput.notFound { - background-color: rgba(255, 102, 102, 1); -} - #toolbarViewerMiddle { position: absolute; left: 50%; transform: translateX(-50%); } -html[dir="ltr"] #toolbarViewerLeft, -html[dir="rtl"] #toolbarViewerRight { +[dir="ltr"] #toolbarViewerLeft,[dir="ltr"] +#toolbarSidebarLeft { float: left; } -html[dir="ltr"] #toolbarViewerRight, -html[dir="rtl"] #toolbarViewerLeft { - float: right; -} -html[dir="ltr"] #toolbarViewerLeft > *, -html[dir="ltr"] #toolbarViewerMiddle > *, -html[dir="ltr"] #toolbarViewerRight > *, -html[dir="ltr"] .findbar * { - position: relative; - float: left; -} -html[dir="rtl"] #toolbarViewerLeft > *, -html[dir="rtl"] #toolbarViewerMiddle > *, -html[dir="rtl"] #toolbarViewerRight > *, -html[dir="rtl"] .findbar * { - position: relative; + +[dir="rtl"] #toolbarViewerLeft,[dir="rtl"] +#toolbarSidebarLeft { float: right; } -html[dir="ltr"] .splitToolbarButton { - margin: 2px 2px 0; - display: inline-block; +#toolbarViewerLeft, +#toolbarSidebarLeft { + float: inline-start; } -html[dir="rtl"] .splitToolbarButton { - margin: 2px 2px 0; - display: inline-block; +[dir="ltr"] #toolbarViewerRight,[dir="ltr"] +#toolbarSidebarRight { + float: right; } -html[dir="ltr"] .splitToolbarButton > .toolbarButton { - border-radius: 2px; +[dir="rtl"] #toolbarViewerRight,[dir="rtl"] +#toolbarSidebarRight { float: left; } -html[dir="rtl"] .splitToolbarButton > .toolbarButton { - border-radius: 2px; +#toolbarViewerRight, +#toolbarSidebarRight { + float: inline-end; +} + +[dir="ltr"] #toolbarViewerLeft > *,[dir="ltr"] +#toolbarViewerMiddle > *,[dir="ltr"] +#toolbarViewerRight > *,[dir="ltr"] +#toolbarSidebarLeft *,[dir="ltr"] +#toolbarSidebarRight *,[dir="ltr"] +.findbar * { + float: left; +} + +[dir="rtl"] #toolbarViewerLeft > *,[dir="rtl"] +#toolbarViewerMiddle > *,[dir="rtl"] +#toolbarViewerRight > *,[dir="rtl"] +#toolbarSidebarLeft *,[dir="rtl"] +#toolbarSidebarRight *,[dir="rtl"] +.findbar * { float: right; } +#toolbarViewerLeft > *, +#toolbarViewerMiddle > *, +#toolbarViewerRight > *, +#toolbarSidebarLeft *, +#toolbarSidebarRight *, +.findbar * { + position: relative; + float: inline-start; +} + +[dir="ltr"] #toolbarViewerLeft { + padding-left: 1px; +} + +[dir="rtl"] #toolbarViewerLeft { + padding-right: 1px; +} + +#toolbarViewerLeft { + -webkit-padding-start: 1px; + padding-inline-start: 1px; +} +[dir="ltr"] #toolbarViewerRight { + padding-right: 1px; +} +[dir="rtl"] #toolbarViewerRight { + padding-left: 1px; +} +#toolbarViewerRight { + -webkit-padding-end: 1px; + padding-inline-end: 1px; +} +[dir="ltr"] #toolbarSidebarRight { + padding-right: 2px; +} +[dir="rtl"] #toolbarSidebarRight { + padding-left: 2px; +} +#toolbarSidebarRight { + -webkit-padding-end: 2px; + padding-inline-end: 2px; +} + +.splitToolbarButton { + margin: 2px; + display: inline-block; +} +[dir="ltr"] .splitToolbarButton > .toolbarButton { + float: left; +} +[dir="rtl"] .splitToolbarButton > .toolbarButton { + float: right; +} +.splitToolbarButton > .toolbarButton { + float: inline-start; +} + .toolbarButton, .secondaryToolbarButton, -.overlayButton { +.dialogButton { border: 0 none; background: none; width: 28px; height: 28px; } -.overlayButton { - background-color: rgba(12, 12, 13, 0.1); - background-color: var(--overlay-button-bg-color); -} -@media (prefers-color-scheme: dark) { - .overlayButton { - background-color: rgba(92, 92, 97, 1); - background-color: var(--overlay-button-bg-color); - } +.dialogButton:hover, +.dialogButton:focus-visible { + background-color: var(--dialog-button-hover-bg-color); } -.overlayButton:hover { - background-color: rgba(12, 12, 13, 0.3); - background-color: var(--overlay-button-hover-color); -} - -@media (prefers-color-scheme: dark) { - - .overlayButton:hover { - background-color: rgba(115, 115, 115, 1); - background-color: var(--overlay-button-hover-color); - } -} - -.overlayButton:focus { - background-color: rgba(12, 12, 13, 0.3); - background-color: var(--overlay-button-hover-color); -} - -@media (prefers-color-scheme: dark) { - - .overlayButton:focus { - background-color: rgba(115, 115, 115, 1); - background-color: var(--overlay-button-hover-color); - } +.dialogButton:hover > span, +.dialogButton:focus-visible > span { + color: var(--dialog-button-hover-color); } .toolbarButton > span { @@ -1942,466 +1965,143 @@ html[dir="rtl"] .splitToolbarButton > .toolbarButton { .toolbarButton[disabled], .secondaryToolbarButton[disabled], -.overlayButton[disabled] { +.dialogButton[disabled] { opacity: 0.5; } -.splitToolbarButton.toggled .toolbarButton { - margin: 0; -} - -.splitToolbarButton > .toolbarButton:hover { - background-color: rgba(221, 222, 223, 1); - background-color: var(--button-hover-color); - z-index: 199; -} - -@media (prefers-color-scheme: dark) { - - .splitToolbarButton > .toolbarButton:hover { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} - -.splitToolbarButton > .toolbarButton:focus { - background-color: rgba(221, 222, 223, 1); - background-color: var(--button-hover-color); - z-index: 199; -} - -@media (prefers-color-scheme: dark) { - - .splitToolbarButton > .toolbarButton:focus { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} - +.splitToolbarButton > .toolbarButton:hover, +.splitToolbarButton > .toolbarButton:focus-visible, .dropdownToolbarButton:hover { - background-color: rgba(221, 222, 223, 1); background-color: var(--button-hover-color); - z-index: 199; -} - -@media (prefers-color-scheme: dark) { - - .dropdownToolbarButton:hover { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} - -.toolbarButton.textButton:hover { - background-color: rgba(221, 222, 223, 1); - background-color: var(--button-hover-color); - z-index: 199; -} - -@media (prefers-color-scheme: dark) { - - .toolbarButton.textButton:hover { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} - -.toolbarButton.textButton:focus { - background-color: rgba(221, 222, 223, 1); - background-color: var(--button-hover-color); - z-index: 199; -} - -@media (prefers-color-scheme: dark) { - - .toolbarButton.textButton:focus { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } } .splitToolbarButton > .toolbarButton { position: relative; -} -html[dir="ltr"] .splitToolbarButton > .toolbarButton:first-child, -html[dir="rtl"] .splitToolbarButton > .toolbarButton:last-child { - position: relative; margin: 0; } -html[dir="ltr"] .splitToolbarButton > .toolbarButton:last-child, -html[dir="rtl"] .splitToolbarButton > .toolbarButton:first-child { - position: relative; - margin: 0; +[dir="ltr"] #toolbarSidebar .splitToolbarButton > .toolbarButton { + margin-right: 2px; } -.splitToolbarButtonSeparator { - padding: 10px 0; - width: 1px; - background-color: rgba(0, 0, 0, 0.3); - background-color: var(--separator-color); - z-index: 99; - display: inline-block; - margin: 4px 0; +[dir="rtl"] #toolbarSidebar .splitToolbarButton > .toolbarButton { + margin-left: 2px; } -@media (prefers-color-scheme: dark) { - - .splitToolbarButtonSeparator { - background-color: rgba(0, 0, 0, 0.3); - background-color: var(--separator-color); - } +#toolbarSidebar .splitToolbarButton > .toolbarButton { + -webkit-margin-end: 2px; + margin-inline-end: 2px; } -.findbar .splitToolbarButtonSeparator { - background-color: rgba(187, 187, 188, 1); - background-color: var(--field-border-color); - margin: 0; - padding: 13px 0; -} - -@media (prefers-color-scheme: dark) { - - .findbar .splitToolbarButtonSeparator { - background-color: rgba(115, 115, 115, 1); - background-color: var(--field-border-color); - } -} - -html[dir="ltr"] .splitToolbarButtonSeparator { +[dir="ltr"] .splitToolbarButtonSeparator { float: left; } -html[dir="rtl"] .splitToolbarButtonSeparator { + +[dir="rtl"] .splitToolbarButtonSeparator { float: right; } -.toolbarButton { +.splitToolbarButtonSeparator { + float: inline-start; + margin: 4px 0; + width: 1px; + height: 20px; + background-color: var(--separator-color); +} + +.toolbarButton, +.dropdownToolbarButton, +.secondaryToolbarButton, +.dialogButton { min-width: 16px; - padding: 2px 6px 0; - border: none; - border-radius: 2px; - color: rgba(12, 12, 13, 1); - color: var(--main-color); - font-size: 12px; - line-height: 14px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - /* Opera does not support user-select, use <... unselectable="on"> instead */ - cursor: default; - box-sizing: border-box; -} - -@media (prefers-color-scheme: dark) { - - .toolbarButton { - color: rgba(249, 249, 250, 1); - color: var(--main-color); - } -} - -.dropdownToolbarButton { - min-width: 16px; - padding: 2px 6px 0; - border: none; - border-radius: 2px; - color: rgba(12, 12, 13, 1); - color: var(--main-color); - font-size: 12px; - line-height: 14px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - /* Opera does not support user-select, use <... unselectable="on"> instead */ - cursor: default; - box-sizing: border-box; -} - -@media (prefers-color-scheme: dark) { - - .dropdownToolbarButton { - color: rgba(249, 249, 250, 1); - color: var(--main-color); - } -} - -.secondaryToolbarButton { - min-width: 16px; - padding: 2px 6px 0; - border: none; - border-radius: 2px; - color: rgba(12, 12, 13, 1); - color: var(--main-color); - font-size: 12px; - line-height: 14px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - /* Opera does not support user-select, use <... unselectable="on"> instead */ - cursor: default; - box-sizing: border-box; -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton { - color: rgba(249, 249, 250, 1); - color: var(--main-color); - } -} - -.overlayButton { - min-width: 16px; - padding: 2px 6px 0; - border: none; - border-radius: 2px; - color: rgba(12, 12, 13, 1); - color: var(--main-color); - font-size: 12px; - line-height: 14px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - /* Opera does not support user-select, use <... unselectable="on"> instead */ - cursor: default; - box-sizing: border-box; -} - -@media (prefers-color-scheme: dark) { - - .overlayButton { - color: rgba(249, 249, 250, 1); - color: var(--main-color); - } -} - -html[dir="ltr"] .toolbarButton, -html[dir="ltr"] .overlayButton, -html[dir="ltr"] .dropdownToolbarButton { - margin: 2px 1px; -} -html[dir="rtl"] .toolbarButton, -html[dir="rtl"] .overlayButton, -html[dir="rtl"] .dropdownToolbarButton { margin: 2px 1px; + padding: 2px 6px 0; + border: none; + border-radius: 2px; + color: var(--main-color); + font-size: 12px; + line-height: 14px; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + cursor: default; + box-sizing: border-box; } -html[dir="ltr"] #toolbarViewerLeft > .toolbarButton:first-child, -html[dir="rtl"] #toolbarViewerRight > .toolbarButton:last-child { - margin-left: 2px; -} - -html[dir="ltr"] #toolbarViewerRight > .toolbarButton:last-child, -html[dir="rtl"] #toolbarViewerLeft > .toolbarButton:first-child { - margin-right: 2px; -} -.toolbarButton:hover { - background-color: rgba(221, 222, 223, 1); +.toolbarButton:hover, +.toolbarButton:focus-visible { background-color: var(--button-hover-color); } -@media (prefers-color-scheme: dark) { - - .toolbarButton:hover { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} -.toolbarButton:focus { - background-color: rgba(221, 222, 223, 1); - background-color: var(--button-hover-color); -} -@media (prefers-color-scheme: dark) { - - .toolbarButton:focus { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} -.secondaryToolbarButton:hover { - background-color: rgba(237, 237, 237, 1); - background-color: var(--doorhanger-hover-color); -} -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton:hover { - background-color: rgba(93, 94, 98, 1); - background-color: var(--doorhanger-hover-color); - } -} -.secondaryToolbarButton:focus { - background-color: rgba(237, 237, 237, 1); - background-color: var(--doorhanger-hover-color); -} -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton:focus { - background-color: rgba(93, 94, 98, 1); - background-color: var(--doorhanger-hover-color); - } -} - -.toolbarButton.toggled { - background-color: rgba(0, 0, 0, 0.3); - background-color: var(--toggled-btn-bg-color); -} - -@media (prefers-color-scheme: dark) { - - .toolbarButton.toggled { - background-color: rgba(0, 0, 0, 0.3); - background-color: var(--toggled-btn-bg-color); - } -} - -.splitToolbarButton.toggled > .toolbarButton.toggled { - background-color: rgba(0, 0, 0, 0.3); - background-color: var(--toggled-btn-bg-color); -} - -@media (prefers-color-scheme: dark) { - - .splitToolbarButton.toggled > .toolbarButton.toggled { - background-color: rgba(0, 0, 0, 0.3); - background-color: var(--toggled-btn-bg-color); - } +.secondaryToolbarButton:hover, +.secondaryToolbarButton:focus-visible { + background-color: var(--doorhanger-hover-bg-color); + color: var(--doorhanger-hover-color); } +.toolbarButton.toggled, +.splitToolbarButton.toggled > .toolbarButton.toggled, .secondaryToolbarButton.toggled { - background-color: rgba(0, 0, 0, 0.3); background-color: var(--toggled-btn-bg-color); + color: var(--toggled-btn-color); } -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.toggled { - background-color: rgba(0, 0, 0, 0.3); - background-color: var(--toggled-btn-bg-color); - } +.toolbarButton.toggled::before, +.secondaryToolbarButton.toggled::before { + background-color: var(--toggled-btn-color); } .toolbarButton.toggled:hover:active, .splitToolbarButton.toggled > .toolbarButton.toggled:hover:active, .secondaryToolbarButton.toggled:hover:active { - background-color: rgba(0, 0, 0, 0.4); + background-color: var(--toggled-hover-active-btn-color); } .dropdownToolbarButton { - width: 140px; + width: var(--scale-select-container-width); padding: 0; overflow: hidden; - background-color: rgba(215, 215, 219, 1); background-color: var(--dropdown-btn-bg-color); - margin-top: 2px !important; } - -@media (prefers-color-scheme: dark) { - - .dropdownToolbarButton { - background-color: rgba(74, 74, 79, 1); - background-color: var(--dropdown-btn-bg-color); - } -} -.dropdownToolbarButton::after { - position: absolute; - display: inline-block; - top: 6px; - content: url(images/toolbarButton-menuArrow.svg); - /*content: var(--toolbarButton-menuArrow-icon);*/ - pointer-events: none; - max-width: 16px; -} -@media (prefers-color-scheme: dark) { - - .dropdownToolbarButton::after { - content: url(images/toolbarButton-menuArrow-dark.svg); - /*content: var(--toolbarButton-menuArrow-icon);*/ - } -} -html[dir="ltr"] .dropdownToolbarButton::after { +[dir="ltr"] .dropdownToolbarButton::after { right: 7px; } -html[dir="rtl"] .dropdownToolbarButton::after { +[dir="rtl"] .dropdownToolbarButton::after { left: 7px; } +.dropdownToolbarButton::after { + top: 6px; + inset-inline-end: 7px; + pointer-events: none; + -webkit-mask-image: var(--toolbarButton-menuArrow-icon); + mask-image: var(--toolbarButton-menuArrow-icon); +} + +[dir="ltr"] .dropdownToolbarButton > select { + padding-left: 4px; +} + +[dir="rtl"] .dropdownToolbarButton > select { + padding-right: 4px; +} .dropdownToolbarButton > select { - width: 162px; + width: calc( + var(--scale-select-container-width) + var(--scale-select-overflow) + ); height: 28px; font-size: 12px; - color: rgba(12, 12, 13, 1); color: var(--main-color); margin: 0; padding: 1px 0 2px; + -webkit-padding-start: 4px; + padding-inline-start: 4px; border: none; - background-color: rgba(215, 215, 219, 1); background-color: var(--dropdown-btn-bg-color); } - -@media (prefers-color-scheme: dark) { - - .dropdownToolbarButton > select { - background-color: rgba(74, 74, 79, 1); - background-color: var(--dropdown-btn-bg-color); - } -} - -@media (prefers-color-scheme: dark) { - - .dropdownToolbarButton > select { - color: rgba(249, 249, 250, 1); - color: var(--main-color); - } -} -html[dir="ltr"] .dropdownToolbarButton > select { - padding-left: 4px; -} -html[dir="rtl"] .dropdownToolbarButton > select { - padding-right: 4px; -} -.dropdownToolbarButton > select:hover { - background-color: rgba(221, 222, 223, 1); +.dropdownToolbarButton > select:hover, +.dropdownToolbarButton > select:focus-visible { background-color: var(--button-hover-color); + color: var(--toggled-btn-color); } -@media (prefers-color-scheme: dark) { - - .dropdownToolbarButton > select:hover { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} - -.dropdownToolbarButton > select:focus { - background-color: rgba(221, 222, 223, 1); - background-color: var(--button-hover-color); -} - -@media (prefers-color-scheme: dark) { - - .dropdownToolbarButton > select:focus { - background-color: rgba(102, 102, 103, 1); - background-color: var(--button-hover-color); - } -} - .dropdownToolbarButton > select > option { - background: rgba(255, 255, 255, 1); background: var(--doorhanger-bg-color); -} - -@media (prefers-color-scheme: dark) { - - .dropdownToolbarButton > select > option { - background: rgba(74, 74, 79, 1); - background: var(--doorhanger-bg-color); - } -} - -#customScaleOption { - display: none; -} - -#pageWidthOption { - border-bottom: 1px rgba(255, 255, 255, 0.5) solid; + color: var(--main-color); } .toolbarButtonSpacer { @@ -2410,383 +2110,193 @@ html[dir="rtl"] .dropdownToolbarButton > select { height: 1px; } -html[dir="ltr"] #findPrevious { - margin-left: 0; -} -html[dir="ltr"] #findNext { - margin-right: 3px; -} - -html[dir="rtl"] #findPrevious { - margin-right: 0; -} -html[dir="rtl"] #findNext { - margin-left: 3px; -} - -.toolbarButton::before { - opacity: 0.7; - opacity: var(--toolbar-icon-opacity); - top: 6px; -} - -.secondaryToolbarButton::before { - opacity: 0.9; - opacity: var(--doorhanger-icon-opacity); - top: 5px; -} - .toolbarButton::before, -.secondaryToolbarButton::before { +.secondaryToolbarButton::before, +.dropdownToolbarButton::after, +.treeItemToggler::before { /* All matching images have a size of 16x16 * All relevant containers have a size of 28x28 */ position: absolute; display: inline-block; - left: 6px; - max-width: 16px; + width: 16px; + height: 16px; + + content: ""; + background-color: var(--toolbar-icon-bg-color); + -webkit-mask-size: cover; + mask-size: cover; } -html[dir="ltr"] .secondaryToolbarButton::before { +.dropdownToolbarButton:hover::after, +.dropdownToolbarButton:focus-visible::after, +.dropdownToolbarButton:active::after { + background-color: var(--toolbar-icon-hover-bg-color); +} + +.toolbarButton::before { + opacity: var(--toolbar-icon-opacity); + top: 6px; + left: 6px; +} + +.toolbarButton:hover::before, +.toolbarButton:focus-visible::before, +.secondaryToolbarButton:hover::before, +.secondaryToolbarButton:focus-visible::before { + background-color: var(--toolbar-icon-hover-bg-color); +} + +[dir="ltr"] .secondaryToolbarButton::before { left: 12px; } -html[dir="rtl"] .secondaryToolbarButton::before { + +[dir="rtl"] .secondaryToolbarButton::before { right: 12px; } -.toolbarButton#sidebarToggle::before { - content: url(images/toolbarButton-sidebarToggle.svg); - /*content: var(--toolbarButton-sidebarToggle-icon);*/ +.secondaryToolbarButton::before { + opacity: var(--doorhanger-icon-opacity); + top: 5px; + inset-inline-start: 12px; } -@media (prefers-color-scheme: dark) { - - .toolbarButton#sidebarToggle::before { - content: url(images/toolbarButton-sidebarToggle-dark.svg); - /*content: var(--toolbarButton-sidebarToggle-icon);*/ - } -} -html[dir="rtl"] .toolbarButton#sidebarToggle::before { - transform: scaleX(-1); +#sidebarToggle::before { + -webkit-mask-image: var(--toolbarButton-sidebarToggle-icon); + mask-image: var(--toolbarButton-sidebarToggle-icon); + transform: scaleX(var(--dir-factor)); } -.toolbarButton#secondaryToolbarToggle::before { - content: url(images/toolbarButton-secondaryToolbarToggle.svg); - /*content: var(--toolbarButton-secondaryToolbarToggle-icon);*/ +#secondaryToolbarToggle::before { + -webkit-mask-image: var(--toolbarButton-secondaryToolbarToggle-icon); + mask-image: var(--toolbarButton-secondaryToolbarToggle-icon); + transform: scaleX(var(--dir-factor)); } -@media (prefers-color-scheme: dark) { - - .toolbarButton#secondaryToolbarToggle::before { - content: url(images/toolbarButton-secondaryToolbarToggle-dark.svg); - /*content: var(--toolbarButton-secondaryToolbarToggle-icon);*/ - } -} -html[dir="rtl"] .toolbarButton#secondaryToolbarToggle::before { - transform: scaleX(-1); +#findPrevious::before { + -webkit-mask-image: var(--findbarButton-previous-icon); + mask-image: var(--findbarButton-previous-icon); } -.toolbarButton.findPrevious::before { - content: url(images/findbarButton-previous.svg); - /*content: var(--findbarButton-previous-icon);*/ +#findNext::before { + -webkit-mask-image: var(--findbarButton-next-icon); + mask-image: var(--findbarButton-next-icon); } -@media (prefers-color-scheme: dark) { - - .toolbarButton.findPrevious::before { - content: url(images/findbarButton-previous-dark.svg); - /*content: var(--findbarButton-previous-icon);*/ - } -} -html[dir="rtl"] .toolbarButton.findPrevious::before { - transform: scaleX(-1); +#previous::before { + -webkit-mask-image: var(--toolbarButton-pageUp-icon); + mask-image: var(--toolbarButton-pageUp-icon); } -.toolbarButton.findNext::before { - content: url(images/findbarButton-next.svg); - /*content: var(--findbarButton-next-icon);*/ +#next::before { + -webkit-mask-image: var(--toolbarButton-pageDown-icon); + mask-image: var(--toolbarButton-pageDown-icon); } -@media (prefers-color-scheme: dark) { - - .toolbarButton.findNext::before { - content: url(images/findbarButton-next-dark.svg); - /*content: var(--findbarButton-next-icon);*/ - } -} -html[dir="rtl"] .toolbarButton.findNext::before { - transform: scaleX(-1); +#zoomOut::before { + -webkit-mask-image: var(--toolbarButton-zoomOut-icon); + mask-image: var(--toolbarButton-zoomOut-icon); } -.toolbarButton.pageUp::before { - content: url(images/toolbarButton-pageUp.svg); - /*content: var(--toolbarButton-pageUp-icon);*/ +#zoomIn::before { + -webkit-mask-image: var(--toolbarButton-zoomIn-icon); + mask-image: var(--toolbarButton-zoomIn-icon); } -@media (prefers-color-scheme: dark) { - - .toolbarButton.pageUp::before { - content: url(images/toolbarButton-pageUp-dark.svg); - /*content: var(--toolbarButton-pageUp-icon);*/ - } -} -html[dir="rtl"] .toolbarButton.pageUp::before { - transform: scaleX(-1); +#presentationMode::before, +#secondaryPresentationMode::before { + -webkit-mask-image: var(--toolbarButton-presentationMode-icon); + mask-image: var(--toolbarButton-presentationMode-icon); } -.toolbarButton.pageDown::before { - content: url(images/toolbarButton-pageDown.svg); - /*content: var(--toolbarButton-pageDown-icon);*/ +#editorFreeText::before { + -webkit-mask-image: var(--toolbarButton-editorFreeText-icon); + mask-image: var(--toolbarButton-editorFreeText-icon); } -@media (prefers-color-scheme: dark) { - - .toolbarButton.pageDown::before { - content: url(images/toolbarButton-pageDown-dark.svg); - /*content: var(--toolbarButton-pageDown-icon);*/ - } -} -html[dir="rtl"] .toolbarButton.pageDown::before { - transform: scaleX(-1); +#editorInk::before { + -webkit-mask-image: var(--toolbarButton-editorInk-icon); + mask-image: var(--toolbarButton-editorInk-icon); } -.toolbarButton.zoomOut::before { - content: url(images/toolbarButton-zoomOut.svg); - /*content: var(--toolbarButton-zoomOut-icon);*/ +#print::before, +#secondaryPrint::before { + -webkit-mask-image: var(--toolbarButton-print-icon); + mask-image: var(--toolbarButton-print-icon); } -@media (prefers-color-scheme: dark) { - - .toolbarButton.zoomOut::before { - content: url(images/toolbarButton-zoomOut-dark.svg); - /*content: var(--toolbarButton-zoomOut-icon);*/ - } +#openFile::before, +#secondaryOpenFile::before { + -webkit-mask-image: var(--toolbarButton-openFile-icon); + mask-image: var(--toolbarButton-openFile-icon); } -.toolbarButton.zoomIn::before { - content: url(images/toolbarButton-zoomIn.svg); - /*content: var(--toolbarButton-zoomIn-icon);*/ +#download::before, +#secondaryDownload::before { + -webkit-mask-image: var(--toolbarButton-download-icon); + mask-image: var(--toolbarButton-download-icon); } -@media (prefers-color-scheme: dark) { - - .toolbarButton.zoomIn::before { - content: url(images/toolbarButton-zoomIn-dark.svg); - /*content: var(--toolbarButton-zoomIn-icon);*/ - } -} - -.toolbarButton.presentationMode::before { - content: url(images/toolbarButton-presentationMode.svg); - /*content: var(--toolbarButton-presentationMode-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .toolbarButton.presentationMode::before { - content: url(images/toolbarButton-presentationMode-dark.svg); - /*content: var(--toolbarButton-presentationMode-icon);*/ - } -} - -.secondaryToolbarButton.presentationMode::before { - content: url(images/toolbarButton-presentationMode.svg); - /*content: var(--toolbarButton-presentationMode-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.presentationMode::before { - content: url(images/toolbarButton-presentationMode-dark.svg); - /*content: var(--toolbarButton-presentationMode-icon);*/ - } -} - -.toolbarButton.print::before { - content: url(images/toolbarButton-print.svg); - /*content: var(--toolbarButton-print-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .toolbarButton.print::before { - content: url(images/toolbarButton-print-dark.svg); - /*content: var(--toolbarButton-print-icon);*/ - } -} - -.secondaryToolbarButton.print::before { - content: url(images/toolbarButton-print.svg); - /*content: var(--toolbarButton-print-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.print::before { - content: url(images/toolbarButton-print-dark.svg); - /*content: var(--toolbarButton-print-icon);*/ - } -} - -.toolbarButton.openFile::before { - content: url(images/toolbarButton-openFile.svg); - /*content: var(--toolbarButton-openFile-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .toolbarButton.openFile::before { - content: url(images/toolbarButton-openFile-dark.svg); - /*content: var(--toolbarButton-openFile-icon);*/ - } -} - -.secondaryToolbarButton.openFile::before { - content: url(images/toolbarButton-openFile.svg); - /*content: var(--toolbarButton-openFile-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.openFile::before { - content: url(images/toolbarButton-openFile-dark.svg); - /*content: var(--toolbarButton-openFile-icon);*/ - } -} - -.toolbarButton.download::before { - content: url(images/toolbarButton-download.svg); - /*content: var(--toolbarButton-download-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .toolbarButton.download::before { - content: url(images/toolbarButton-download-dark.svg); - /*content: var(--toolbarButton-download-icon);*/ - } -} - -.secondaryToolbarButton.download::before { - content: url(images/toolbarButton-download.svg); - /*content: var(--toolbarButton-download-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.download::before { - content: url(images/toolbarButton-download-dark.svg); - /*content: var(--toolbarButton-download-icon);*/ - } -} - -.secondaryToolbarButton.bookmark { +a.secondaryToolbarButton { padding-top: 6px; text-decoration: none; } - -.bookmark[href="#"] { +a.toolbarButton[href="#"], +a.secondaryToolbarButton[href="#"] { opacity: 0.5; pointer-events: none; } -.toolbarButton.bookmark::before { - content: url(images/toolbarButton-bookmark.svg); - /*content: var(--toolbarButton-bookmark-icon);*/ +#viewBookmark::before, +#secondaryViewBookmark::before { + -webkit-mask-image: var(--toolbarButton-bookmark-icon); + mask-image: var(--toolbarButton-bookmark-icon); } -@media (prefers-color-scheme: dark) { - - .toolbarButton.bookmark::before { - content: url(images/toolbarButton-bookmark-dark.svg); - /*content: var(--toolbarButton-bookmark-icon);*/ - } +#viewThumbnail::before { + -webkit-mask-image: var(--toolbarButton-viewThumbnail-icon); + mask-image: var(--toolbarButton-viewThumbnail-icon); } -.secondaryToolbarButton.bookmark::before { - content: url(images/toolbarButton-bookmark.svg); - /*content: var(--toolbarButton-bookmark-icon);*/ +#viewOutline::before { + -webkit-mask-image: var(--toolbarButton-viewOutline-icon); + mask-image: var(--toolbarButton-viewOutline-icon); + transform: scaleX(var(--dir-factor)); } -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.bookmark::before { - content: url(images/toolbarButton-bookmark-dark.svg); - /*content: var(--toolbarButton-bookmark-icon);*/ - } +#viewAttachments::before { + -webkit-mask-image: var(--toolbarButton-viewAttachments-icon); + mask-image: var(--toolbarButton-viewAttachments-icon); } -#viewThumbnail.toolbarButton::before { - content: url(images/toolbarButton-viewThumbnail.svg); - /*content: var(--toolbarButton-viewThumbnail-icon);*/ +#viewLayers::before { + -webkit-mask-image: var(--toolbarButton-viewLayers-icon); + mask-image: var(--toolbarButton-viewLayers-icon); } -@media (prefers-color-scheme: dark) { - - #viewThumbnail.toolbarButton::before { - content: url(images/toolbarButton-viewThumbnail-dark.svg); - /*content: var(--toolbarButton-viewThumbnail-icon);*/ - } +#currentOutlineItem::before { + -webkit-mask-image: var(--toolbarButton-currentOutlineItem-icon); + mask-image: var(--toolbarButton-currentOutlineItem-icon); + transform: scaleX(var(--dir-factor)); } -#viewOutline.toolbarButton::before { - content: url(images/toolbarButton-viewOutline.svg); - /*content: var(--toolbarButton-viewOutline-icon);*/ +#viewFind::before { + -webkit-mask-image: var(--toolbarButton-search-icon); + mask-image: var(--toolbarButton-search-icon); } -@media (prefers-color-scheme: dark) { - - #viewOutline.toolbarButton::before { - content: url(images/toolbarButton-viewOutline-dark.svg); - /*content: var(--toolbarButton-viewOutline-icon);*/ - } -} -html[dir="rtl"] #viewOutline.toolbarButton::before { - transform: scaleX(-1); +[dir="ltr"] .pdfSidebarNotification::after { + left: 17px; } -#viewAttachments.toolbarButton::before { - content: url(images/toolbarButton-viewAttachments.svg); - /*content: var(--toolbarButton-viewAttachments-icon);*/ +[dir="rtl"] .pdfSidebarNotification::after { + right: 17px; } -@media (prefers-color-scheme: dark) { - - #viewAttachments.toolbarButton::before { - content: url(images/toolbarButton-viewAttachments-dark.svg); - /*content: var(--toolbarButton-viewAttachments-icon);*/ - } -} - -#viewLayers.toolbarButton::before { - content: url(images/toolbarButton-viewLayers.svg); - /*content: var(--toolbarButton-viewLayers-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - #viewLayers.toolbarButton::before { - content: url(images/toolbarButton-viewLayers-dark.svg); - /*content: var(--toolbarButton-viewLayers-icon);*/ - } -} - -#viewFind.toolbarButton::before { - content: url(images/toolbarButton-search.svg); - /*content: var(--toolbarButton-search-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - #viewFind.toolbarButton::before { - content: url(images/toolbarButton-search-dark.svg); - /*content: var(--toolbarButton-search-icon);*/ - } -} - -.toolbarButton.pdfSidebarNotification::after { +.pdfSidebarNotification::after { position: absolute; display: inline-block; top: 1px; + inset-inline-start: 17px; /* Create a filled circle, with a diameter of 9 pixels, using only CSS: */ content: ""; background-color: rgba(112, 219, 85, 1); @@ -2794,333 +2304,177 @@ html[dir="rtl"] #viewOutline.toolbarButton::before { width: 9px; border-radius: 50%; } -html[dir="ltr"] .toolbarButton.pdfSidebarNotification::after { - left: 17px; + +[dir="ltr"] .secondaryToolbarButton { + padding-left: 36px; } -html[dir="rtl"] .toolbarButton.pdfSidebarNotification::after { - right: 17px; + +[dir="rtl"] .secondaryToolbarButton { + padding-right: 36px; +} + +[dir="ltr"] .secondaryToolbarButton { + text-align: left; +} + +[dir="rtl"] .secondaryToolbarButton { + text-align: right; } .secondaryToolbarButton { position: relative; margin: 0; - padding: 0 0 1px 0; + padding: 0 0 1px; + -webkit-padding-start: 36px; + padding-inline-start: 36px; height: auto; min-height: 26px; width: auto; min-width: 100%; + text-align: start; white-space: normal; border-radius: 0; box-sizing: border-box; } -html[dir="ltr"] .secondaryToolbarButton { - padding-left: 36px; - text-align: left; -} -html[dir="rtl"] .secondaryToolbarButton { - padding-right: 36px; - text-align: right; -} - -html[dir="ltr"] .secondaryToolbarButton > span { +[dir="ltr"] .secondaryToolbarButton > span { padding-right: 4px; } -html[dir="rtl"] .secondaryToolbarButton > span { +[dir="rtl"] .secondaryToolbarButton > span { padding-left: 4px; } - -.secondaryToolbarButton.firstPage::before { - content: url(images/secondaryToolbarButton-firstPage.svg); - /*content: var(--secondaryToolbarButton-firstPage-icon);*/ +.secondaryToolbarButton > span { + -webkit-padding-end: 4px; + padding-inline-end: 4px; } -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.firstPage::before { - content: url(images/secondaryToolbarButton-firstPage-dark.svg); - /*content: var(--secondaryToolbarButton-firstPage-icon);*/ - } +#firstPage::before { + -webkit-mask-image: var(--secondaryToolbarButton-firstPage-icon); + mask-image: var(--secondaryToolbarButton-firstPage-icon); } -.secondaryToolbarButton.lastPage::before { - content: url(images/secondaryToolbarButton-lastPage.svg); - /*content: var(--secondaryToolbarButton-lastPage-icon);*/ +#lastPage::before { + -webkit-mask-image: var(--secondaryToolbarButton-lastPage-icon); + mask-image: var(--secondaryToolbarButton-lastPage-icon); } -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.lastPage::before { - content: url(images/secondaryToolbarButton-lastPage-dark.svg); - /*content: var(--secondaryToolbarButton-lastPage-icon);*/ - } +#pageRotateCcw::before { + -webkit-mask-image: var(--secondaryToolbarButton-rotateCcw-icon); + mask-image: var(--secondaryToolbarButton-rotateCcw-icon); } -.secondaryToolbarButton.rotateCcw::before { - content: url(images/secondaryToolbarButton-rotateCcw.svg); - /*content: var(--secondaryToolbarButton-rotateCcw-icon);*/ +#pageRotateCw::before { + -webkit-mask-image: var(--secondaryToolbarButton-rotateCw-icon); + mask-image: var(--secondaryToolbarButton-rotateCw-icon); } -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.rotateCcw::before { - content: url(images/secondaryToolbarButton-rotateCcw-dark.svg); - /*content: var(--secondaryToolbarButton-rotateCcw-icon);*/ - } +#cursorSelectTool::before { + -webkit-mask-image: var(--secondaryToolbarButton-selectTool-icon); + mask-image: var(--secondaryToolbarButton-selectTool-icon); } -.secondaryToolbarButton.rotateCw::before { - content: url(images/secondaryToolbarButton-rotateCw.svg); - /*content: var(--secondaryToolbarButton-rotateCw-icon);*/ +#cursorHandTool::before { + -webkit-mask-image: var(--secondaryToolbarButton-handTool-icon); + mask-image: var(--secondaryToolbarButton-handTool-icon); } -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.rotateCw::before { - content: url(images/secondaryToolbarButton-rotateCw-dark.svg); - /*content: var(--secondaryToolbarButton-rotateCw-icon);*/ - } +#scrollPage::before { + -webkit-mask-image: var(--secondaryToolbarButton-scrollPage-icon); + mask-image: var(--secondaryToolbarButton-scrollPage-icon); } -.secondaryToolbarButton.selectTool::before { - content: url(images/secondaryToolbarButton-selectTool.svg); - /*content: var(--secondaryToolbarButton-selectTool-icon);*/ +#scrollVertical::before { + -webkit-mask-image: var(--secondaryToolbarButton-scrollVertical-icon); + mask-image: var(--secondaryToolbarButton-scrollVertical-icon); } -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.selectTool::before { - content: url(images/secondaryToolbarButton-selectTool-dark.svg); - /*content: var(--secondaryToolbarButton-selectTool-icon);*/ - } +#scrollHorizontal::before { + -webkit-mask-image: var(--secondaryToolbarButton-scrollHorizontal-icon); + mask-image: var(--secondaryToolbarButton-scrollHorizontal-icon); } -.secondaryToolbarButton.handTool::before { - content: url(images/secondaryToolbarButton-handTool.svg); - /*content: var(--secondaryToolbarButton-handTool-icon);*/ +#scrollWrapped::before { + -webkit-mask-image: var(--secondaryToolbarButton-scrollWrapped-icon); + mask-image: var(--secondaryToolbarButton-scrollWrapped-icon); } -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.handTool::before { - content: url(images/secondaryToolbarButton-handTool-dark.svg); - /*content: var(--secondaryToolbarButton-handTool-icon);*/ - } +#spreadNone::before { + -webkit-mask-image: var(--secondaryToolbarButton-spreadNone-icon); + mask-image: var(--secondaryToolbarButton-spreadNone-icon); } -.secondaryToolbarButton.scrollVertical::before { - content: url(images/secondaryToolbarButton-scrollVertical.svg); - /*content: var(--secondaryToolbarButton-scrollVertical-icon);*/ +#spreadOdd::before { + -webkit-mask-image: var(--secondaryToolbarButton-spreadOdd-icon); + mask-image: var(--secondaryToolbarButton-spreadOdd-icon); } -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.scrollVertical::before { - content: url(images/secondaryToolbarButton-scrollVertical-dark.svg); - /*content: var(--secondaryToolbarButton-scrollVertical-icon);*/ - } +#spreadEven::before { + -webkit-mask-image: var(--secondaryToolbarButton-spreadEven-icon); + mask-image: var(--secondaryToolbarButton-spreadEven-icon); } -.secondaryToolbarButton.scrollHorizontal::before { - content: url(images/secondaryToolbarButton-scrollHorizontal.svg); - /*content: var(--secondaryToolbarButton-scrollHorizontal-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.scrollHorizontal::before { - content: url(images/secondaryToolbarButton-scrollHorizontal-dark.svg); - /*content: var(--secondaryToolbarButton-scrollHorizontal-icon);*/ - } -} - -.secondaryToolbarButton.scrollWrapped::before { - content: url(images/secondaryToolbarButton-scrollWrapped.svg); - /*content: var(--secondaryToolbarButton-scrollWrapped-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.scrollWrapped::before { - content: url(images/secondaryToolbarButton-scrollWrapped-dark.svg); - /*content: var(--secondaryToolbarButton-scrollWrapped-icon);*/ - } -} - -.secondaryToolbarButton.spreadNone::before { - content: url(images/secondaryToolbarButton-spreadNone.svg); - /*content: var(--secondaryToolbarButton-spreadNone-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.spreadNone::before { - content: url(images/secondaryToolbarButton-spreadNone-dark.svg); - /*content: var(--secondaryToolbarButton-spreadNone-icon);*/ - } -} - -.secondaryToolbarButton.spreadOdd::before { - content: url(images/secondaryToolbarButton-spreadOdd.svg); - /*content: var(--secondaryToolbarButton-spreadOdd-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.spreadOdd::before { - content: url(images/secondaryToolbarButton-spreadOdd-dark.svg); - /*content: var(--secondaryToolbarButton-spreadOdd-icon);*/ - } -} - -.secondaryToolbarButton.spreadEven::before { - content: url(images/secondaryToolbarButton-spreadEven.svg); - /*content: var(--secondaryToolbarButton-spreadEven-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.spreadEven::before { - content: url(images/secondaryToolbarButton-spreadEven-dark.svg); - /*content: var(--secondaryToolbarButton-spreadEven-icon);*/ - } -} - -.secondaryToolbarButton.documentProperties::before { - content: url(images/secondaryToolbarButton-documentProperties.svg); - /*content: var(--secondaryToolbarButton-documentProperties-icon);*/ -} - -@media (prefers-color-scheme: dark) { - - .secondaryToolbarButton.documentProperties::before { - content: url(images/secondaryToolbarButton-documentProperties-dark.svg); - /*content: var(--secondaryToolbarButton-documentProperties-icon);*/ - } +#documentProperties::before { + -webkit-mask-image: var(--secondaryToolbarButton-documentProperties-icon); + mask-image: var(--secondaryToolbarButton-documentProperties-icon); } .verticalToolbarSeparator { display: block; - padding: 11px 0; margin: 5px 2px; width: 1px; - background-color: rgba(0, 0, 0, 0.3); + height: 22px; background-color: var(--separator-color); } - -@media (prefers-color-scheme: dark) { - - .verticalToolbarSeparator { - background-color: rgba(0, 0, 0, 0.3); - background-color: var(--separator-color); - } -} -html[dir="ltr"] .verticalToolbarSeparator { - margin-left: 2px; -} -html[dir="rtl"] .verticalToolbarSeparator { - margin-right: 2px; -} - .horizontalToolbarSeparator { display: block; - margin: 6px 0 5px 0; + margin: 6px 0; height: 1px; width: 100%; - border-top: 1px solid rgba(222, 222, 222, 1); - border-top: 1px solid var(--doorhanger-separator-color); -} - -@media (prefers-color-scheme: dark) { - - .horizontalToolbarSeparator { - border-top: 1px solid rgba(92, 92, 97, 1); - border-top: 1px solid var(--doorhanger-separator-color); - } + background-color: var(--doorhanger-separator-color); } .toolbarField { padding: 4px 7px; - margin: 3px 0 3px 0; + margin: 3px 0; border-radius: 2px; - background-color: rgba(255, 255, 255, 1); background-color: var(--field-bg-color); background-clip: padding-box; - border-width: 1px; - border-style: solid; - border-color: rgba(187, 187, 188, 1); - border-color: var(--field-border-color); + border: 1px solid var(--field-border-color); box-shadow: none; - color: rgba(6, 6, 6, 1); color: var(--field-color); font-size: 12px; line-height: 16px; outline-style: none; } -@media (prefers-color-scheme: dark) { - - .toolbarField { - color: rgba(250, 250, 250, 1); - color: var(--field-color); - } +[dir="ltr"] .toolbarField[type="checkbox"] { + margin-left: 7px; } -@media (prefers-color-scheme: dark) { - - .toolbarField { - border-color: rgba(115, 115, 115, 1); - border-color: var(--field-border-color); - } -} - -@media (prefers-color-scheme: dark) { - - .toolbarField { - background-color: rgba(64, 64, 68, 1); - background-color: var(--field-bg-color); - } +[dir="rtl"] .toolbarField[type="checkbox"] { + margin-right: 7px; } .toolbarField[type="checkbox"] { opacity: 0; position: absolute !important; left: 0; + margin: 10px 0 3px; + -webkit-margin-start: 7px; + margin-inline-start: 7px; } -html[dir="ltr"] .toolbarField[type="checkbox"] { - margin: 10px 0 3px 7px; -} - -html[dir="rtl"] .toolbarField[type="checkbox"] { - margin: 10px 7px 3px 0; -} - -.toolbarField.pageNumber { +#pageNumber { -moz-appearance: textfield; /* hides the spinner in moz */ - min-width: 16px; text-align: right; width: 40px; } - -.toolbarField.pageNumber.visiblePageIsLoading { - background-image: url(images/loading.svg); - /*background-image: var(--loading-icon);*/ +#pageNumber.visiblePageIsLoading { + background-image: var(--loading-icon); background-repeat: no-repeat; background-position: 3px; } - -@media (prefers-color-scheme: dark) { - - .toolbarField.pageNumber.visiblePageIsLoading { - background-image: url(images/loading-dark.svg); - /*background-image: var(--loading-icon);*/ - } -} - -.toolbarField.pageNumber::-webkit-inner-spin-button, -.toolbarField.pageNumber::-webkit-outer-spin-button { +#pageNumber::-webkit-inner-spin-button { -webkit-appearance: none; - margin: 0; } .toolbarField:focus { @@ -3129,45 +2483,49 @@ html[dir="rtl"] .toolbarField[type="checkbox"] { .toolbarLabel { min-width: 16px; - padding: 6px; + padding: 7px; margin: 2px; - border: 1px solid rgba(0, 0, 0, 0); border-radius: 2px; - color: rgba(12, 12, 13, 1); color: var(--main-color); font-size: 12px; line-height: 14px; text-align: left; -webkit-user-select: none; -moz-user-select: none; - -ms-user-select: none; user-select: none; cursor: default; } -@media (prefers-color-scheme: dark) { - - .toolbarLabel { - color: rgba(249, 249, 250, 1); - color: var(--main-color); - } +[dir="ltr"] #numPages.toolbarLabel { + padding-left: 3px; } -html[dir="ltr"] #numPages.toolbarLabel { - padding-left: 2px; -} -html[dir="rtl"] #numPages.toolbarLabel { - padding-right: 2px; +[dir="rtl"] #numPages.toolbarLabel { + padding-right: 3px; } -#thumbnailView { +#numPages.toolbarLabel { + -webkit-padding-start: 3px; + padding-inline-start: 3px; +} + +#thumbnailView, +#outlineView, +#attachmentsView, +#layersView { position: absolute; - width: calc(100% - 60px); + width: calc(100% - 8px); top: 0; bottom: 0; - padding: 10px 30px 0; + padding: 4px 4px 0; overflow: auto; - -webkit-overflow-scrolling: touch; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +#thumbnailView { + width: calc(100% - 60px); + padding: 10px 30px 0; } #thumbnailView > a:active, @@ -3175,27 +2533,29 @@ html[dir="rtl"] #numPages.toolbarLabel { outline: 0; } -.thumbnail { - margin: 0 10px 5px 10px; -} -html[dir="ltr"] .thumbnail { +[dir="ltr"] .thumbnail { float: left; } -html[dir="rtl"] .thumbnail { + +[dir="rtl"] .thumbnail { float: right; } +.thumbnail { + float: inline-start; + margin: 0 10px 5px; +} + #thumbnailView > a:last-of-type > .thumbnail { margin-bottom: 10px; } - #thumbnailView > a:last-of-type > .thumbnail:not([data-loaded]) { margin-bottom: 9px; } .thumbnail:not([data-loaded]) { border: 1px dashed rgba(132, 132, 132, 1); - margin: -1px 9px 4px 9px; + margin: -1px 9px 4px; } .thumbnailImage { @@ -3217,306 +2577,140 @@ a:focus > .thumbnail > .thumbnailSelectionRing > .thumbnailImage, opacity: 0.9; } -a:focus > .thumbnail > .thumbnailSelectionRing { - background-color: rgba(0, 0, 0, 0.15); - background-color: var(--sidebaritem-bg-color); - background-clip: padding-box; - color: rgba(255, 255, 255, 0.9); -} - -@media (prefers-color-scheme: dark) { - - a:focus > .thumbnail > .thumbnailSelectionRing { - background-color: rgba(255, 255, 255, 0.15); - background-color: var(--sidebaritem-bg-color); - } -} - +a:focus > .thumbnail > .thumbnailSelectionRing, .thumbnail:hover > .thumbnailSelectionRing { - background-color: rgba(0, 0, 0, 0.15); background-color: var(--sidebaritem-bg-color); background-clip: padding-box; color: rgba(255, 255, 255, 0.9); } -@media (prefers-color-scheme: dark) { - - .thumbnail:hover > .thumbnailSelectionRing { - background-color: rgba(255, 255, 255, 0.15); - background-color: var(--sidebaritem-bg-color); - } -} - .thumbnail.selected > .thumbnailSelectionRing > .thumbnailImage { opacity: 1; } .thumbnail.selected > .thumbnailSelectionRing { - background-color: rgba(0, 0, 0, 0.15); background-color: var(--sidebaritem-bg-color); background-clip: padding-box; color: rgba(255, 255, 255, 1); } -@media (prefers-color-scheme: dark) { - - .thumbnail.selected > .thumbnailSelectionRing { - background-color: rgba(255, 255, 255, 0.15); - background-color: var(--sidebaritem-bg-color); - } -} - -#outlineView, -#attachmentsView, -#layersView { - position: absolute; - width: calc(100% - 8px); - top: 0; - bottom: 0; - padding: 4px 4px 0; - overflow: auto; - -webkit-overflow-scrolling: touch; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -html[dir="ltr"] .treeWithDeepNesting > .treeItem, -html[dir="ltr"] .treeItem > .treeItems { +[dir="ltr"] .treeWithDeepNesting > .treeItem,[dir="ltr"] +.treeItem > .treeItems { margin-left: 20px; } -html[dir="rtl"] .treeWithDeepNesting > .treeItem, -html[dir="rtl"] .treeItem > .treeItems { +[dir="rtl"] .treeWithDeepNesting > .treeItem,[dir="rtl"] +.treeItem > .treeItems { margin-right: 20px; } +.treeWithDeepNesting > .treeItem, +.treeItem > .treeItems { + -webkit-margin-start: 20px; + margin-inline-start: 20px; +} + +[dir="ltr"] .treeItem > a { + padding-left: 4px; +} + +[dir="rtl"] .treeItem > a { + padding-right: 4px; +} + .treeItem > a { text-decoration: none; display: inline-block; - min-width: 95%; /* Subtract the right padding (left, in RTL mode) of the container: */ min-width: calc(100% - 4px); height: auto; margin-bottom: 1px; + padding: 2px 0 5px; + -webkit-padding-start: 4px; + padding-inline-start: 4px; border-radius: 2px; - color: rgba(0, 0, 0, 0.8); - color: var(--outline-color); + color: var(--treeitem-color); font-size: 13px; line-height: 15px; -webkit-user-select: none; -moz-user-select: none; - -ms-user-select: none; user-select: none; white-space: normal; cursor: pointer; } -@media (prefers-color-scheme: dark) { - - .treeItem > a { - color: rgba(255, 255, 255, 0.8); - color: var(--outline-color); - } -} -html[dir="ltr"] .treeItem > a { - padding: 2px 0 5px 4px; -} -html[dir="rtl"] .treeItem > a { - padding: 2px 4px 5px 0; -} - -#layersView .treeItem > a > * { +#layersView .treeItem > a * { cursor: pointer; } -html[dir="ltr"] #layersView .treeItem > a > label { +[dir="ltr"] #layersView .treeItem > a > label { padding-left: 4px; } -html[dir="rtl"] #layersView .treesItem > a > label { +[dir="rtl"] #layersView .treeItem > a > label { padding-right: 4px; } +#layersView .treeItem > a > label { + -webkit-padding-start: 4px; + padding-inline-start: 4px; +} +[dir="ltr"] #layersView .treeItem > a > label > input { + float: left; +} +[dir="rtl"] #layersView .treeItem > a > label > input { + float: right; +} +#layersView .treeItem > a > label > input { + float: inline-start; + margin-top: 1px; +} + +[dir="ltr"] .treeItemToggler { + float: left; +} + +[dir="rtl"] .treeItemToggler { + float: right; +} .treeItemToggler { position: relative; + float: inline-start; height: 0; width: 0; color: rgba(255, 255, 255, 0.5); } -.treeItemToggler::before { - content: url(images/treeitem-expanded.svg); - /*content: var(--treeitem-expanded-icon);*/ - display: inline-block; - position: absolute; - max-width: 16px; +[dir="ltr"] .treeItemToggler::before { + right: 4px; } -@media (prefers-color-scheme: dark) { - - .treeItemToggler::before { - content: url(images/treeitem-expanded-dark.svg); - /*content: var(--treeitem-expanded-icon);*/ - } +[dir="rtl"] .treeItemToggler::before { + left: 4px; +} +.treeItemToggler::before { + inset-inline-end: 4px; + -webkit-mask-image: var(--treeitem-expanded-icon); + mask-image: var(--treeitem-expanded-icon); } .treeItemToggler.treeItemsHidden::before { - content: url(images/treeitem-collapsed.svg); - /*content: var(--treeitem-collapsed-icon);*/ - max-width: 16px; -} -@media (prefers-color-scheme: dark) { - - .treeItemToggler.treeItemsHidden::before { - content: url(images/treeitem-collapsed-dark.svg); - /*content: var(--treeitem-collapsed-icon);*/ - } -} -html[dir="rtl"] .treeItemToggler.treeItemsHidden::before { - transform: scaleX(-1); + -webkit-mask-image: var(--treeitem-collapsed-icon); + mask-image: var(--treeitem-collapsed-icon); + transform: scaleX(var(--dir-factor)); } .treeItemToggler.treeItemsHidden ~ .treeItems { display: none; } -html[dir="ltr"] .treeItemToggler { - float: left; -} -html[dir="rtl"] .treeItemToggler { - float: right; -} -html[dir="ltr"] .treeItemToggler::before { - right: 4px; -} -html[dir="rtl"] .treeItemToggler::before { - left: 4px; -} - -.treeItemToggler:hover { - background-color: rgba(0, 0, 0, 0.15); - background-color: var(--sidebaritem-bg-color); - background-clip: padding-box; - border-radius: 2px; - color: rgba(0, 0, 0, 0.9); - color: var(--outline-hover-color); -} - -@media (prefers-color-scheme: dark) { - - .treeItemToggler:hover { - color: rgba(255, 255, 255, 0.9); - color: var(--outline-hover-color); - } -} - -@media (prefers-color-scheme: dark) { - - .treeItemToggler:hover { - background-color: rgba(255, 255, 255, 0.15); - background-color: var(--sidebaritem-bg-color); - } -} - -.treeItemToggler:hover + a { - background-color: rgba(0, 0, 0, 0.15); - background-color: var(--sidebaritem-bg-color); - background-clip: padding-box; - border-radius: 2px; - color: rgba(0, 0, 0, 0.9); - color: var(--outline-hover-color); -} - -@media (prefers-color-scheme: dark) { - - .treeItemToggler:hover + a { - color: rgba(255, 255, 255, 0.9); - color: var(--outline-hover-color); - } -} - -@media (prefers-color-scheme: dark) { - - .treeItemToggler:hover + a { - background-color: rgba(255, 255, 255, 0.15); - background-color: var(--sidebaritem-bg-color); - } -} - -.treeItemToggler:hover ~ .treeItems { - background-color: rgba(0, 0, 0, 0.15); - background-color: var(--sidebaritem-bg-color); - background-clip: padding-box; - border-radius: 2px; - color: rgba(0, 0, 0, 0.9); - color: var(--outline-hover-color); -} - -@media (prefers-color-scheme: dark) { - - .treeItemToggler:hover ~ .treeItems { - color: rgba(255, 255, 255, 0.9); - color: var(--outline-hover-color); - } -} - -@media (prefers-color-scheme: dark) { - - .treeItemToggler:hover ~ .treeItems { - background-color: rgba(255, 255, 255, 0.15); - background-color: var(--sidebaritem-bg-color); - } + +.treeItem.selected > a { + background-color: var(--treeitem-selected-bg-color); + color: var(--treeitem-selected-color); } +.treeItemToggler:hover, +.treeItemToggler:hover + a, +.treeItemToggler:hover ~ .treeItems, .treeItem > a:hover { - background-color: rgba(0, 0, 0, 0.15); background-color: var(--sidebaritem-bg-color); background-clip: padding-box; border-radius: 2px; - color: rgba(0, 0, 0, 0.9); - color: var(--outline-hover-color); -} - -@media (prefers-color-scheme: dark) { - - .treeItem > a:hover { - color: rgba(255, 255, 255, 0.9); - color: var(--outline-hover-color); - } -} - -@media (prefers-color-scheme: dark) { - - .treeItem > a:hover { - background-color: rgba(255, 255, 255, 0.15); - background-color: var(--sidebaritem-bg-color); - } -} - -.treeItem.selected { - background-color: rgba(0, 0, 0, 1); - background-color: var(--outline-active-bg-color); - background-clip: padding-box; - color: rgba(0, 0, 0, 0.08); - color: var(--outline-active-color); -} - -@media (prefers-color-scheme: dark) { - - .treeItem.selected { - color: rgba(255, 255, 255, 0.08); - color: var(--outline-active-color); - } -} - -@media (prefers-color-scheme: dark) { - - .treeItem.selected { - background-color: rgba(255, 255, 255, 1); - background-color: var(--outline-active-bg-color); - } -} - -.noResults { - font-size: 12px; - color: rgba(255, 255, 255, 0.8); - font-style: italic; - cursor: default; + color: var(--treeitem-hover-color); } /* TODO: file FF bug to support ::-moz-selection:window-inactive @@ -3530,9 +2724,7 @@ html[dir="rtl"] .treeItemToggler::before { } #errorWrapper { - background: none repeat scroll 0 0 rgba(255, 74, 74, 1); - background: none repeat scroll 0 0 var(--errorWrapper-bg-color); - color: rgba(12, 12, 13, 1); + background-color: var(--errorWrapper-bg-color); color: var(--main-color); left: 0; position: absolute; @@ -3541,289 +2733,115 @@ html[dir="rtl"] .treeItemToggler::before { padding: 3px 6px; } -@media (prefers-color-scheme: dark) { - - #errorWrapper { - color: rgba(249, 249, 250, 1); - color: var(--main-color); - } -} - -@media (prefers-color-scheme: dark) { - - #errorWrapper { - background: none repeat scroll 0 0 rgba(199, 17, 17, 1); - background: none repeat scroll 0 0 var(--errorWrapper-bg-color); - } -} -.loadingInProgress #errorWrapper { - top: 37px; -} - #errorMessageLeft { float: left; } - #errorMessageRight { float: right; } +#errorSpacer { + clear: both; +} #errorMoreInfo { - background-color: rgba(255, 255, 255, 1); background-color: var(--field-bg-color); - color: rgba(6, 6, 6, 1); color: var(--field-color); - border: 1px solid rgba(187, 187, 188, 1); border: 1px solid var(--field-border-color); padding: 3px; margin: 3px; width: 98%; } -@media (prefers-color-scheme: dark) { - - #errorMoreInfo { - border: 1px solid rgba(115, 115, 115, 1); - border: 1px solid var(--field-border-color); - } -} - -@media (prefers-color-scheme: dark) { - - #errorMoreInfo { - color: rgba(250, 250, 250, 1); - color: var(--field-color); - } -} - -@media (prefers-color-scheme: dark) { - - #errorMoreInfo { - background-color: rgba(64, 64, 68, 1); - background-color: var(--field-bg-color); - } -} - -.overlayButton { +.dialogButton { width: auto; - margin: 3px 4px 2px 4px !important; - padding: 2px 11px 2px 11px; + margin: 3px 4px 2px !important; + padding: 2px 11px; + color: var(--main-color); + background-color: var(--dialog-button-bg-color); + border: var(--dialog-button-border) !important; } -#overlayContainer { - display: table; - position: absolute; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.2); - z-index: 40000; -} -#overlayContainer > * { - overflow: auto; - -webkit-overflow-scrolling: touch; -} - -#overlayContainer > .container { - display: table-cell; - vertical-align: middle; - text-align: center; -} - -#overlayContainer > .container > .dialog { - display: inline-block; +dialog { + margin: auto; padding: 15px; border-spacing: 4px; - color: rgba(12, 12, 13, 1); color: var(--main-color); font-size: 12px; line-height: 14px; - background-color: rgba(255, 255, 255, 1); background-color: var(--doorhanger-bg-color); border: 1px solid rgba(0, 0, 0, 0.5); border-radius: 4px; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); } - -@media (prefers-color-scheme: dark) { - - #overlayContainer > .container > .dialog { - background-color: rgba(74, 74, 79, 1); - background-color: var(--doorhanger-bg-color); - } +dialog::-webkit-backdrop { + background-color: rgba(0, 0, 0, 0.2); +} +dialog::backdrop { + background-color: rgba(0, 0, 0, 0.2); } -@media (prefers-color-scheme: dark) { - - #overlayContainer > .container > .dialog { - color: rgba(249, 249, 250, 1); - color: var(--main-color); - } -} - -.dialog > .row { +dialog > .row { display: table-row; } -.dialog > .row > * { +dialog > .row > * { display: table-cell; } -.dialog .toolbarField { +dialog .toolbarField { margin: 5px 0; } -.dialog .separator { +dialog .separator { display: block; - margin: 4px 0 4px 0; + margin: 4px 0; height: 1px; width: 100%; - background-color: rgba(0, 0, 0, 0.3); background-color: var(--separator-color); } -@media (prefers-color-scheme: dark) { - - .dialog .separator { - background-color: rgba(0, 0, 0, 0.3); - background-color: var(--separator-color); - } -} - -.dialog .buttonRow { +dialog .buttonRow { text-align: center; vertical-align: middle; } -.dialog :link { +dialog :link { color: rgba(255, 255, 255, 1); } -#passwordOverlay > .dialog { +#passwordDialog { text-align: center; } -#passwordOverlay .toolbarField { +#passwordDialog .toolbarField { width: 200px; } -#documentPropertiesOverlay > .dialog { +#documentPropertiesDialog { text-align: left; } -#documentPropertiesOverlay .row > * { - min-width: 100px; -} -html[dir="ltr"] #documentPropertiesOverlay .row > * { +[dir="ltr"] #documentPropertiesDialog .row > * { text-align: left; } -html[dir="rtl"] #documentPropertiesOverlay .row > * { +[dir="rtl"] #documentPropertiesDialog .row > * { text-align: right; } -#documentPropertiesOverlay .row > span { +#documentPropertiesDialog .row > * { + min-width: 100px; + text-align: start; +} +#documentPropertiesDialog .row > span { width: 125px; word-wrap: break-word; } -#documentPropertiesOverlay .row > p { +#documentPropertiesDialog .row > p { max-width: 225px; word-wrap: break-word; } -#documentPropertiesOverlay .buttonRow { +#documentPropertiesDialog .buttonRow { margin-top: 10px; } -.clearBoth { - clear: both; -} - -.fileInput { - background: rgba(255, 255, 255, 1); - color: rgba(0, 0, 0, 1); - margin-top: 5px; - visibility: hidden; - position: fixed; - right: 0; - top: 0; -} - -#PDFBug { - background: none repeat scroll 0 0 rgba(255, 255, 255, 1); - border: 1px solid rgba(102, 102, 102, 1); - position: fixed; - top: 32px; - right: 0; - bottom: 0; - font-size: 10px; - padding: 0; - width: 300px; -} -#PDFBug .controls { - background: rgba(238, 238, 238, 1); - border-bottom: 1px solid rgba(102, 102, 102, 1); - padding: 3px; -} -#PDFBug .panels { - bottom: 0; - left: 0; - overflow: auto; - -webkit-overflow-scrolling: touch; - position: absolute; - right: 0; - top: 27px; -} -#PDFBug .panels > div { - padding: 5px; -} -#PDFBug button.active { - font-weight: bold; -} -.debuggerShowText { - background: none repeat scroll 0 0 rgba(255, 255, 0, 1); - color: rgba(0, 0, 255, 1); -} -.debuggerHideText:hover { - background: none repeat scroll 0 0 rgba(255, 255, 0, 1); -} -#PDFBug .stats { - font-family: courier; - font-size: 10px; - white-space: pre; -} -#PDFBug .stats .title { - font-weight: bold; -} -#PDFBug table { - font-size: 10px; -} - -#viewer.textLayer-visible .textLayer { - opacity: 1; -} - -#viewer.textLayer-visible .canvasWrapper { - background-color: rgba(128, 255, 128, 1); -} - -#viewer.textLayer-visible .canvasWrapper canvas { - mix-blend-mode: screen; -} - -#viewer.textLayer-visible .textLayer > span { - background-color: rgba(255, 255, 0, 0.1); - color: rgba(0, 0, 0, 1); - border: solid 1px rgba(255, 0, 0, 0.5); - box-sizing: border-box; -} - -#viewer.textLayer-hover .textLayer > span:hover { - background-color: rgba(255, 255, 255, 1); - color: rgba(0, 0, 0, 1); -} - -#viewer.textLayer-shadow .textLayer > span { - background-color: rgba(255, 255, 255, 0.6); - color: rgba(0, 0, 0, 1); -} - .grab-to-pan-grab { - cursor: url("images/grab.cur"), move !important; cursor: -webkit-grab !important; cursor: grab !important; } @@ -3833,7 +2851,6 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { } .grab-to-pan-grab:active, .grab-to-pan-grabbing { - cursor: url("images/grabbing.cur"), move !important; cursor: -webkit-grabbing !important; cursor: grabbing !important; position: fixed; @@ -3856,51 +2873,9 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { } @media print { - /* General rules for printing. */ body { background: rgba(0, 0, 0, 0) none; } - - /* Rules for browsers that don't support mozPrintCallback. */ - #sidebarContainer, - #secondaryToolbar, - .toolbar, - #loadingBox, - #errorWrapper, - .textLayer { - display: none; - } - #viewerContainer { - overflow: visible; - } - - #mainContainer, - #viewerContainer, - .page, - .page canvas { - position: static; - padding: 0; - margin: 0; - } - - .page { - float: left; - display: none; - border: none; - box-shadow: none; - background-clip: content-box; - background-color: rgba(255, 255, 255, 1); - } - - .page[data-loaded] { - display: block; - } - - .fileInput { - display: none; - } - - /* Rules for browsers that support PDF.js printing */ body[data-pdfjsprinting] #outerContainer { display: none; } @@ -3911,18 +2886,38 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { height: 100%; } /* wrapper around (scaled) print canvas elements */ - #printContainer > div { - position: relative; - top: 0; - left: 0; - width: 1px; - height: 1px; - overflow: visible; + #printContainer > .printedPage { page-break-after: always; page-break-inside: avoid; + + /* The wrapper always cover the whole page. */ + height: 100%; + width: 100%; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; } - #printContainer canvas, - #printContainer img { + + #printContainer > .xfaPrintedPage .xfaPage { + position: absolute; + } + + #printContainer > .xfaPrintedPage { + page-break-after: always; + page-break-inside: avoid; + width: 100%; + height: 100%; + position: relative; + } + + #printContainer > .printedPage canvas, + #printContainer > .printedPage img { + /* The intrinsic canvas / image size will make sure that we fit the page. */ + max-width: 100%; + max-height: 100%; + direction: ltr; display: block; } @@ -3945,28 +2940,21 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { } @media all and (max-width: 840px) { - #sidebarContent { - background-color: rgba(0, 0, 0, 0.7); + #sidebarContainer { + background-color: var(--sidebar-narrow-bg-color); } - - html[dir="ltr"] #outerContainer.sidebarOpen #viewerContainer { - left: 0px !important; + [dir="ltr"] #outerContainer.sidebarOpen #viewerContainer { + left: 0 !important; } - html[dir="rtl"] #outerContainer.sidebarOpen #viewerContainer { - right: 0px !important; + [dir="rtl"] #outerContainer.sidebarOpen #viewerContainer { + right: 0 !important; } - - #outerContainer .hiddenLargeView, - #outerContainer .hiddenMediumView { - display: inherit; - } - #outerContainer .visibleLargeView, - #outerContainer .visibleMediumView { - display: none; + #outerContainer.sidebarOpen #viewerContainer { + inset-inline-start: 0 !important; } } -@media all and (max-width: 770px) { +@media all and (max-width: 820px) { #outerContainer .hiddenLargeView { display: none; } @@ -3975,7 +2963,7 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { } } -@media all and (max-width: 700px) { +@media all and (max-width: 750px) { #outerContainer .hiddenMediumView { display: none; } @@ -3984,7 +2972,7 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { } } -@media all and (max-width: 640px) { +@media all and (max-width: 690px) { .hiddenSmallView, .hiddenSmallView * { display: none; @@ -3995,15 +2983,18 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { .toolbarButtonSpacer { width: 0; } - html[dir="ltr"] .findbar { + [dir="ltr"] .findbar { left: 34px; } - html[dir="rtl"] .findbar { + [dir="rtl"] .findbar { right: 34px; } + .findbar { + inset-inline-start: 34px; + } } -@media all and (max-width: 535px) { +@media all and (max-width: 560px) { #scaleSelectContainer { display: none; } diff --git a/cps/static/css/main.css b/cps/static/css/main.css index adbfbfdfb..03cb0a011 100644 --- a/cps/static/css/main.css +++ b/cps/static/css/main.css @@ -567,6 +567,36 @@ input:-moz-placeholder { color: #454545; } font-size: 0.8em; } +.md-content .themes button { + display: inline-block; + border: none; + text-align: center; + text-decoration: none; + margin-top: 5%; + margin-right: 1%; + font-size: 16px; +} + +.md-content .themes button.darkTheme { + background-color: #202124; + color: white; +} + +.md-content .themes button.whiteTheme { + background-color: white; + color: black; +} + +.md-content .themes button.sepiaTheme { + background-color: #ece1ca; + color: black; +} + +.md-content .themes button.blackTheme { + background-color: black; + color: white; +} + /* Effect 1: Fade in and scale up */ .md-effect-1 .md-content { -webkit-transform: scale(0.7); diff --git a/cps/static/css/reader.css b/cps/static/css/reader.css new file mode 100644 index 000000000..ec8054ca0 --- /dev/null +++ b/cps/static/css/reader.css @@ -0,0 +1,29 @@ +.fontSizeWrapper { + position: relative; +} +.slider { + position: absolute; + top: 50%; + transform: translate(0,-50%); + width: 90%; + height: 60px; + background: transparent; + border-radius: 20px; + display: flex; + align-items: center; + box-shadow: 0px 15px 40px #7E6D5766; +} +.slider label { + font-size: 20px; + font-weight: 400; + font-family: Open Sans; + padding-right: 10px; + color: white; +} +.slider input[type="range"] { + width: 80%; + height: 5px; + background: black; + border: none; + outline: none; +} diff --git a/cps/static/css/style.css b/cps/static/css/style.css index bf2257e65..59bcd2c03 100644 --- a/cps/static/css/style.css +++ b/cps/static/css/style.css @@ -140,6 +140,7 @@ table .bg-dark-danger a { color: #fff; } .container-fluid .book { margin-top: 20px; + max-width: 180px; display: flex; flex-direction: column; } @@ -429,7 +430,7 @@ div.log { } #detailcover { cursor:zoom-in; } -#detailcover:-webkit-full-screen { cursor:zoom-out; } -#detailcover:-moz-full-screen { cursor:zoom-out; } -#detailcover:-ms-fullscreen { cursor:zoom-out; } -#detailcover:fullscreen { cursor:zoom-out; } +#detailcover:-webkit-full-screen { cursor:zoom-out; border: 0; } +#detailcover:-moz-full-screen { cursor:zoom-out; border: 0; } +#detailcover:-ms-fullscreen { cursor:zoom-out; border: 0; } +#detailcover:fullscreen { cursor:zoom-out; border: 0; } diff --git a/cps/static/js/caliBlur.js b/cps/static/js/caliBlur.js old mode 100644 new mode 100755 index 3203c255d..ec394d0b1 --- a/cps/static/js/caliBlur.js +++ b/cps/static/js/caliBlur.js @@ -16,7 +16,6 @@ */ // Move advanced search to side-menu $("a[href*='advanced']").parent().insertAfter("#nav_new"); -$("body").addClass("blur"); $("body.stat").addClass("stats"); $("body.config").addClass("admin"); $("body.uiconfig").addClass("admin"); @@ -29,8 +28,8 @@ $("body > div.container-fluid > div > div.col-sm-10 > div.filterheader").attr("s // Back button curHref = window.location.href.split("/"); prevHref = document.referrer.split("/"); -$(".navbar-form.navbar-left") - .before('
'); +$(".plexBack a").attr('href', encodeURI(document.referrer)); + if (history.length === 1 || curHref[0] + curHref[1] + @@ -44,14 +43,9 @@ if (history.length === 1 || //Weird missing a after pressing back from edit. setTimeout(function () { - if ($(".plexBack a").length < 1) { - $(".plexBack").append(''); - } + $(".plexBack a").attr('href', encodeURI(document.referrer)); }, 10); -// Home button -$(".plexBack").before('
'); -$("a.navbar-brand").clone().appendTo(".home-btn").empty().removeClass("navbar-brand"); ///////////////////////////////// // Start of Book Details Work // /////////////////////////////// @@ -201,7 +195,7 @@ if ($("body.book").length > 0) { // Move dropdown lists higher in dom, replace bootstrap toggle with own toggle. $('ul[aria-labelledby="read-in-browser"]').insertBefore(".blur-wrapper").addClass("readinbrowser-drop"); - $('ul[aria-labelledby="send-to-kindle"]').insertBefore(".blur-wrapper").addClass("sendtokindle-drop"); + $('ul[aria-labelledby="send-to-kereader"]').insertBefore(".blur-wrapper").addClass("sendtoereader-drop"); $(".leramslist").insertBefore(".blur-wrapper"); $('ul[aria-labelledby="btnGroupDrop1"]').insertBefore(".blur-wrapper").addClass("leramslist"); $("#add-to-shelves").insertBefore(".blur-wrapper"); @@ -215,7 +209,7 @@ if ($("body.book").length > 0) { }); $("#sendbtn2").click(function () { - $(".sendtokindle-drop").toggle(); + $(".sendtoereader-drop").toggle(); }); @@ -242,12 +236,12 @@ if ($("body.book").length > 0) { if ($("#sendbtn2").length > 0) { position = $("#sendbtn2").offset().left - if (position + $(".sendtokindle-drop").width() > $(window).width()) { - positionOff = position + $(".sendtokindle-drop").width() - $(window).width(); + if (position + $(".sendtoereader-drop").width() > $(window).width()) { + positionOff = position + $(".sendtoereader-drop").width() - $(window).width(); ribPosition = position - positionOff - 5 - $(".sendtokindle-drop").attr("style", "left: " + ribPosition + "px !important; right: auto; top: " + topPos + "px"); + $(".sendtoereader-drop").attr("style", "left: " + ribPosition + "px !important; right: auto; top: " + topPos + "px"); } else { - $(".sendtokindle-drop").attr("style", "left: " + position + "px !important; right: auto; top: " + topPos + "px"); + $(".sendtoereader-drop").attr("style", "left: " + position + "px !important; right: auto; top: " + topPos + "px"); } } @@ -270,7 +264,7 @@ if ($("body.book").length > 0) { if (position + $("#add-to-shelves").width() > $(window).width()) { positionOff = position + $("#add-to-shelves").width() - $(window).width(); - adsPosition = position - positionOff - 5 + adsPosition = position - positionOff - 5; $("#add-to-shelves").attr("style", "left: " + adsPosition + "px !important; right: auto; top: " + topPos + "px"); } else { $("#add-to-shelves").attr("style", "left: " + position + "px !important; right: auto; top: " + topPos + "px"); @@ -300,7 +294,7 @@ if ($("body.book").length > 0) { $(document).mouseup(function (e) { var container = new Array(); container.push($('ul[aria-labelledby="read-in-browser"]')); - container.push($(".sendtokindle-drop")); + container.push($(".sendtoereader-drop")); container.push($(".leramslist")); container.push($("#add-to-shelves")); container.push($(".navbar-collapse.collapse.in")); @@ -326,13 +320,8 @@ url = window.location.pathname // Move create shelf $("#nav_createshelf").prependTo(".your-shelves"); -// Create drop-down for profile and move elements to it -$("#main-nav") - .prepend(''); -$("#top_user").parent().addClass("dropdown").appendTo(".profileDropli"); -$("#nav_about").addClass("dropdown").appendTo(".profileDropli"); -$("#register").parent().addClass("dropdown").appendTo(".profileDropli"); -$("#logout").parent().addClass("dropdown").appendTo(".profileDropli"); +// Move About link it the profile dropdown +$(".profileDropli #top_user").parent().after($("#nav_about").addClass("dropdown")) // Remove the modals except from some areas where they are needed bodyClass = $("body").attr("class").split(" "); @@ -429,7 +418,7 @@ if($("body.advsearch").length > 0) { if (position + $("#add-to-shelves").width() > $(window).width()) { positionOff = position + $("#add-to-shelves").width() - $(window).width(); - adsPosition = position - positionOff - 5 + adsPosition = position - positionOff - 5; $("#add-to-shelves").attr("style", "left: " + adsPosition + "px !important; right: auto; top: " + topPos + "px"); } else { $("#add-to-shelves").attr("style", "left: " + position + "px !important; right: auto; top: " + topPos + "px"); @@ -479,12 +468,12 @@ if ($.trim($("#add-to-shelves").html()).length === 0) { $("#add-to-shelf").addClass("empty-ul"); } -shelfLength = $("#add-to-shelves li").length -emptyLength = 0 +shelfLength = $("#add-to-shelves li").length; +emptyLength = 0; $("#add-to-shelves").on("click", "li a", function () { console.log("#remove-from-shelves change registered"); - emptyLength++ + emptyLength++; setTimeout(function () { if (emptyLength >= shelfLength) { @@ -666,7 +655,7 @@ $("#sendbtn").attr({ $("#sendbtn2").attr({ "data-toggle-two": "tooltip", - "title": $("#sendbtn2").text(), // "Send to Kindle", + "title": $("#sendbtn2").text(), // "Send to eReader", "data-placement": "bottom", "data-viewport": ".btn-toolbar" }) diff --git a/cps/static/js/compress/jszip.js b/cps/static/js/compress/jszip.js deleted file mode 100644 index 1546d7fcb..000000000 --- a/cps/static/js/compress/jszip.js +++ /dev/null @@ -1,9155 +0,0 @@ -/*! - -JSZip - A Javascript class for generating and reading zip files - - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library pako released under the MIT license : -https://github.com/nodeca/pako/blob/master/LICENSE -*/ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.JSZip=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } - else if (isNaN(chr3)) { - enc4 = 64; - } - - output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); - - } - - return output; -}; - -// public method for decoding -exports.decode = function(input, utf8) { - var output = ""; - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0; - - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - - while (i < input.length) { - - enc1 = _keyStr.indexOf(input.charAt(i++)); - enc2 = _keyStr.indexOf(input.charAt(i++)); - enc3 = _keyStr.indexOf(input.charAt(i++)); - enc4 = _keyStr.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output = output + String.fromCharCode(chr1); - - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } - - } - - return output; - -}; - -},{}],2:[function(_dereq_,module,exports){ -'use strict'; -function CompressedObject() { - this.compressedSize = 0; - this.uncompressedSize = 0; - this.crc32 = 0; - this.compressionMethod = null; - this.compressedContent = null; -} - -CompressedObject.prototype = { - /** - * Return the decompressed content in an unspecified format. - * The format will depend on the decompressor. - * @return {Object} the decompressed content. - */ - getContent: function() { - return null; // see implementation - }, - /** - * Return the compressed content in an unspecified format. - * The format will depend on the compressed conten source. - * @return {Object} the compressed content. - */ - getCompressedContent: function() { - return null; // see implementation - } -}; -module.exports = CompressedObject; - -},{}],3:[function(_dereq_,module,exports){ -'use strict'; -exports.STORE = { - magic: "\x00\x00", - compress: function(content, compressionOptions) { - return content; // no compression - }, - uncompress: function(content) { - return content; // no compression - }, - compressInputType: null, - uncompressInputType: null -}; -exports.DEFLATE = _dereq_('./flate'); - -},{"./flate":8}],4:[function(_dereq_,module,exports){ -'use strict'; - -var utils = _dereq_('./utils'); - -var table = [ - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -]; - -/** - * - * Javascript crc32 - * http://www.webtoolkit.info/ - * - */ -module.exports = function crc32(input, crc) { - if (typeof input === "undefined" || !input.length) { - return 0; - } - - var isArray = utils.getTypeOf(input) !== "string"; - - if (typeof(crc) == "undefined") { - crc = 0; - } - var x = 0; - var y = 0; - var b = 0; - - crc = crc ^ (-1); - for (var i = 0, iTop = input.length; i < iTop; i++) { - b = isArray ? input[i] : input.charCodeAt(i); - y = (crc ^ b) & 0xFF; - x = table[y]; - crc = (crc >>> 8) ^ x; - } - - return crc ^ (-1); -}; -// vim: set shiftwidth=4 softtabstop=4: - -},{"./utils":21}],5:[function(_dereq_,module,exports){ -'use strict'; -var utils = _dereq_('./utils'); - -function DataReader(data) { - this.data = null; // type : see implementation - this.length = 0; - this.index = 0; -} -DataReader.prototype = { - /** - * Check that the offset will not go too far. - * @param {string} offset the additional offset to check. - * @throws {Error} an Error if the offset is out of bounds. - */ - checkOffset: function(offset) { - this.checkIndex(this.index + offset); - }, - /** - * Check that the specifed index will not be too far. - * @param {string} newIndex the index to check. - * @throws {Error} an Error if the index is out of bounds. - */ - checkIndex: function(newIndex) { - if (this.length < newIndex || newIndex < 0) { - throw new Error("End of data reached (data length = " + this.length + ", asked index = " + (newIndex) + "). Corrupted zip ?"); - } - }, - /** - * Change the index. - * @param {number} newIndex The new index. - * @throws {Error} if the new index is out of the data. - */ - setIndex: function(newIndex) { - this.checkIndex(newIndex); - this.index = newIndex; - }, - /** - * Skip the next n bytes. - * @param {number} n the number of bytes to skip. - * @throws {Error} if the new index is out of the data. - */ - skip: function(n) { - this.setIndex(this.index + n); - }, - /** - * Get the byte at the specified index. - * @param {number} i the index to use. - * @return {number} a byte. - */ - byteAt: function(i) { - // see implementations - }, - /** - * Get the next number with a given byte size. - * @param {number} size the number of bytes to read. - * @return {number} the corresponding number. - */ - readInt: function(size) { - var result = 0, - i; - this.checkOffset(size); - for (i = this.index + size - 1; i >= this.index; i--) { - result = (result << 8) + this.byteAt(i); - } - this.index += size; - return result; - }, - /** - * Get the next string with a given byte size. - * @param {number} size the number of bytes to read. - * @return {string} the corresponding string. - */ - readString: function(size) { - return utils.transformTo("string", this.readData(size)); - }, - /** - * Get raw data without conversion, bytes. - * @param {number} size the number of bytes to read. - * @return {Object} the raw data, implementation specific. - */ - readData: function(size) { - // see implementations - }, - /** - * Find the last occurence of a zip signature (4 bytes). - * @param {string} sig the signature to find. - * @return {number} the index of the last occurence, -1 if not found. - */ - lastIndexOfSignature: function(sig) { - // see implementations - }, - /** - * Get the next date. - * @return {Date} the date. - */ - readDate: function() { - var dostime = this.readInt(4); - return new Date( - ((dostime >> 25) & 0x7f) + 1980, // year - ((dostime >> 21) & 0x0f) - 1, // month - (dostime >> 16) & 0x1f, // day - (dostime >> 11) & 0x1f, // hour - (dostime >> 5) & 0x3f, // minute - (dostime & 0x1f) << 1); // second - } -}; -module.exports = DataReader; - -},{"./utils":21}],6:[function(_dereq_,module,exports){ -'use strict'; -exports.base64 = false; -exports.binary = false; -exports.dir = false; -exports.createFolders = false; -exports.date = null; -exports.compression = null; -exports.compressionOptions = null; -exports.comment = null; -exports.unixPermissions = null; -exports.dosPermissions = null; - -},{}],7:[function(_dereq_,module,exports){ -'use strict'; -var utils = _dereq_('./utils'); - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.string2binary = function(str) { - return utils.string2binary(str); -}; - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.string2Uint8Array = function(str) { - return utils.transformTo("uint8array", str); -}; - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.uint8Array2String = function(array) { - return utils.transformTo("string", array); -}; - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.string2Blob = function(str) { - var buffer = utils.transformTo("arraybuffer", str); - return utils.arrayBuffer2Blob(buffer); -}; - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.arrayBuffer2Blob = function(buffer) { - return utils.arrayBuffer2Blob(buffer); -}; - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.transformTo = function(outputType, input) { - return utils.transformTo(outputType, input); -}; - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.getTypeOf = function(input) { - return utils.getTypeOf(input); -}; - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.checkSupport = function(type) { - return utils.checkSupport(type); -}; - -/** - * @deprecated - * This value will be removed in a future version without replacement. - */ -exports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS; - -/** - * @deprecated - * This value will be removed in a future version without replacement. - */ -exports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS; - - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.pretty = function(str) { - return utils.pretty(str); -}; - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.findCompression = function(compressionMethod) { - return utils.findCompression(compressionMethod); -}; - -/** - * @deprecated - * This function will be removed in a future version without replacement. - */ -exports.isRegExp = function (object) { - return utils.isRegExp(object); -}; - - -},{"./utils":21}],8:[function(_dereq_,module,exports){ -'use strict'; -var USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined'); - -var pako = _dereq_("pako"); -exports.uncompressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; -exports.compressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; - -exports.magic = "\x08\x00"; -exports.compress = function(input, compressionOptions) { - return pako.deflateRaw(input, { - level : compressionOptions.level || -1 // default compression - }); -}; -exports.uncompress = function(input) { - return pako.inflateRaw(input); -}; - -},{"pako":24}],9:[function(_dereq_,module,exports){ -'use strict'; - -var base64 = _dereq_('./base64'); - -/** -Usage: - zip = new JSZip(); - zip.file("hello.txt", "Hello, World!").file("tempfile", "nothing"); - zip.folder("images").file("smile.gif", base64Data, {base64: true}); - zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")}); - zip.remove("tempfile"); - - base64zip = zip.generate(); - -**/ - -/** - * Representation a of zip file in js - * @constructor - * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional). - * @param {Object=} options the options for creating this objects (optional). - */ -function JSZip(data, options) { - // if this constructor is used without `new`, it adds `new` before itself: - if(!(this instanceof JSZip)) return new JSZip(data, options); - - // object containing the files : - // { - // "folder/" : {...}, - // "folder/data.txt" : {...} - // } - this.files = {}; - - this.comment = null; - - // Where we are in the hierarchy - this.root = ""; - if (data) { - this.load(data, options); - } - this.clone = function() { - var newObj = new JSZip(); - for (var i in this) { - if (typeof this[i] !== "function") { - newObj[i] = this[i]; - } - } - return newObj; - }; -} -JSZip.prototype = _dereq_('./object'); -JSZip.prototype.load = _dereq_('./load'); -JSZip.support = _dereq_('./support'); -JSZip.defaults = _dereq_('./defaults'); - -/** - * @deprecated - * This namespace will be removed in a future version without replacement. - */ -JSZip.utils = _dereq_('./deprecatedPublicUtils'); - -JSZip.base64 = { - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - encode : function(input) { - return base64.encode(input); - }, - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - decode : function(input) { - return base64.decode(input); - } -}; -JSZip.compressions = _dereq_('./compressions'); -module.exports = JSZip; - -},{"./base64":1,"./compressions":3,"./defaults":6,"./deprecatedPublicUtils":7,"./load":10,"./object":13,"./support":17}],10:[function(_dereq_,module,exports){ -'use strict'; -var base64 = _dereq_('./base64'); -var ZipEntries = _dereq_('./zipEntries'); -module.exports = function(data, options) { - var files, zipEntries, i, input; - options = options || {}; - if (options.base64) { - data = base64.decode(data); - } - - zipEntries = new ZipEntries(data, options); - files = zipEntries.files; - for (i = 0; i < files.length; i++) { - input = files[i]; - this.file(input.fileName, input.decompressed, { - binary: true, - optimizedBinaryString: true, - date: input.date, - dir: input.dir, - comment : input.fileComment.length ? input.fileComment : null, - unixPermissions : input.unixPermissions, - dosPermissions : input.dosPermissions, - createFolders: options.createFolders - }); - } - if (zipEntries.zipComment.length) { - this.comment = zipEntries.zipComment; - } - - return this; -}; - -},{"./base64":1,"./zipEntries":22}],11:[function(_dereq_,module,exports){ -(function (Buffer){ -'use strict'; -module.exports = function(data, encoding){ - return new Buffer(data, encoding); -}; -module.exports.test = function(b){ - return Buffer.isBuffer(b); -}; - -}).call(this,(typeof Buffer !== "undefined" ? Buffer : undefined)) -},{}],12:[function(_dereq_,module,exports){ -'use strict'; -var Uint8ArrayReader = _dereq_('./uint8ArrayReader'); - -function NodeBufferReader(data) { - this.data = data; - this.length = this.data.length; - this.index = 0; -} -NodeBufferReader.prototype = new Uint8ArrayReader(); - -/** - * @see DataReader.readData - */ -NodeBufferReader.prototype.readData = function(size) { - this.checkOffset(size); - var result = this.data.slice(this.index, this.index + size); - this.index += size; - return result; -}; -module.exports = NodeBufferReader; - -},{"./uint8ArrayReader":18}],13:[function(_dereq_,module,exports){ -'use strict'; -var support = _dereq_('./support'); -var utils = _dereq_('./utils'); -var crc32 = _dereq_('./crc32'); -var signature = _dereq_('./signature'); -var defaults = _dereq_('./defaults'); -var base64 = _dereq_('./base64'); -var compressions = _dereq_('./compressions'); -var CompressedObject = _dereq_('./compressedObject'); -var nodeBuffer = _dereq_('./nodeBuffer'); -var utf8 = _dereq_('./utf8'); -var StringWriter = _dereq_('./stringWriter'); -var Uint8ArrayWriter = _dereq_('./uint8ArrayWriter'); - -/** - * Returns the raw data of a ZipObject, decompress the content if necessary. - * @param {ZipObject} file the file to use. - * @return {String|ArrayBuffer|Uint8Array|Buffer} the data. - */ -var getRawData = function(file) { - if (file._data instanceof CompressedObject) { - file._data = file._data.getContent(); - file.options.binary = true; - file.options.base64 = false; - - if (utils.getTypeOf(file._data) === "uint8array") { - var copy = file._data; - // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array. - // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file). - file._data = new Uint8Array(copy.length); - // with an empty Uint8Array, Opera fails with a "Offset larger than array size" - if (copy.length !== 0) { - file._data.set(copy, 0); - } - } - } - return file._data; -}; - -/** - * Returns the data of a ZipObject in a binary form. If the content is an unicode string, encode it. - * @param {ZipObject} file the file to use. - * @return {String|ArrayBuffer|Uint8Array|Buffer} the data. - */ -var getBinaryData = function(file) { - var result = getRawData(file), - type = utils.getTypeOf(result); - if (type === "string") { - if (!file.options.binary) { - // unicode text ! - // unicode string => binary string is a painful process, check if we can avoid it. - if (support.nodebuffer) { - return nodeBuffer(result, "utf-8"); - } - } - return file.asBinary(); - } - return result; -}; - -/** - * Transform this._data into a string. - * @param {function} filter a function String -> String, applied if not null on the result. - * @return {String} the string representing this._data. - */ -var dataToString = function(asUTF8) { - var result = getRawData(this); - if (result === null || typeof result === "undefined") { - return ""; - } - // if the data is a base64 string, we decode it before checking the encoding ! - if (this.options.base64) { - result = base64.decode(result); - } - if (asUTF8 && this.options.binary) { - // JSZip.prototype.utf8decode supports arrays as input - // skip to array => string step, utf8decode will do it. - result = out.utf8decode(result); - } - else { - // no utf8 transformation, do the array => string step. - result = utils.transformTo("string", result); - } - - if (!asUTF8 && !this.options.binary) { - result = utils.transformTo("string", out.utf8encode(result)); - } - return result; -}; -/** - * A simple object representing a file in the zip file. - * @constructor - * @param {string} name the name of the file - * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data - * @param {Object} options the options of the file - */ -var ZipObject = function(name, data, options) { - this.name = name; - this.dir = options.dir; - this.date = options.date; - this.comment = options.comment; - this.unixPermissions = options.unixPermissions; - this.dosPermissions = options.dosPermissions; - - this._data = data; - this.options = options; - - /* - * This object contains initial values for dir and date. - * With them, we can check if the user changed the deprecated metadata in - * `ZipObject#options` or not. - */ - this._initialMetadata = { - dir : options.dir, - date : options.date - }; -}; - -ZipObject.prototype = { - /** - * Return the content as UTF8 string. - * @return {string} the UTF8 string. - */ - asText: function() { - return dataToString.call(this, true); - }, - /** - * Returns the binary content. - * @return {string} the content as binary. - */ - asBinary: function() { - return dataToString.call(this, false); - }, - /** - * Returns the content as a nodejs Buffer. - * @return {Buffer} the content as a Buffer. - */ - asNodeBuffer: function() { - var result = getBinaryData(this); - return utils.transformTo("nodebuffer", result); - }, - /** - * Returns the content as an Uint8Array. - * @return {Uint8Array} the content as an Uint8Array. - */ - asUint8Array: function() { - var result = getBinaryData(this); - return utils.transformTo("uint8array", result); - }, - /** - * Returns the content as an ArrayBuffer. - * @return {ArrayBuffer} the content as an ArrayBufer. - */ - asArrayBuffer: function() { - return this.asUint8Array().buffer; - } -}; - -/** - * Transform an integer into a string in hexadecimal. - * @private - * @param {number} dec the number to convert. - * @param {number} bytes the number of bytes to generate. - * @returns {string} the result. - */ -var decToHex = function(dec, bytes) { - var hex = "", - i; - for (i = 0; i < bytes; i++) { - hex += String.fromCharCode(dec & 0xff); - dec = dec >>> 8; - } - return hex; -}; - -/** - * Merge the objects passed as parameters into a new one. - * @private - * @param {...Object} var_args All objects to merge. - * @return {Object} a new object with the data of the others. - */ -var extend = function() { - var result = {}, i, attr; - for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers - for (attr in arguments[i]) { - if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === "undefined") { - result[attr] = arguments[i][attr]; - } - } - } - return result; -}; - -/** - * Transforms the (incomplete) options from the user into the complete - * set of options to create a file. - * @private - * @param {Object} o the options from the user. - * @return {Object} the complete set of options. - */ -var prepareFileAttrs = function(o) { - o = o || {}; - if (o.base64 === true && (o.binary === null || o.binary === undefined)) { - o.binary = true; - } - o = extend(o, defaults); - o.date = o.date || new Date(); - if (o.compression !== null) o.compression = o.compression.toUpperCase(); - - return o; -}; - -/** - * Add a file in the current folder. - * @private - * @param {string} name the name of the file - * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file - * @param {Object} o the options of the file - * @return {Object} the new file. - */ -var fileAdd = function(name, data, o) { - // be sure sub folders exist - var dataType = utils.getTypeOf(data), - parent; - - o = prepareFileAttrs(o); - - if (typeof o.unixPermissions === "string") { - o.unixPermissions = parseInt(o.unixPermissions, 8); - } - - // UNX_IFDIR 0040000 see zipinfo.c - if (o.unixPermissions && (o.unixPermissions & 0x4000)) { - o.dir = true; - } - // Bit 4 Directory - if (o.dosPermissions && (o.dosPermissions & 0x0010)) { - o.dir = true; - } - - if (o.dir) { - name = forceTrailingSlash(name); - } - - if (o.createFolders && (parent = parentFolder(name))) { - folderAdd.call(this, parent, true); - } - - if (o.dir || data === null || typeof data === "undefined") { - o.base64 = false; - o.binary = false; - data = null; - dataType = null; - } - else if (dataType === "string") { - if (o.binary && !o.base64) { - // optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask - if (o.optimizedBinaryString !== true) { - // this is a string, not in a base64 format. - // Be sure that this is a correct "binary string" - data = utils.string2binary(data); - } - } - } - else { // arraybuffer, uint8array, ... - o.base64 = false; - o.binary = true; - - if (!dataType && !(data instanceof CompressedObject)) { - throw new Error("The data of '" + name + "' is in an unsupported format !"); - } - - // special case : it's way easier to work with Uint8Array than with ArrayBuffer - if (dataType === "arraybuffer") { - data = utils.transformTo("uint8array", data); - } - } - - var object = new ZipObject(name, data, o); - this.files[name] = object; - return object; -}; - -/** - * Find the parent folder of the path. - * @private - * @param {string} path the path to use - * @return {string} the parent folder, or "" - */ -var parentFolder = function (path) { - if (path.slice(-1) == '/') { - path = path.substring(0, path.length - 1); - } - var lastSlash = path.lastIndexOf('/'); - return (lastSlash > 0) ? path.substring(0, lastSlash) : ""; -}; - - -/** - * Returns the path with a slash at the end. - * @private - * @param {String} path the path to check. - * @return {String} the path with a trailing slash. - */ -var forceTrailingSlash = function(path) { - // Check the name ends with a / - if (path.slice(-1) != "/") { - path += "/"; // IE doesn't like substr(-1) - } - return path; -}; -/** - * Add a (sub) folder in the current folder. - * @private - * @param {string} name the folder's name - * @param {boolean=} [createFolders] If true, automatically create sub - * folders. Defaults to false. - * @return {Object} the new folder. - */ -var folderAdd = function(name, createFolders) { - createFolders = (typeof createFolders !== 'undefined') ? createFolders : false; - - name = forceTrailingSlash(name); - - // Does this folder already exist? - if (!this.files[name]) { - fileAdd.call(this, name, null, { - dir: true, - createFolders: createFolders - }); - } - return this.files[name]; -}; - -/** - * Generate a JSZip.CompressedObject for a given zipOject. - * @param {ZipObject} file the object to read. - * @param {JSZip.compression} compression the compression to use. - * @param {Object} compressionOptions the options to use when compressing. - * @return {JSZip.CompressedObject} the compressed result. - */ -var generateCompressedObjectFrom = function(file, compression, compressionOptions) { - var result = new CompressedObject(), - content; - - // the data has not been decompressed, we might reuse things ! - if (file._data instanceof CompressedObject) { - result.uncompressedSize = file._data.uncompressedSize; - result.crc32 = file._data.crc32; - - if (result.uncompressedSize === 0 || file.dir) { - compression = compressions['STORE']; - result.compressedContent = ""; - result.crc32 = 0; - } - else if (file._data.compressionMethod === compression.magic) { - result.compressedContent = file._data.getCompressedContent(); - } - else { - content = file._data.getContent(); - // need to decompress / recompress - result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions); - } - } - else { - // have uncompressed data - content = getBinaryData(file); - if (!content || content.length === 0 || file.dir) { - compression = compressions['STORE']; - content = ""; - } - result.uncompressedSize = content.length; - result.crc32 = crc32(content); - result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions); - } - - result.compressedSize = result.compressedContent.length; - result.compressionMethod = compression.magic; - - return result; -}; - - - - -/** - * Generate the UNIX part of the external file attributes. - * @param {Object} unixPermissions the unix permissions or null. - * @param {Boolean} isDir true if the entry is a directory, false otherwise. - * @return {Number} a 32 bit integer. - * - * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute : - * - * TTTTsstrwxrwxrwx0000000000ADVSHR - * ^^^^____________________________ file type, see zipinfo.c (UNX_*) - * ^^^_________________________ setuid, setgid, sticky - * ^^^^^^^^^________________ permissions - * ^^^^^^^^^^______ not used ? - * ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only - */ -var generateUnixExternalFileAttr = function (unixPermissions, isDir) { - - var result = unixPermissions; - if (!unixPermissions) { - // I can't use octal values in strict mode, hence the hexa. - // 040775 => 0x41fd - // 0100664 => 0x81b4 - result = isDir ? 0x41fd : 0x81b4; - } - - return (result & 0xFFFF) << 16; -}; - -/** - * Generate the DOS part of the external file attributes. - * @param {Object} dosPermissions the dos permissions or null. - * @param {Boolean} isDir true if the entry is a directory, false otherwise. - * @return {Number} a 32 bit integer. - * - * Bit 0 Read-Only - * Bit 1 Hidden - * Bit 2 System - * Bit 3 Volume Label - * Bit 4 Directory - * Bit 5 Archive - */ -var generateDosExternalFileAttr = function (dosPermissions, isDir) { - - // the dir flag is already set for compatibility - - return (dosPermissions || 0) & 0x3F; -}; - -/** - * Generate the various parts used in the construction of the final zip file. - * @param {string} name the file name. - * @param {ZipObject} file the file content. - * @param {JSZip.CompressedObject} compressedObject the compressed object. - * @param {number} offset the current offset from the start of the zip file. - * @param {String} platform let's pretend we are this platform (change platform dependents fields) - * @return {object} the zip parts. - */ -var generateZipParts = function(name, file, compressedObject, offset, platform) { - var data = compressedObject.compressedContent, - utfEncodedFileName = utils.transformTo("string", utf8.utf8encode(file.name)), - comment = file.comment || "", - utfEncodedComment = utils.transformTo("string", utf8.utf8encode(comment)), - useUTF8ForFileName = utfEncodedFileName.length !== file.name.length, - useUTF8ForComment = utfEncodedComment.length !== comment.length, - o = file.options, - dosTime, - dosDate, - extraFields = "", - unicodePathExtraField = "", - unicodeCommentExtraField = "", - dir, date; - - - // handle the deprecated options.dir - if (file._initialMetadata.dir !== file.dir) { - dir = file.dir; - } else { - dir = o.dir; - } - - // handle the deprecated options.date - if(file._initialMetadata.date !== file.date) { - date = file.date; - } else { - date = o.date; - } - - var extFileAttr = 0; - var versionMadeBy = 0; - if (dir) { - // dos or unix, we set the dos dir flag - extFileAttr |= 0x00010; - } - if(platform === "UNIX") { - versionMadeBy = 0x031E; // UNIX, version 3.0 - extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir); - } else { // DOS or other, fallback to DOS - versionMadeBy = 0x0014; // DOS, version 2.0 - extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir); - } - - // date - // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html - // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html - // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html - - dosTime = date.getHours(); - dosTime = dosTime << 6; - dosTime = dosTime | date.getMinutes(); - dosTime = dosTime << 5; - dosTime = dosTime | date.getSeconds() / 2; - - dosDate = date.getFullYear() - 1980; - dosDate = dosDate << 4; - dosDate = dosDate | (date.getMonth() + 1); - dosDate = dosDate << 5; - dosDate = dosDate | date.getDate(); - - if (useUTF8ForFileName) { - // set the unicode path extra field. unzip needs at least one extra - // field to correctly handle unicode path, so using the path is as good - // as any other information. This could improve the situation with - // other archive managers too. - // This field is usually used without the utf8 flag, with a non - // unicode path in the header (winrar, winzip). This helps (a bit) - // with the messy Windows' default compressed folders feature but - // breaks on p7zip which doesn't seek the unicode path extra field. - // So for now, UTF-8 everywhere ! - unicodePathExtraField = - // Version - decToHex(1, 1) + - // NameCRC32 - decToHex(crc32(utfEncodedFileName), 4) + - // UnicodeName - utfEncodedFileName; - - extraFields += - // Info-ZIP Unicode Path Extra Field - "\x75\x70" + - // size - decToHex(unicodePathExtraField.length, 2) + - // content - unicodePathExtraField; - } - - if(useUTF8ForComment) { - - unicodeCommentExtraField = - // Version - decToHex(1, 1) + - // CommentCRC32 - decToHex(this.crc32(utfEncodedComment), 4) + - // UnicodeName - utfEncodedComment; - - extraFields += - // Info-ZIP Unicode Path Extra Field - "\x75\x63" + - // size - decToHex(unicodeCommentExtraField.length, 2) + - // content - unicodeCommentExtraField; - } - - var header = ""; - - // version needed to extract - header += "\x0A\x00"; - // general purpose bit flag - // set bit 11 if utf8 - header += (useUTF8ForFileName || useUTF8ForComment) ? "\x00\x08" : "\x00\x00"; - // compression method - header += compressedObject.compressionMethod; - // last mod file time - header += decToHex(dosTime, 2); - // last mod file date - header += decToHex(dosDate, 2); - // crc-32 - header += decToHex(compressedObject.crc32, 4); - // compressed size - header += decToHex(compressedObject.compressedSize, 4); - // uncompressed size - header += decToHex(compressedObject.uncompressedSize, 4); - // file name length - header += decToHex(utfEncodedFileName.length, 2); - // extra field length - header += decToHex(extraFields.length, 2); - - - var fileRecord = signature.LOCAL_FILE_HEADER + header + utfEncodedFileName + extraFields; - - var dirRecord = signature.CENTRAL_FILE_HEADER + - // version made by (00: DOS) - decToHex(versionMadeBy, 2) + - // file header (common to file and central directory) - header + - // file comment length - decToHex(utfEncodedComment.length, 2) + - // disk number start - "\x00\x00" + - // internal file attributes TODO - "\x00\x00" + - // external file attributes - decToHex(extFileAttr, 4) + - // relative offset of local header - decToHex(offset, 4) + - // file name - utfEncodedFileName + - // extra field - extraFields + - // file comment - utfEncodedComment; - - return { - fileRecord: fileRecord, - dirRecord: dirRecord, - compressedObject: compressedObject - }; -}; - - -// return the actual prototype of JSZip -var out = { - /** - * Read an existing zip and merge the data in the current JSZip object. - * The implementation is in jszip-load.js, don't forget to include it. - * @param {String|ArrayBuffer|Uint8Array|Buffer} stream The stream to load - * @param {Object} options Options for loading the stream. - * options.base64 : is the stream in base64 ? default : false - * @return {JSZip} the current JSZip object - */ - load: function(stream, options) { - throw new Error("Load method is not defined. Is the file jszip-load.js included ?"); - }, - - /** - * Filter nested files/folders with the specified function. - * @param {Function} search the predicate to use : - * function (relativePath, file) {...} - * It takes 2 arguments : the relative path and the file. - * @return {Array} An array of matching elements. - */ - filter: function(search) { - var result = [], - filename, relativePath, file, fileClone; - for (filename in this.files) { - if (!this.files.hasOwnProperty(filename)) { - continue; - } - file = this.files[filename]; - // return a new object, don't let the user mess with our internal objects :) - fileClone = new ZipObject(file.name, file._data, extend(file.options)); - relativePath = filename.slice(this.root.length, filename.length); - if (filename.slice(0, this.root.length) === this.root && // the file is in the current root - search(relativePath, fileClone)) { // and the file matches the function - result.push(fileClone); - } - } - return result; - }, - - /** - * Add a file to the zip file, or search a file. - * @param {string|RegExp} name The name of the file to add (if data is defined), - * the name of the file to find (if no data) or a regex to match files. - * @param {String|ArrayBuffer|Uint8Array|Buffer} data The file data, either raw or base64 encoded - * @param {Object} o File options - * @return {JSZip|Object|Array} this JSZip object (when adding a file), - * a file (when searching by string) or an array of files (when searching by regex). - */ - file: function(name, data, o) { - if (arguments.length === 1) { - if (utils.isRegExp(name)) { - var regexp = name; - return this.filter(function(relativePath, file) { - return !file.dir && regexp.test(relativePath); - }); - } - else { // text - return this.filter(function(relativePath, file) { - return !file.dir && relativePath === name; - })[0] || null; - } - } - else { // more than one argument : we have data ! - name = this.root + name; - fileAdd.call(this, name, data, o); - } - return this; - }, - - /** - * Add a directory to the zip file, or search. - * @param {String|RegExp} arg The name of the directory to add, or a regex to search folders. - * @return {JSZip} an object with the new directory as the root, or an array containing matching folders. - */ - folder: function(arg) { - if (!arg) { - return this; - } - - if (utils.isRegExp(arg)) { - return this.filter(function(relativePath, file) { - return file.dir && arg.test(relativePath); - }); - } - - // else, name is a new folder - var name = this.root + arg; - var newFolder = folderAdd.call(this, name); - - // Allow chaining by returning a new object with this folder as the root - var ret = this.clone(); - ret.root = newFolder.name; - return ret; - }, - - /** - * Delete a file, or a directory and all sub-files, from the zip - * @param {string} name the name of the file to delete - * @return {JSZip} this JSZip object - */ - remove: function(name) { - name = this.root + name; - var file = this.files[name]; - if (!file) { - // Look for any folders - if (name.slice(-1) != "/") { - name += "/"; - } - file = this.files[name]; - } - - if (file && !file.dir) { - // file - delete this.files[name]; - } else { - // maybe a folder, delete recursively - var kids = this.filter(function(relativePath, file) { - return file.name.slice(0, name.length) === name; - }); - for (var i = 0; i < kids.length; i++) { - delete this.files[kids[i].name]; - } - } - - return this; - }, - - /** - * Generate the complete zip file - * @param {Object} options the options to generate the zip file : - * - base64, (deprecated, use type instead) true to generate base64. - * - compression, "STORE" by default. - * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob. - * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file - */ - generate: function(options) { - options = extend(options || {}, { - base64: true, - compression: "STORE", - compressionOptions : null, - type: "base64", - platform: "DOS", - comment: null, - mimeType: 'application/zip' - }); - - utils.checkSupport(options.type); - - // accept nodejs `process.platform` - if( - options.platform === 'darwin' || - options.platform === 'freebsd' || - options.platform === 'linux' || - options.platform === 'sunos' - ) { - options.platform = "UNIX"; - } - if (options.platform === 'win32') { - options.platform = "DOS"; - } - - var zipData = [], - localDirLength = 0, - centralDirLength = 0, - writer, i, - utfEncodedComment = utils.transformTo("string", this.utf8encode(options.comment || this.comment || "")); - - // first, generate all the zip parts. - for (var name in this.files) { - if (!this.files.hasOwnProperty(name)) { - continue; - } - var file = this.files[name]; - - var compressionName = file.options.compression || options.compression.toUpperCase(); - var compression = compressions[compressionName]; - if (!compression) { - throw new Error(compressionName + " is not a valid compression method !"); - } - var compressionOptions = file.options.compressionOptions || options.compressionOptions || {}; - - var compressedObject = generateCompressedObjectFrom.call(this, file, compression, compressionOptions); - - var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength, options.platform); - localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize; - centralDirLength += zipPart.dirRecord.length; - zipData.push(zipPart); - } - - var dirEnd = ""; - - // end of central dir signature - dirEnd = signature.CENTRAL_DIRECTORY_END + - // number of this disk - "\x00\x00" + - // number of the disk with the start of the central directory - "\x00\x00" + - // total number of entries in the central directory on this disk - decToHex(zipData.length, 2) + - // total number of entries in the central directory - decToHex(zipData.length, 2) + - // size of the central directory 4 bytes - decToHex(centralDirLength, 4) + - // offset of start of central directory with respect to the starting disk number - decToHex(localDirLength, 4) + - // .ZIP file comment length - decToHex(utfEncodedComment.length, 2) + - // .ZIP file comment - utfEncodedComment; - - - // we have all the parts (and the total length) - // time to create a writer ! - var typeName = options.type.toLowerCase(); - if(typeName==="uint8array"||typeName==="arraybuffer"||typeName==="blob"||typeName==="nodebuffer") { - writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length); - }else{ - writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length); - } - - for (i = 0; i < zipData.length; i++) { - writer.append(zipData[i].fileRecord); - writer.append(zipData[i].compressedObject.compressedContent); - } - for (i = 0; i < zipData.length; i++) { - writer.append(zipData[i].dirRecord); - } - - writer.append(dirEnd); - - var zip = writer.finalize(); - - - - switch(options.type.toLowerCase()) { - // case "zip is an Uint8Array" - case "uint8array" : - case "arraybuffer" : - case "nodebuffer" : - return utils.transformTo(options.type.toLowerCase(), zip); - case "blob" : - return utils.arrayBuffer2Blob(utils.transformTo("arraybuffer", zip), options.mimeType); - // case "zip is a string" - case "base64" : - return (options.base64) ? base64.encode(zip) : zip; - default : // case "string" : - return zip; - } - - }, - - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - crc32: function (input, crc) { - return crc32(input, crc); - }, - - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - utf8encode: function (string) { - return utils.transformTo("string", utf8.utf8encode(string)); - }, - - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - utf8decode: function (input) { - return utf8.utf8decode(input); - } -}; -module.exports = out; - -},{"./base64":1,"./compressedObject":2,"./compressions":3,"./crc32":4,"./defaults":6,"./nodeBuffer":11,"./signature":14,"./stringWriter":16,"./support":17,"./uint8ArrayWriter":19,"./utf8":20,"./utils":21}],14:[function(_dereq_,module,exports){ -'use strict'; -exports.LOCAL_FILE_HEADER = "PK\x03\x04"; -exports.CENTRAL_FILE_HEADER = "PK\x01\x02"; -exports.CENTRAL_DIRECTORY_END = "PK\x05\x06"; -exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07"; -exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06"; -exports.DATA_DESCRIPTOR = "PK\x07\x08"; - -},{}],15:[function(_dereq_,module,exports){ -'use strict'; -var DataReader = _dereq_('./dataReader'); -var utils = _dereq_('./utils'); - -function StringReader(data, optimizedBinaryString) { - this.data = data; - if (!optimizedBinaryString) { - this.data = utils.string2binary(this.data); - } - this.length = this.data.length; - this.index = 0; -} -StringReader.prototype = new DataReader(); -/** - * @see DataReader.byteAt - */ -StringReader.prototype.byteAt = function(i) { - return this.data.charCodeAt(i); -}; -/** - * @see DataReader.lastIndexOfSignature - */ -StringReader.prototype.lastIndexOfSignature = function(sig) { - return this.data.lastIndexOf(sig); -}; -/** - * @see DataReader.readData - */ -StringReader.prototype.readData = function(size) { - this.checkOffset(size); - // this will work because the constructor applied the "& 0xff" mask. - var result = this.data.slice(this.index, this.index + size); - this.index += size; - return result; -}; -module.exports = StringReader; - -},{"./dataReader":5,"./utils":21}],16:[function(_dereq_,module,exports){ -'use strict'; - -var utils = _dereq_('./utils'); - -/** - * An object to write any content to a string. - * @constructor - */ -var StringWriter = function() { - this.data = []; -}; -StringWriter.prototype = { - /** - * Append any content to the current string. - * @param {Object} input the content to add. - */ - append: function(input) { - input = utils.transformTo("string", input); - this.data.push(input); - }, - /** - * Finalize the construction an return the result. - * @return {string} the generated string. - */ - finalize: function() { - return this.data.join(""); - } -}; - -module.exports = StringWriter; - -},{"./utils":21}],17:[function(_dereq_,module,exports){ -(function (Buffer){ -'use strict'; -exports.base64 = true; -exports.array = true; -exports.string = true; -exports.arraybuffer = typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined"; -// contains true if JSZip can read/generate nodejs Buffer, false otherwise. -// Browserify will provide a Buffer implementation for browsers, which is -// an augmented Uint8Array (i.e., can be used as either Buffer or U8). -exports.nodebuffer = typeof Buffer !== "undefined"; -// contains true if JSZip can read/generate Uint8Array, false otherwise. -exports.uint8array = typeof Uint8Array !== "undefined"; - -if (typeof ArrayBuffer === "undefined") { - exports.blob = false; -} -else { - var buffer = new ArrayBuffer(0); - try { - exports.blob = new Blob([buffer], { - type: "application/zip" - }).size === 0; - } - catch (e) { - try { - var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; - var builder = new Builder(); - builder.append(buffer); - exports.blob = builder.getBlob('application/zip').size === 0; - } - catch (e) { - exports.blob = false; - } - } -} - -}).call(this,(typeof Buffer !== "undefined" ? Buffer : undefined)) -},{}],18:[function(_dereq_,module,exports){ -'use strict'; -var DataReader = _dereq_('./dataReader'); - -function Uint8ArrayReader(data) { - if (data) { - this.data = data; - this.length = this.data.length; - this.index = 0; - } -} -Uint8ArrayReader.prototype = new DataReader(); -/** - * @see DataReader.byteAt - */ -Uint8ArrayReader.prototype.byteAt = function(i) { - return this.data[i]; -}; -/** - * @see DataReader.lastIndexOfSignature - */ -Uint8ArrayReader.prototype.lastIndexOfSignature = function(sig) { - var sig0 = sig.charCodeAt(0), - sig1 = sig.charCodeAt(1), - sig2 = sig.charCodeAt(2), - sig3 = sig.charCodeAt(3); - for (var i = this.length - 4; i >= 0; --i) { - if (this.data[i] === sig0 && this.data[i + 1] === sig1 && this.data[i + 2] === sig2 && this.data[i + 3] === sig3) { - return i; - } - } - - return -1; -}; -/** - * @see DataReader.readData - */ -Uint8ArrayReader.prototype.readData = function(size) { - this.checkOffset(size); - if(size === 0) { - // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of []. - return new Uint8Array(0); - } - var result = this.data.subarray(this.index, this.index + size); - this.index += size; - return result; -}; -module.exports = Uint8ArrayReader; - -},{"./dataReader":5}],19:[function(_dereq_,module,exports){ -'use strict'; - -var utils = _dereq_('./utils'); - -/** - * An object to write any content to an Uint8Array. - * @constructor - * @param {number} length The length of the array. - */ -var Uint8ArrayWriter = function(length) { - this.data = new Uint8Array(length); - this.index = 0; -}; -Uint8ArrayWriter.prototype = { - /** - * Append any content to the current array. - * @param {Object} input the content to add. - */ - append: function(input) { - if (input.length !== 0) { - // with an empty Uint8Array, Opera fails with a "Offset larger than array size" - input = utils.transformTo("uint8array", input); - this.data.set(input, this.index); - this.index += input.length; - } - }, - /** - * Finalize the construction an return the result. - * @return {Uint8Array} the generated array. - */ - finalize: function() { - return this.data; - } -}; - -module.exports = Uint8ArrayWriter; - -},{"./utils":21}],20:[function(_dereq_,module,exports){ -'use strict'; - -var utils = _dereq_('./utils'); -var support = _dereq_('./support'); -var nodeBuffer = _dereq_('./nodeBuffer'); - -/** - * The following functions come from pako, from pako/lib/utils/strings - * released under the MIT license, see pako https://github.com/nodeca/pako/ - */ - -// Table with utf8 lengths (calculated by first byte of sequence) -// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, -// because max possible codepoint is 0x10ffff -var _utf8len = new Array(256); -for (var i=0; i<256; i++) { - _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1); -} -_utf8len[254]=_utf8len[254]=1; // Invalid sequence start - -// convert string to array (typed, when possible) -var string2buf = function (str) { - var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; - - // count binary size - for (m_pos = 0; m_pos < str_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { - c2 = str.charCodeAt(m_pos+1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; - } - - // allocate buffer - if (support.uint8array) { - buf = new Uint8Array(buf_len); - } else { - buf = new Array(buf_len); - } - - // convert - for (i=0, m_pos = 0; i < buf_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { - c2 = str.charCodeAt(m_pos+1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - if (c < 0x80) { - /* one byte */ - buf[i++] = c; - } else if (c < 0x800) { - /* two bytes */ - buf[i++] = 0xC0 | (c >>> 6); - buf[i++] = 0x80 | (c & 0x3f); - } else if (c < 0x10000) { - /* three bytes */ - buf[i++] = 0xE0 | (c >>> 12); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } else { - /* four bytes */ - buf[i++] = 0xf0 | (c >>> 18); - buf[i++] = 0x80 | (c >>> 12 & 0x3f); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } - } - - return buf; -}; - -// Calculate max possible position in utf8 buffer, -// that will not break sequence. If that's not possible -// - (very small limits) return max size as is. -// -// buf[] - utf8 bytes array -// max - length limit (mandatory); -var utf8border = function(buf, max) { - var pos; - - max = max || buf.length; - if (max > buf.length) { max = buf.length; } - - // go back from last position, until start of sequence found - pos = max-1; - while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } - - // Fuckup - very small and broken sequence, - // return max, because we should return something anyway. - if (pos < 0) { return max; } - - // If we came to start of buffer - that means vuffer is too small, - // return max too. - if (pos === 0) { return max; } - - return (pos + _utf8len[buf[pos]] > max) ? pos : max; -}; - -// convert array to string -var buf2string = function (buf) { - var str, i, out, c, c_len; - var len = buf.length; - - // Reserve max possible length (2 words per char) - // NB: by unknown reasons, Array is significantly faster for - // String.fromCharCode.apply than Uint16Array. - var utf16buf = new Array(len*2); - - for (out=0, i=0; i 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; } - - // apply mask on first byte - c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; - // join the rest - while (c_len > 1 && i < len) { - c = (c << 6) | (buf[i++] & 0x3f); - c_len--; - } - - // terminated by end of string? - if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } - - if (c < 0x10000) { - utf16buf[out++] = c; - } else { - c -= 0x10000; - utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); - utf16buf[out++] = 0xdc00 | (c & 0x3ff); - } - } - - // shrinkBuf(utf16buf, out) - if (utf16buf.length !== out) { - if(utf16buf.subarray) { - utf16buf = utf16buf.subarray(0, out); - } else { - utf16buf.length = out; - } - } - - // return String.fromCharCode.apply(null, utf16buf); - return utils.applyFromCharCode(utf16buf); -}; - - -// That's all for the pako functions. - - -/** - * Transform a javascript string into an array (typed if possible) of bytes, - * UTF-8 encoded. - * @param {String} str the string to encode - * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string. - */ -exports.utf8encode = function utf8encode(str) { - if (support.nodebuffer) { - return nodeBuffer(str, "utf-8"); - } - - return string2buf(str); -}; - - -/** - * Transform a bytes array (or a representation) representing an UTF-8 encoded - * string into a javascript string. - * @param {Array|Uint8Array|Buffer} buf the data de decode - * @return {String} the decoded string. - */ -exports.utf8decode = function utf8decode(buf) { - if (support.nodebuffer) { - return utils.transformTo("nodebuffer", buf).toString("utf-8"); - } - - buf = utils.transformTo(support.uint8array ? "uint8array" : "array", buf); - - // return buf2string(buf); - // Chrome prefers to work with "small" chunks of data - // for the method buf2string. - // Firefox and Chrome has their own shortcut, IE doesn't seem to really care. - var result = [], k = 0, len = buf.length, chunk = 65536; - while (k < len) { - var nextBoundary = utf8border(buf, Math.min(k + chunk, len)); - if (support.uint8array) { - result.push(buf2string(buf.subarray(k, nextBoundary))); - } else { - result.push(buf2string(buf.slice(k, nextBoundary))); - } - k = nextBoundary; - } - return result.join(""); - -}; -// vim: set shiftwidth=4 softtabstop=4: - -},{"./nodeBuffer":11,"./support":17,"./utils":21}],21:[function(_dereq_,module,exports){ -'use strict'; -var support = _dereq_('./support'); -var compressions = _dereq_('./compressions'); -var nodeBuffer = _dereq_('./nodeBuffer'); -/** - * Convert a string to a "binary string" : a string containing only char codes between 0 and 255. - * @param {string} str the string to transform. - * @return {String} the binary string. - */ -exports.string2binary = function(str) { - var result = ""; - for (var i = 0; i < str.length; i++) { - result += String.fromCharCode(str.charCodeAt(i) & 0xff); - } - return result; -}; -exports.arrayBuffer2Blob = function(buffer, mimeType) { - exports.checkSupport("blob"); - mimeType = mimeType || 'application/zip'; - - try { - // Blob constructor - return new Blob([buffer], { - type: mimeType - }); - } - catch (e) { - - try { - // deprecated, browser only, old way - var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; - var builder = new Builder(); - builder.append(buffer); - return builder.getBlob(mimeType); - } - catch (e) { - - // well, fuck ?! - throw new Error("Bug : can't construct the Blob."); - } - } - - -}; -/** - * The identity function. - * @param {Object} input the input. - * @return {Object} the same input. - */ -function identity(input) { - return input; -} - -/** - * Fill in an array with a string. - * @param {String} str the string to use. - * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated). - * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array. - */ -function stringToArrayLike(str, array) { - for (var i = 0; i < str.length; ++i) { - array[i] = str.charCodeAt(i) & 0xFF; - } - return array; -} - -/** - * Transform an array-like object to a string. - * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform. - * @return {String} the result. - */ -function arrayLikeToString(array) { - // Performances notes : - // -------------------- - // String.fromCharCode.apply(null, array) is the fastest, see - // see http://jsperf.com/converting-a-uint8array-to-a-string/2 - // but the stack is limited (and we can get huge arrays !). - // - // result += String.fromCharCode(array[i]); generate too many strings ! - // - // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2 - var chunk = 65536; - var result = [], - len = array.length, - type = exports.getTypeOf(array), - k = 0, - canUseApply = true; - try { - switch(type) { - case "uint8array": - String.fromCharCode.apply(null, new Uint8Array(0)); - break; - case "nodebuffer": - String.fromCharCode.apply(null, nodeBuffer(0)); - break; - } - } catch(e) { - canUseApply = false; - } - - // no apply : slow and painful algorithm - // default browser on android 4.* - if (!canUseApply) { - var resultStr = ""; - for(var i = 0; i < array.length;i++) { - resultStr += String.fromCharCode(array[i]); - } - return resultStr; - } - while (k < len && chunk > 1) { - try { - if (type === "array" || type === "nodebuffer") { - result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len)))); - } - else { - result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len)))); - } - k += chunk; - } - catch (e) { - chunk = Math.floor(chunk / 2); - } - } - return result.join(""); -} - -exports.applyFromCharCode = arrayLikeToString; - - -/** - * Copy the data from an array-like to an other array-like. - * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array. - * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated. - * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array. - */ -function arrayLikeToArrayLike(arrayFrom, arrayTo) { - for (var i = 0; i < arrayFrom.length; i++) { - arrayTo[i] = arrayFrom[i]; - } - return arrayTo; -} - -// a matrix containing functions to transform everything into everything. -var transform = {}; - -// string to ? -transform["string"] = { - "string": identity, - "array": function(input) { - return stringToArrayLike(input, new Array(input.length)); - }, - "arraybuffer": function(input) { - return transform["string"]["uint8array"](input).buffer; - }, - "uint8array": function(input) { - return stringToArrayLike(input, new Uint8Array(input.length)); - }, - "nodebuffer": function(input) { - return stringToArrayLike(input, nodeBuffer(input.length)); - } -}; - -// array to ? -transform["array"] = { - "string": arrayLikeToString, - "array": identity, - "arraybuffer": function(input) { - return (new Uint8Array(input)).buffer; - }, - "uint8array": function(input) { - return new Uint8Array(input); - }, - "nodebuffer": function(input) { - return nodeBuffer(input); - } -}; - -// arraybuffer to ? -transform["arraybuffer"] = { - "string": function(input) { - return arrayLikeToString(new Uint8Array(input)); - }, - "array": function(input) { - return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength)); - }, - "arraybuffer": identity, - "uint8array": function(input) { - return new Uint8Array(input); - }, - "nodebuffer": function(input) { - return nodeBuffer(new Uint8Array(input)); - } -}; - -// uint8array to ? -transform["uint8array"] = { - "string": arrayLikeToString, - "array": function(input) { - return arrayLikeToArrayLike(input, new Array(input.length)); - }, - "arraybuffer": function(input) { - return input.buffer; - }, - "uint8array": identity, - "nodebuffer": function(input) { - return nodeBuffer(input); - } -}; - -// nodebuffer to ? -transform["nodebuffer"] = { - "string": arrayLikeToString, - "array": function(input) { - return arrayLikeToArrayLike(input, new Array(input.length)); - }, - "arraybuffer": function(input) { - return transform["nodebuffer"]["uint8array"](input).buffer; - }, - "uint8array": function(input) { - return arrayLikeToArrayLike(input, new Uint8Array(input.length)); - }, - "nodebuffer": identity -}; - -/** - * Transform an input into any type. - * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer. - * If no output type is specified, the unmodified input will be returned. - * @param {String} outputType the output type. - * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert. - * @throws {Error} an Error if the browser doesn't support the requested output type. - */ -exports.transformTo = function(outputType, input) { - if (!input) { - // undefined, null, etc - // an empty string won't harm. - input = ""; - } - if (!outputType) { - return input; - } - exports.checkSupport(outputType); - var inputType = exports.getTypeOf(input); - var result = transform[inputType][outputType](input); - return result; -}; - -/** - * Return the type of the input. - * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer. - * @param {Object} input the input to identify. - * @return {String} the (lowercase) type of the input. - */ -exports.getTypeOf = function(input) { - if (typeof input === "string") { - return "string"; - } - if (Object.prototype.toString.call(input) === "[object Array]") { - return "array"; - } - if (support.nodebuffer && nodeBuffer.test(input)) { - return "nodebuffer"; - } - if (support.uint8array && input instanceof Uint8Array) { - return "uint8array"; - } - if (support.arraybuffer && input instanceof ArrayBuffer) { - return "arraybuffer"; - } -}; - -/** - * Throw an exception if the type is not supported. - * @param {String} type the type to check. - * @throws {Error} an Error if the browser doesn't support the requested type. - */ -exports.checkSupport = function(type) { - var supported = support[type.toLowerCase()]; - if (!supported) { - throw new Error(type + " is not supported by this browser"); - } -}; -exports.MAX_VALUE_16BITS = 65535; -exports.MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1 - -/** - * Prettify a string read as binary. - * @param {string} str the string to prettify. - * @return {string} a pretty string. - */ -exports.pretty = function(str) { - var res = '', - code, i; - for (i = 0; i < (str || "").length; i++) { - code = str.charCodeAt(i); - res += '\\x' + (code < 16 ? "0" : "") + code.toString(16).toUpperCase(); - } - return res; -}; - -/** - * Find a compression registered in JSZip. - * @param {string} compressionMethod the method magic to find. - * @return {Object|null} the JSZip compression object, null if none found. - */ -exports.findCompression = function(compressionMethod) { - for (var method in compressions) { - if (!compressions.hasOwnProperty(method)) { - continue; - } - if (compressions[method].magic === compressionMethod) { - return compressions[method]; - } - } - return null; -}; -/** -* Cross-window, cross-Node-context regular expression detection -* @param {Object} object Anything -* @return {Boolean} true if the object is a regular expression, -* false otherwise -*/ -exports.isRegExp = function (object) { - return Object.prototype.toString.call(object) === "[object RegExp]"; -}; - - -},{"./compressions":3,"./nodeBuffer":11,"./support":17}],22:[function(_dereq_,module,exports){ -'use strict'; -var StringReader = _dereq_('./stringReader'); -var NodeBufferReader = _dereq_('./nodeBufferReader'); -var Uint8ArrayReader = _dereq_('./uint8ArrayReader'); -var utils = _dereq_('./utils'); -var sig = _dereq_('./signature'); -var ZipEntry = _dereq_('./zipEntry'); -var support = _dereq_('./support'); -var jszipProto = _dereq_('./object'); -// class ZipEntries {{{ -/** - * All the entries in the zip file. - * @constructor - * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load. - * @param {Object} loadOptions Options for loading the stream. - */ -function ZipEntries(data, loadOptions) { - this.files = []; - this.loadOptions = loadOptions; - if (data) { - this.load(data); - } -} -ZipEntries.prototype = { - /** - * Check that the reader is on the speficied signature. - * @param {string} expectedSignature the expected signature. - * @throws {Error} if it is an other signature. - */ - checkSignature: function(expectedSignature) { - var signature = this.reader.readString(4); - if (signature !== expectedSignature) { - throw new Error("Corrupted zip or bug : unexpected signature " + "(" + utils.pretty(signature) + ", expected " + utils.pretty(expectedSignature) + ")"); - } - }, - /** - * Read the end of the central directory. - */ - readBlockEndOfCentral: function() { - this.diskNumber = this.reader.readInt(2); - this.diskWithCentralDirStart = this.reader.readInt(2); - this.centralDirRecordsOnThisDisk = this.reader.readInt(2); - this.centralDirRecords = this.reader.readInt(2); - this.centralDirSize = this.reader.readInt(4); - this.centralDirOffset = this.reader.readInt(4); - - this.zipCommentLength = this.reader.readInt(2); - // warning : the encoding depends of the system locale - // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded. - // On a windows machine, this field is encoded with the localized windows code page. - this.zipComment = this.reader.readString(this.zipCommentLength); - // To get consistent behavior with the generation part, we will assume that - // this is utf8 encoded. - this.zipComment = jszipProto.utf8decode(this.zipComment); - }, - /** - * Read the end of the Zip 64 central directory. - * Not merged with the method readEndOfCentral : - * The end of central can coexist with its Zip64 brother, - * I don't want to read the wrong number of bytes ! - */ - readBlockZip64EndOfCentral: function() { - this.zip64EndOfCentralSize = this.reader.readInt(8); - this.versionMadeBy = this.reader.readString(2); - this.versionNeeded = this.reader.readInt(2); - this.diskNumber = this.reader.readInt(4); - this.diskWithCentralDirStart = this.reader.readInt(4); - this.centralDirRecordsOnThisDisk = this.reader.readInt(8); - this.centralDirRecords = this.reader.readInt(8); - this.centralDirSize = this.reader.readInt(8); - this.centralDirOffset = this.reader.readInt(8); - - this.zip64ExtensibleData = {}; - var extraDataSize = this.zip64EndOfCentralSize - 44, - index = 0, - extraFieldId, - extraFieldLength, - extraFieldValue; - while (index < extraDataSize) { - extraFieldId = this.reader.readInt(2); - extraFieldLength = this.reader.readInt(4); - extraFieldValue = this.reader.readString(extraFieldLength); - this.zip64ExtensibleData[extraFieldId] = { - id: extraFieldId, - length: extraFieldLength, - value: extraFieldValue - }; - } - }, - /** - * Read the end of the Zip 64 central directory locator. - */ - readBlockZip64EndOfCentralLocator: function() { - this.diskWithZip64CentralDirStart = this.reader.readInt(4); - this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8); - this.disksCount = this.reader.readInt(4); - if (this.disksCount > 1) { - throw new Error("Multi-volumes zip are not supported"); - } - }, - /** - * Read the local files, based on the offset read in the central part. - */ - readLocalFiles: function() { - var i, file; - for (i = 0; i < this.files.length; i++) { - file = this.files[i]; - this.reader.setIndex(file.localHeaderOffset); - this.checkSignature(sig.LOCAL_FILE_HEADER); - file.readLocalPart(this.reader); - file.handleUTF8(); - file.processAttributes(); - } - }, - /** - * Read the central directory. - */ - readCentralDir: function() { - var file; - - this.reader.setIndex(this.centralDirOffset); - while (this.reader.readString(4) === sig.CENTRAL_FILE_HEADER) { - file = new ZipEntry({ - zip64: this.zip64 - }, this.loadOptions); - file.readCentralPart(this.reader); - this.files.push(file); - } - }, - /** - * Read the end of central directory. - */ - readEndOfCentral: function() { - var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END); - if (offset === -1) { - // Check if the content is a truncated zip or complete garbage. - // A "LOCAL_FILE_HEADER" is not required at the beginning (auto - // extractible zip for example) but it can give a good hint. - // If an ajax request was used without responseType, we will also - // get unreadable data. - var isGarbage = true; - try { - this.reader.setIndex(0); - this.checkSignature(sig.LOCAL_FILE_HEADER); - isGarbage = false; - } catch (e) {} - - if (isGarbage) { - throw new Error("Can't find end of central directory : is this a zip file ? " + - "If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html"); - } else { - throw new Error("Corrupted zip : can't find end of central directory"); - } - } - this.reader.setIndex(offset); - this.checkSignature(sig.CENTRAL_DIRECTORY_END); - this.readBlockEndOfCentral(); - - - /* extract from the zip spec : - 4) If one of the fields in the end of central directory - record is too small to hold required data, the field - should be set to -1 (0xFFFF or 0xFFFFFFFF) and the - ZIP64 format record should be created. - 5) The end of central directory record and the - Zip64 end of central directory locator record must - reside on the same disk when splitting or spanning - an archive. - */ - if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) { - this.zip64 = true; - - /* - Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from - the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents - all numbers as 64-bit double precision IEEE 754 floating point numbers. - So, we have 53bits for integers and bitwise operations treat everything as 32bits. - see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators - and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5 - */ - - // should look for a zip64 EOCD locator - offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); - if (offset === -1) { - throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator"); - } - this.reader.setIndex(offset); - this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); - this.readBlockZip64EndOfCentralLocator(); - - // now the zip64 EOCD record - this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir); - this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END); - this.readBlockZip64EndOfCentral(); - } - }, - prepareReader: function(data) { - var type = utils.getTypeOf(data); - if (type === "string" && !support.uint8array) { - this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString); - } - else if (type === "nodebuffer") { - this.reader = new NodeBufferReader(data); - } - else { - this.reader = new Uint8ArrayReader(utils.transformTo("uint8array", data)); - } - }, - /** - * Read a zip file and create ZipEntries. - * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file. - */ - load: function(data) { - this.prepareReader(data); - this.readEndOfCentral(); - this.readCentralDir(); - this.readLocalFiles(); - } -}; -// }}} end of ZipEntries -module.exports = ZipEntries; - -},{"./nodeBufferReader":12,"./object":13,"./signature":14,"./stringReader":15,"./support":17,"./uint8ArrayReader":18,"./utils":21,"./zipEntry":23}],23:[function(_dereq_,module,exports){ -'use strict'; -var StringReader = _dereq_('./stringReader'); -var utils = _dereq_('./utils'); -var CompressedObject = _dereq_('./compressedObject'); -var jszipProto = _dereq_('./object'); - -var MADE_BY_DOS = 0x00; -var MADE_BY_UNIX = 0x03; - -// class ZipEntry {{{ -/** - * An entry in the zip file. - * @constructor - * @param {Object} options Options of the current file. - * @param {Object} loadOptions Options for loading the stream. - */ -function ZipEntry(options, loadOptions) { - this.options = options; - this.loadOptions = loadOptions; -} -ZipEntry.prototype = { - /** - * say if the file is encrypted. - * @return {boolean} true if the file is encrypted, false otherwise. - */ - isEncrypted: function() { - // bit 1 is set - return (this.bitFlag & 0x0001) === 0x0001; - }, - /** - * say if the file has utf-8 filename/comment. - * @return {boolean} true if the filename/comment is in utf-8, false otherwise. - */ - useUTF8: function() { - // bit 11 is set - return (this.bitFlag & 0x0800) === 0x0800; - }, - /** - * Prepare the function used to generate the compressed content from this ZipFile. - * @param {DataReader} reader the reader to use. - * @param {number} from the offset from where we should read the data. - * @param {number} length the length of the data to read. - * @return {Function} the callback to get the compressed content (the type depends of the DataReader class). - */ - prepareCompressedContent: function(reader, from, length) { - return function() { - var previousIndex = reader.index; - reader.setIndex(from); - var compressedFileData = reader.readData(length); - reader.setIndex(previousIndex); - - return compressedFileData; - }; - }, - /** - * Prepare the function used to generate the uncompressed content from this ZipFile. - * @param {DataReader} reader the reader to use. - * @param {number} from the offset from where we should read the data. - * @param {number} length the length of the data to read. - * @param {JSZip.compression} compression the compression used on this file. - * @param {number} uncompressedSize the uncompressed size to expect. - * @return {Function} the callback to get the uncompressed content (the type depends of the DataReader class). - */ - prepareContent: function(reader, from, length, compression, uncompressedSize) { - return function() { - - var compressedFileData = utils.transformTo(compression.uncompressInputType, this.getCompressedContent()); - var uncompressedFileData = compression.uncompress(compressedFileData); - - if (uncompressedFileData.length !== uncompressedSize) { - throw new Error("Bug : uncompressed data size mismatch"); - } - - return uncompressedFileData; - }; - }, - /** - * Read the local part of a zip file and add the info in this object. - * @param {DataReader} reader the reader to use. - */ - readLocalPart: function(reader) { - var compression, localExtraFieldsLength; - - // we already know everything from the central dir ! - // If the central dir data are false, we are doomed. - // On the bright side, the local part is scary : zip64, data descriptors, both, etc. - // The less data we get here, the more reliable this should be. - // Let's skip the whole header and dash to the data ! - reader.skip(22); - // in some zip created on windows, the filename stored in the central dir contains \ instead of /. - // Strangely, the filename here is OK. - // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes - // or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators... - // Search "unzip mismatching "local" filename continuing with "central" filename version" on - // the internet. - // - // I think I see the logic here : the central directory is used to display - // content and the local directory is used to extract the files. Mixing / and \ - // may be used to display \ to windows users and use / when extracting the files. - // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394 - this.fileNameLength = reader.readInt(2); - localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir - this.fileName = reader.readString(this.fileNameLength); - reader.skip(localExtraFieldsLength); - - if (this.compressedSize == -1 || this.uncompressedSize == -1) { - throw new Error("Bug or corrupted zip : didn't get enough informations from the central directory " + "(compressedSize == -1 || uncompressedSize == -1)"); - } - - compression = utils.findCompression(this.compressionMethod); - if (compression === null) { // no compression found - throw new Error("Corrupted zip : compression " + utils.pretty(this.compressionMethod) + " unknown (inner file : " + this.fileName + ")"); - } - this.decompressed = new CompressedObject(); - this.decompressed.compressedSize = this.compressedSize; - this.decompressed.uncompressedSize = this.uncompressedSize; - this.decompressed.crc32 = this.crc32; - this.decompressed.compressionMethod = this.compressionMethod; - this.decompressed.getCompressedContent = this.prepareCompressedContent(reader, reader.index, this.compressedSize, compression); - this.decompressed.getContent = this.prepareContent(reader, reader.index, this.compressedSize, compression, this.uncompressedSize); - - // we need to compute the crc32... - if (this.loadOptions.checkCRC32) { - this.decompressed = utils.transformTo("string", this.decompressed.getContent()); - if (jszipProto.crc32(this.decompressed) !== this.crc32) { - throw new Error("Corrupted zip : CRC32 mismatch"); - } - } - }, - - /** - * Read the central part of a zip file and add the info in this object. - * @param {DataReader} reader the reader to use. - */ - readCentralPart: function(reader) { - this.versionMadeBy = reader.readInt(2); - this.versionNeeded = reader.readInt(2); - this.bitFlag = reader.readInt(2); - this.compressionMethod = reader.readString(2); - this.date = reader.readDate(); - this.crc32 = reader.readInt(4); - this.compressedSize = reader.readInt(4); - this.uncompressedSize = reader.readInt(4); - this.fileNameLength = reader.readInt(2); - this.extraFieldsLength = reader.readInt(2); - this.fileCommentLength = reader.readInt(2); - this.diskNumberStart = reader.readInt(2); - this.internalFileAttributes = reader.readInt(2); - this.externalFileAttributes = reader.readInt(4); - this.localHeaderOffset = reader.readInt(4); - - if (this.isEncrypted()) { - throw new Error("Encrypted zip are not supported"); - } - - this.fileName = reader.readString(this.fileNameLength); - this.readExtraFields(reader); - this.parseZIP64ExtraField(reader); - this.fileComment = reader.readString(this.fileCommentLength); - }, - - /** - * Parse the external file attributes and get the unix/dos permissions. - */ - processAttributes: function () { - this.unixPermissions = null; - this.dosPermissions = null; - var madeBy = this.versionMadeBy >> 8; - - // Check if we have the DOS directory flag set. - // We look for it in the DOS and UNIX permissions - // but some unknown platform could set it as a compatibility flag. - this.dir = this.externalFileAttributes & 0x0010 ? true : false; - - if(madeBy === MADE_BY_DOS) { - // first 6 bits (0 to 5) - this.dosPermissions = this.externalFileAttributes & 0x3F; - } - - if(madeBy === MADE_BY_UNIX) { - this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF; - // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8); - } - - // fail safe : if the name ends with a / it probably means a folder - if (!this.dir && this.fileName.slice(-1) === '/') { - this.dir = true; - } - }, - - /** - * Parse the ZIP64 extra field and merge the info in the current ZipEntry. - * @param {DataReader} reader the reader to use. - */ - parseZIP64ExtraField: function(reader) { - - if (!this.extraFields[0x0001]) { - return; - } - - // should be something, preparing the extra reader - var extraReader = new StringReader(this.extraFields[0x0001].value); - - // I really hope that these 64bits integer can fit in 32 bits integer, because js - // won't let us have more. - if (this.uncompressedSize === utils.MAX_VALUE_32BITS) { - this.uncompressedSize = extraReader.readInt(8); - } - if (this.compressedSize === utils.MAX_VALUE_32BITS) { - this.compressedSize = extraReader.readInt(8); - } - if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) { - this.localHeaderOffset = extraReader.readInt(8); - } - if (this.diskNumberStart === utils.MAX_VALUE_32BITS) { - this.diskNumberStart = extraReader.readInt(4); - } - }, - /** - * Read the central part of a zip file and add the info in this object. - * @param {DataReader} reader the reader to use. - */ - readExtraFields: function(reader) { - var start = reader.index, - extraFieldId, - extraFieldLength, - extraFieldValue; - - this.extraFields = this.extraFields || {}; - - while (reader.index < start + this.extraFieldsLength) { - extraFieldId = reader.readInt(2); - extraFieldLength = reader.readInt(2); - extraFieldValue = reader.readString(extraFieldLength); - - this.extraFields[extraFieldId] = { - id: extraFieldId, - length: extraFieldLength, - value: extraFieldValue - }; - } - }, - /** - * Apply an UTF8 transformation if needed. - */ - handleUTF8: function() { - if (this.useUTF8()) { - this.fileName = jszipProto.utf8decode(this.fileName); - this.fileComment = jszipProto.utf8decode(this.fileComment); - } else { - var upath = this.findExtraFieldUnicodePath(); - if (upath !== null) { - this.fileName = upath; - } - var ucomment = this.findExtraFieldUnicodeComment(); - if (ucomment !== null) { - this.fileComment = ucomment; - } - } - }, - - /** - * Find the unicode path declared in the extra field, if any. - * @return {String} the unicode path, null otherwise. - */ - findExtraFieldUnicodePath: function() { - var upathField = this.extraFields[0x7075]; - if (upathField) { - var extraReader = new StringReader(upathField.value); - - // wrong version - if (extraReader.readInt(1) !== 1) { - return null; - } - - // the crc of the filename changed, this field is out of date. - if (jszipProto.crc32(this.fileName) !== extraReader.readInt(4)) { - return null; - } - - return jszipProto.utf8decode(extraReader.readString(upathField.length - 5)); - } - return null; - }, - - /** - * Find the unicode comment declared in the extra field, if any. - * @return {String} the unicode comment, null otherwise. - */ - findExtraFieldUnicodeComment: function() { - var ucommentField = this.extraFields[0x6375]; - if (ucommentField) { - var extraReader = new StringReader(ucommentField.value); - - // wrong version - if (extraReader.readInt(1) !== 1) { - return null; - } - - // the crc of the comment changed, this field is out of date. - if (jszipProto.crc32(this.fileComment) !== extraReader.readInt(4)) { - return null; - } - - return jszipProto.utf8decode(extraReader.readString(ucommentField.length - 5)); - } - return null; - } -}; -module.exports = ZipEntry; - -},{"./compressedObject":2,"./object":13,"./stringReader":15,"./utils":21}],24:[function(_dereq_,module,exports){ -// Top level file is just a mixin of submodules & constants -'use strict'; - -var assign = _dereq_('./lib/utils/common').assign; - -var deflate = _dereq_('./lib/deflate'); -var inflate = _dereq_('./lib/inflate'); -var constants = _dereq_('./lib/zlib/constants'); - -var pako = {}; - -assign(pako, deflate, inflate, constants); - -module.exports = pako; -},{"./lib/deflate":25,"./lib/inflate":26,"./lib/utils/common":27,"./lib/zlib/constants":30}],25:[function(_dereq_,module,exports){ -'use strict'; - - -var zlib_deflate = _dereq_('./zlib/deflate.js'); -var utils = _dereq_('./utils/common'); -var strings = _dereq_('./utils/strings'); -var msg = _dereq_('./zlib/messages'); -var zstream = _dereq_('./zlib/zstream'); - - -/* Public constants ==========================================================*/ -/* ===========================================================================*/ - -var Z_NO_FLUSH = 0; -var Z_FINISH = 4; - -var Z_OK = 0; -var Z_STREAM_END = 1; - -var Z_DEFAULT_COMPRESSION = -1; - -var Z_DEFAULT_STRATEGY = 0; - -var Z_DEFLATED = 8; - -/* ===========================================================================*/ - - -/** - * class Deflate - * - * Generic JS-style wrapper for zlib calls. If you don't need - * streaming behaviour - use more simple functions: [[deflate]], - * [[deflateRaw]] and [[gzip]]. - **/ - -/* internal - * Deflate.chunks -> Array - * - * Chunks of output data, if [[Deflate#onData]] not overriden. - **/ - -/** - * Deflate.result -> Uint8Array|Array - * - * Compressed result, generated by default [[Deflate#onData]] - * and [[Deflate#onEnd]] handlers. Filled after you push last chunk - * (call [[Deflate#push]] with `Z_FINISH` / `true` param). - **/ - -/** - * Deflate.err -> Number - * - * Error code after deflate finished. 0 (Z_OK) on success. - * You will not need it in real life, because deflate errors - * are possible only on wrong options or bad `onData` / `onEnd` - * custom handlers. - **/ - -/** - * Deflate.msg -> String - * - * Error message, if [[Deflate.err]] != 0 - **/ - - -/** - * new Deflate(options) - * - options (Object): zlib deflate options. - * - * Creates new deflator instance with specified params. Throws exception - * on bad params. Supported options: - * - * - `level` - * - `windowBits` - * - `memLevel` - * - `strategy` - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * Additional options, for internal needs: - * - * - `chunkSize` - size of generated data chunks (16K by default) - * - `raw` (Boolean) - do raw deflate - * - `gzip` (Boolean) - create gzip wrapper - * - `to` (String) - if equal to 'string', then result will be "binary string" - * (each char code [0..255]) - * - `header` (Object) - custom header for gzip - * - `text` (Boolean) - true if compressed data believed to be text - * - `time` (Number) - modification time, unix timestamp - * - `os` (Number) - operation system code - * - `extra` (Array) - array of bytes with extra data (max 65536) - * - `name` (String) - file name (binary string) - * - `comment` (String) - comment (binary string) - * - `hcrc` (Boolean) - true if header crc should be added - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) - * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); - * - * var deflate = new pako.Deflate({ level: 3}); - * - * deflate.push(chunk1, false); - * deflate.push(chunk2, true); // true -> last chunk - * - * if (deflate.err) { throw new Error(deflate.err); } - * - * console.log(deflate.result); - * ``` - **/ -var Deflate = function(options) { - - this.options = utils.assign({ - level: Z_DEFAULT_COMPRESSION, - method: Z_DEFLATED, - chunkSize: 16384, - windowBits: 15, - memLevel: 8, - strategy: Z_DEFAULT_STRATEGY, - to: '' - }, options || {}); - - var opt = this.options; - - if (opt.raw && (opt.windowBits > 0)) { - opt.windowBits = -opt.windowBits; - } - - else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) { - opt.windowBits += 16; - } - - this.err = 0; // error code, if happens (0 = Z_OK) - this.msg = ''; // error message - this.ended = false; // used to avoid multiple onEnd() calls - this.chunks = []; // chunks of compressed data - - this.strm = new zstream(); - this.strm.avail_out = 0; - - var status = zlib_deflate.deflateInit2( - this.strm, - opt.level, - opt.method, - opt.windowBits, - opt.memLevel, - opt.strategy - ); - - if (status !== Z_OK) { - throw new Error(msg[status]); - } - - if (opt.header) { - zlib_deflate.deflateSetHeader(this.strm, opt.header); - } -}; - -/** - * Deflate#push(data[, mode]) -> Boolean - * - data (Uint8Array|Array|String): input data. Strings will be converted to - * utf8 byte sequence. - * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. - * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH. - * - * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with - * new compressed chunks. Returns `true` on success. The last data block must have - * mode Z_FINISH (or `true`). That flush internal pending buffers and call - * [[Deflate#onEnd]]. - * - * On fail call [[Deflate#onEnd]] with error code and return false. - * - * We strongly recommend to use `Uint8Array` on input for best speed (output - * array format is detected automatically). Also, don't skip last param and always - * use the same type in your code (boolean or number). That will improve JS speed. - * - * For regular `Array`-s make sure all elements are [0..255]. - * - * ##### Example - * - * ```javascript - * push(chunk, false); // push one of data chunks - * ... - * push(chunk, true); // push last chunk - * ``` - **/ -Deflate.prototype.push = function(data, mode) { - var strm = this.strm; - var chunkSize = this.options.chunkSize; - var status, _mode; - - if (this.ended) { return false; } - - _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH); - - // Convert data if needed - if (typeof data === 'string') { - // If we need to compress text, change encoding to utf8. - strm.input = strings.string2buf(data); - } else { - strm.input = data; - } - - strm.next_in = 0; - strm.avail_in = strm.input.length; - - do { - if (strm.avail_out === 0) { - strm.output = new utils.Buf8(chunkSize); - strm.next_out = 0; - strm.avail_out = chunkSize; - } - status = zlib_deflate.deflate(strm, _mode); /* no bad return value */ - - if (status !== Z_STREAM_END && status !== Z_OK) { - this.onEnd(status); - this.ended = true; - return false; - } - if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) { - if (this.options.to === 'string') { - this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out))); - } else { - this.onData(utils.shrinkBuf(strm.output, strm.next_out)); - } - } - } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END); - - // Finalize on the last chunk. - if (_mode === Z_FINISH) { - status = zlib_deflate.deflateEnd(this.strm); - this.onEnd(status); - this.ended = true; - return status === Z_OK; - } - - return true; -}; - - -/** - * Deflate#onData(chunk) -> Void - * - chunk (Uint8Array|Array|String): ouput data. Type of array depends - * on js engine support. When string output requested, each chunk - * will be string. - * - * By default, stores data blocks in `chunks[]` property and glue - * those in `onEnd`. Override this handler, if you need another behaviour. - **/ -Deflate.prototype.onData = function(chunk) { - this.chunks.push(chunk); -}; - - -/** - * Deflate#onEnd(status) -> Void - * - status (Number): deflate status. 0 (Z_OK) on success, - * other if not. - * - * Called once after you tell deflate that input stream complete - * or error happenned. By default - join collected chunks, - * free memory and fill `results` / `err` properties. - **/ -Deflate.prototype.onEnd = function(status) { - // On success - join - if (status === Z_OK) { - if (this.options.to === 'string') { - this.result = this.chunks.join(''); - } else { - this.result = utils.flattenChunks(this.chunks); - } - } - this.chunks = []; - this.err = status; - this.msg = this.strm.msg; -}; - - -/** - * deflate(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to compress. - * - options (Object): zlib deflate options. - * - * Compress `data` with deflate alrorythm and `options`. - * - * Supported options are: - * - * - level - * - windowBits - * - memLevel - * - strategy - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * Sugar (options): - * - * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify - * negative windowBits implicitly. - * - `to` (String) - if equal to 'string', then result will be "binary string" - * (each char code [0..255]) - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , data = Uint8Array([1,2,3,4,5,6,7,8,9]); - * - * console.log(pako.deflate(data)); - * ``` - **/ -function deflate(input, options) { - var deflator = new Deflate(options); - - deflator.push(input, true); - - // That will never happens, if you don't cheat with options :) - if (deflator.err) { throw deflator.msg; } - - return deflator.result; -} - - -/** - * deflateRaw(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to compress. - * - options (Object): zlib deflate options. - * - * The same as [[deflate]], but creates raw data, without wrapper - * (header and adler32 crc). - **/ -function deflateRaw(input, options) { - options = options || {}; - options.raw = true; - return deflate(input, options); -} - - -/** - * gzip(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to compress. - * - options (Object): zlib deflate options. - * - * The same as [[deflate]], but create gzip wrapper instead of - * deflate one. - **/ -function gzip(input, options) { - options = options || {}; - options.gzip = true; - return deflate(input, options); -} - - -exports.Deflate = Deflate; -exports.deflate = deflate; -exports.deflateRaw = deflateRaw; -exports.gzip = gzip; -},{"./utils/common":27,"./utils/strings":28,"./zlib/deflate.js":32,"./zlib/messages":37,"./zlib/zstream":39}],26:[function(_dereq_,module,exports){ -'use strict'; - - -var zlib_inflate = _dereq_('./zlib/inflate.js'); -var utils = _dereq_('./utils/common'); -var strings = _dereq_('./utils/strings'); -var c = _dereq_('./zlib/constants'); -var msg = _dereq_('./zlib/messages'); -var zstream = _dereq_('./zlib/zstream'); -var gzheader = _dereq_('./zlib/gzheader'); - - -/** - * class Inflate - * - * Generic JS-style wrapper for zlib calls. If you don't need - * streaming behaviour - use more simple functions: [[inflate]] - * and [[inflateRaw]]. - **/ - -/* internal - * inflate.chunks -> Array - * - * Chunks of output data, if [[Inflate#onData]] not overriden. - **/ - -/** - * Inflate.result -> Uint8Array|Array|String - * - * Uncompressed result, generated by default [[Inflate#onData]] - * and [[Inflate#onEnd]] handlers. Filled after you push last chunk - * (call [[Inflate#push]] with `Z_FINISH` / `true` param). - **/ - -/** - * Inflate.err -> Number - * - * Error code after inflate finished. 0 (Z_OK) on success. - * Should be checked if broken data possible. - **/ - -/** - * Inflate.msg -> String - * - * Error message, if [[Inflate.err]] != 0 - **/ - - -/** - * new Inflate(options) - * - options (Object): zlib inflate options. - * - * Creates new inflator instance with specified params. Throws exception - * on bad params. Supported options: - * - * - `windowBits` - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * Additional options, for internal needs: - * - * - `chunkSize` - size of generated data chunks (16K by default) - * - `raw` (Boolean) - do raw inflate - * - `to` (String) - if equal to 'string', then result will be converted - * from utf8 to utf16 (javascript) string. When string output requested, - * chunk length can differ from `chunkSize`, depending on content. - * - * By default, when no options set, autodetect deflate/gzip data format via - * wrapper header. - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) - * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); - * - * var inflate = new pako.Inflate({ level: 3}); - * - * inflate.push(chunk1, false); - * inflate.push(chunk2, true); // true -> last chunk - * - * if (inflate.err) { throw new Error(inflate.err); } - * - * console.log(inflate.result); - * ``` - **/ -var Inflate = function(options) { - - this.options = utils.assign({ - chunkSize: 16384, - windowBits: 0, - to: '' - }, options || {}); - - var opt = this.options; - - // Force window size for `raw` data, if not set directly, - // because we have no header for autodetect. - if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) { - opt.windowBits = -opt.windowBits; - if (opt.windowBits === 0) { opt.windowBits = -15; } - } - - // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate - if ((opt.windowBits >= 0) && (opt.windowBits < 16) && - !(options && options.windowBits)) { - opt.windowBits += 32; - } - - // Gzip header has no info about windows size, we can do autodetect only - // for deflate. So, if window size not set, force it to max when gzip possible - if ((opt.windowBits > 15) && (opt.windowBits < 48)) { - // bit 3 (16) -> gzipped data - // bit 4 (32) -> autodetect gzip/deflate - if ((opt.windowBits & 15) === 0) { - opt.windowBits |= 15; - } - } - - this.err = 0; // error code, if happens (0 = Z_OK) - this.msg = ''; // error message - this.ended = false; // used to avoid multiple onEnd() calls - this.chunks = []; // chunks of compressed data - - this.strm = new zstream(); - this.strm.avail_out = 0; - - var status = zlib_inflate.inflateInit2( - this.strm, - opt.windowBits - ); - - if (status !== c.Z_OK) { - throw new Error(msg[status]); - } - - this.header = new gzheader(); - - zlib_inflate.inflateGetHeader(this.strm, this.header); -}; - -/** - * Inflate#push(data[, mode]) -> Boolean - * - data (Uint8Array|Array|String): input data - * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. - * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH. - * - * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with - * new output chunks. Returns `true` on success. The last data block must have - * mode Z_FINISH (or `true`). That flush internal pending buffers and call - * [[Inflate#onEnd]]. - * - * On fail call [[Inflate#onEnd]] with error code and return false. - * - * We strongly recommend to use `Uint8Array` on input for best speed (output - * format is detected automatically). Also, don't skip last param and always - * use the same type in your code (boolean or number). That will improve JS speed. - * - * For regular `Array`-s make sure all elements are [0..255]. - * - * ##### Example - * - * ```javascript - * push(chunk, false); // push one of data chunks - * ... - * push(chunk, true); // push last chunk - * ``` - **/ -Inflate.prototype.push = function(data, mode) { - var strm = this.strm; - var chunkSize = this.options.chunkSize; - var status, _mode; - var next_out_utf8, tail, utf8str; - - if (this.ended) { return false; } - _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH); - - // Convert data if needed - if (typeof data === 'string') { - // Only binary strings can be decompressed on practice - strm.input = strings.binstring2buf(data); - } else { - strm.input = data; - } - - strm.next_in = 0; - strm.avail_in = strm.input.length; - - do { - if (strm.avail_out === 0) { - strm.output = new utils.Buf8(chunkSize); - strm.next_out = 0; - strm.avail_out = chunkSize; - } - - status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */ - - if (status !== c.Z_STREAM_END && status !== c.Z_OK) { - this.onEnd(status); - this.ended = true; - return false; - } - - if (strm.next_out) { - if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) { - - if (this.options.to === 'string') { - - next_out_utf8 = strings.utf8border(strm.output, strm.next_out); - - tail = strm.next_out - next_out_utf8; - utf8str = strings.buf2string(strm.output, next_out_utf8); - - // move tail - strm.next_out = tail; - strm.avail_out = chunkSize - tail; - if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); } - - this.onData(utf8str); - - } else { - this.onData(utils.shrinkBuf(strm.output, strm.next_out)); - } - } - } - } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END); - - if (status === c.Z_STREAM_END) { - _mode = c.Z_FINISH; - } - // Finalize on the last chunk. - if (_mode === c.Z_FINISH) { - status = zlib_inflate.inflateEnd(this.strm); - this.onEnd(status); - this.ended = true; - return status === c.Z_OK; - } - - return true; -}; - - -/** - * Inflate#onData(chunk) -> Void - * - chunk (Uint8Array|Array|String): ouput data. Type of array depends - * on js engine support. When string output requested, each chunk - * will be string. - * - * By default, stores data blocks in `chunks[]` property and glue - * those in `onEnd`. Override this handler, if you need another behaviour. - **/ -Inflate.prototype.onData = function(chunk) { - this.chunks.push(chunk); -}; - - -/** - * Inflate#onEnd(status) -> Void - * - status (Number): inflate status. 0 (Z_OK) on success, - * other if not. - * - * Called once after you tell inflate that input stream complete - * or error happenned. By default - join collected chunks, - * free memory and fill `results` / `err` properties. - **/ -Inflate.prototype.onEnd = function(status) { - // On success - join - if (status === c.Z_OK) { - if (this.options.to === 'string') { - // Glue & convert here, until we teach pako to send - // utf8 alligned strings to onData - this.result = this.chunks.join(''); - } else { - this.result = utils.flattenChunks(this.chunks); - } - } - this.chunks = []; - this.err = status; - this.msg = this.strm.msg; -}; - - -/** - * inflate(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to decompress. - * - options (Object): zlib inflate options. - * - * Decompress `data` with inflate/ungzip and `options`. Autodetect - * format via wrapper header by default. That's why we don't provide - * separate `ungzip` method. - * - * Supported options are: - * - * - windowBits - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information. - * - * Sugar (options): - * - * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify - * negative windowBits implicitly. - * - `to` (String) - if equal to 'string', then result will be converted - * from utf8 to utf16 (javascript) string. When string output requested, - * chunk length can differ from `chunkSize`, depending on content. - * - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , input = pako.deflate([1,2,3,4,5,6,7,8,9]) - * , output; - * - * try { - * output = pako.inflate(input); - * } catch (err) - * console.log(err); - * } - * ``` - **/ -function inflate(input, options) { - var inflator = new Inflate(options); - - inflator.push(input, true); - - // That will never happens, if you don't cheat with options :) - if (inflator.err) { throw inflator.msg; } - - return inflator.result; -} - - -/** - * inflateRaw(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to decompress. - * - options (Object): zlib inflate options. - * - * The same as [[inflate]], but creates raw data, without wrapper - * (header and adler32 crc). - **/ -function inflateRaw(input, options) { - options = options || {}; - options.raw = true; - return inflate(input, options); -} - - -/** - * ungzip(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to decompress. - * - options (Object): zlib inflate options. - * - * Just shortcut to [[inflate]], because it autodetects format - * by header.content. Done for convenience. - **/ - - -exports.Inflate = Inflate; -exports.inflate = inflate; -exports.inflateRaw = inflateRaw; -exports.ungzip = inflate; - -},{"./utils/common":27,"./utils/strings":28,"./zlib/constants":30,"./zlib/gzheader":33,"./zlib/inflate.js":35,"./zlib/messages":37,"./zlib/zstream":39}],27:[function(_dereq_,module,exports){ -'use strict'; - - -var TYPED_OK = (typeof Uint8Array !== 'undefined') && - (typeof Uint16Array !== 'undefined') && - (typeof Int32Array !== 'undefined'); - - -exports.assign = function (obj /*from1, from2, from3, ...*/) { - var sources = Array.prototype.slice.call(arguments, 1); - while (sources.length) { - var source = sources.shift(); - if (!source) { continue; } - - if (typeof(source) !== 'object') { - throw new TypeError(source + 'must be non-object'); - } - - for (var p in source) { - if (source.hasOwnProperty(p)) { - obj[p] = source[p]; - } - } - } - - return obj; -}; - - -// reduce buffer size, avoiding mem copy -exports.shrinkBuf = function (buf, size) { - if (buf.length === size) { return buf; } - if (buf.subarray) { return buf.subarray(0, size); } - buf.length = size; - return buf; -}; - - -var fnTyped = { - arraySet: function (dest, src, src_offs, len, dest_offs) { - if (src.subarray && dest.subarray) { - dest.set(src.subarray(src_offs, src_offs+len), dest_offs); - return; - } - // Fallback to ordinary array - for(var i=0; i= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1); -} -_utf8len[254]=_utf8len[254]=1; // Invalid sequence start - - -// convert string to array (typed, when possible) -exports.string2buf = function (str) { - var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; - - // count binary size - for (m_pos = 0; m_pos < str_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { - c2 = str.charCodeAt(m_pos+1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; - } - - // allocate buffer - buf = new utils.Buf8(buf_len); - - // convert - for (i=0, m_pos = 0; i < buf_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { - c2 = str.charCodeAt(m_pos+1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - if (c < 0x80) { - /* one byte */ - buf[i++] = c; - } else if (c < 0x800) { - /* two bytes */ - buf[i++] = 0xC0 | (c >>> 6); - buf[i++] = 0x80 | (c & 0x3f); - } else if (c < 0x10000) { - /* three bytes */ - buf[i++] = 0xE0 | (c >>> 12); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } else { - /* four bytes */ - buf[i++] = 0xf0 | (c >>> 18); - buf[i++] = 0x80 | (c >>> 12 & 0x3f); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } - } - - return buf; -}; - -// Helper (used in 2 places) -function buf2binstring(buf, len) { - // use fallback for big arrays to avoid stack overflow - if (len < 65537) { - if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) { - return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len)); - } - } - - var result = ''; - for(var i=0; i < len; i++) { - result += String.fromCharCode(buf[i]); - } - return result; -} - - -// Convert byte array to binary string -exports.buf2binstring = function(buf) { - return buf2binstring(buf, buf.length); -}; - - -// Convert binary string (typed, when possible) -exports.binstring2buf = function(str) { - var buf = new utils.Buf8(str.length); - for(var i=0, len=buf.length; i < len; i++) { - buf[i] = str.charCodeAt(i); - } - return buf; -}; - - -// convert array to string -exports.buf2string = function (buf, max) { - var i, out, c, c_len; - var len = max || buf.length; - - // Reserve max possible length (2 words per char) - // NB: by unknown reasons, Array is significantly faster for - // String.fromCharCode.apply than Uint16Array. - var utf16buf = new Array(len*2); - - for (out=0, i=0; i 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; } - - // apply mask on first byte - c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; - // join the rest - while (c_len > 1 && i < len) { - c = (c << 6) | (buf[i++] & 0x3f); - c_len--; - } - - // terminated by end of string? - if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } - - if (c < 0x10000) { - utf16buf[out++] = c; - } else { - c -= 0x10000; - utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); - utf16buf[out++] = 0xdc00 | (c & 0x3ff); - } - } - - return buf2binstring(utf16buf, out); -}; - - -// Calculate max possible position in utf8 buffer, -// that will not break sequence. If that's not possible -// - (very small limits) return max size as is. -// -// buf[] - utf8 bytes array -// max - length limit (mandatory); -exports.utf8border = function(buf, max) { - var pos; - - max = max || buf.length; - if (max > buf.length) { max = buf.length; } - - // go back from last position, until start of sequence found - pos = max-1; - while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } - - // Fuckup - very small and broken sequence, - // return max, because we should return something anyway. - if (pos < 0) { return max; } - - // If we came to start of buffer - that means vuffer is too small, - // return max too. - if (pos === 0) { return max; } - - return (pos + _utf8len[buf[pos]] > max) ? pos : max; -}; - -},{"./common":27}],29:[function(_dereq_,module,exports){ -'use strict'; - -// Note: adler32 takes 12% for level 0 and 2% for level 6. -// It doesn't worth to make additional optimizationa as in original. -// Small size is preferable. - -function adler32(adler, buf, len, pos) { - var s1 = (adler & 0xffff) |0 - , s2 = ((adler >>> 16) & 0xffff) |0 - , n = 0; - - while (len !== 0) { - // Set limit ~ twice less than 5552, to keep - // s2 in 31-bits, because we force signed ints. - // in other case %= will fail. - n = len > 2000 ? 2000 : len; - len -= n; - - do { - s1 = (s1 + buf[pos++]) |0; - s2 = (s2 + s1) |0; - } while (--n); - - s1 %= 65521; - s2 %= 65521; - } - - return (s1 | (s2 << 16)) |0; -} - - -module.exports = adler32; -},{}],30:[function(_dereq_,module,exports){ -module.exports = { - - /* Allowed flush values; see deflate() and inflate() below for details */ - Z_NO_FLUSH: 0, - Z_PARTIAL_FLUSH: 1, - Z_SYNC_FLUSH: 2, - Z_FULL_FLUSH: 3, - Z_FINISH: 4, - Z_BLOCK: 5, - Z_TREES: 6, - - /* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - Z_OK: 0, - Z_STREAM_END: 1, - Z_NEED_DICT: 2, - Z_ERRNO: -1, - Z_STREAM_ERROR: -2, - Z_DATA_ERROR: -3, - //Z_MEM_ERROR: -4, - Z_BUF_ERROR: -5, - //Z_VERSION_ERROR: -6, - - /* compression levels */ - Z_NO_COMPRESSION: 0, - Z_BEST_SPEED: 1, - Z_BEST_COMPRESSION: 9, - Z_DEFAULT_COMPRESSION: -1, - - - Z_FILTERED: 1, - Z_HUFFMAN_ONLY: 2, - Z_RLE: 3, - Z_FIXED: 4, - Z_DEFAULT_STRATEGY: 0, - - /* Possible values of the data_type field (though see inflate()) */ - Z_BINARY: 0, - Z_TEXT: 1, - //Z_ASCII: 1, // = Z_TEXT (deprecated) - Z_UNKNOWN: 2, - - /* The deflate compression method */ - Z_DEFLATED: 8 - //Z_NULL: null // Use -1 or null inline, depending on var type -}; -},{}],31:[function(_dereq_,module,exports){ -'use strict'; - -// Note: we can't get significant speed boost here. -// So write code to minimize size - no pregenerated tables -// and array tools dependencies. - - -// Use ordinary array, since untyped makes no boost here -function makeTable() { - var c, table = []; - - for(var n =0; n < 256; n++){ - c = n; - for(var k =0; k < 8; k++){ - c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); - } - table[n] = c; - } - - return table; -} - -// Create table on load. Just 255 signed longs. Not a problem. -var crcTable = makeTable(); - - -function crc32(crc, buf, len, pos) { - var t = crcTable - , end = pos + len; - - crc = crc ^ (-1); - - for (var i = pos; i < end; i++ ) { - crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; - } - - return (crc ^ (-1)); // >>> 0; -} - - -module.exports = crc32; -},{}],32:[function(_dereq_,module,exports){ -'use strict'; - -var utils = _dereq_('../utils/common'); -var trees = _dereq_('./trees'); -var adler32 = _dereq_('./adler32'); -var crc32 = _dereq_('./crc32'); -var msg = _dereq_('./messages'); - -/* Public constants ==========================================================*/ -/* ===========================================================================*/ - - -/* Allowed flush values; see deflate() and inflate() below for details */ -var Z_NO_FLUSH = 0; -var Z_PARTIAL_FLUSH = 1; -//var Z_SYNC_FLUSH = 2; -var Z_FULL_FLUSH = 3; -var Z_FINISH = 4; -var Z_BLOCK = 5; -//var Z_TREES = 6; - - -/* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ -var Z_OK = 0; -var Z_STREAM_END = 1; -//var Z_NEED_DICT = 2; -//var Z_ERRNO = -1; -var Z_STREAM_ERROR = -2; -var Z_DATA_ERROR = -3; -//var Z_MEM_ERROR = -4; -var Z_BUF_ERROR = -5; -//var Z_VERSION_ERROR = -6; - - -/* compression levels */ -//var Z_NO_COMPRESSION = 0; -//var Z_BEST_SPEED = 1; -//var Z_BEST_COMPRESSION = 9; -var Z_DEFAULT_COMPRESSION = -1; - - -var Z_FILTERED = 1; -var Z_HUFFMAN_ONLY = 2; -var Z_RLE = 3; -var Z_FIXED = 4; -var Z_DEFAULT_STRATEGY = 0; - -/* Possible values of the data_type field (though see inflate()) */ -//var Z_BINARY = 0; -//var Z_TEXT = 1; -//var Z_ASCII = 1; // = Z_TEXT -var Z_UNKNOWN = 2; - - -/* The deflate compression method */ -var Z_DEFLATED = 8; - -/*============================================================================*/ - - -var MAX_MEM_LEVEL = 9; -/* Maximum value for memLevel in deflateInit2 */ -var MAX_WBITS = 15; -/* 32K LZ77 window */ -var DEF_MEM_LEVEL = 8; - - -var LENGTH_CODES = 29; -/* number of length codes, not counting the special END_BLOCK code */ -var LITERALS = 256; -/* number of literal bytes 0..255 */ -var L_CODES = LITERALS + 1 + LENGTH_CODES; -/* number of Literal or Length codes, including the END_BLOCK code */ -var D_CODES = 30; -/* number of distance codes */ -var BL_CODES = 19; -/* number of codes used to transfer the bit lengths */ -var HEAP_SIZE = 2*L_CODES + 1; -/* maximum heap size */ -var MAX_BITS = 15; -/* All codes must not exceed MAX_BITS bits */ - -var MIN_MATCH = 3; -var MAX_MATCH = 258; -var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); - -var PRESET_DICT = 0x20; - -var INIT_STATE = 42; -var EXTRA_STATE = 69; -var NAME_STATE = 73; -var COMMENT_STATE = 91; -var HCRC_STATE = 103; -var BUSY_STATE = 113; -var FINISH_STATE = 666; - -var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ -var BS_BLOCK_DONE = 2; /* block flush performed */ -var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ -var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ - -var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. - -function err(strm, errorCode) { - strm.msg = msg[errorCode]; - return errorCode; -} - -function rank(f) { - return ((f) << 1) - ((f) > 4 ? 9 : 0); -} - -function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } - - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->output buffer and copying into it. - * (See also read_buf()). - */ -function flush_pending(strm) { - var s = strm.state; - - //_tr_flush_bits(s); - var len = s.pending; - if (len > strm.avail_out) { - len = strm.avail_out; - } - if (len === 0) { return; } - - utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); - strm.next_out += len; - s.pending_out += len; - strm.total_out += len; - strm.avail_out -= len; - s.pending -= len; - if (s.pending === 0) { - s.pending_out = 0; - } -} - - -function flush_block_only (s, last) { - trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); - s.block_start = s.strstart; - flush_pending(s.strm); -} - - -function put_byte(s, b) { - s.pending_buf[s.pending++] = b; -} - - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -function putShortMSB(s, b) { -// put_byte(s, (Byte)(b >> 8)); -// put_byte(s, (Byte)(b & 0xff)); - s.pending_buf[s.pending++] = (b >>> 8) & 0xff; - s.pending_buf[s.pending++] = b & 0xff; -} - - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->input buffer and copying from it. - * (See also flush_pending()). - */ -function read_buf(strm, buf, start, size) { - var len = strm.avail_in; - - if (len > size) { len = size; } - if (len === 0) { return 0; } - - strm.avail_in -= len; - - utils.arraySet(buf, strm.input, strm.next_in, len, start); - if (strm.state.wrap === 1) { - strm.adler = adler32(strm.adler, buf, len, start); - } - - else if (strm.state.wrap === 2) { - strm.adler = crc32(strm.adler, buf, len, start); - } - - strm.next_in += len; - strm.total_in += len; - - return len; -} - - -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -function longest_match(s, cur_match) { - var chain_length = s.max_chain_length; /* max hash chain length */ - var scan = s.strstart; /* current string */ - var match; /* matched string */ - var len; /* length of current match */ - var best_len = s.prev_length; /* best match length so far */ - var nice_match = s.nice_match; /* stop if match long enough */ - var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? - s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; - - var _win = s.window; // shortcut - - var wmask = s.w_mask; - var prev = s.prev; - - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - - var strend = s.strstart + MAX_MATCH; - var scan_end1 = _win[scan + best_len - 1]; - var scan_end = _win[scan + best_len]; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s.prev_length >= s.good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if (nice_match > s.lookahead) { nice_match = s.lookahead; } - - // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - // Assert(cur_match < s->strstart, "no future"); - match = cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ - - if (_win[match + best_len] !== scan_end || - _win[match + best_len - 1] !== scan_end1 || - _win[match] !== _win[scan] || - _win[++match] !== _win[scan + 1]) { - continue; - } - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2; - match++; - // Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - /*jshint noempty:false*/ - } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - scan < strend); - - // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (strend - scan); - scan = strend - MAX_MATCH; - - if (len > best_len) { - s.match_start = cur_match; - best_len = len; - if (len >= nice_match) { - break; - } - scan_end1 = _win[scan + best_len - 1]; - scan_end = _win[scan + best_len]; - } - } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); - - if (best_len <= s.lookahead) { - return best_len; - } - return s.lookahead; -} - - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -function fill_window(s) { - var _w_size = s.w_size; - var p, n, m, more, str; - - //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - - do { - more = s.window_size - s.lookahead - s.strstart; - - // JS ints have 32 bit, block below not needed - /* Deal with !@#$% 64K limit: */ - //if (sizeof(int) <= 2) { - // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - // more = wsize; - // - // } else if (more == (unsigned)(-1)) { - // /* Very unlikely, but possible on 16 bit machine if - // * strstart == 0 && lookahead == 1 (input done a byte at time) - // */ - // more--; - // } - //} - - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { - - utils.arraySet(s.window, s.window, _w_size, _w_size, 0); - s.match_start -= _w_size; - s.strstart -= _w_size; - /* we now have strstart >= MAX_DIST */ - s.block_start -= _w_size; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - - n = s.hash_size; - p = n; - do { - m = s.head[--p]; - s.head[p] = (m >= _w_size ? m - _w_size : 0); - } while (--n); - - n = _w_size; - p = n; - do { - m = s.prev[--p]; - s.prev[p] = (m >= _w_size ? m - _w_size : 0); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); - - more += _w_size; - } - if (s.strm.avail_in === 0) { - break; - } - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - //Assert(more >= 2, "more < 2"); - n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); - s.lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s.lookahead + s.insert >= MIN_MATCH) { - str = s.strstart - s.insert; - s.ins_h = s.window[str]; - - /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask; -//#if MIN_MATCH != 3 -// Call update_hash() MIN_MATCH-3 more times -//#endif - while (s.insert) { - /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask; - - s.prev[str & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = str; - str++; - s.insert--; - if (s.lookahead + s.insert < MIN_MATCH) { - break; - } - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); - - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ -// if (s.high_water < s.window_size) { -// var curr = s.strstart + s.lookahead; -// var init = 0; -// -// if (s.high_water < curr) { -// /* Previous high water mark below current data -- zero WIN_INIT -// * bytes or up to end of window, whichever is less. -// */ -// init = s.window_size - curr; -// if (init > WIN_INIT) -// init = WIN_INIT; -// zmemzero(s->window + curr, (unsigned)init); -// s->high_water = curr + init; -// } -// else if (s->high_water < (ulg)curr + WIN_INIT) { -// /* High water mark at or above current data, but below current data -// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up -// * to end of window, whichever is less. -// */ -// init = (ulg)curr + WIN_INIT - s->high_water; -// if (init > s->window_size - s->high_water) -// init = s->window_size - s->high_water; -// zmemzero(s->window + s->high_water, (unsigned)init); -// s->high_water += init; -// } -// } -// -// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, -// "not enough room for search"); -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -function deflate_stored(s, flush) { - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - var max_block_size = 0xffff; - - if (max_block_size > s.pending_buf_size - 5) { - max_block_size = s.pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s.lookahead <= 1) { - - //Assert(s->strstart < s->w_size+MAX_DIST(s) || - // s->block_start >= (long)s->w_size, "slide too late"); -// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || -// s.block_start >= s.w_size)) { -// throw new Error("slide too late"); -// } - - fill_window(s); - if (s.lookahead === 0 && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - - if (s.lookahead === 0) { - break; - } - /* flush the current block */ - } - //Assert(s->block_start >= 0L, "block gone"); -// if (s.block_start < 0) throw new Error("block gone"); - - s.strstart += s.lookahead; - s.lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - var max_start = s.block_start + max_block_size; - - if (s.strstart === 0 || s.strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s.lookahead = s.strstart - max_start; - s.strstart = max_start; - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - - - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - - s.insert = 0; - - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - - if (s.strstart > s.block_start) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - - return BS_NEED_MORE; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -function deflate_fast(s, flush) { - var hash_head; /* head of the hash chain */ - var bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { - break; /* flush the current block */ - } - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = 0/*NIL*/; - if (s.lookahead >= MIN_MATCH) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s.match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ - } - if (s.match_length >= MIN_MATCH) { - // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only - - /*** _tr_tally_dist(s, s.strstart - s.match_start, - s.match_length - MIN_MATCH, bflush); ***/ - bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); - - s.lookahead -= s.match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { - s.match_length--; /* string at strstart already in table */ - do { - s.strstart++; - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s.match_length !== 0); - s.strstart++; - } else - { - s.strstart += s.match_length; - s.match_length = 0; - s.ins_h = s.window[s.strstart]; - /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask; - -//#if MIN_MATCH != 3 -// Call UPDATE_HASH() MIN_MATCH-3 more times -//#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - //Tracevv((stderr,"%c", s.window[s.strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - - s.lookahead--; - s.strstart++; - } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1); - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; -} - -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -function deflate_slow(s, flush) { - var hash_head; /* head of hash chain */ - var bflush; /* set if current block must be flushed */ - - var max_insert; - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { break; } /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = 0/*NIL*/; - if (s.lookahead >= MIN_MATCH) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - - /* Find the longest match, discarding those <= prev_length. - */ - s.prev_length = s.match_length; - s.prev_match = s.match_start; - s.match_length = MIN_MATCH-1; - - if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && - s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s.match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ - - if (s.match_length <= 5 && - (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s.match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { - max_insert = s.strstart + s.lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - //check_match(s, s.strstart-1, s.prev_match, s.prev_length); - - /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, - s.prev_length - MIN_MATCH, bflush);***/ - bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH); - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s.lookahead -= s.prev_length-1; - s.prev_length -= 2; - do { - if (++s.strstart <= max_insert) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - } while (--s.prev_length !== 0); - s.match_available = 0; - s.match_length = MIN_MATCH-1; - s.strstart++; - - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - - } else if (s.match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - //Tracevv((stderr,"%c", s->window[s->strstart-1])); - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); - - if (bflush) { - /*** FLUSH_BLOCK_ONLY(s, 0) ***/ - flush_block_only(s, false); - /***/ - } - s.strstart++; - s.lookahead--; - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s.match_available = 1; - s.strstart++; - s.lookahead--; - } - } - //Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s.match_available) { - //Tracevv((stderr,"%c", s->window[s->strstart-1])); - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); - - s.match_available = 0; - } - s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - - return BS_BLOCK_DONE; -} - - -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -function deflate_rle(s, flush) { - var bflush; /* set if current block must be flushed */ - var prev; /* byte at distance one to match */ - var scan, strend; /* scan goes up to strend for length of run */ - - var _win = s.window; - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest run, plus one for the unrolled loop. - */ - if (s.lookahead <= MAX_MATCH) { - fill_window(s); - if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { break; } /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - s.match_length = 0; - if (s.lookahead >= MIN_MATCH && s.strstart > 0) { - scan = s.strstart - 1; - prev = _win[scan]; - if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { - strend = s.strstart + MAX_MATCH; - do { - /*jshint noempty:false*/ - } while (prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - scan < strend); - s.match_length = MAX_MATCH - (strend - scan); - if (s.match_length > s.lookahead) { - s.match_length = s.lookahead; - } - } - //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (s.match_length >= MIN_MATCH) { - //check_match(s, s.strstart, s.strstart - 1, s.match_length); - - /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ - bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); - - s.lookahead -= s.match_length; - s.strstart += s.match_length; - s.match_length = 0; - } else { - /* No match, output a literal byte */ - //Tracevv((stderr,"%c", s->window[s->strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - - s.lookahead--; - s.strstart++; - } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = 0; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; -} - -/* =========================================================================== - * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. - * (It will be regenerated if this run of deflate switches away from Huffman.) - */ -function deflate_huff(s, flush) { - var bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we have a literal to write. */ - if (s.lookahead === 0) { - fill_window(s); - if (s.lookahead === 0) { - if (flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - break; /* flush the current block */ - } - } - - /* Output a literal byte */ - s.match_length = 0; - //Tracevv((stderr,"%c", s->window[s->strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = 0; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; -} - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -var Config = function (good_length, max_lazy, nice_length, max_chain, func) { - this.good_length = good_length; - this.max_lazy = max_lazy; - this.nice_length = nice_length; - this.max_chain = max_chain; - this.func = func; -}; - -var configuration_table; - -configuration_table = [ - /* good lazy nice chain */ - new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ - new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ - new Config(4, 5, 16, 8, deflate_fast), /* 2 */ - new Config(4, 6, 32, 32, deflate_fast), /* 3 */ - - new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ - new Config(8, 16, 32, 32, deflate_slow), /* 5 */ - new Config(8, 16, 128, 128, deflate_slow), /* 6 */ - new Config(8, 32, 128, 256, deflate_slow), /* 7 */ - new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ - new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ -]; - - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -function lm_init(s) { - s.window_size = 2 * s.w_size; - - /*** CLEAR_HASH(s); ***/ - zero(s.head); // Fill with NIL (= 0); - - /* Set the default configuration parameters: - */ - s.max_lazy_match = configuration_table[s.level].max_lazy; - s.good_match = configuration_table[s.level].good_length; - s.nice_match = configuration_table[s.level].nice_length; - s.max_chain_length = configuration_table[s.level].max_chain; - - s.strstart = 0; - s.block_start = 0; - s.lookahead = 0; - s.insert = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - s.ins_h = 0; -} - - -function DeflateState() { - this.strm = null; /* pointer back to this zlib stream */ - this.status = 0; /* as the name implies */ - this.pending_buf = null; /* output still pending */ - this.pending_buf_size = 0; /* size of pending_buf */ - this.pending_out = 0; /* next pending byte to output to the stream */ - this.pending = 0; /* nb of bytes in the pending buffer */ - this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ - this.gzhead = null; /* gzip header information to write */ - this.gzindex = 0; /* where in extra, name, or comment */ - this.method = Z_DEFLATED; /* can only be DEFLATED */ - this.last_flush = -1; /* value of flush param for previous deflate call */ - - this.w_size = 0; /* LZ77 window size (32K by default) */ - this.w_bits = 0; /* log2(w_size) (8..16) */ - this.w_mask = 0; /* w_size - 1 */ - - this.window = null; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. - */ - - this.window_size = 0; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - this.prev = null; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - this.head = null; /* Heads of the hash chains or NIL. */ - - this.ins_h = 0; /* hash index of string to be inserted */ - this.hash_size = 0; /* number of elements in hash table */ - this.hash_bits = 0; /* log2(hash_size) */ - this.hash_mask = 0; /* hash_size-1 */ - - this.hash_shift = 0; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - this.block_start = 0; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - this.match_length = 0; /* length of best match */ - this.prev_match = 0; /* previous match */ - this.match_available = 0; /* set if previous match exists */ - this.strstart = 0; /* start of string to insert */ - this.match_start = 0; /* start of matching string */ - this.lookahead = 0; /* number of valid bytes ahead in window */ - - this.prev_length = 0; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - this.max_chain_length = 0; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - this.max_lazy_match = 0; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ - // That's alias to max_lazy_match, don't use directly - //this.max_insert_length = 0; - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - this.level = 0; /* compression level (1..9) */ - this.strategy = 0; /* favor or force Huffman coding*/ - - this.good_match = 0; - /* Use a faster search when the previous match is longer than this */ - - this.nice_match = 0; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - - /* Didn't use ct_data typedef below to suppress compiler warning */ - - // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - // Use flat array of DOUBLE size, with interleaved fata, - // because JS does not support effective - this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); - this.dyn_dtree = new utils.Buf16((2*D_CODES+1) * 2); - this.bl_tree = new utils.Buf16((2*BL_CODES+1) * 2); - zero(this.dyn_ltree); - zero(this.dyn_dtree); - zero(this.bl_tree); - - this.l_desc = null; /* desc. for literal tree */ - this.d_desc = null; /* desc. for distance tree */ - this.bl_desc = null; /* desc. for bit length tree */ - - //ush bl_count[MAX_BITS+1]; - this.bl_count = new utils.Buf16(MAX_BITS+1); - /* number of codes at each bit length for an optimal tree */ - - //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - this.heap = new utils.Buf16(2*L_CODES+1); /* heap used to build the Huffman trees */ - zero(this.heap); - - this.heap_len = 0; /* number of elements in the heap */ - this.heap_max = 0; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1]; - zero(this.depth); - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - this.l_buf = 0; /* buffer index for literals or lengths */ - - this.lit_bufsize = 0; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - this.last_lit = 0; /* running index in l_buf */ - - this.d_buf = 0; - /* Buffer index for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - this.opt_len = 0; /* bit length of current block with optimal trees */ - this.static_len = 0; /* bit length of current block with static trees */ - this.matches = 0; /* number of string matches in current block */ - this.insert = 0; /* bytes at end of window left to insert */ - - - this.bi_buf = 0; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - this.bi_valid = 0; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - - // Used for window memory init. We safely ignore it for JS. That makes - // sense only for pointers and memory check tools. - //this.high_water = 0; - /* High water mark offset in window for initialized bytes -- bytes above - * this are set to zero in order to avoid memory check warnings when - * longest match routines access bytes past the input. This is then - * updated to the new high water mark. - */ -} - - -function deflateResetKeep(strm) { - var s; - - if (!strm || !strm.state) { - return err(strm, Z_STREAM_ERROR); - } - - strm.total_in = strm.total_out = 0; - strm.data_type = Z_UNKNOWN; - - s = strm.state; - s.pending = 0; - s.pending_out = 0; - - if (s.wrap < 0) { - s.wrap = -s.wrap; - /* was made negative by deflate(..., Z_FINISH); */ - } - s.status = (s.wrap ? INIT_STATE : BUSY_STATE); - strm.adler = (s.wrap === 2) ? - 0 // crc32(0, Z_NULL, 0) - : - 1; // adler32(0, Z_NULL, 0) - s.last_flush = Z_NO_FLUSH; - trees._tr_init(s); - return Z_OK; -} - - -function deflateReset(strm) { - var ret = deflateResetKeep(strm); - if (ret === Z_OK) { - lm_init(strm.state); - } - return ret; -} - - -function deflateSetHeader(strm, head) { - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; } - strm.state.gzhead = head; - return Z_OK; -} - - -function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { - if (!strm) { // === Z_NULL - return Z_STREAM_ERROR; - } - var wrap = 1; - - if (level === Z_DEFAULT_COMPRESSION) { - level = 6; - } - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } - - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } - - - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { - return err(strm, Z_STREAM_ERROR); - } - - - if (windowBits === 8) { - windowBits = 9; - } - /* until 256-byte window bug fixed */ - - var s = new DeflateState(); - - strm.state = s; - s.strm = strm; - - s.wrap = wrap; - s.gzhead = null; - s.w_bits = windowBits; - s.w_size = 1 << s.w_bits; - s.w_mask = s.w_size - 1; - - s.hash_bits = memLevel + 7; - s.hash_size = 1 << s.hash_bits; - s.hash_mask = s.hash_size - 1; - s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); - - s.window = new utils.Buf8(s.w_size * 2); - s.head = new utils.Buf16(s.hash_size); - s.prev = new utils.Buf16(s.w_size); - - // Don't need mem init magic for JS. - //s.high_water = 0; /* nothing written to s->window yet */ - - s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - s.pending_buf_size = s.lit_bufsize * 4; - s.pending_buf = new utils.Buf8(s.pending_buf_size); - - s.d_buf = s.lit_bufsize >> 1; - s.l_buf = (1 + 2) * s.lit_bufsize; - - s.level = level; - s.strategy = strategy; - s.method = method; - - return deflateReset(strm); -} - -function deflateInit(strm, level) { - return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); -} - - -function deflate(strm, flush) { - var old_flush, s; - var beg, val; // for gzip header write only - - if (!strm || !strm.state || - flush > Z_BLOCK || flush < 0) { - return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; - } - - s = strm.state; - - if (!strm.output || - (!strm.input && strm.avail_in !== 0) || - (s.status === FINISH_STATE && flush !== Z_FINISH)) { - return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR); - } - - s.strm = strm; /* just in case */ - old_flush = s.last_flush; - s.last_flush = flush; - - /* Write the header */ - if (s.status === INIT_STATE) { - - if (s.wrap === 2) { // GZIP header - strm.adler = 0; //crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (!s.gzhead) { // s->gzhead == Z_NULL - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s.level === 9 ? 2 : - (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s.status = BUSY_STATE; - } - else { - put_byte(s, (s.gzhead.text ? 1 : 0) + - (s.gzhead.hcrc ? 2 : 0) + - (!s.gzhead.extra ? 0 : 4) + - (!s.gzhead.name ? 0 : 8) + - (!s.gzhead.comment ? 0 : 16) - ); - put_byte(s, s.gzhead.time & 0xff); - put_byte(s, (s.gzhead.time >> 8) & 0xff); - put_byte(s, (s.gzhead.time >> 16) & 0xff); - put_byte(s, (s.gzhead.time >> 24) & 0xff); - put_byte(s, s.level === 9 ? 2 : - (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? - 4 : 0)); - put_byte(s, s.gzhead.os & 0xff); - if (s.gzhead.extra && s.gzhead.extra.length) { - put_byte(s, s.gzhead.extra.length & 0xff); - put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); - } - if (s.gzhead.hcrc) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); - } - s.gzindex = 0; - s.status = EXTRA_STATE; - } - } - else // DEFLATE header - { - var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; - var level_flags = -1; - - if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { - level_flags = 0; - } else if (s.level < 6) { - level_flags = 1; - } else if (s.level === 6) { - level_flags = 2; - } else { - level_flags = 3; - } - header |= (level_flags << 6); - if (s.strstart !== 0) { header |= PRESET_DICT; } - header += 31 - (header % 31); - - s.status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s.strstart !== 0) { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 0xffff); - } - strm.adler = 1; // adler32(0L, Z_NULL, 0); - } - } - -//#ifdef GZIP - if (s.status === EXTRA_STATE) { - if (s.gzhead.extra/* != Z_NULL*/) { - beg = s.pending; /* start of bytes to update crc */ - - while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - break; - } - } - put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); - s.gzindex++; - } - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (s.gzindex === s.gzhead.extra.length) { - s.gzindex = 0; - s.status = NAME_STATE; - } - } - else { - s.status = NAME_STATE; - } - } - if (s.status === NAME_STATE) { - if (s.gzhead.name/* != Z_NULL*/) { - beg = s.pending; /* start of bytes to update crc */ - //int val; - - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - val = 1; - break; - } - } - // JS specific: little magic to add zero terminator to end of string - if (s.gzindex < s.gzhead.name.length) { - val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); - - if (s.gzhead.hcrc && s.pending > beg){ - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (val === 0) { - s.gzindex = 0; - s.status = COMMENT_STATE; - } - } - else { - s.status = COMMENT_STATE; - } - } - if (s.status === COMMENT_STATE) { - if (s.gzhead.comment/* != Z_NULL*/) { - beg = s.pending; /* start of bytes to update crc */ - //int val; - - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - val = 1; - break; - } - } - // JS specific: little magic to add zero terminator to end of string - if (s.gzindex < s.gzhead.comment.length) { - val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); - - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (val === 0) { - s.status = HCRC_STATE; - } - } - else { - s.status = HCRC_STATE; - } - } - if (s.status === HCRC_STATE) { - if (s.gzhead.hcrc) { - if (s.pending + 2 > s.pending_buf_size) { - flush_pending(strm); - } - if (s.pending + 2 <= s.pending_buf_size) { - put_byte(s, strm.adler & 0xff); - put_byte(s, (strm.adler >> 8) & 0xff); - strm.adler = 0; //crc32(0L, Z_NULL, 0); - s.status = BUSY_STATE; - } - } - else { - s.status = BUSY_STATE; - } - } -//#endif - - /* Flush as much pending output as possible */ - if (s.pending !== 0) { - flush_pending(strm); - if (strm.avail_out === 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s.last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && - flush !== Z_FINISH) { - return err(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s.status === FINISH_STATE && strm.avail_in !== 0) { - return err(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm.avail_in !== 0 || s.lookahead !== 0 || - (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) { - var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) : - (s.strategy === Z_RLE ? deflate_rle(s, flush) : - configuration_table[s.level].func(s, flush)); - - if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { - s.status = FINISH_STATE; - } - if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { - if (strm.avail_out === 0) { - s.last_flush = -1; - /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate === BS_BLOCK_DONE) { - if (flush === Z_PARTIAL_FLUSH) { - trees._tr_align(s); - } - else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ - - trees._tr_stored_block(s, 0, 0, false); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush === Z_FULL_FLUSH) { - /*** CLEAR_HASH(s); ***/ /* forget history */ - zero(s.head); // Fill with NIL (= 0); - - if (s.lookahead === 0) { - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - } - } - flush_pending(strm); - if (strm.avail_out === 0) { - s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - //Assert(strm->avail_out > 0, "bug2"); - //if (strm.avail_out <= 0) { throw new Error("bug2");} - - if (flush !== Z_FINISH) { return Z_OK; } - if (s.wrap <= 0) { return Z_STREAM_END; } - - /* Write the trailer */ - if (s.wrap === 2) { - put_byte(s, strm.adler & 0xff); - put_byte(s, (strm.adler >> 8) & 0xff); - put_byte(s, (strm.adler >> 16) & 0xff); - put_byte(s, (strm.adler >> 24) & 0xff); - put_byte(s, strm.total_in & 0xff); - put_byte(s, (strm.total_in >> 8) & 0xff); - put_byte(s, (strm.total_in >> 16) & 0xff); - put_byte(s, (strm.total_in >> 24) & 0xff); - } - else - { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 0xffff); - } - - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s.wrap > 0) { s.wrap = -s.wrap; } - /* write the trailer only once! */ - return s.pending !== 0 ? Z_OK : Z_STREAM_END; -} - -function deflateEnd(strm) { - var status; - - if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { - return Z_STREAM_ERROR; - } - - status = strm.state.status; - if (status !== INIT_STATE && - status !== EXTRA_STATE && - status !== NAME_STATE && - status !== COMMENT_STATE && - status !== HCRC_STATE && - status !== BUSY_STATE && - status !== FINISH_STATE - ) { - return err(strm, Z_STREAM_ERROR); - } - - strm.state = null; - - return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state - */ -//function deflateCopy(dest, source) { -// -//} - -exports.deflateInit = deflateInit; -exports.deflateInit2 = deflateInit2; -exports.deflateReset = deflateReset; -exports.deflateResetKeep = deflateResetKeep; -exports.deflateSetHeader = deflateSetHeader; -exports.deflate = deflate; -exports.deflateEnd = deflateEnd; -exports.deflateInfo = 'pako deflate (from Nodeca project)'; - -/* Not implemented -exports.deflateBound = deflateBound; -exports.deflateCopy = deflateCopy; -exports.deflateSetDictionary = deflateSetDictionary; -exports.deflateParams = deflateParams; -exports.deflatePending = deflatePending; -exports.deflatePrime = deflatePrime; -exports.deflateTune = deflateTune; -*/ -},{"../utils/common":27,"./adler32":29,"./crc32":31,"./messages":37,"./trees":38}],33:[function(_dereq_,module,exports){ -'use strict'; - - -function GZheader() { - /* true if compressed data believed to be text */ - this.text = 0; - /* modification time */ - this.time = 0; - /* extra flags (not used when writing a gzip file) */ - this.xflags = 0; - /* operating system */ - this.os = 0; - /* pointer to extra field or Z_NULL if none */ - this.extra = null; - /* extra field length (valid if extra != Z_NULL) */ - this.extra_len = 0; // Actually, we don't need it in JS, - // but leave for few code modifications - - // - // Setup limits is not necessary because in js we should not preallocate memory - // for inflate use constant limit in 65536 bytes - // - - /* space at extra (only when reading header) */ - // this.extra_max = 0; - /* pointer to zero-terminated file name or Z_NULL */ - this.name = ''; - /* space at name (only when reading header) */ - // this.name_max = 0; - /* pointer to zero-terminated comment or Z_NULL */ - this.comment = ''; - /* space at comment (only when reading header) */ - // this.comm_max = 0; - /* true if there was or will be a header crc */ - this.hcrc = 0; - /* true when done reading gzip header (not used when writing a gzip file) */ - this.done = false; -} - -module.exports = GZheader; -},{}],34:[function(_dereq_,module,exports){ -'use strict'; - -// See state defs from inflate.js -var BAD = 30; /* got a data error -- remain here until reset */ -var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state.mode === LEN - strm.avail_in >= 6 - strm.avail_out >= 258 - start >= strm.avail_out - state.bits < 8 - - On return, state.mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm.avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm.avail_out >= 258 for each loop to avoid checking for - output space. - */ -module.exports = function inflate_fast(strm, start) { - var state; - var _in; /* local strm.input */ - var last; /* have enough input while in < last */ - var _out; /* local strm.output */ - var beg; /* inflate()'s initial strm.output */ - var end; /* while out < end, enough space available */ -//#ifdef INFLATE_STRICT - var dmax; /* maximum distance from zlib header */ -//#endif - var wsize; /* window size or zero if not using window */ - var whave; /* valid bytes in the window */ - var wnext; /* window write index */ - var window; /* allocated sliding window, if wsize != 0 */ - var hold; /* local strm.hold */ - var bits; /* local strm.bits */ - var lcode; /* local strm.lencode */ - var dcode; /* local strm.distcode */ - var lmask; /* mask for first level of length codes */ - var dmask; /* mask for first level of distance codes */ - var here; /* retrieved table entry */ - var op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - var len; /* match length, unused bytes */ - var dist; /* match distance */ - var from; /* where to copy match from */ - var from_source; - - - var input, output; // JS specific, because we have no pointers - - /* copy state to local variables */ - state = strm.state; - //here = state.here; - _in = strm.next_in; - input = strm.input; - last = _in + (strm.avail_in - 5); - _out = strm.next_out; - output = strm.output; - beg = _out - (start - strm.avail_out); - end = _out + (strm.avail_out - 257); -//#ifdef INFLATE_STRICT - dmax = state.dmax; -//#endif - wsize = state.wsize; - whave = state.whave; - wnext = state.wnext; - window = state.window; - hold = state.hold; - bits = state.bits; - lcode = state.lencode; - dcode = state.distcode; - lmask = (1 << state.lenbits) - 1; - dmask = (1 << state.distbits) - 1; - - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - - top: - do { - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; - } - - here = lcode[hold & lmask]; - - dolen: - for (;;) { // Goto emulation - op = here >>> 24/*here.bits*/; - hold >>>= op; - bits -= op; - op = (here >>> 16) & 0xff/*here.op*/; - if (op === 0) { /* literal */ - //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - // "inflate: literal '%c'\n" : - // "inflate: literal 0x%02x\n", here.val)); - output[_out++] = here & 0xffff/*here.val*/; - } - else if (op & 16) { /* length base */ - len = here & 0xffff/*here.val*/; - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - len += hold & ((1 << op) - 1); - hold >>>= op; - bits -= op; - } - //Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; - } - here = dcode[hold & dmask]; - - dodist: - for (;;) { // goto emulation - op = here >>> 24/*here.bits*/; - hold >>>= op; - bits -= op; - op = (here >>> 16) & 0xff/*here.op*/; - - if (op & 16) { /* distance base */ - dist = here & 0xffff/*here.val*/; - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - } - dist += hold & ((1 << op) - 1); -//#ifdef INFLATE_STRICT - if (dist > dmax) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break top; - } -//#endif - hold >>>= op; - bits -= op; - //Tracevv((stderr, "inflate: distance %u\n", dist)); - op = _out - beg; /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - if (state.sane) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break top; - } - -// (!) This block is disabled in zlib defailts, -// don't enable it for binary compatibility -//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR -// if (len <= op - whave) { -// do { -// output[_out++] = 0; -// } while (--len); -// continue top; -// } -// len -= op - whave; -// do { -// output[_out++] = 0; -// } while (--op > whave); -// if (op === 0) { -// from = _out - dist; -// do { -// output[_out++] = output[from++]; -// } while (--len); -// continue top; -// } -//#endif - } - from = 0; // window index - from_source = window; - if (wnext === 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - output[_out++] = window[from++]; - } while (--op); - from = _out - dist; /* rest from output */ - from_source = output; - } - } - else if (wnext < op) { /* wrap around window */ - from += wsize + wnext - op; - op -= wnext; - if (op < len) { /* some from end of window */ - len -= op; - do { - output[_out++] = window[from++]; - } while (--op); - from = 0; - if (wnext < len) { /* some from start of window */ - op = wnext; - len -= op; - do { - output[_out++] = window[from++]; - } while (--op); - from = _out - dist; /* rest from output */ - from_source = output; - } - } - } - else { /* contiguous in window */ - from += wnext - op; - if (op < len) { /* some from window */ - len -= op; - do { - output[_out++] = window[from++]; - } while (--op); - from = _out - dist; /* rest from output */ - from_source = output; - } - } - while (len > 2) { - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - len -= 3; - } - if (len) { - output[_out++] = from_source[from++]; - if (len > 1) { - output[_out++] = from_source[from++]; - } - } - } - else { - from = _out - dist; /* copy direct from output */ - do { /* minimum length is three */ - output[_out++] = output[from++]; - output[_out++] = output[from++]; - output[_out++] = output[from++]; - len -= 3; - } while (len > 2); - if (len) { - output[_out++] = output[from++]; - if (len > 1) { - output[_out++] = output[from++]; - } - } - } - } - else if ((op & 64) === 0) { /* 2nd level distance code */ - here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; - continue dodist; - } - else { - strm.msg = 'invalid distance code'; - state.mode = BAD; - break top; - } - - break; // need to emulate goto via "continue" - } - } - else if ((op & 64) === 0) { /* 2nd level length code */ - here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; - continue dolen; - } - else if (op & 32) { /* end-of-block */ - //Tracevv((stderr, "inflate: end of block\n")); - state.mode = TYPE; - break top; - } - else { - strm.msg = 'invalid literal/length code'; - state.mode = BAD; - break top; - } - - break; // need to emulate goto via "continue" - } - } while (_in < last && _out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - _in -= len; - bits -= len << 3; - hold &= (1 << bits) - 1; - - /* update state and return */ - strm.next_in = _in; - strm.next_out = _out; - strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); - strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); - state.hold = hold; - state.bits = bits; - return; -}; - -},{}],35:[function(_dereq_,module,exports){ -'use strict'; - - -var utils = _dereq_('../utils/common'); -var adler32 = _dereq_('./adler32'); -var crc32 = _dereq_('./crc32'); -var inflate_fast = _dereq_('./inffast'); -var inflate_table = _dereq_('./inftrees'); - -var CODES = 0; -var LENS = 1; -var DISTS = 2; - -/* Public constants ==========================================================*/ -/* ===========================================================================*/ - - -/* Allowed flush values; see deflate() and inflate() below for details */ -//var Z_NO_FLUSH = 0; -//var Z_PARTIAL_FLUSH = 1; -//var Z_SYNC_FLUSH = 2; -//var Z_FULL_FLUSH = 3; -var Z_FINISH = 4; -var Z_BLOCK = 5; -var Z_TREES = 6; - - -/* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ -var Z_OK = 0; -var Z_STREAM_END = 1; -var Z_NEED_DICT = 2; -//var Z_ERRNO = -1; -var Z_STREAM_ERROR = -2; -var Z_DATA_ERROR = -3; -var Z_MEM_ERROR = -4; -var Z_BUF_ERROR = -5; -//var Z_VERSION_ERROR = -6; - -/* The deflate compression method */ -var Z_DEFLATED = 8; - - -/* STATES ====================================================================*/ -/* ===========================================================================*/ - - -var HEAD = 1; /* i: waiting for magic header */ -var FLAGS = 2; /* i: waiting for method and flags (gzip) */ -var TIME = 3; /* i: waiting for modification time (gzip) */ -var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ -var EXLEN = 5; /* i: waiting for extra length (gzip) */ -var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ -var NAME = 7; /* i: waiting for end of file name (gzip) */ -var COMMENT = 8; /* i: waiting for end of comment (gzip) */ -var HCRC = 9; /* i: waiting for header crc (gzip) */ -var DICTID = 10; /* i: waiting for dictionary check value */ -var DICT = 11; /* waiting for inflateSetDictionary() call */ -var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ -var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ -var STORED = 14; /* i: waiting for stored size (length and complement) */ -var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ -var COPY = 16; /* i/o: waiting for input or output to copy stored block */ -var TABLE = 17; /* i: waiting for dynamic block table lengths */ -var LENLENS = 18; /* i: waiting for code length code lengths */ -var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ -var LEN_ = 20; /* i: same as LEN below, but only first time in */ -var LEN = 21; /* i: waiting for length/lit/eob code */ -var LENEXT = 22; /* i: waiting for length extra bits */ -var DIST = 23; /* i: waiting for distance code */ -var DISTEXT = 24; /* i: waiting for distance extra bits */ -var MATCH = 25; /* o: waiting for output space to copy string */ -var LIT = 26; /* o: waiting for output space to write literal */ -var CHECK = 27; /* i: waiting for 32-bit check value */ -var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ -var DONE = 29; /* finished check, done -- remain here until reset */ -var BAD = 30; /* got a data error -- remain here until reset */ -var MEM = 31; /* got an inflate() memory error -- remain here until reset */ -var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ - -/* ===========================================================================*/ - - - -var ENOUGH_LENS = 852; -var ENOUGH_DISTS = 592; -//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); - -var MAX_WBITS = 15; -/* 32K LZ77 window */ -var DEF_WBITS = MAX_WBITS; - - -function ZSWAP32(q) { - return (((q >>> 24) & 0xff) + - ((q >>> 8) & 0xff00) + - ((q & 0xff00) << 8) + - ((q & 0xff) << 24)); -} - - -function InflateState() { - this.mode = 0; /* current inflate mode */ - this.last = false; /* true if processing last block */ - this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ - this.havedict = false; /* true if dictionary provided */ - this.flags = 0; /* gzip header method and flags (0 if zlib) */ - this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ - this.check = 0; /* protected copy of check value */ - this.total = 0; /* protected copy of output count */ - // TODO: may be {} - this.head = null; /* where to save gzip header information */ - - /* sliding window */ - this.wbits = 0; /* log base 2 of requested window size */ - this.wsize = 0; /* window size or zero if not using window */ - this.whave = 0; /* valid bytes in the window */ - this.wnext = 0; /* window write index */ - this.window = null; /* allocated sliding window, if needed */ - - /* bit accumulator */ - this.hold = 0; /* input bit accumulator */ - this.bits = 0; /* number of bits in "in" */ - - /* for string and stored block copying */ - this.length = 0; /* literal or length of data to copy */ - this.offset = 0; /* distance back to copy string from */ - - /* for table and code decoding */ - this.extra = 0; /* extra bits needed */ - - /* fixed and dynamic code tables */ - this.lencode = null; /* starting table for length/literal codes */ - this.distcode = null; /* starting table for distance codes */ - this.lenbits = 0; /* index bits for lencode */ - this.distbits = 0; /* index bits for distcode */ - - /* dynamic table building */ - this.ncode = 0; /* number of code length code lengths */ - this.nlen = 0; /* number of length code lengths */ - this.ndist = 0; /* number of distance code lengths */ - this.have = 0; /* number of code lengths in lens[] */ - this.next = null; /* next available space in codes[] */ - - this.lens = new utils.Buf16(320); /* temporary storage for code lengths */ - this.work = new utils.Buf16(288); /* work area for code table building */ - - /* - because we don't have pointers in js, we use lencode and distcode directly - as buffers so we don't need codes - */ - //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ - this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ - this.distdyn = null; /* dynamic table for distance codes (JS specific) */ - this.sane = 0; /* if false, allow invalid distance too far */ - this.back = 0; /* bits back of last unprocessed length/lit */ - this.was = 0; /* initial length of match */ -} - -function inflateResetKeep(strm) { - var state; - - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - strm.total_in = strm.total_out = state.total = 0; - strm.msg = ''; /*Z_NULL*/ - if (state.wrap) { /* to support ill-conceived Java test suite */ - strm.adler = state.wrap & 1; - } - state.mode = HEAD; - state.last = 0; - state.havedict = 0; - state.dmax = 32768; - state.head = null/*Z_NULL*/; - state.hold = 0; - state.bits = 0; - //state.lencode = state.distcode = state.next = state.codes; - state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); - state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); - - state.sane = 1; - state.back = -1; - //Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -function inflateReset(strm) { - var state; - - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - state.wsize = 0; - state.whave = 0; - state.wnext = 0; - return inflateResetKeep(strm); - -} - -function inflateReset2(strm, windowBits) { - var wrap; - var state; - - /* get the state */ - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - - /* extract wrap request from windowBits parameter */ - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } - else { - wrap = (windowBits >> 4) + 1; - if (windowBits < 48) { - windowBits &= 15; - } - } - - /* set number of window bits, free window if different */ - if (windowBits && (windowBits < 8 || windowBits > 15)) { - return Z_STREAM_ERROR; - } - if (state.window !== null && state.wbits !== windowBits) { - state.window = null; - } - - /* update state and reset the rest of it */ - state.wrap = wrap; - state.wbits = windowBits; - return inflateReset(strm); -} - -function inflateInit2(strm, windowBits) { - var ret; - var state; - - if (!strm) { return Z_STREAM_ERROR; } - //strm.msg = Z_NULL; /* in case we return an error */ - - state = new InflateState(); - - //if (state === Z_NULL) return Z_MEM_ERROR; - //Tracev((stderr, "inflate: allocated\n")); - strm.state = state; - state.window = null/*Z_NULL*/; - ret = inflateReset2(strm, windowBits); - if (ret !== Z_OK) { - strm.state = null/*Z_NULL*/; - } - return ret; -} - -function inflateInit(strm) { - return inflateInit2(strm, DEF_WBITS); -} - - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -var virgin = true; - -var lenfix, distfix; // We have no pointers in JS, so keep tables separate - -function fixedtables(state) { - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - var sym; - - lenfix = new utils.Buf32(512); - distfix = new utils.Buf32(32); - - /* literal/length table */ - sym = 0; - while (sym < 144) { state.lens[sym++] = 8; } - while (sym < 256) { state.lens[sym++] = 9; } - while (sym < 280) { state.lens[sym++] = 7; } - while (sym < 288) { state.lens[sym++] = 8; } - - inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, {bits: 9}); - - /* distance table */ - sym = 0; - while (sym < 32) { state.lens[sym++] = 5; } - - inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, {bits: 5}); - - /* do this just once */ - virgin = false; - } - - state.lencode = lenfix; - state.lenbits = 9; - state.distcode = distfix; - state.distbits = 5; -} - - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -function updatewindow(strm, src, end, copy) { - var dist; - var state = strm.state; - - /* if it hasn't been done already, allocate space for the window */ - if (state.window === null) { - state.wsize = 1 << state.wbits; - state.wnext = 0; - state.whave = 0; - - state.window = new utils.Buf8(state.wsize); - } - - /* copy state->wsize or less output bytes into the circular window */ - if (copy >= state.wsize) { - utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0); - state.wnext = 0; - state.whave = state.wsize; - } - else { - dist = state.wsize - state.wnext; - if (dist > copy) { - dist = copy; - } - //zmemcpy(state->window + state->wnext, end - copy, dist); - utils.arraySet(state.window,src, end - copy, dist, state.wnext); - copy -= dist; - if (copy) { - //zmemcpy(state->window, end - copy, copy); - utils.arraySet(state.window,src, end - copy, copy, 0); - state.wnext = copy; - state.whave = state.wsize; - } - else { - state.wnext += dist; - if (state.wnext === state.wsize) { state.wnext = 0; } - if (state.whave < state.wsize) { state.whave += dist; } - } - } - return 0; -} - -function inflate(strm, flush) { - var state; - var input, output; // input/output buffers - var next; /* next input INDEX */ - var put; /* next output INDEX */ - var have, left; /* available input and output */ - var hold; /* bit buffer */ - var bits; /* bits in bit buffer */ - var _in, _out; /* save starting available input and output */ - var copy; /* number of stored or match bytes to copy */ - var from; /* where to copy match bytes from */ - var from_source; - var here = 0; /* current decoding table entry */ - var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) - //var last; /* parent table entry */ - var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) - var len; /* length to copy for repeats, bits to drop */ - var ret; /* return code */ - var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */ - var opts; - - var n; // temporary var for NEED_BITS - - var order = /* permutation of code lengths */ - [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; - - - if (!strm || !strm.state || !strm.output || - (!strm.input && strm.avail_in !== 0)) { - return Z_STREAM_ERROR; - } - - state = strm.state; - if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ - - - //--- LOAD() --- - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - //--- - - _in = have; - _out = left; - ret = Z_OK; - - inf_leave: // goto emulation - for (;;) { - switch (state.mode) { - case HEAD: - if (state.wrap === 0) { - state.mode = TYPEDO; - break; - } - //=== NEEDBITS(16); - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ - state.check = 0/*crc32(0L, Z_NULL, 0)*/; - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = FLAGS; - break; - } - state.flags = 0; /* expect zlib header */ - if (state.head) { - state.head.done = false; - } - if (!(state.wrap & 1) || /* check if zlib header allowed */ - (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { - strm.msg = 'incorrect header check'; - state.mode = BAD; - break; - } - if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { - strm.msg = 'unknown compression method'; - state.mode = BAD; - break; - } - //--- DROPBITS(4) ---// - hold >>>= 4; - bits -= 4; - //---// - len = (hold & 0x0f)/*BITS(4)*/ + 8; - if (state.wbits === 0) { - state.wbits = len; - } - else if (len > state.wbits) { - strm.msg = 'invalid window size'; - state.mode = BAD; - break; - } - state.dmax = 1 << len; - //Tracev((stderr, "inflate: zlib header ok\n")); - strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; - state.mode = hold & 0x200 ? DICTID : TYPE; - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - break; - case FLAGS: - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.flags = hold; - if ((state.flags & 0xff) !== Z_DEFLATED) { - strm.msg = 'unknown compression method'; - state.mode = BAD; - break; - } - if (state.flags & 0xe000) { - strm.msg = 'unknown header flags set'; - state.mode = BAD; - break; - } - if (state.head) { - state.head.text = ((hold >> 8) & 1); - } - if (state.flags & 0x0200) { - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = TIME; - /* falls through */ - case TIME: - //=== NEEDBITS(32); */ - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (state.head) { - state.head.time = hold; - } - if (state.flags & 0x0200) { - //=== CRC4(state.check, hold) - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - hbuf[2] = (hold >>> 16) & 0xff; - hbuf[3] = (hold >>> 24) & 0xff; - state.check = crc32(state.check, hbuf, 4, 0); - //=== - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = OS; - /* falls through */ - case OS: - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (state.head) { - state.head.xflags = (hold & 0xff); - state.head.os = (hold >> 8); - } - if (state.flags & 0x0200) { - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = EXLEN; - /* falls through */ - case EXLEN: - if (state.flags & 0x0400) { - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.length = hold; - if (state.head) { - state.head.extra_len = hold; - } - if (state.flags & 0x0200) { - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - } - else if (state.head) { - state.head.extra = null/*Z_NULL*/; - } - state.mode = EXTRA; - /* falls through */ - case EXTRA: - if (state.flags & 0x0400) { - copy = state.length; - if (copy > have) { copy = have; } - if (copy) { - if (state.head) { - len = state.head.extra_len - state.length; - if (!state.head.extra) { - // Use untyped array for more conveniend processing later - state.head.extra = new Array(state.head.extra_len); - } - utils.arraySet( - state.head.extra, - input, - next, - // extra field is limited to 65536 bytes - // - no need for additional size check - copy, - /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ - len - ); - //zmemcpy(state.head.extra + len, next, - // len + copy > state.head.extra_max ? - // state.head.extra_max - len : copy); - } - if (state.flags & 0x0200) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - state.length -= copy; - } - if (state.length) { break inf_leave; } - } - state.length = 0; - state.mode = NAME; - /* falls through */ - case NAME: - if (state.flags & 0x0800) { - if (have === 0) { break inf_leave; } - copy = 0; - do { - // TODO: 2 or 1 bytes? - len = input[next + copy++]; - /* use constant limit because in js we should not preallocate memory */ - if (state.head && len && - (state.length < 65536 /*state.head.name_max*/)) { - state.head.name += String.fromCharCode(len); - } - } while (len && copy < have); - - if (state.flags & 0x0200) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - if (len) { break inf_leave; } - } - else if (state.head) { - state.head.name = null; - } - state.length = 0; - state.mode = COMMENT; - /* falls through */ - case COMMENT: - if (state.flags & 0x1000) { - if (have === 0) { break inf_leave; } - copy = 0; - do { - len = input[next + copy++]; - /* use constant limit because in js we should not preallocate memory */ - if (state.head && len && - (state.length < 65536 /*state.head.comm_max*/)) { - state.head.comment += String.fromCharCode(len); - } - } while (len && copy < have); - if (state.flags & 0x0200) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - if (len) { break inf_leave; } - } - else if (state.head) { - state.head.comment = null; - } - state.mode = HCRC; - /* falls through */ - case HCRC: - if (state.flags & 0x0200) { - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (hold !== (state.check & 0xffff)) { - strm.msg = 'header crc mismatch'; - state.mode = BAD; - break; - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - } - if (state.head) { - state.head.hcrc = ((state.flags >> 9) & 1); - state.head.done = true; - } - strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/; - state.mode = TYPE; - break; - case DICTID: - //=== NEEDBITS(32); */ - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - strm.adler = state.check = ZSWAP32(hold); - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = DICT; - /* falls through */ - case DICT: - if (state.havedict === 0) { - //--- RESTORE() --- - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - //--- - return Z_NEED_DICT; - } - strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; - state.mode = TYPE; - /* falls through */ - case TYPE: - if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } - /* falls through */ - case TYPEDO: - if (state.last) { - //--- BYTEBITS() ---// - hold >>>= bits & 7; - bits -= bits & 7; - //---// - state.mode = CHECK; - break; - } - //=== NEEDBITS(3); */ - while (bits < 3) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.last = (hold & 0x01)/*BITS(1)*/; - //--- DROPBITS(1) ---// - hold >>>= 1; - bits -= 1; - //---// - - switch ((hold & 0x03)/*BITS(2)*/) { - case 0: /* stored block */ - //Tracev((stderr, "inflate: stored block%s\n", - // state.last ? " (last)" : "")); - state.mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - //Tracev((stderr, "inflate: fixed codes block%s\n", - // state.last ? " (last)" : "")); - state.mode = LEN_; /* decode codes */ - if (flush === Z_TREES) { - //--- DROPBITS(2) ---// - hold >>>= 2; - bits -= 2; - //---// - break inf_leave; - } - break; - case 2: /* dynamic block */ - //Tracev((stderr, "inflate: dynamic codes block%s\n", - // state.last ? " (last)" : "")); - state.mode = TABLE; - break; - case 3: - strm.msg = 'invalid block type'; - state.mode = BAD; - } - //--- DROPBITS(2) ---// - hold >>>= 2; - bits -= 2; - //---// - break; - case STORED: - //--- BYTEBITS() ---// /* go to byte boundary */ - hold >>>= bits & 7; - bits -= bits & 7; - //---// - //=== NEEDBITS(32); */ - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { - strm.msg = 'invalid stored block lengths'; - state.mode = BAD; - break; - } - state.length = hold & 0xffff; - //Tracev((stderr, "inflate: stored length %u\n", - // state.length)); - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = COPY_; - if (flush === Z_TREES) { break inf_leave; } - /* falls through */ - case COPY_: - state.mode = COPY; - /* falls through */ - case COPY: - copy = state.length; - if (copy) { - if (copy > have) { copy = have; } - if (copy > left) { copy = left; } - if (copy === 0) { break inf_leave; } - //--- zmemcpy(put, next, copy); --- - utils.arraySet(output, input, next, copy, put); - //---// - have -= copy; - next += copy; - left -= copy; - put += copy; - state.length -= copy; - break; - } - //Tracev((stderr, "inflate: stored end\n")); - state.mode = TYPE; - break; - case TABLE: - //=== NEEDBITS(14); */ - while (bits < 14) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; - //--- DROPBITS(5) ---// - hold >>>= 5; - bits -= 5; - //---// - state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; - //--- DROPBITS(5) ---// - hold >>>= 5; - bits -= 5; - //---// - state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; - //--- DROPBITS(4) ---// - hold >>>= 4; - bits -= 4; - //---// -//#ifndef PKZIP_BUG_WORKAROUND - if (state.nlen > 286 || state.ndist > 30) { - strm.msg = 'too many length or distance symbols'; - state.mode = BAD; - break; - } -//#endif - //Tracev((stderr, "inflate: table sizes ok\n")); - state.have = 0; - state.mode = LENLENS; - /* falls through */ - case LENLENS: - while (state.have < state.ncode) { - //=== NEEDBITS(3); - while (bits < 3) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); - //--- DROPBITS(3) ---// - hold >>>= 3; - bits -= 3; - //---// - } - while (state.have < 19) { - state.lens[order[state.have++]] = 0; - } - // We have separate tables & no pointers. 2 commented lines below not needed. - //state.next = state.codes; - //state.lencode = state.next; - // Switch to use dynamic table - state.lencode = state.lendyn; - state.lenbits = 7; - - opts = {bits: state.lenbits}; - ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); - state.lenbits = opts.bits; - - if (ret) { - strm.msg = 'invalid code lengths set'; - state.mode = BAD; - break; - } - //Tracev((stderr, "inflate: code lengths ok\n")); - state.have = 0; - state.mode = CODELENS; - /* falls through */ - case CODELENS: - while (state.have < state.nlen + state.ndist) { - for (;;) { - here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - if (here_val < 16) { - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - state.lens[state.have++] = here_val; - } - else { - if (here_val === 16) { - //=== NEEDBITS(here.bits + 2); - n = here_bits + 2; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - if (state.have === 0) { - strm.msg = 'invalid bit length repeat'; - state.mode = BAD; - break; - } - len = state.lens[state.have - 1]; - copy = 3 + (hold & 0x03);//BITS(2); - //--- DROPBITS(2) ---// - hold >>>= 2; - bits -= 2; - //---// - } - else if (here_val === 17) { - //=== NEEDBITS(here.bits + 3); - n = here_bits + 3; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - len = 0; - copy = 3 + (hold & 0x07);//BITS(3); - //--- DROPBITS(3) ---// - hold >>>= 3; - bits -= 3; - //---// - } - else { - //=== NEEDBITS(here.bits + 7); - n = here_bits + 7; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - len = 0; - copy = 11 + (hold & 0x7f);//BITS(7); - //--- DROPBITS(7) ---// - hold >>>= 7; - bits -= 7; - //---// - } - if (state.have + copy > state.nlen + state.ndist) { - strm.msg = 'invalid bit length repeat'; - state.mode = BAD; - break; - } - while (copy--) { - state.lens[state.have++] = len; - } - } - } - - /* handle error breaks in while */ - if (state.mode === BAD) { break; } - - /* check for end-of-block code (better have one) */ - if (state.lens[256] === 0) { - strm.msg = 'invalid code -- missing end-of-block'; - state.mode = BAD; - break; - } - - /* build code tables -- note: do not change the lenbits or distbits - values here (9 and 6) without reading the comments in inftrees.h - concerning the ENOUGH constants, which depend on those values */ - state.lenbits = 9; - - opts = {bits: state.lenbits}; - ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); - // We have separate tables & no pointers. 2 commented lines below not needed. - // state.next_index = opts.table_index; - state.lenbits = opts.bits; - // state.lencode = state.next; - - if (ret) { - strm.msg = 'invalid literal/lengths set'; - state.mode = BAD; - break; - } - - state.distbits = 6; - //state.distcode.copy(state.codes); - // Switch to use dynamic table - state.distcode = state.distdyn; - opts = {bits: state.distbits}; - ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); - // We have separate tables & no pointers. 2 commented lines below not needed. - // state.next_index = opts.table_index; - state.distbits = opts.bits; - // state.distcode = state.next; - - if (ret) { - strm.msg = 'invalid distances set'; - state.mode = BAD; - break; - } - //Tracev((stderr, 'inflate: codes ok\n')); - state.mode = LEN_; - if (flush === Z_TREES) { break inf_leave; } - /* falls through */ - case LEN_: - state.mode = LEN; - /* falls through */ - case LEN: - if (have >= 6 && left >= 258) { - //--- RESTORE() --- - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - //--- - inflate_fast(strm, _out); - //--- LOAD() --- - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - //--- - - if (state.mode === TYPE) { - state.back = -1; - } - break; - } - state.back = 0; - for (;;) { - here = state.lencode[hold & ((1 << state.lenbits) -1)]; /*BITS(state.lenbits)*/ - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if (here_bits <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - if (here_op && (here_op & 0xf0) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.lencode[last_val + - ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((last_bits + here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - //--- DROPBITS(last.bits) ---// - hold >>>= last_bits; - bits -= last_bits; - //---// - state.back += last_bits; - } - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - state.back += here_bits; - state.length = here_val; - if (here_op === 0) { - //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - // "inflate: literal '%c'\n" : - // "inflate: literal 0x%02x\n", here.val)); - state.mode = LIT; - break; - } - if (here_op & 32) { - //Tracevv((stderr, "inflate: end of block\n")); - state.back = -1; - state.mode = TYPE; - break; - } - if (here_op & 64) { - strm.msg = 'invalid literal/length code'; - state.mode = BAD; - break; - } - state.extra = here_op & 15; - state.mode = LENEXT; - /* falls through */ - case LENEXT: - if (state.extra) { - //=== NEEDBITS(state.extra); - n = state.extra; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; - //--- DROPBITS(state.extra) ---// - hold >>>= state.extra; - bits -= state.extra; - //---// - state.back += state.extra; - } - //Tracevv((stderr, "inflate: length %u\n", state.length)); - state.was = state.length; - state.mode = DIST; - /* falls through */ - case DIST: - for (;;) { - here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/ - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - if ((here_op & 0xf0) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.distcode[last_val + - ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((last_bits + here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - //--- DROPBITS(last.bits) ---// - hold >>>= last_bits; - bits -= last_bits; - //---// - state.back += last_bits; - } - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - state.back += here_bits; - if (here_op & 64) { - strm.msg = 'invalid distance code'; - state.mode = BAD; - break; - } - state.offset = here_val; - state.extra = (here_op) & 15; - state.mode = DISTEXT; - /* falls through */ - case DISTEXT: - if (state.extra) { - //=== NEEDBITS(state.extra); - n = state.extra; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; - //--- DROPBITS(state.extra) ---// - hold >>>= state.extra; - bits -= state.extra; - //---// - state.back += state.extra; - } -//#ifdef INFLATE_STRICT - if (state.offset > state.dmax) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break; - } -//#endif - //Tracevv((stderr, "inflate: distance %u\n", state.offset)); - state.mode = MATCH; - /* falls through */ - case MATCH: - if (left === 0) { break inf_leave; } - copy = _out - left; - if (state.offset > copy) { /* copy from window */ - copy = state.offset - copy; - if (copy > state.whave) { - if (state.sane) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break; - } -// (!) This block is disabled in zlib defailts, -// don't enable it for binary compatibility -//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR -// Trace((stderr, "inflate.c too far\n")); -// copy -= state.whave; -// if (copy > state.length) { copy = state.length; } -// if (copy > left) { copy = left; } -// left -= copy; -// state.length -= copy; -// do { -// output[put++] = 0; -// } while (--copy); -// if (state.length === 0) { state.mode = LEN; } -// break; -//#endif - } - if (copy > state.wnext) { - copy -= state.wnext; - from = state.wsize - copy; - } - else { - from = state.wnext - copy; - } - if (copy > state.length) { copy = state.length; } - from_source = state.window; - } - else { /* copy from output */ - from_source = output; - from = put - state.offset; - copy = state.length; - } - if (copy > left) { copy = left; } - left -= copy; - state.length -= copy; - do { - output[put++] = from_source[from++]; - } while (--copy); - if (state.length === 0) { state.mode = LEN; } - break; - case LIT: - if (left === 0) { break inf_leave; } - output[put++] = state.length; - left--; - state.mode = LEN; - break; - case CHECK: - if (state.wrap) { - //=== NEEDBITS(32); - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - // Use '|' insdead of '+' to make sure that result is signed - hold |= input[next++] << bits; - bits += 8; - } - //===// - _out -= left; - strm.total_out += _out; - state.total += _out; - if (_out) { - strm.adler = state.check = - /*UPDATE(state.check, put - _out, _out);*/ - (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out)); - - } - _out = left; - // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too - if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) { - strm.msg = 'incorrect data check'; - state.mode = BAD; - break; - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - //Tracev((stderr, "inflate: check matches trailer\n")); - } - state.mode = LENGTH; - /* falls through */ - case LENGTH: - if (state.wrap && state.flags) { - //=== NEEDBITS(32); - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (hold !== (state.total & 0xffffffff)) { - strm.msg = 'incorrect length check'; - state.mode = BAD; - break; - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - //Tracev((stderr, "inflate: length matches trailer\n")); - } - state.mode = DONE; - /* falls through */ - case DONE: - ret = Z_STREAM_END; - break inf_leave; - case BAD: - ret = Z_DATA_ERROR; - break inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - /* falls through */ - default: - return Z_STREAM_ERROR; - } - } - - // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - - //--- RESTORE() --- - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - //--- - - if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && - (state.mode < CHECK || flush !== Z_FINISH))) { - if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) { - state.mode = MEM; - return Z_MEM_ERROR; - } - } - _in -= strm.avail_in; - _out -= strm.avail_out; - strm.total_in += _in; - strm.total_out += _out; - state.total += _out; - if (state.wrap && _out) { - strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ - (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out)); - } - strm.data_type = state.bits + (state.last ? 64 : 0) + - (state.mode === TYPE ? 128 : 0) + - (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); - if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { - ret = Z_BUF_ERROR; - } - return ret; -} - -function inflateEnd(strm) { - - if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { - return Z_STREAM_ERROR; - } - - var state = strm.state; - if (state.window) { - state.window = null; - } - strm.state = null; - return Z_OK; -} - -function inflateGetHeader(strm, head) { - var state; - - /* check state */ - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; } - - /* save header structure */ - state.head = head; - head.done = false; - return Z_OK; -} - - -exports.inflateReset = inflateReset; -exports.inflateReset2 = inflateReset2; -exports.inflateResetKeep = inflateResetKeep; -exports.inflateInit = inflateInit; -exports.inflateInit2 = inflateInit2; -exports.inflate = inflate; -exports.inflateEnd = inflateEnd; -exports.inflateGetHeader = inflateGetHeader; -exports.inflateInfo = 'pako inflate (from Nodeca project)'; - -/* Not implemented -exports.inflateCopy = inflateCopy; -exports.inflateGetDictionary = inflateGetDictionary; -exports.inflateMark = inflateMark; -exports.inflatePrime = inflatePrime; -exports.inflateSetDictionary = inflateSetDictionary; -exports.inflateSync = inflateSync; -exports.inflateSyncPoint = inflateSyncPoint; -exports.inflateUndermine = inflateUndermine; -*/ -},{"../utils/common":27,"./adler32":29,"./crc32":31,"./inffast":34,"./inftrees":36}],36:[function(_dereq_,module,exports){ -'use strict'; - - -var utils = _dereq_('../utils/common'); - -var MAXBITS = 15; -var ENOUGH_LENS = 852; -var ENOUGH_DISTS = 592; -//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); - -var CODES = 0; -var LENS = 1; -var DISTS = 2; - -var lbase = [ /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 -]; - -var lext = [ /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 -]; - -var dbase = [ /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0 -]; - -var dext = [ /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64 -]; - -module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) -{ - var bits = opts.bits; - //here = opts.here; /* table entry for duplication */ - - var len = 0; /* a code's length in bits */ - var sym = 0; /* index of code symbols */ - var min = 0, max = 0; /* minimum and maximum code lengths */ - var root = 0; /* number of index bits for root table */ - var curr = 0; /* number of index bits for current table */ - var drop = 0; /* code bits to drop for sub-table */ - var left = 0; /* number of prefix codes available */ - var used = 0; /* code entries in table used */ - var huff = 0; /* Huffman code */ - var incr; /* for incrementing code, index */ - var fill; /* index for replicating entries */ - var low; /* low bits for current root entry */ - var mask; /* mask for low root bits */ - var next; /* next available space in table */ - var base = null; /* base value table to use */ - var base_index = 0; -// var shoextra; /* extra bits table to use */ - var end; /* use base and extra for symbol > end */ - var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */ - var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */ - var extra = null; - var extra_index = 0; - - var here_bits, here_op, here_val; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) { - count[len] = 0; - } - for (sym = 0; sym < codes; sym++) { - count[lens[lens_index + sym]]++; - } - - /* bound code lengths, force root to be within code lengths */ - root = bits; - for (max = MAXBITS; max >= 1; max--) { - if (count[max] !== 0) { break; } - } - if (root > max) { - root = max; - } - if (max === 0) { /* no symbols to code at all */ - //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ - //table.bits[opts.table_index] = 1; //here.bits = (var char)1; - //table.val[opts.table_index++] = 0; //here.val = (var short)0; - table[table_index++] = (1 << 24) | (64 << 16) | 0; - - - //table.op[opts.table_index] = 64; - //table.bits[opts.table_index] = 1; - //table.val[opts.table_index++] = 0; - table[table_index++] = (1 << 24) | (64 << 16) | 0; - - opts.bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min < max; min++) { - if (count[min] !== 0) { break; } - } - if (root < min) { - root = min; - } - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) { - return -1; - } /* over-subscribed */ - } - if (left > 0 && (type === CODES || max !== 1)) { - return -1; /* incomplete set */ - } - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) { - offs[len + 1] = offs[len] + count[len]; - } - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) { - if (lens[lens_index + sym] !== 0) { - work[offs[lens[lens_index + sym]]++] = sym; - } - } - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked for LENS and DIST tables against - the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in - the initial root table size constants. See the comments in inftrees.h - for more information. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - // poor man optimization - use if-else instead of switch, - // to avoid deopts in old v8 - if (type === CODES) { - base = extra = work; /* dummy value--not used */ - end = 19; - } else if (type === LENS) { - base = lbase; - base_index -= 257; - extra = lext; - extra_index -= 257; - end = 256; - } else { /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize opts for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = table_index; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = -1; /* trigger new sub-table when len > root */ - used = 1 << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if ((type === LENS && used > ENOUGH_LENS) || - (type === DISTS && used > ENOUGH_DISTS)) { - return 1; - } - - var i=0; - /* process all codes and make table entries */ - for (;;) { - i++; - /* create table entry */ - here_bits = len - drop; - if (work[sym] < end) { - here_op = 0; - here_val = work[sym]; - } - else if (work[sym] > end) { - here_op = extra[extra_index + work[sym]]; - here_val = base[base_index + work[sym]]; - } - else { - here_op = 32 + 64; /* end of block */ - here_val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1 << (len - drop); - fill = 1 << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; - } while (fill !== 0); - - /* backwards increment the len-bit code huff */ - incr = 1 << (len - 1); - while (huff & incr) { - incr >>= 1; - } - if (incr !== 0) { - huff &= incr - 1; - huff += incr; - } else { - huff = 0; - } - - /* go to next symbol, update count, len */ - sym++; - if (--count[len] === 0) { - if (len === max) { break; } - len = lens[lens_index + work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) !== low) { - /* if first time, transition to sub-tables */ - if (drop === 0) { - drop = root; - } - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = 1 << curr; - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) { break; } - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1 << curr; - if ((type === LENS && used > ENOUGH_LENS) || - (type === DISTS && used > ENOUGH_DISTS)) { - return 1; - } - - /* point entry in root table to sub-table */ - low = huff & mask; - /*table.op[low] = curr; - table.bits[low] = root; - table.val[low] = next - opts.table_index;*/ - table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; - } - } - - /* fill in remaining table entry if code is incomplete (guaranteed to have - at most one remaining entry, since if the code is incomplete, the - maximum code length that was allowed to get this far is one bit) */ - if (huff !== 0) { - //table.op[next + huff] = 64; /* invalid code marker */ - //table.bits[next + huff] = len - drop; - //table.val[next + huff] = 0; - table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; - } - - /* set return parameters */ - //opts.table_index += used; - opts.bits = root; - return 0; -}; - -},{"../utils/common":27}],37:[function(_dereq_,module,exports){ -'use strict'; - -module.exports = { - '2': 'need dictionary', /* Z_NEED_DICT 2 */ - '1': 'stream end', /* Z_STREAM_END 1 */ - '0': '', /* Z_OK 0 */ - '-1': 'file error', /* Z_ERRNO (-1) */ - '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ - '-3': 'data error', /* Z_DATA_ERROR (-3) */ - '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ - '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ - '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ -}; -},{}],38:[function(_dereq_,module,exports){ -'use strict'; - - -var utils = _dereq_('../utils/common'); - -/* Public constants ==========================================================*/ -/* ===========================================================================*/ - - -//var Z_FILTERED = 1; -//var Z_HUFFMAN_ONLY = 2; -//var Z_RLE = 3; -var Z_FIXED = 4; -//var Z_DEFAULT_STRATEGY = 0; - -/* Possible values of the data_type field (though see inflate()) */ -var Z_BINARY = 0; -var Z_TEXT = 1; -//var Z_ASCII = 1; // = Z_TEXT -var Z_UNKNOWN = 2; - -/*============================================================================*/ - - -function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } - -// From zutil.h - -var STORED_BLOCK = 0; -var STATIC_TREES = 1; -var DYN_TREES = 2; -/* The three kinds of block type */ - -var MIN_MATCH = 3; -var MAX_MATCH = 258; -/* The minimum and maximum match lengths */ - -// From deflate.h -/* =========================================================================== - * Internal compression state. - */ - -var LENGTH_CODES = 29; -/* number of length codes, not counting the special END_BLOCK code */ - -var LITERALS = 256; -/* number of literal bytes 0..255 */ - -var L_CODES = LITERALS + 1 + LENGTH_CODES; -/* number of Literal or Length codes, including the END_BLOCK code */ - -var D_CODES = 30; -/* number of distance codes */ - -var BL_CODES = 19; -/* number of codes used to transfer the bit lengths */ - -var HEAP_SIZE = 2*L_CODES + 1; -/* maximum heap size */ - -var MAX_BITS = 15; -/* All codes must not exceed MAX_BITS bits */ - -var Buf_size = 16; -/* size of bit buffer in bi_buf */ - - -/* =========================================================================== - * Constants - */ - -var MAX_BL_BITS = 7; -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -var END_BLOCK = 256; -/* end of block literal code */ - -var REP_3_6 = 16; -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -var REPZ_3_10 = 17; -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -var REPZ_11_138 = 18; -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -var extra_lbits = /* extra bits for each length code */ - [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]; - -var extra_dbits = /* extra bits for each distance code */ - [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]; - -var extra_blbits = /* extra bits for each bit length code */ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]; - -var bl_order = - [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -// We pre-fill arrays with 0 to avoid uninitialized gaps - -var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ - -// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1 -var static_ltree = new Array((L_CODES+2) * 2); -zero(static_ltree); -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -var static_dtree = new Array(D_CODES * 2); -zero(static_dtree); -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -var _dist_code = new Array(DIST_CODE_LEN); -zero(_dist_code); -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -var _length_code = new Array(MAX_MATCH-MIN_MATCH+1); -zero(_length_code); -/* length code for each normalized match length (0 == MIN_MATCH) */ - -var base_length = new Array(LENGTH_CODES); -zero(base_length); -/* First normalized length for each code (0 = MIN_MATCH) */ - -var base_dist = new Array(D_CODES); -zero(base_dist); -/* First normalized distance for each code (0 = distance of 1) */ - - -var StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) { - - this.static_tree = static_tree; /* static tree or NULL */ - this.extra_bits = extra_bits; /* extra bits for each code or NULL */ - this.extra_base = extra_base; /* base index for extra_bits */ - this.elems = elems; /* max number of elements in the tree */ - this.max_length = max_length; /* max bit length for the codes */ - - // show if `static_tree` has data or dummy - needed for monomorphic objects - this.has_stree = static_tree && static_tree.length; -}; - - -var static_l_desc; -var static_d_desc; -var static_bl_desc; - - -var TreeDesc = function(dyn_tree, stat_desc) { - this.dyn_tree = dyn_tree; /* the dynamic tree */ - this.max_code = 0; /* largest code with non zero frequency */ - this.stat_desc = stat_desc; /* the corresponding static tree */ -}; - - - -function d_code(dist) { - return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; -} - - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -function put_short (s, w) { -// put_byte(s, (uch)((w) & 0xff)); -// put_byte(s, (uch)((ush)(w) >> 8)); - s.pending_buf[s.pending++] = (w) & 0xff; - s.pending_buf[s.pending++] = (w >>> 8) & 0xff; -} - - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -function send_bits(s, value, length) { - if (s.bi_valid > (Buf_size - length)) { - s.bi_buf |= (value << s.bi_valid) & 0xffff; - put_short(s, s.bi_buf); - s.bi_buf = value >> (Buf_size - s.bi_valid); - s.bi_valid += length - Buf_size; - } else { - s.bi_buf |= (value << s.bi_valid) & 0xffff; - s.bi_valid += length; - } -} - - -function send_code(s, c, tree) { - send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/); -} - - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -function bi_reverse(code, len) { - var res = 0; - do { - res |= code & 1; - code >>>= 1; - res <<= 1; - } while (--len > 0); - return res >>> 1; -} - - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -function bi_flush(s) { - if (s.bi_valid === 16) { - put_short(s, s.bi_buf); - s.bi_buf = 0; - s.bi_valid = 0; - - } else if (s.bi_valid >= 8) { - s.pending_buf[s.pending++] = s.bi_buf & 0xff; - s.bi_buf >>= 8; - s.bi_valid -= 8; - } -} - - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -function gen_bitlen(s, desc) -// deflate_state *s; -// tree_desc *desc; /* the tree descriptor */ -{ - var tree = desc.dyn_tree; - var max_code = desc.max_code; - var stree = desc.stat_desc.static_tree; - var has_stree = desc.stat_desc.has_stree; - var extra = desc.stat_desc.extra_bits; - var base = desc.stat_desc.extra_base; - var max_length = desc.stat_desc.max_length; - var h; /* heap index */ - var n, m; /* iterate over the tree elements */ - var bits; /* bit length */ - var xbits; /* extra bits */ - var f; /* frequency */ - var overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) { - s.bl_count[bits] = 0; - } - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */ - - for (h = s.heap_max+1; h < HEAP_SIZE; h++) { - n = s.heap[h]; - bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; - if (bits > max_length) { - bits = max_length; - overflow++; - } - tree[n*2 + 1]/*.Len*/ = bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) { continue; } /* not a leaf node */ - - s.bl_count[bits]++; - xbits = 0; - if (n >= base) { - xbits = extra[n-base]; - } - f = tree[n * 2]/*.Freq*/; - s.opt_len += f * (bits + xbits); - if (has_stree) { - s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits); - } - } - if (overflow === 0) { return; } - - // Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s.bl_count[bits] === 0) { bits--; } - s.bl_count[bits]--; /* move one leaf down the tree */ - s.bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s.bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits !== 0; bits--) { - n = s.bl_count[bits]; - while (n !== 0) { - m = s.heap[--h]; - if (m > max_code) { continue; } - if (tree[m*2 + 1]/*.Len*/ !== bits) { - // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/; - tree[m*2 + 1]/*.Len*/ = bits; - } - n--; - } - } -} - - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -function gen_codes(tree, max_code, bl_count) -// ct_data *tree; /* the tree to decorate */ -// int max_code; /* largest code with non zero frequency */ -// ushf *bl_count; /* number of codes at each bit length */ -{ - var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */ - var code = 0; /* running code value */ - var bits; /* bit index */ - var n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - //Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = code; - } - } - //Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) { - bl_count[bits] = 0; - } - - n = 0; - while (n <= 143) { - static_ltree[n*2 + 1]/*.Len*/ = 8; - n++; - bl_count[8]++; - } - while (n <= 255) { - static_ltree[n*2 + 1]/*.Len*/ = 9; - n++; - bl_count[9]++; - } - while (n <= 279) { - static_ltree[n*2 + 1]/*.Len*/ = 7; - n++; - bl_count[7]++; - } - while (n <= 287) { - static_ltree[n*2 + 1]/*.Len*/ = 8; - n++; - bl_count[8]++; - } - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes(static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n*2 + 1]/*.Len*/ = 5; - static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5); - } - - // Now data ready and we can init static trees - static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS); - static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); - static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); - - //static_init_done = true; -} - - -/* =========================================================================== - * Initialize a new block. - */ -function init_block(s) { - var n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; } - for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; } - for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; } - - s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1; - s.opt_len = s.static_len = 0; - s.last_lit = s.matches = 0; -} - - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -function bi_windup(s) -{ - if (s.bi_valid > 8) { - put_short(s, s.bi_buf); - } else if (s.bi_valid > 0) { - //put_byte(s, (Byte)s->bi_buf); - s.pending_buf[s.pending++] = s.bi_buf; - } - s.bi_buf = 0; - s.bi_valid = 0; -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -function copy_block(s, buf, len, header) -//DeflateState *s; -//charf *buf; /* the input data */ -//unsigned len; /* its length */ -//int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - - if (header) { - put_short(s, len); - put_short(s, ~len); - } -// while (len--) { -// put_byte(s, *buf++); -// } - utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); - s.pending += len; -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -function smaller(tree, n, m, depth) { - var _n2 = n*2; - var _m2 = m*2; - return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || - (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); -} - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -function pqdownheap(s, tree, k) -// deflate_state *s; -// ct_data *tree; /* the tree to restore */ -// int k; /* node to move down */ -{ - var v = s.heap[k]; - var j = k << 1; /* left son of k */ - while (j <= s.heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s.heap_len && - smaller(tree, s.heap[j+1], s.heap[j], s.depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s.heap[j], s.depth)) { break; } - - /* Exchange v with the smallest son */ - s.heap[k] = s.heap[j]; - k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s.heap[k] = v; -} - - -// inlined manually -// var SMALLEST = 1; - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -function compress_block(s, ltree, dtree) -// deflate_state *s; -// const ct_data *ltree; /* literal tree */ -// const ct_data *dtree; /* distance tree */ -{ - var dist; /* distance of matched string */ - var lc; /* match length or unmatched char (if dist == 0) */ - var lx = 0; /* running index in l_buf */ - var code; /* the code to send */ - var extra; /* number of extra bits to send */ - - if (s.last_lit !== 0) { - do { - dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]); - lc = s.pending_buf[s.l_buf + lx]; - lx++; - - if (dist === 0) { - send_code(s, lc, ltree); /* send a literal byte */ - //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra !== 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - //Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra !== 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - // "pendingBuf overflow"); - - } while (lx < s.last_lit); - } - - send_code(s, END_BLOCK, ltree); -} - - -/* =========================================================================== - * Construct one Huffman tree and assigns the code bit strings and lengths. - * Update the total bit length for the current block. - * IN assertion: the field freq is set for all tree elements. - * OUT assertions: the fields len and code are set to the optimal bit length - * and corresponding code. The length opt_len is updated; static_len is - * also updated if stree is not null. The field max_code is set. - */ -function build_tree(s, desc) -// deflate_state *s; -// tree_desc *desc; /* the tree descriptor */ -{ - var tree = desc.dyn_tree; - var stree = desc.stat_desc.static_tree; - var has_stree = desc.stat_desc.has_stree; - var elems = desc.stat_desc.elems; - var n, m; /* iterate over heap elements */ - var max_code = -1; /* largest code with non zero frequency */ - var node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s.heap_len = 0; - s.heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n * 2]/*.Freq*/ !== 0) { - s.heap[++s.heap_len] = max_code = n; - s.depth[n] = 0; - - } else { - tree[n*2 + 1]/*.Len*/ = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s.heap_len < 2) { - node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); - tree[node * 2]/*.Freq*/ = 1; - s.depth[node] = 0; - s.opt_len--; - - if (has_stree) { - s.static_len -= stree[node*2 + 1]/*.Len*/; - } - /* node is 0 or 1 so it does not have extra bits */ - } - desc.max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - //pqremove(s, tree, n); /* n = node of least frequency */ - /*** pqremove ***/ - n = s.heap[1/*SMALLEST*/]; - s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; - pqdownheap(s, tree, 1/*SMALLEST*/); - /***/ - - m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ - - s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ - s.heap[--s.heap_max] = m; - - /* Create a new node father of n and m */ - tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; - s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; - tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node; - - /* and insert the new node in the heap */ - s.heap[1/*SMALLEST*/] = node++; - pqdownheap(s, tree, 1/*SMALLEST*/); - - } while (s.heap_len >= 2); - - s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes(tree, max_code, s.bl_count); -} - - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -function scan_tree(s, tree, max_code) -// deflate_state *s; -// ct_data *tree; /* the tree to be scanned */ -// int max_code; /* and its largest code of non zero frequency */ -{ - var n; /* iterates over all tree elements */ - var prevlen = -1; /* last emitted length */ - var curlen; /* length of current code */ - - var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ - - var count = 0; /* repeat count of the current code */ - var max_count = 7; /* max repeat count */ - var min_count = 4; /* min repeat count */ - - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n+1)*2 + 1]/*.Len*/; - - if (++count < max_count && curlen === nextlen) { - continue; - - } else if (count < min_count) { - s.bl_tree[curlen * 2]/*.Freq*/ += count; - - } else if (curlen !== 0) { - - if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } - s.bl_tree[REP_3_6*2]/*.Freq*/++; - - } else if (count <= 10) { - s.bl_tree[REPZ_3_10*2]/*.Freq*/++; - - } else { - s.bl_tree[REPZ_11_138*2]/*.Freq*/++; - } - - count = 0; - prevlen = curlen; - - if (nextlen === 0) { - max_count = 138; - min_count = 3; - - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - - } else { - max_count = 7; - min_count = 4; - } - } -} - - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -function send_tree(s, tree, max_code) -// deflate_state *s; -// ct_data *tree; /* the tree to be scanned */ -// int max_code; /* and its largest code of non zero frequency */ -{ - var n; /* iterates over all tree elements */ - var prevlen = -1; /* last emitted length */ - var curlen; /* length of current code */ - - var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ - - var count = 0; /* repeat count of the current code */ - var max_count = 7; /* max repeat count */ - var min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n+1)*2 + 1]/*.Len*/; - - if (++count < max_count && curlen === nextlen) { - continue; - - } else if (count < min_count) { - do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); - - } else if (curlen !== 0) { - if (curlen !== prevlen) { - send_code(s, curlen, s.bl_tree); - count--; - } - //Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s.bl_tree); - send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s.bl_tree); - send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s.bl_tree); - send_bits(s, count-11, 7); - } - - count = 0; - prevlen = curlen; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - - } else { - max_count = 7; - min_count = 4; - } - } -} - - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -function build_bl_tree(s) { - var max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, s.dyn_ltree, s.l_desc.max_code); - scan_tree(s, s.dyn_dtree, s.d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, s.bl_desc); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) { - break; - } - } - /* Update opt_len to include the bit length tree and counts */ - s.opt_len += 3*(max_blindex+1) + 5+5+4; - //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - // s->opt_len, s->static_len)); - - return max_blindex; -} - - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -function send_all_trees(s, lcodes, dcodes, blcodes) -// deflate_state *s; -// int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - var rank; /* index in bl_order */ - - //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - // "too many codes"); - //Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3); - } - //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */ - //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */ - //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - - -/* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "black list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ -function detect_data_type(s) { - /* black_mask is the bit mask of black-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - var black_mask = 0xf3ffc07f; - var n; - - /* Check for non-textual ("black-listed") bytes. */ - for (n = 0; n <= 31; n++, black_mask >>>= 1) { - if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) { - return Z_BINARY; - } - } - - /* Check for textual ("white-listed") bytes. */ - if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || - s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { - return Z_TEXT; - } - for (n = 32; n < LITERALS; n++) { - if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { - return Z_TEXT; - } - } - - /* There are no "black-listed" or "white-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; -} - - -var static_init_done = false; - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -function _tr_init(s) -{ - - if (!static_init_done) { - tr_static_init(); - static_init_done = true; - } - - s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); - s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); - s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); - - s.bi_buf = 0; - s.bi_valid = 0; - - /* Initialize the first block of the first file: */ - init_block(s); -} - - -/* =========================================================================== - * Send a stored block - */ -function _tr_stored_block(s, buf, stored_len, last) -//DeflateState *s; -//charf *buf; /* input block */ -//ulg stored_len; /* length of input block */ -//int last; /* one if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3); /* send block type */ - copy_block(s, buf, stored_len, true); /* with header */ -} - - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - */ -function _tr_align(s) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); - bi_flush(s); -} - - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ -function _tr_flush_block(s, buf, stored_len, last) -//DeflateState *s; -//charf *buf; /* input block, or NULL if too old */ -//ulg stored_len; /* length of input block */ -//int last; /* one if this is the last block for a file */ -{ - var opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - var max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s.level > 0) { - - /* Check if the file is binary or text */ - if (s.strm.data_type === Z_UNKNOWN) { - s.strm.data_type = detect_data_type(s); - } - - /* Construct the literal and distance trees */ - build_tree(s, s.l_desc); - // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - // s->static_len)); - - build_tree(s, s.d_desc); - // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - // s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s.opt_len+3+7) >>> 3; - static_lenb = (s.static_len+3+7) >>> 3; - - // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - // s->last_lit)); - - if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } - - } else { - // Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - - if ((stored_len+4 <= opt_lenb) && (buf !== -1)) { - /* 4: two words for the lengths */ - - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, last); - - } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { - - send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3); - compress_block(s, static_ltree, static_dtree); - - } else { - send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3); - send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1); - compress_block(s, s.dyn_ltree, s.dyn_dtree); - } - // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (last) { - bi_windup(s); - } - // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - // s->compressed_len-7*last)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -function _tr_tally(s, dist, lc) -// deflate_state *s; -// unsigned dist; /* distance of matched string */ -// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - //var out_length, in_length, dcode; - - s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff; - s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; - - s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; - s.last_lit++; - - if (dist === 0) { - /* lc is the unmatched char */ - s.dyn_ltree[lc*2]/*.Freq*/++; - } else { - s.matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - //Assert((ush)dist < (ush)MAX_DIST(s) && - // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++; - s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; - } - -// (!) This block is disabled in zlib defailts, -// don't enable it for binary compatibility - -//#ifdef TRUNCATE_BLOCK -// /* Try to guess if it is profitable to stop the current block here */ -// if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { -// /* Compute an upper bound for the compressed length */ -// out_length = s.last_lit*8; -// in_length = s.strstart - s.block_start; -// -// for (dcode = 0; dcode < D_CODES; dcode++) { -// out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); -// } -// out_length >>>= 3; -// //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", -// // s->last_lit, in_length, out_length, -// // 100L - out_length*100L/in_length)); -// if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { -// return true; -// } -// } -//#endif - - return (s.last_lit === s.lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -exports._tr_init = _tr_init; -exports._tr_stored_block = _tr_stored_block; -exports._tr_flush_block = _tr_flush_block; -exports._tr_tally = _tr_tally; -exports._tr_align = _tr_align; -},{"../utils/common":27}],39:[function(_dereq_,module,exports){ -'use strict'; - - -function ZStream() { - /* next input byte */ - this.input = null; // JS specific, because we have no pointers - this.next_in = 0; - /* number of bytes available at input */ - this.avail_in = 0; - /* total number of input bytes read so far */ - this.total_in = 0; - /* next output byte should be put there */ - this.output = null; // JS specific, because we have no pointers - this.next_out = 0; - /* remaining free space at output */ - this.avail_out = 0; - /* total number of bytes output so far */ - this.total_out = 0; - /* last error message, NULL if no error */ - this.msg = ''/*Z_NULL*/; - /* not visible by applications */ - this.state = null; - /* best guess about the data type: binary or text */ - this.data_type = 2/*Z_UNKNOWN*/; - /* adler32 value of the uncompressed data */ - this.adler = 0; -} - -module.exports = ZStream; -},{}]},{},[9]) -(9) -}); \ No newline at end of file diff --git a/cps/static/js/compress/jszip.min.js b/cps/static/js/compress/jszip.min.js new file mode 100644 index 000000000..3b36cd8b2 --- /dev/null +++ b/cps/static/js/compress/jszip.min.js @@ -0,0 +1,14 @@ +/*! + +JSZip - A Javascript class for generating and reading zip files + + +(c) 2009-2014 Stuart Knightley +Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. + +JSZip uses the library pako released under the MIT license : +https://github.com/nodeca/pako/blob/master/LICENSE +*/ +!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.JSZip=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f-this.zero;return-1},d.prototype.readData=function(a){if(this.checkOffset(a),0===a)return[];var b=this.data.slice(this.zero+this.index,this.zero+this.index+a);return this.index+=a,b},b.exports=d},{"./dataReader":6}],2:[function(a,b,c){"use strict";var d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";c.encode=function(a,b){for(var c,e,f,g,h,i,j,k="",l=0;l>2,h=(3&c)<<4|e>>4,i=(15&e)<<2|f>>6,j=63&f,isNaN(e)?i=j=64:isNaN(f)&&(j=64),k=k+d.charAt(g)+d.charAt(h)+d.charAt(i)+d.charAt(j);return k},c.decode=function(a,b){var c,e,f,g,h,i,j,k="",l=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");l>4,e=(15&h)<<4|i>>2,f=(3&i)<<6|j,k+=String.fromCharCode(c),64!=i&&(k+=String.fromCharCode(e)),64!=j&&(k+=String.fromCharCode(f));return k}},{}],3:[function(a,b,c){"use strict";function d(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}d.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=d},{}],4:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a,b){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":9}],5:[function(a,b,c){"use strict";var d=a("./utils"),e=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918e3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117];b.exports=function(a,b){if("undefined"==typeof a||!a.length)return 0;var c="string"!==d.getTypeOf(a);"undefined"==typeof b&&(b=0);var f=0,g=0,h=0;b=-1^b;for(var i=0,j=a.length;j>i;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),f=e[g],b=b>>>8^f;return-1^b}},{"./utils":22}],6:[function(a,b,c){"use strict";function d(a){this.data=null,this.length=0,this.index=0,this.zero=0}var e=a("./utils");d.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(a){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return e.transformTo("string",this.readData(a))},readData:function(a){},lastIndexOfSignature:function(a){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=d},{"./utils":22}],7:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.createFolders=!1,c.date=null,c.compression=null,c.compressionOptions=null,c.comment=null,c.unixPermissions=null,c.dosPermissions=null},{}],8:[function(a,b,c){"use strict";var d=a("./utils");c.string2binary=function(a){return d.string2binary(a)},c.string2Uint8Array=function(a){return d.transformTo("uint8array",a)},c.uint8Array2String=function(a){return d.transformTo("string",a)},c.string2Blob=function(a){var b=d.transformTo("arraybuffer",a);return d.arrayBuffer2Blob(b)},c.arrayBuffer2Blob=function(a){return d.arrayBuffer2Blob(a)},c.transformTo=function(a,b){return d.transformTo(a,b)},c.getTypeOf=function(a){return d.getTypeOf(a)},c.checkSupport=function(a){return d.checkSupport(a)},c.MAX_VALUE_16BITS=d.MAX_VALUE_16BITS,c.MAX_VALUE_32BITS=d.MAX_VALUE_32BITS,c.pretty=function(a){return d.pretty(a)},c.findCompression=function(a){return d.findCompression(a)},c.isRegExp=function(a){return d.isRegExp(a)}},{"./utils":22}],9:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("pako");c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a,b){return e.deflateRaw(a,{level:b.level||-1})},c.uncompress=function(a){return e.inflateRaw(a)}},{pako:25}],10:[function(a,b,c){"use strict";function d(a,b){return this instanceof d?(this.files={},this.comment=null,this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new d;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new d(a,b)}var e=a("./base64");d.prototype=a("./object"),d.prototype.load=a("./load"),d.support=a("./support"),d.defaults=a("./defaults"),d.utils=a("./deprecatedPublicUtils"),d.base64={encode:function(a){return e.encode(a)},decode:function(a){return e.decode(a)}},d.compressions=a("./compressions"),b.exports=d},{"./base64":2,"./compressions":4,"./defaults":7,"./deprecatedPublicUtils":8,"./load":11,"./object":14,"./support":18}],11:[function(a,b,c){"use strict";var d=a("./base64"),e=a("./utf8"),f=a("./utils"),g=a("./zipEntries");b.exports=function(a,b){var c,h,i,j;for(b=f.extend(b||{},{base64:!1,checkCRC32:!1,optimizedBinaryString:!1,createFolders:!1,decodeFileName:e.utf8decode}),b.base64&&(a=d.decode(a)),h=new g(a,b),c=h.files,i=0;ic;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},u=function(a){return a=a||{},a.base64!==!0||null!==a.binary&&void 0!==a.binary||(a.binary=!0),a=e.extend(a,h),a.date=a.date||new Date,null!==a.compression&&(a.compression=a.compression.toUpperCase()),a},v=function(a,b,c){var d,f=e.getTypeOf(b);if(c=u(c),"string"==typeof c.unixPermissions&&(c.unixPermissions=parseInt(c.unixPermissions,8)),c.unixPermissions&&16384&c.unixPermissions&&(c.dir=!0),c.dosPermissions&&16&c.dosPermissions&&(c.dir=!0),c.dir&&(a=x(a)),c.createFolders&&(d=w(a))&&y.call(this,d,!0),c.dir||null===b||"undefined"==typeof b)c.base64=!1,c.binary=!1,b=null,f=null;else if("string"===f)c.binary&&!c.base64&&c.optimizedBinaryString!==!0&&(b=e.string2binary(b));else{if(c.base64=!1,c.binary=!0,!(f||b instanceof k))throw new Error("The data of '"+a+"' is in an unsupported format !");"arraybuffer"===f&&(b=e.transformTo("uint8array",b))}var g=new s(a,b,c);return this.files[a]=g,g},w=function(a){"/"==a.slice(-1)&&(a=a.substring(0,a.length-1));var b=a.lastIndexOf("/");return b>0?a.substring(0,b):""},x=function(a){return"/"!=a.slice(-1)&&(a+="/"),a},y=function(a,b){return b="undefined"!=typeof b?b:!1,a=x(a),this.files[a]||v.call(this,a,null,{dir:!0,createFolders:b}),this.files[a]},z=function(a,b,c){var d,g=new k;return a._data instanceof k?(g.uncompressedSize=a._data.uncompressedSize,g.crc32=a._data.crc32,0===g.uncompressedSize||a.dir?(b=j.STORE,g.compressedContent="",g.crc32=0):a._data.compressionMethod===b.magic?g.compressedContent=a._data.getCompressedContent():(d=a._data.getContent(),g.compressedContent=b.compress(e.transformTo(b.compressInputType,d),c))):(d=q(a),d&&0!==d.length&&!a.dir||(b=j.STORE,d=""),g.uncompressedSize=d.length,g.crc32=f(d),g.compressedContent=b.compress(e.transformTo(b.compressInputType,d),c)),g.compressedSize=g.compressedContent.length,g.compressionMethod=b.magic,g},A=function(a,b){var c=a;return a||(c=b?16893:33204),(65535&c)<<16},B=function(a,b){return 63&(a||0)},C=function(a,b,c,d,h,i){var j,k,l,n,o=(c.compressedContent,i!==m.utf8encode),p=e.transformTo("string",i(b.name)),q=e.transformTo("string",m.utf8encode(b.name)),r=b.comment||"",s=e.transformTo("string",i(r)),u=e.transformTo("string",m.utf8encode(r)),v=q.length!==b.name.length,w=u.length!==r.length,x=b.options,y="",z="",C="";l=b._initialMetadata.dir!==b.dir?b.dir:x.dir,n=b._initialMetadata.date!==b.date?b.date:x.date;var D=0,E=0;l&&(D|=16),"UNIX"===h?(E=798,D|=A(b.unixPermissions,l)):(E=20,D|=B(b.dosPermissions,l)),j=n.getHours(),j<<=6,j|=n.getMinutes(),j<<=5,j|=n.getSeconds()/2,k=n.getFullYear()-1980,k<<=4,k|=n.getMonth()+1,k<<=5,k|=n.getDate(),v&&(z=t(1,1)+t(f(p),4)+q,y+="up"+t(z.length,2)+z),w&&(C=t(1,1)+t(this.crc32(s),4)+u,y+="uc"+t(C.length,2)+C);var F="";F+="\n\x00",F+=o||!v&&!w?"\x00\x00":"\x00\b",F+=c.compressionMethod,F+=t(j,2),F+=t(k,2),F+=t(c.crc32,4),F+=t(c.compressedSize,4),F+=t(c.uncompressedSize,4),F+=t(p.length,2),F+=t(y.length,2);var G=g.LOCAL_FILE_HEADER+F+p+y,H=g.CENTRAL_FILE_HEADER+t(E,2)+F+t(s.length,2)+"\x00\x00\x00\x00"+t(D,4)+t(d,4)+p+y+s;return{fileRecord:G,dirRecord:H,compressedObject:c}},D={load:function(a,b){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,f,g=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],f=new s(d.name,d._data,e.extend(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,f)&&g.push(f));return g},file:function(a,b,c){if(1===arguments.length){if(e.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.dir&&d.test(a)})}return this.filter(function(b,c){return!c.dir&&b===a})[0]||null}return a=this.root+a,v.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(e.isRegExp(a))return this.filter(function(b,c){return c.dir&&a.test(b)});var b=this.root+a,c=y.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b&&!b.dir)delete this.files[a];else for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;dh;h++)g[h]=h>=252?6:h>=248?5:h>=240?4:h>=224?3:h>=192?2:1;g[254]=g[254]=1;var i=function(a){var b,c,d,f,g,h=a.length,i=0;for(f=0;h>f;f++)c=a.charCodeAt(f),55296===(64512&c)&&h>f+1&&(d=a.charCodeAt(f+1),56320===(64512&d)&&(c=65536+(c-55296<<10)+(d-56320),f++)),i+=128>c?1:2048>c?2:65536>c?3:4;for(b=e.uint8array?new Uint8Array(i):new Array(i),g=0,f=0;i>g;f++)c=a.charCodeAt(f),55296===(64512&c)&&h>f+1&&(d=a.charCodeAt(f+1),56320===(64512&d)&&(c=65536+(c-55296<<10)+(d-56320),f++)),128>c?b[g++]=c:2048>c?(b[g++]=192|c>>>6,b[g++]=128|63&c):65536>c?(b[g++]=224|c>>>12,b[g++]=128|c>>>6&63,b[g++]=128|63&c):(b[g++]=240|c>>>18,b[g++]=128|c>>>12&63,b[g++]=128|c>>>6&63,b[g++]=128|63&c);return b},j=function(a,b){var c;for(b=b||a.length,b>a.length&&(b=a.length),c=b-1;c>=0&&128===(192&a[c]);)c--;return 0>c?b:0===c?b:c+g[a[c]]>b?c:b},k=function(a){var b,c,e,f,h=a.length,i=new Array(2*h);for(c=0,b=0;h>b;)if(e=a[b++],128>e)i[c++]=e;else if(f=g[e],f>4)i[c++]=65533,b+=f-1;else{for(e&=2===f?31:3===f?15:7;f>1&&h>b;)e=e<<6|63&a[b++],f--;f>1?i[c++]=65533:65536>e?i[c++]=e:(e-=65536,i[c++]=55296|e>>10&1023,i[c++]=56320|1023&e)}return i.length!==c&&(i.subarray?i=i.subarray(0,c):i.length=c),d.applyFromCharCode(i)};c.utf8encode=function(a){return e.nodebuffer?f(a,"utf-8"):i(a)},c.utf8decode=function(a){if(e.nodebuffer)return d.transformTo("nodebuffer",a).toString("utf-8");a=d.transformTo(e.uint8array?"uint8array":"array",a);for(var b=[],c=0,f=a.length,g=65536;f>c;){var h=j(a,Math.min(c+g,f));e.uint8array?b.push(k(a.subarray(c,h))):b.push(k(a.slice(c,h))),c=h}return b.join("")}},{"./nodeBuffer":12,"./support":18,"./utils":22}],22:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{"array"===f||"nodebuffer"===f?d.push(String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e)))):d.push(String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)},c.extend=function(){var a,b,c={};for(a=0;ae;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;aa){var b=!this.isSignature(0,j.LOCAL_FILE_HEADER);throw b?new Error("Can't find end of central directory : is this a zip file ? If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html"):new Error("Corrupted zip : can't find end of central directory")}this.reader.setIndex(a);var c=a;if(this.checkSignature(j.CENTRAL_DIRECTORY_END),this.readBlockEndOfCentral(),this.diskNumber===i.MAX_VALUE_16BITS||this.diskWithCentralDirStart===i.MAX_VALUE_16BITS||this.centralDirRecordsOnThisDisk===i.MAX_VALUE_16BITS||this.centralDirRecords===i.MAX_VALUE_16BITS||this.centralDirSize===i.MAX_VALUE_32BITS||this.centralDirOffset===i.MAX_VALUE_32BITS){if(this.zip64=!0,a=this.reader.lastIndexOfSignature(j.ZIP64_CENTRAL_DIRECTORY_LOCATOR),0>a)throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator");if(this.reader.setIndex(a),this.checkSignature(j.ZIP64_CENTRAL_DIRECTORY_LOCATOR),this.readBlockZip64EndOfCentralLocator(),!this.isSignature(this.relativeOffsetEndOfZip64CentralDir,j.ZIP64_CENTRAL_DIRECTORY_END)&&(this.relativeOffsetEndOfZip64CentralDir=this.reader.lastIndexOfSignature(j.ZIP64_CENTRAL_DIRECTORY_END),this.relativeOffsetEndOfZip64CentralDir<0))throw new Error("Corrupted zip : can't find the ZIP64 end of central directory");this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir),this.checkSignature(j.ZIP64_CENTRAL_DIRECTORY_END),this.readBlockZip64EndOfCentral()}var d=this.centralDirOffset+this.centralDirSize;this.zip64&&(d+=20,d+=12+this.zip64EndOfCentralSize);var e=c-d;if(e>0)this.isSignature(c,j.CENTRAL_FILE_HEADER)||(this.reader.zero=e);else if(0>e)throw new Error("Corrupted zip: missing "+Math.abs(e)+" bytes.")},prepareReader:function(a){var b=i.getTypeOf(a);if(i.checkSupport(b),"string"!==b||l.uint8array)if("nodebuffer"===b)this.reader=new f(a);else if(l.uint8array)this.reader=new g(i.transformTo("uint8array",a));else{if(!l.array)throw new Error("Unexpected error: unsupported type '"+b+"'");this.reader=new h(i.transformTo("array",a))}else this.reader=new e(a,this.loadOptions.optimizedBinaryString)},load:function(a){this.prepareReader(a),this.readEndOfCentral(),this.readCentralDir(),this.readLocalFiles()}},b.exports=d},{"./arrayReader":1,"./nodeBufferReader":13,"./object":14,"./signature":15,"./stringReader":16,"./support":18,"./uint8ArrayReader":19,"./utils":22,"./zipEntry":24}],24:[function(a,b,c){"use strict";function d(a,b){this.options=a,this.loadOptions=b}var e=a("./stringReader"),f=a("./utils"),g=a("./compressedObject"),h=a("./object"),i=a("./support"),j=0,k=3;d.prototype={isEncrypted:function(){return 1===(1&this.bitFlag)},useUTF8:function(){return 2048===(2048&this.bitFlag)},prepareCompressedContent:function(a,b,c){return function(){var d=a.index;a.setIndex(b);var e=a.readData(c);return a.setIndex(d),e}},prepareContent:function(a,b,c,d,e){return function(){var a=f.transformTo(d.uncompressInputType,this.getCompressedContent()),b=d.uncompress(a);if(b.length!==e)throw new Error("Bug : uncompressed data size mismatch");return b}},readLocalPart:function(a){var b,c;if(a.skip(22),this.fileNameLength=a.readInt(2),c=a.readInt(2),this.fileName=a.readData(this.fileNameLength),a.skip(c),-1==this.compressedSize||-1==this.uncompressedSize)throw new Error("Bug or corrupted zip : didn't get enough informations from the central directory (compressedSize == -1 || uncompressedSize == -1)");if(b=f.findCompression(this.compressionMethod),null===b)throw new Error("Corrupted zip : compression "+f.pretty(this.compressionMethod)+" unknown (inner file : "+f.transformTo("string",this.fileName)+")");if(this.decompressed=new g,this.decompressed.compressedSize=this.compressedSize,this.decompressed.uncompressedSize=this.uncompressedSize,this.decompressed.crc32=this.crc32,this.decompressed.compressionMethod=this.compressionMethod,this.decompressed.getCompressedContent=this.prepareCompressedContent(a,a.index,this.compressedSize,b),this.decompressed.getContent=this.prepareContent(a,a.index,this.compressedSize,b,this.uncompressedSize),this.loadOptions.checkCRC32&&(this.decompressed=f.transformTo("string",this.decompressed.getContent()), +h.crc32(this.decompressed)!==this.crc32))throw new Error("Corrupted zip : CRC32 mismatch")},readCentralPart:function(a){if(this.versionMadeBy=a.readInt(2),this.versionNeeded=a.readInt(2),this.bitFlag=a.readInt(2),this.compressionMethod=a.readString(2),this.date=a.readDate(),this.crc32=a.readInt(4),this.compressedSize=a.readInt(4),this.uncompressedSize=a.readInt(4),this.fileNameLength=a.readInt(2),this.extraFieldsLength=a.readInt(2),this.fileCommentLength=a.readInt(2),this.diskNumberStart=a.readInt(2),this.internalFileAttributes=a.readInt(2),this.externalFileAttributes=a.readInt(4),this.localHeaderOffset=a.readInt(4),this.isEncrypted())throw new Error("Encrypted zip are not supported");this.fileName=a.readData(this.fileNameLength),this.readExtraFields(a),this.parseZIP64ExtraField(a),this.fileComment=a.readData(this.fileCommentLength)},processAttributes:function(){this.unixPermissions=null,this.dosPermissions=null;var a=this.versionMadeBy>>8;this.dir=!!(16&this.externalFileAttributes),a===j&&(this.dosPermissions=63&this.externalFileAttributes),a===k&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(a){if(this.extraFields[1]){var b=new e(this.extraFields[1].value);this.uncompressedSize===f.MAX_VALUE_32BITS&&(this.uncompressedSize=b.readInt(8)),this.compressedSize===f.MAX_VALUE_32BITS&&(this.compressedSize=b.readInt(8)),this.localHeaderOffset===f.MAX_VALUE_32BITS&&(this.localHeaderOffset=b.readInt(8)),this.diskNumberStart===f.MAX_VALUE_32BITS&&(this.diskNumberStart=b.readInt(4))}},readExtraFields:function(a){var b,c,d,e=a.index;for(this.extraFields=this.extraFields||{};a.index0?b.windowBits=-b.windowBits:b.gzip&&b.windowBits>0&&b.windowBits<16&&(b.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new l,this.strm.avail_out=0;var c=h.deflateInit2(this.strm,b.level,b.method,b.windowBits,b.memLevel,b.strategy);if(c!==p)throw new Error(k[c]);b.header&&h.deflateSetHeader(this.strm,b.header)}function e(a,b){var c=new d(b);if(c.push(a,!0),c.err)throw c.msg;return c.result}function f(a,b){return b=b||{},b.raw=!0,e(a,b)}function g(a,b){return b=b||{},b.gzip=!0,e(a,b)}var h=a("./zlib/deflate"),i=a("./utils/common"),j=a("./utils/strings"),k=a("./zlib/messages"),l=a("./zlib/zstream"),m=Object.prototype.toString,n=0,o=4,p=0,q=1,r=2,s=-1,t=0,u=8;d.prototype.push=function(a,b){var c,d,e=this.strm,f=this.options.chunkSize;if(this.ended)return!1;d=b===~~b?b:b===!0?o:n,"string"==typeof a?e.input=j.string2buf(a):"[object ArrayBuffer]"===m.call(a)?e.input=new Uint8Array(a):e.input=a,e.next_in=0,e.avail_in=e.input.length;do{if(0===e.avail_out&&(e.output=new i.Buf8(f),e.next_out=0,e.avail_out=f),c=h.deflate(e,d),c!==q&&c!==p)return this.onEnd(c),this.ended=!0,!1;0!==e.avail_out&&(0!==e.avail_in||d!==o&&d!==r)||("string"===this.options.to?this.onData(j.buf2binstring(i.shrinkBuf(e.output,e.next_out))):this.onData(i.shrinkBuf(e.output,e.next_out)))}while((e.avail_in>0||0===e.avail_out)&&c!==q);return d===o?(c=h.deflateEnd(this.strm),this.onEnd(c),this.ended=!0,c===p):d===r?(this.onEnd(p),e.avail_out=0,!0):!0},d.prototype.onData=function(a){this.chunks.push(a)},d.prototype.onEnd=function(a){a===p&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=i.flattenChunks(this.chunks)),this.chunks=[],this.err=a,this.msg=this.strm.msg},c.Deflate=d,c.deflate=e,c.deflateRaw=f,c.gzip=g},{"./utils/common":28,"./utils/strings":29,"./zlib/deflate":33,"./zlib/messages":38,"./zlib/zstream":40}],27:[function(a,b,c){"use strict";function d(a){if(!(this instanceof d))return new d(a);this.options=h.assign({chunkSize:16384,windowBits:0,to:""},a||{});var b=this.options;b.raw&&b.windowBits>=0&&b.windowBits<16&&(b.windowBits=-b.windowBits,0===b.windowBits&&(b.windowBits=-15)),!(b.windowBits>=0&&b.windowBits<16)||a&&a.windowBits||(b.windowBits+=32),b.windowBits>15&&b.windowBits<48&&0===(15&b.windowBits)&&(b.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new l,this.strm.avail_out=0;var c=g.inflateInit2(this.strm,b.windowBits);if(c!==j.Z_OK)throw new Error(k[c]);this.header=new m,g.inflateGetHeader(this.strm,this.header)}function e(a,b){var c=new d(b);if(c.push(a,!0),c.err)throw c.msg;return c.result}function f(a,b){return b=b||{},b.raw=!0,e(a,b)}var g=a("./zlib/inflate"),h=a("./utils/common"),i=a("./utils/strings"),j=a("./zlib/constants"),k=a("./zlib/messages"),l=a("./zlib/zstream"),m=a("./zlib/gzheader"),n=Object.prototype.toString;d.prototype.push=function(a,b){var c,d,e,f,k,l=this.strm,m=this.options.chunkSize,o=!1;if(this.ended)return!1;d=b===~~b?b:b===!0?j.Z_FINISH:j.Z_NO_FLUSH,"string"==typeof a?l.input=i.binstring2buf(a):"[object ArrayBuffer]"===n.call(a)?l.input=new Uint8Array(a):l.input=a,l.next_in=0,l.avail_in=l.input.length;do{if(0===l.avail_out&&(l.output=new h.Buf8(m),l.next_out=0,l.avail_out=m),c=g.inflate(l,j.Z_NO_FLUSH),c===j.Z_BUF_ERROR&&o===!0&&(c=j.Z_OK,o=!1),c!==j.Z_STREAM_END&&c!==j.Z_OK)return this.onEnd(c),this.ended=!0,!1;l.next_out&&(0!==l.avail_out&&c!==j.Z_STREAM_END&&(0!==l.avail_in||d!==j.Z_FINISH&&d!==j.Z_SYNC_FLUSH)||("string"===this.options.to?(e=i.utf8border(l.output,l.next_out),f=l.next_out-e,k=i.buf2string(l.output,e),l.next_out=f,l.avail_out=m-f,f&&h.arraySet(l.output,l.output,e,f,0),this.onData(k)):this.onData(h.shrinkBuf(l.output,l.next_out)))),0===l.avail_in&&0===l.avail_out&&(o=!0)}while((l.avail_in>0||0===l.avail_out)&&c!==j.Z_STREAM_END);return c===j.Z_STREAM_END&&(d=j.Z_FINISH),d===j.Z_FINISH?(c=g.inflateEnd(this.strm),this.onEnd(c),this.ended=!0,c===j.Z_OK):d===j.Z_SYNC_FLUSH?(this.onEnd(j.Z_OK),l.avail_out=0,!0):!0},d.prototype.onData=function(a){this.chunks.push(a)},d.prototype.onEnd=function(a){a===j.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=h.flattenChunks(this.chunks)),this.chunks=[],this.err=a,this.msg=this.strm.msg},c.Inflate=d,c.inflate=e,c.inflateRaw=f,c.ungzip=e},{"./utils/common":28,"./utils/strings":29,"./zlib/constants":31,"./zlib/gzheader":34,"./zlib/inflate":36,"./zlib/messages":38,"./zlib/zstream":40}],28:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;c.assign=function(a){for(var b=Array.prototype.slice.call(arguments,1);b.length;){var c=b.shift();if(c){if("object"!=typeof c)throw new TypeError(c+"must be non-object");for(var d in c)c.hasOwnProperty(d)&&(a[d]=c[d])}}return a},c.shrinkBuf=function(a,b){return a.length===b?a:a.subarray?a.subarray(0,b):(a.length=b,a)};var e={arraySet:function(a,b,c,d,e){if(b.subarray&&a.subarray)return void a.set(b.subarray(c,c+d),e);for(var f=0;d>f;f++)a[e+f]=b[c+f]},flattenChunks:function(a){var b,c,d,e,f,g;for(d=0,b=0,c=a.length;c>b;b++)d+=a[b].length;for(g=new Uint8Array(d),e=0,b=0,c=a.length;c>b;b++)f=a[b],g.set(f,e),e+=f.length;return g}},f={arraySet:function(a,b,c,d,e){for(var f=0;d>f;f++)a[e+f]=b[c+f]},flattenChunks:function(a){return[].concat.apply([],a)}};c.setTyped=function(a){a?(c.Buf8=Uint8Array,c.Buf16=Uint16Array,c.Buf32=Int32Array,c.assign(c,e)):(c.Buf8=Array,c.Buf16=Array,c.Buf32=Array,c.assign(c,f))},c.setTyped(d)},{}],29:[function(a,b,c){"use strict";function d(a,b){if(65537>b&&(a.subarray&&g||!a.subarray&&f))return String.fromCharCode.apply(null,e.shrinkBuf(a,b));for(var c="",d=0;b>d;d++)c+=String.fromCharCode(a[d]);return c}var e=a("./common"),f=!0,g=!0;try{String.fromCharCode.apply(null,[0])}catch(h){f=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(h){g=!1}for(var i=new e.Buf8(256),j=0;256>j;j++)i[j]=j>=252?6:j>=248?5:j>=240?4:j>=224?3:j>=192?2:1;i[254]=i[254]=1,c.string2buf=function(a){var b,c,d,f,g,h=a.length,i=0;for(f=0;h>f;f++)c=a.charCodeAt(f),55296===(64512&c)&&h>f+1&&(d=a.charCodeAt(f+1),56320===(64512&d)&&(c=65536+(c-55296<<10)+(d-56320),f++)),i+=128>c?1:2048>c?2:65536>c?3:4;for(b=new e.Buf8(i),g=0,f=0;i>g;f++)c=a.charCodeAt(f),55296===(64512&c)&&h>f+1&&(d=a.charCodeAt(f+1),56320===(64512&d)&&(c=65536+(c-55296<<10)+(d-56320),f++)),128>c?b[g++]=c:2048>c?(b[g++]=192|c>>>6,b[g++]=128|63&c):65536>c?(b[g++]=224|c>>>12,b[g++]=128|c>>>6&63,b[g++]=128|63&c):(b[g++]=240|c>>>18,b[g++]=128|c>>>12&63,b[g++]=128|c>>>6&63,b[g++]=128|63&c);return b},c.buf2binstring=function(a){return d(a,a.length)},c.binstring2buf=function(a){for(var b=new e.Buf8(a.length),c=0,d=b.length;d>c;c++)b[c]=a.charCodeAt(c);return b},c.buf2string=function(a,b){var c,e,f,g,h=b||a.length,j=new Array(2*h);for(e=0,c=0;h>c;)if(f=a[c++],128>f)j[e++]=f;else if(g=i[f],g>4)j[e++]=65533,c+=g-1;else{for(f&=2===g?31:3===g?15:7;g>1&&h>c;)f=f<<6|63&a[c++],g--;g>1?j[e++]=65533:65536>f?j[e++]=f:(f-=65536,j[e++]=55296|f>>10&1023,j[e++]=56320|1023&f)}return d(j,e)},c.utf8border=function(a,b){var c;for(b=b||a.length,b>a.length&&(b=a.length),c=b-1;c>=0&&128===(192&a[c]);)c--;return 0>c?b:0===c?b:c+i[a[c]]>b?c:b}},{"./common":28}],30:[function(a,b,c){"use strict";function d(a,b,c,d){for(var e=65535&a|0,f=a>>>16&65535|0,g=0;0!==c;){g=c>2e3?2e3:c,c-=g;do e=e+b[d++]|0,f=f+e|0;while(--g);e%=65521,f%=65521}return e|f<<16|0}b.exports=d},{}],31:[function(a,b,c){"use strict";b.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],32:[function(a,b,c){"use strict";function d(){for(var a,b=[],c=0;256>c;c++){a=c;for(var d=0;8>d;d++)a=1&a?3988292384^a>>>1:a>>>1;b[c]=a}return b}function e(a,b,c,d){var e=f,g=d+c;a^=-1;for(var h=d;g>h;h++)a=a>>>8^e[255&(a^b[h])];return-1^a}var f=d();b.exports=e},{}],33:[function(a,b,c){"use strict";function d(a,b){return a.msg=H[b],b}function e(a){return(a<<1)-(a>4?9:0)}function f(a){for(var b=a.length;--b>=0;)a[b]=0}function g(a){var b=a.state,c=b.pending;c>a.avail_out&&(c=a.avail_out),0!==c&&(D.arraySet(a.output,b.pending_buf,b.pending_out,c,a.next_out),a.next_out+=c,b.pending_out+=c,a.total_out+=c,a.avail_out-=c,b.pending-=c,0===b.pending&&(b.pending_out=0))}function h(a,b){E._tr_flush_block(a,a.block_start>=0?a.block_start:-1,a.strstart-a.block_start,b),a.block_start=a.strstart,g(a.strm)}function i(a,b){a.pending_buf[a.pending++]=b}function j(a,b){a.pending_buf[a.pending++]=b>>>8&255,a.pending_buf[a.pending++]=255&b}function k(a,b,c,d){var e=a.avail_in;return e>d&&(e=d),0===e?0:(a.avail_in-=e,D.arraySet(b,a.input,a.next_in,e,c),1===a.state.wrap?a.adler=F(a.adler,b,e,c):2===a.state.wrap&&(a.adler=G(a.adler,b,e,c)),a.next_in+=e,a.total_in+=e,e)}function l(a,b){var c,d,e=a.max_chain_length,f=a.strstart,g=a.prev_length,h=a.nice_match,i=a.strstart>a.w_size-ka?a.strstart-(a.w_size-ka):0,j=a.window,k=a.w_mask,l=a.prev,m=a.strstart+ja,n=j[f+g-1],o=j[f+g];a.prev_length>=a.good_match&&(e>>=2),h>a.lookahead&&(h=a.lookahead);do if(c=b,j[c+g]===o&&j[c+g-1]===n&&j[c]===j[f]&&j[++c]===j[f+1]){f+=2,c++;do;while(j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&m>f);if(d=ja-(m-f),f=m-ja,d>g){if(a.match_start=b,g=d,d>=h)break;n=j[f+g-1],o=j[f+g]}}while((b=l[b&k])>i&&0!==--e);return g<=a.lookahead?g:a.lookahead}function m(a){var b,c,d,e,f,g=a.w_size;do{if(e=a.window_size-a.lookahead-a.strstart,a.strstart>=g+(g-ka)){D.arraySet(a.window,a.window,g,g,0),a.match_start-=g,a.strstart-=g,a.block_start-=g,c=a.hash_size,b=c;do d=a.head[--b],a.head[b]=d>=g?d-g:0;while(--c);c=g,b=c;do d=a.prev[--b],a.prev[b]=d>=g?d-g:0;while(--c);e+=g}if(0===a.strm.avail_in)break;if(c=k(a.strm,a.window,a.strstart+a.lookahead,e),a.lookahead+=c,a.lookahead+a.insert>=ia)for(f=a.strstart-a.insert,a.ins_h=a.window[f],a.ins_h=(a.ins_h<a.pending_buf_size-5&&(c=a.pending_buf_size-5);;){if(a.lookahead<=1){if(m(a),0===a.lookahead&&b===I)return ta;if(0===a.lookahead)break}a.strstart+=a.lookahead,a.lookahead=0;var d=a.block_start+c;if((0===a.strstart||a.strstart>=d)&&(a.lookahead=a.strstart-d,a.strstart=d,h(a,!1),0===a.strm.avail_out))return ta;if(a.strstart-a.block_start>=a.w_size-ka&&(h(a,!1),0===a.strm.avail_out))return ta}return a.insert=0,b===L?(h(a,!0),0===a.strm.avail_out?va:wa):a.strstart>a.block_start&&(h(a,!1),0===a.strm.avail_out)?ta:ta}function o(a,b){for(var c,d;;){if(a.lookahead=ia&&(a.ins_h=(a.ins_h<=ia)if(d=E._tr_tally(a,a.strstart-a.match_start,a.match_length-ia),a.lookahead-=a.match_length,a.match_length<=a.max_lazy_match&&a.lookahead>=ia){a.match_length--;do a.strstart++,a.ins_h=(a.ins_h<=ia&&(a.ins_h=(a.ins_h<4096)&&(a.match_length=ia-1)),a.prev_length>=ia&&a.match_length<=a.prev_length){e=a.strstart+a.lookahead-ia,d=E._tr_tally(a,a.strstart-1-a.prev_match,a.prev_length-ia),a.lookahead-=a.prev_length-1,a.prev_length-=2;do++a.strstart<=e&&(a.ins_h=(a.ins_h<=ia&&a.strstart>0&&(e=a.strstart-1,d=g[e],d===g[++e]&&d===g[++e]&&d===g[++e])){f=a.strstart+ja;do;while(d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&f>e);a.match_length=ja-(f-e),a.match_length>a.lookahead&&(a.match_length=a.lookahead)}if(a.match_length>=ia?(c=E._tr_tally(a,1,a.match_length-ia),a.lookahead-=a.match_length,a.strstart+=a.match_length,a.match_length=0):(c=E._tr_tally(a,0,a.window[a.strstart]),a.lookahead--,a.strstart++),c&&(h(a,!1),0===a.strm.avail_out))return ta}return a.insert=0,b===L?(h(a,!0),0===a.strm.avail_out?va:wa):a.last_lit&&(h(a,!1),0===a.strm.avail_out)?ta:ua}function r(a,b){for(var c;;){if(0===a.lookahead&&(m(a),0===a.lookahead)){if(b===I)return ta;break}if(a.match_length=0,c=E._tr_tally(a,0,a.window[a.strstart]),a.lookahead--,a.strstart++,c&&(h(a,!1),0===a.strm.avail_out))return ta}return a.insert=0,b===L?(h(a,!0),0===a.strm.avail_out?va:wa):a.last_lit&&(h(a,!1),0===a.strm.avail_out)?ta:ua}function s(a,b,c,d,e){this.good_length=a,this.max_lazy=b,this.nice_length=c,this.max_chain=d,this.func=e}function t(a){a.window_size=2*a.w_size,f(a.head),a.max_lazy_match=C[a.level].max_lazy,a.good_match=C[a.level].good_length,a.nice_match=C[a.level].nice_length,a.max_chain_length=C[a.level].max_chain,a.strstart=0,a.block_start=0,a.lookahead=0,a.insert=0,a.match_length=a.prev_length=ia-1,a.match_available=0,a.ins_h=0}function u(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=Z,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new D.Buf16(2*ga),this.dyn_dtree=new D.Buf16(2*(2*ea+1)),this.bl_tree=new D.Buf16(2*(2*fa+1)),f(this.dyn_ltree),f(this.dyn_dtree),f(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new D.Buf16(ha+1),this.heap=new D.Buf16(2*da+1),f(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new D.Buf16(2*da+1),f(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function v(a){var b;return a&&a.state?(a.total_in=a.total_out=0,a.data_type=Y,b=a.state,b.pending=0,b.pending_out=0,b.wrap<0&&(b.wrap=-b.wrap),b.status=b.wrap?ma:ra,a.adler=2===b.wrap?0:1,b.last_flush=I,E._tr_init(b),N):d(a,P)}function w(a){var b=v(a);return b===N&&t(a.state),b}function x(a,b){return a&&a.state?2!==a.state.wrap?P:(a.state.gzhead=b,N):P}function y(a,b,c,e,f,g){if(!a)return P;var h=1;if(b===S&&(b=6),0>e?(h=0,e=-e):e>15&&(h=2,e-=16),1>f||f>$||c!==Z||8>e||e>15||0>b||b>9||0>g||g>W)return d(a,P);8===e&&(e=9);var i=new u;return a.state=i,i.strm=a,i.wrap=h,i.gzhead=null,i.w_bits=e,i.w_size=1<>1,i.l_buf=3*i.lit_bufsize,i.level=b,i.strategy=g,i.method=c,w(a)}function z(a,b){return y(a,b,Z,_,aa,X)}function A(a,b){var c,h,k,l;if(!a||!a.state||b>M||0>b)return a?d(a,P):P;if(h=a.state,!a.output||!a.input&&0!==a.avail_in||h.status===sa&&b!==L)return d(a,0===a.avail_out?R:P);if(h.strm=a,c=h.last_flush,h.last_flush=b,h.status===ma)if(2===h.wrap)a.adler=0,i(h,31),i(h,139),i(h,8),h.gzhead?(i(h,(h.gzhead.text?1:0)+(h.gzhead.hcrc?2:0)+(h.gzhead.extra?4:0)+(h.gzhead.name?8:0)+(h.gzhead.comment?16:0)),i(h,255&h.gzhead.time),i(h,h.gzhead.time>>8&255),i(h,h.gzhead.time>>16&255),i(h,h.gzhead.time>>24&255),i(h,9===h.level?2:h.strategy>=U||h.level<2?4:0),i(h,255&h.gzhead.os),h.gzhead.extra&&h.gzhead.extra.length&&(i(h,255&h.gzhead.extra.length),i(h,h.gzhead.extra.length>>8&255)),h.gzhead.hcrc&&(a.adler=G(a.adler,h.pending_buf,h.pending,0)),h.gzindex=0,h.status=na):(i(h,0),i(h,0),i(h,0),i(h,0),i(h,0),i(h,9===h.level?2:h.strategy>=U||h.level<2?4:0),i(h,xa),h.status=ra);else{var m=Z+(h.w_bits-8<<4)<<8,n=-1;n=h.strategy>=U||h.level<2?0:h.level<6?1:6===h.level?2:3,m|=n<<6,0!==h.strstart&&(m|=la),m+=31-m%31,h.status=ra,j(h,m),0!==h.strstart&&(j(h,a.adler>>>16),j(h,65535&a.adler)),a.adler=1}if(h.status===na)if(h.gzhead.extra){for(k=h.pending;h.gzindex<(65535&h.gzhead.extra.length)&&(h.pending!==h.pending_buf_size||(h.gzhead.hcrc&&h.pending>k&&(a.adler=G(a.adler,h.pending_buf,h.pending-k,k)),g(a),k=h.pending,h.pending!==h.pending_buf_size));)i(h,255&h.gzhead.extra[h.gzindex]),h.gzindex++;h.gzhead.hcrc&&h.pending>k&&(a.adler=G(a.adler,h.pending_buf,h.pending-k,k)),h.gzindex===h.gzhead.extra.length&&(h.gzindex=0,h.status=oa)}else h.status=oa;if(h.status===oa)if(h.gzhead.name){k=h.pending;do{if(h.pending===h.pending_buf_size&&(h.gzhead.hcrc&&h.pending>k&&(a.adler=G(a.adler,h.pending_buf,h.pending-k,k)),g(a),k=h.pending,h.pending===h.pending_buf_size)){l=1;break}l=h.gzindexk&&(a.adler=G(a.adler,h.pending_buf,h.pending-k,k)),0===l&&(h.gzindex=0,h.status=pa)}else h.status=pa;if(h.status===pa)if(h.gzhead.comment){k=h.pending;do{if(h.pending===h.pending_buf_size&&(h.gzhead.hcrc&&h.pending>k&&(a.adler=G(a.adler,h.pending_buf,h.pending-k,k)),g(a),k=h.pending,h.pending===h.pending_buf_size)){l=1;break}l=h.gzindexk&&(a.adler=G(a.adler,h.pending_buf,h.pending-k,k)),0===l&&(h.status=qa)}else h.status=qa;if(h.status===qa&&(h.gzhead.hcrc?(h.pending+2>h.pending_buf_size&&g(a),h.pending+2<=h.pending_buf_size&&(i(h,255&a.adler),i(h,a.adler>>8&255),a.adler=0,h.status=ra)):h.status=ra),0!==h.pending){if(g(a),0===a.avail_out)return h.last_flush=-1,N}else if(0===a.avail_in&&e(b)<=e(c)&&b!==L)return d(a,R);if(h.status===sa&&0!==a.avail_in)return d(a,R);if(0!==a.avail_in||0!==h.lookahead||b!==I&&h.status!==sa){var o=h.strategy===U?r(h,b):h.strategy===V?q(h,b):C[h.level].func(h,b);if(o!==va&&o!==wa||(h.status=sa),o===ta||o===va)return 0===a.avail_out&&(h.last_flush=-1),N;if(o===ua&&(b===J?E._tr_align(h):b!==M&&(E._tr_stored_block(h,0,0,!1),b===K&&(f(h.head),0===h.lookahead&&(h.strstart=0,h.block_start=0,h.insert=0))),g(a),0===a.avail_out))return h.last_flush=-1,N}return b!==L?N:h.wrap<=0?O:(2===h.wrap?(i(h,255&a.adler),i(h,a.adler>>8&255),i(h,a.adler>>16&255),i(h,a.adler>>24&255),i(h,255&a.total_in),i(h,a.total_in>>8&255),i(h,a.total_in>>16&255),i(h,a.total_in>>24&255)):(j(h,a.adler>>>16),j(h,65535&a.adler)),g(a),h.wrap>0&&(h.wrap=-h.wrap),0!==h.pending?N:O)}function B(a){var b;return a&&a.state?(b=a.state.status,b!==ma&&b!==na&&b!==oa&&b!==pa&&b!==qa&&b!==ra&&b!==sa?d(a,P):(a.state=null,b===ra?d(a,Q):N)):P}var C,D=a("../utils/common"),E=a("./trees"),F=a("./adler32"),G=a("./crc32"),H=a("./messages"),I=0,J=1,K=3,L=4,M=5,N=0,O=1,P=-2,Q=-3,R=-5,S=-1,T=1,U=2,V=3,W=4,X=0,Y=2,Z=8,$=9,_=15,aa=8,ba=29,ca=256,da=ca+1+ba,ea=30,fa=19,ga=2*da+1,ha=15,ia=3,ja=258,ka=ja+ia+1,la=32,ma=42,na=69,oa=73,pa=91,qa=103,ra=113,sa=666,ta=1,ua=2,va=3,wa=4,xa=3;C=[new s(0,0,0,0,n),new s(4,4,8,4,o),new s(4,5,16,8,o),new s(4,6,32,32,o),new s(4,4,16,16,p),new s(8,16,32,32,p),new s(8,16,128,128,p),new s(8,32,128,256,p),new s(32,128,258,1024,p),new s(32,258,258,4096,p)],c.deflateInit=z,c.deflateInit2=y,c.deflateReset=w,c.deflateResetKeep=v,c.deflateSetHeader=x,c.deflate=A,c.deflateEnd=B,c.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":28,"./adler32":30,"./crc32":32,"./messages":38,"./trees":39}],34:[function(a,b,c){"use strict";function d(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}b.exports=d},{}],35:[function(a,b,c){"use strict";var d=30,e=12;b.exports=function(a,b){var c,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C;c=a.state,f=a.next_in,B=a.input,g=f+(a.avail_in-5),h=a.next_out,C=a.output,i=h-(b-a.avail_out),j=h+(a.avail_out-257),k=c.dmax,l=c.wsize,m=c.whave,n=c.wnext,o=c.window,p=c.hold,q=c.bits,r=c.lencode,s=c.distcode,t=(1<q&&(p+=B[f++]<>>24,p>>>=w,q-=w,w=v>>>16&255,0===w)C[h++]=65535&v;else{if(!(16&w)){if(0===(64&w)){v=r[(65535&v)+(p&(1<q&&(p+=B[f++]<>>=w,q-=w),15>q&&(p+=B[f++]<>>24,p>>>=w,q-=w,w=v>>>16&255,!(16&w)){if(0===(64&w)){v=s[(65535&v)+(p&(1<q&&(p+=B[f++]<q&&(p+=B[f++]<k){a.msg="invalid distance too far back",c.mode=d;break a}if(p>>>=w,q-=w,w=h-i,y>w){if(w=y-w,w>m&&c.sane){a.msg="invalid distance too far back",c.mode=d;break a}if(z=0,A=o,0===n){if(z+=l-w,x>w){x-=w;do C[h++]=o[z++];while(--w);z=h-y,A=C}}else if(w>n){if(z+=l+n-w,w-=n,x>w){x-=w;do C[h++]=o[z++];while(--w);if(z=0,x>n){w=n,x-=w;do C[h++]=o[z++];while(--w);z=h-y,A=C}}}else if(z+=n-w,x>w){x-=w;do C[h++]=o[z++];while(--w);z=h-y,A=C}for(;x>2;)C[h++]=A[z++],C[h++]=A[z++],C[h++]=A[z++],x-=3;x&&(C[h++]=A[z++],x>1&&(C[h++]=A[z++]))}else{z=h-y;do C[h++]=C[z++],C[h++]=C[z++],C[h++]=C[z++],x-=3;while(x>2);x&&(C[h++]=C[z++],x>1&&(C[h++]=C[z++]))}break}}break}}while(g>f&&j>h);x=q>>3,f-=x,q-=x<<3,p&=(1<f?5+(g-f):5-(f-g),a.avail_out=j>h?257+(j-h):257-(h-j),c.hold=p,c.bits=q}},{}],36:[function(a,b,c){"use strict";function d(a){return(a>>>24&255)+(a>>>8&65280)+((65280&a)<<8)+((255&a)<<24)}function e(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new r.Buf16(320),this.work=new r.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function f(a){var b;return a&&a.state?(b=a.state,a.total_in=a.total_out=b.total=0,a.msg="",b.wrap&&(a.adler=1&b.wrap),b.mode=K,b.last=0,b.havedict=0,b.dmax=32768,b.head=null,b.hold=0,b.bits=0,b.lencode=b.lendyn=new r.Buf32(oa),b.distcode=b.distdyn=new r.Buf32(pa),b.sane=1,b.back=-1,C):F}function g(a){var b;return a&&a.state?(b=a.state,b.wsize=0,b.whave=0,b.wnext=0,f(a)):F}function h(a,b){var c,d;return a&&a.state?(d=a.state,0>b?(c=0,b=-b):(c=(b>>4)+1,48>b&&(b&=15)),b&&(8>b||b>15)?F:(null!==d.window&&d.wbits!==b&&(d.window=null),d.wrap=c,d.wbits=b,g(a))):F}function i(a,b){var c,d;return a?(d=new e,a.state=d,d.window=null,c=h(a,b),c!==C&&(a.state=null),c):F}function j(a){return i(a,ra)}function k(a){if(sa){var b;for(p=new r.Buf32(512),q=new r.Buf32(32),b=0;144>b;)a.lens[b++]=8;for(;256>b;)a.lens[b++]=9;for(;280>b;)a.lens[b++]=7;for(;288>b;)a.lens[b++]=8;for(v(x,a.lens,0,288,p,0,a.work,{bits:9}),b=0;32>b;)a.lens[b++]=5;v(y,a.lens,0,32,q,0,a.work,{bits:5}),sa=!1}a.lencode=p,a.lenbits=9,a.distcode=q,a.distbits=5}function l(a,b,c,d){var e,f=a.state;return null===f.window&&(f.wsize=1<=f.wsize?(r.arraySet(f.window,b,c-f.wsize,f.wsize,0),f.wnext=0,f.whave=f.wsize):(e=f.wsize-f.wnext,e>d&&(e=d),r.arraySet(f.window,b,c-d,e,f.wnext),d-=e,d?(r.arraySet(f.window,b,c-d,d,0),f.wnext=d,f.whave=f.wsize):(f.wnext+=e,f.wnext===f.wsize&&(f.wnext=0),f.whaven;){if(0===i)break a;i--,m+=e[g++]<>>8&255,c.check=t(c.check,Ba,2,0),m=0,n=0,c.mode=L;break}if(c.flags=0,c.head&&(c.head.done=!1),!(1&c.wrap)||(((255&m)<<8)+(m>>8))%31){a.msg="incorrect header check",c.mode=la;break}if((15&m)!==J){a.msg="unknown compression method",c.mode=la;break}if(m>>>=4,n-=4,wa=(15&m)+8,0===c.wbits)c.wbits=wa;else if(wa>c.wbits){a.msg="invalid window size",c.mode=la;break}c.dmax=1<n;){if(0===i)break a;i--,m+=e[g++]<>8&1),512&c.flags&&(Ba[0]=255&m,Ba[1]=m>>>8&255,c.check=t(c.check,Ba,2,0)),m=0,n=0,c.mode=M;case M:for(;32>n;){if(0===i)break a;i--,m+=e[g++]<>>8&255,Ba[2]=m>>>16&255,Ba[3]=m>>>24&255,c.check=t(c.check,Ba,4,0)),m=0,n=0,c.mode=N;case N:for(;16>n;){if(0===i)break a;i--,m+=e[g++]<>8),512&c.flags&&(Ba[0]=255&m,Ba[1]=m>>>8&255,c.check=t(c.check,Ba,2,0)),m=0,n=0,c.mode=O;case O:if(1024&c.flags){for(;16>n;){if(0===i)break a;i--,m+=e[g++]<>>8&255,c.check=t(c.check,Ba,2,0)),m=0,n=0}else c.head&&(c.head.extra=null);c.mode=P;case P:if(1024&c.flags&&(q=c.length,q>i&&(q=i),q&&(c.head&&(wa=c.head.extra_len-c.length,c.head.extra||(c.head.extra=new Array(c.head.extra_len)),r.arraySet(c.head.extra,e,g,q,wa)),512&c.flags&&(c.check=t(c.check,e,q,g)),i-=q,g+=q,c.length-=q),c.length))break a;c.length=0,c.mode=Q;case Q:if(2048&c.flags){if(0===i)break a;q=0;do wa=e[g+q++],c.head&&wa&&c.length<65536&&(c.head.name+=String.fromCharCode(wa));while(wa&&i>q);if(512&c.flags&&(c.check=t(c.check,e,q,g)),i-=q,g+=q,wa)break a}else c.head&&(c.head.name=null);c.length=0,c.mode=R;case R:if(4096&c.flags){if(0===i)break a;q=0;do wa=e[g+q++],c.head&&wa&&c.length<65536&&(c.head.comment+=String.fromCharCode(wa));while(wa&&i>q);if(512&c.flags&&(c.check=t(c.check,e,q,g)),i-=q,g+=q,wa)break a}else c.head&&(c.head.comment=null);c.mode=S;case S:if(512&c.flags){for(;16>n;){ +if(0===i)break a;i--,m+=e[g++]<>9&1,c.head.done=!0),a.adler=c.check=0,c.mode=V;break;case T:for(;32>n;){if(0===i)break a;i--,m+=e[g++]<>>=7&n,n-=7&n,c.mode=ia;break}for(;3>n;){if(0===i)break a;i--,m+=e[g++]<>>=1,n-=1,3&m){case 0:c.mode=X;break;case 1:if(k(c),c.mode=ba,b===B){m>>>=2,n-=2;break a}break;case 2:c.mode=$;break;case 3:a.msg="invalid block type",c.mode=la}m>>>=2,n-=2;break;case X:for(m>>>=7&n,n-=7&n;32>n;){if(0===i)break a;i--,m+=e[g++]<>>16^65535)){a.msg="invalid stored block lengths",c.mode=la;break}if(c.length=65535&m,m=0,n=0,c.mode=Y,b===B)break a;case Y:c.mode=Z;case Z:if(q=c.length){if(q>i&&(q=i),q>j&&(q=j),0===q)break a;r.arraySet(f,e,g,q,h),i-=q,g+=q,j-=q,h+=q,c.length-=q;break}c.mode=V;break;case $:for(;14>n;){if(0===i)break a;i--,m+=e[g++]<>>=5,n-=5,c.ndist=(31&m)+1,m>>>=5,n-=5,c.ncode=(15&m)+4,m>>>=4,n-=4,c.nlen>286||c.ndist>30){a.msg="too many length or distance symbols",c.mode=la;break}c.have=0,c.mode=_;case _:for(;c.haven;){if(0===i)break a;i--,m+=e[g++]<>>=3,n-=3}for(;c.have<19;)c.lens[Ca[c.have++]]=0;if(c.lencode=c.lendyn,c.lenbits=7,ya={bits:c.lenbits},xa=v(w,c.lens,0,19,c.lencode,0,c.work,ya),c.lenbits=ya.bits,xa){a.msg="invalid code lengths set",c.mode=la;break}c.have=0,c.mode=aa;case aa:for(;c.have>>24,ra=Aa>>>16&255,sa=65535&Aa,!(n>=qa);){if(0===i)break a;i--,m+=e[g++]<sa)m>>>=qa,n-=qa,c.lens[c.have++]=sa;else{if(16===sa){for(za=qa+2;za>n;){if(0===i)break a;i--,m+=e[g++]<>>=qa,n-=qa,0===c.have){a.msg="invalid bit length repeat",c.mode=la;break}wa=c.lens[c.have-1],q=3+(3&m),m>>>=2,n-=2}else if(17===sa){for(za=qa+3;za>n;){if(0===i)break a;i--,m+=e[g++]<>>=qa,n-=qa,wa=0,q=3+(7&m),m>>>=3,n-=3}else{for(za=qa+7;za>n;){if(0===i)break a;i--,m+=e[g++]<>>=qa,n-=qa,wa=0,q=11+(127&m),m>>>=7,n-=7}if(c.have+q>c.nlen+c.ndist){a.msg="invalid bit length repeat",c.mode=la;break}for(;q--;)c.lens[c.have++]=wa}}if(c.mode===la)break;if(0===c.lens[256]){a.msg="invalid code -- missing end-of-block",c.mode=la;break}if(c.lenbits=9,ya={bits:c.lenbits},xa=v(x,c.lens,0,c.nlen,c.lencode,0,c.work,ya),c.lenbits=ya.bits,xa){a.msg="invalid literal/lengths set",c.mode=la;break}if(c.distbits=6,c.distcode=c.distdyn,ya={bits:c.distbits},xa=v(y,c.lens,c.nlen,c.ndist,c.distcode,0,c.work,ya),c.distbits=ya.bits,xa){a.msg="invalid distances set",c.mode=la;break}if(c.mode=ba,b===B)break a;case ba:c.mode=ca;case ca:if(i>=6&&j>=258){a.next_out=h,a.avail_out=j,a.next_in=g,a.avail_in=i,c.hold=m,c.bits=n,u(a,p),h=a.next_out,f=a.output,j=a.avail_out,g=a.next_in,e=a.input,i=a.avail_in,m=c.hold,n=c.bits,c.mode===V&&(c.back=-1);break}for(c.back=0;Aa=c.lencode[m&(1<>>24,ra=Aa>>>16&255,sa=65535&Aa,!(n>=qa);){if(0===i)break a;i--,m+=e[g++]<>ta)],qa=Aa>>>24,ra=Aa>>>16&255,sa=65535&Aa,!(n>=ta+qa);){if(0===i)break a;i--,m+=e[g++]<>>=ta,n-=ta,c.back+=ta}if(m>>>=qa,n-=qa,c.back+=qa,c.length=sa,0===ra){c.mode=ha;break}if(32&ra){c.back=-1,c.mode=V;break}if(64&ra){a.msg="invalid literal/length code",c.mode=la;break}c.extra=15&ra,c.mode=da;case da:if(c.extra){for(za=c.extra;za>n;){if(0===i)break a;i--,m+=e[g++]<>>=c.extra,n-=c.extra,c.back+=c.extra}c.was=c.length,c.mode=ea;case ea:for(;Aa=c.distcode[m&(1<>>24,ra=Aa>>>16&255,sa=65535&Aa,!(n>=qa);){if(0===i)break a;i--,m+=e[g++]<>ta)],qa=Aa>>>24,ra=Aa>>>16&255,sa=65535&Aa,!(n>=ta+qa);){if(0===i)break a;i--,m+=e[g++]<>>=ta,n-=ta,c.back+=ta}if(m>>>=qa,n-=qa,c.back+=qa,64&ra){a.msg="invalid distance code",c.mode=la;break}c.offset=sa,c.extra=15&ra,c.mode=fa;case fa:if(c.extra){for(za=c.extra;za>n;){if(0===i)break a;i--,m+=e[g++]<>>=c.extra,n-=c.extra,c.back+=c.extra}if(c.offset>c.dmax){a.msg="invalid distance too far back",c.mode=la;break}c.mode=ga;case ga:if(0===j)break a;if(q=p-j,c.offset>q){if(q=c.offset-q,q>c.whave&&c.sane){a.msg="invalid distance too far back",c.mode=la;break}q>c.wnext?(q-=c.wnext,oa=c.wsize-q):oa=c.wnext-q,q>c.length&&(q=c.length),pa=c.window}else pa=f,oa=h-c.offset,q=c.length;q>j&&(q=j),j-=q,c.length-=q;do f[h++]=pa[oa++];while(--q);0===c.length&&(c.mode=ca);break;case ha:if(0===j)break a;f[h++]=c.length,j--,c.mode=ca;break;case ia:if(c.wrap){for(;32>n;){if(0===i)break a;i--,m|=e[g++]<n;){if(0===i)break a;i--,m+=e[g++]<=D;D++)P[D]=0;for(E=0;o>E;E++)P[b[c+E]]++;for(H=C,G=e;G>=1&&0===P[G];G--);if(H>G&&(H=G),0===G)return p[q++]=20971520,p[q++]=20971520,s.bits=1,0;for(F=1;G>F&&0===P[F];F++);for(F>H&&(H=F),K=1,D=1;e>=D;D++)if(K<<=1,K-=P[D],0>K)return-1;if(K>0&&(a===h||1!==G))return-1;for(Q[1]=0,D=1;e>D;D++)Q[D+1]=Q[D]+P[D];for(E=0;o>E;E++)0!==b[c+E]&&(r[Q[b[c+E]]++]=E);if(a===h?(N=R=r,y=19):a===i?(N=k,O-=257,R=l,S-=257,y=256):(N=m,R=n,y=-1),M=0,E=0,D=F,x=q,I=H,J=0,v=-1,L=1<f||a===j&&L>g)return 1;for(var T=0;;){T++,z=D-J,r[E]y?(A=R[S+r[E]],B=N[O+r[E]]):(A=96,B=0),t=1<>J)+u]=z<<24|A<<16|B|0;while(0!==u);for(t=1<>=1;if(0!==t?(M&=t-1,M+=t):M=0,E++,0===--P[D]){if(D===G)break;D=b[c+r[E]]}if(D>H&&(M&w)!==v){for(0===J&&(J=H),x+=F,I=D-J,K=1<I+J&&(K-=P[I+J],!(0>=K));)I++,K<<=1;if(L+=1<f||a===j&&L>g)return 1;v=M&w,p[v]=H<<24|I<<16|x-q|0}}return 0!==M&&(p[x+M]=D-J<<24|64<<16|0),s.bits=H,0}},{"../utils/common":28}],38:[function(a,b,c){"use strict";b.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],39:[function(a,b,c){"use strict";function d(a){for(var b=a.length;--b>=0;)a[b]=0}function e(a,b,c,d,e){this.static_tree=a,this.extra_bits=b,this.extra_base=c,this.elems=d,this.max_length=e,this.has_stree=a&&a.length}function f(a,b){this.dyn_tree=a,this.max_code=0,this.stat_desc=b}function g(a){return 256>a?ia[a]:ia[256+(a>>>7)]}function h(a,b){a.pending_buf[a.pending++]=255&b,a.pending_buf[a.pending++]=b>>>8&255}function i(a,b,c){a.bi_valid>X-c?(a.bi_buf|=b<>X-a.bi_valid,a.bi_valid+=c-X):(a.bi_buf|=b<>>=1,c<<=1;while(--b>0);return c>>>1}function l(a){16===a.bi_valid?(h(a,a.bi_buf),a.bi_buf=0,a.bi_valid=0):a.bi_valid>=8&&(a.pending_buf[a.pending++]=255&a.bi_buf,a.bi_buf>>=8,a.bi_valid-=8)}function m(a,b){var c,d,e,f,g,h,i=b.dyn_tree,j=b.max_code,k=b.stat_desc.static_tree,l=b.stat_desc.has_stree,m=b.stat_desc.extra_bits,n=b.stat_desc.extra_base,o=b.stat_desc.max_length,p=0;for(f=0;W>=f;f++)a.bl_count[f]=0;for(i[2*a.heap[a.heap_max]+1]=0,c=a.heap_max+1;V>c;c++)d=a.heap[c],f=i[2*i[2*d+1]+1]+1,f>o&&(f=o,p++),i[2*d+1]=f,d>j||(a.bl_count[f]++,g=0,d>=n&&(g=m[d-n]),h=i[2*d],a.opt_len+=h*(f+g),l&&(a.static_len+=h*(k[2*d+1]+g)));if(0!==p){do{for(f=o-1;0===a.bl_count[f];)f--;a.bl_count[f]--,a.bl_count[f+1]+=2,a.bl_count[o]--,p-=2}while(p>0);for(f=o;0!==f;f--)for(d=a.bl_count[f];0!==d;)e=a.heap[--c],e>j||(i[2*e+1]!==f&&(a.opt_len+=(f-i[2*e+1])*i[2*e],i[2*e+1]=f),d--)}}function n(a,b,c){var d,e,f=new Array(W+1),g=0;for(d=1;W>=d;d++)f[d]=g=g+c[d-1]<<1;for(e=0;b>=e;e++){var h=a[2*e+1];0!==h&&(a[2*e]=k(f[h]++,h))}}function o(){var a,b,c,d,f,g=new Array(W+1);for(c=0,d=0;Q-1>d;d++)for(ka[d]=c,a=0;a<1<d;d++)for(la[d]=f,a=0;a<1<>=7;T>d;d++)for(la[d]=f<<7,a=0;a<1<=b;b++)g[b]=0;for(a=0;143>=a;)ga[2*a+1]=8,a++,g[8]++;for(;255>=a;)ga[2*a+1]=9,a++,g[9]++;for(;279>=a;)ga[2*a+1]=7,a++,g[7]++;for(;287>=a;)ga[2*a+1]=8,a++,g[8]++;for(n(ga,S+1,g),a=0;T>a;a++)ha[2*a+1]=5,ha[2*a]=k(a,5);ma=new e(ga,ba,R+1,S,W),na=new e(ha,ca,0,T,W),oa=new e(new Array(0),da,0,U,Y)}function p(a){var b;for(b=0;S>b;b++)a.dyn_ltree[2*b]=0;for(b=0;T>b;b++)a.dyn_dtree[2*b]=0;for(b=0;U>b;b++)a.bl_tree[2*b]=0;a.dyn_ltree[2*Z]=1,a.opt_len=a.static_len=0,a.last_lit=a.matches=0}function q(a){a.bi_valid>8?h(a,a.bi_buf):a.bi_valid>0&&(a.pending_buf[a.pending++]=a.bi_buf),a.bi_buf=0,a.bi_valid=0}function r(a,b,c,d){q(a),d&&(h(a,c),h(a,~c)),G.arraySet(a.pending_buf,a.window,b,c,a.pending),a.pending+=c}function s(a,b,c,d){var e=2*b,f=2*c;return a[e]c;c++)0!==f[2*c]?(a.heap[++a.heap_len]=j=c,a.depth[c]=0):f[2*c+1]=0;for(;a.heap_len<2;)e=a.heap[++a.heap_len]=2>j?++j:0,f[2*e]=1,a.depth[e]=0,a.opt_len--,h&&(a.static_len-=g[2*e+1]);for(b.max_code=j,c=a.heap_len>>1;c>=1;c--)t(a,f,c);e=i;do c=a.heap[1],a.heap[1]=a.heap[a.heap_len--],t(a,f,1),d=a.heap[1],a.heap[--a.heap_max]=c,a.heap[--a.heap_max]=d,f[2*e]=f[2*c]+f[2*d],a.depth[e]=(a.depth[c]>=a.depth[d]?a.depth[c]:a.depth[d])+1,f[2*c+1]=f[2*d+1]=e,a.heap[1]=e++,t(a,f,1);while(a.heap_len>=2);a.heap[--a.heap_max]=a.heap[1],m(a,b),n(f,j,a.bl_count)}function w(a,b,c){var d,e,f=-1,g=b[1],h=0,i=7,j=4;for(0===g&&(i=138,j=3),b[2*(c+1)+1]=65535,d=0;c>=d;d++)e=g,g=b[2*(d+1)+1],++hh?a.bl_tree[2*e]+=h:0!==e?(e!==f&&a.bl_tree[2*e]++,a.bl_tree[2*$]++):10>=h?a.bl_tree[2*_]++:a.bl_tree[2*aa]++,h=0,f=e,0===g?(i=138,j=3):e===g?(i=6,j=3):(i=7,j=4))}function x(a,b,c){var d,e,f=-1,g=b[1],h=0,k=7,l=4;for(0===g&&(k=138,l=3),d=0;c>=d;d++)if(e=g,g=b[2*(d+1)+1],!(++hh){do j(a,e,a.bl_tree);while(0!==--h)}else 0!==e?(e!==f&&(j(a,e,a.bl_tree),h--),j(a,$,a.bl_tree),i(a,h-3,2)):10>=h?(j(a,_,a.bl_tree),i(a,h-3,3)):(j(a,aa,a.bl_tree),i(a,h-11,7));h=0,f=e,0===g?(k=138,l=3):e===g?(k=6,l=3):(k=7,l=4)}}function y(a){var b;for(w(a,a.dyn_ltree,a.l_desc.max_code),w(a,a.dyn_dtree,a.d_desc.max_code),v(a,a.bl_desc),b=U-1;b>=3&&0===a.bl_tree[2*ea[b]+1];b--);return a.opt_len+=3*(b+1)+5+5+4,b}function z(a,b,c,d){var e;for(i(a,b-257,5),i(a,c-1,5),i(a,d-4,4),e=0;d>e;e++)i(a,a.bl_tree[2*ea[e]+1],3);x(a,a.dyn_ltree,b-1),x(a,a.dyn_dtree,c-1)}function A(a){var b,c=4093624447;for(b=0;31>=b;b++,c>>>=1)if(1&c&&0!==a.dyn_ltree[2*b])return I;if(0!==a.dyn_ltree[18]||0!==a.dyn_ltree[20]||0!==a.dyn_ltree[26])return J;for(b=32;R>b;b++)if(0!==a.dyn_ltree[2*b])return J;return I}function B(a){pa||(o(),pa=!0),a.l_desc=new f(a.dyn_ltree,ma),a.d_desc=new f(a.dyn_dtree,na),a.bl_desc=new f(a.bl_tree,oa),a.bi_buf=0,a.bi_valid=0,p(a)}function C(a,b,c,d){i(a,(L<<1)+(d?1:0),3),r(a,b,c,!0)}function D(a){i(a,M<<1,3),j(a,Z,ga),l(a)}function E(a,b,c,d){var e,f,g=0;a.level>0?(a.strm.data_type===K&&(a.strm.data_type=A(a)),v(a,a.l_desc),v(a,a.d_desc),g=y(a),e=a.opt_len+3+7>>>3,f=a.static_len+3+7>>>3,e>=f&&(e=f)):e=f=c+5,e>=c+4&&-1!==b?C(a,b,c,d):a.strategy===H||f===e?(i(a,(M<<1)+(d?1:0),3),u(a,ga,ha)):(i(a,(N<<1)+(d?1:0),3),z(a,a.l_desc.max_code+1,a.d_desc.max_code+1,g+1),u(a,a.dyn_ltree,a.dyn_dtree)),p(a),d&&q(a)}function F(a,b,c){return a.pending_buf[a.d_buf+2*a.last_lit]=b>>>8&255,a.pending_buf[a.d_buf+2*a.last_lit+1]=255&b,a.pending_buf[a.l_buf+a.last_lit]=255&c,a.last_lit++,0===b?a.dyn_ltree[2*c]++:(a.matches++,b--,a.dyn_ltree[2*(ja[c]+R+1)]++,a.dyn_dtree[2*g(b)]++),a.last_lit===a.lit_bufsize-1}var G=a("../utils/common"),H=4,I=0,J=1,K=2,L=0,M=1,N=2,O=3,P=258,Q=29,R=256,S=R+1+Q,T=30,U=19,V=2*S+1,W=15,X=16,Y=7,Z=256,$=16,_=17,aa=18,ba=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],ca=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],da=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],ea=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],fa=512,ga=new Array(2*(S+2));d(ga);var ha=new Array(2*T);d(ha);var ia=new Array(fa);d(ia);var ja=new Array(P-O+1);d(ja);var ka=new Array(Q);d(ka);var la=new Array(T);d(la);var ma,na,oa,pa=!1;c._tr_init=B,c._tr_stored_block=C,c._tr_flush_block=E,c._tr_tally=F,c._tr_align=D},{"../utils/common":28}],40:[function(a,b,c){"use strict";function d(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}b.exports=d},{}]},{},[10])(10)}); \ No newline at end of file diff --git a/cps/static/js/compress/jszip_epub.min.js b/cps/static/js/compress/jszip_epub.min.js new file mode 100644 index 000000000..ff4cfd5e8 --- /dev/null +++ b/cps/static/js/compress/jszip_epub.min.js @@ -0,0 +1,13 @@ +/*! + +JSZip v3.10.1 - A JavaScript class for generating and reading zip files + + +(c) 2009-2016 Stuart Knightley +Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/main/LICENSE.markdown. + +JSZip uses the library pako released under the MIT license : +https://github.com/nodeca/pako/blob/main/LICENSE +*/ + +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=e()}}(function(){return function s(a,o,h){function u(r,e){if(!o[r]){if(!a[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(l)return l(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var i=o[r]={exports:{}};a[r][0].call(i.exports,function(e){var t=a[r][1][e];return u(t||e)},i,i.exports,s,a,o,h)}return o[r].exports}for(var l="function"==typeof require&&require,e=0;e>2,s=(3&t)<<4|r>>4,a=1>6:64,o=2>4,r=(15&i)<<4|(s=p.indexOf(e.charAt(o++)))>>2,n=(3&s)<<6|(a=p.indexOf(e.charAt(o++))),l[h++]=t,64!==s&&(l[h++]=r),64!==a&&(l[h++]=n);return l}},{"./support":30,"./utils":32}],2:[function(e,t,r){"use strict";var n=e("./external"),i=e("./stream/DataWorker"),s=e("./stream/Crc32Probe"),a=e("./stream/DataLengthProbe");function o(e,t,r,n,i){this.compressedSize=e,this.uncompressedSize=t,this.crc32=r,this.compression=n,this.compressedContent=i}o.prototype={getContentWorker:function(){var e=new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),t=this;return e.on("end",function(){if(this.streamInfo.data_length!==t.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),e},getCompressedWorker:function(){return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(e,t,r){return e.pipe(new s).pipe(new a("uncompressedSize")).pipe(t.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",t)},t.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(e,t,r){"use strict";var n=e("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(){return new n("STORE compression")},uncompressWorker:function(){return new n("STORE decompression")}},r.DEFLATE=e("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(e,t,r){"use strict";var n=e("./utils");var o=function(){for(var e,t=[],r=0;r<256;r++){e=r;for(var n=0;n<8;n++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t){return void 0!==e&&e.length?"string"!==n.getTypeOf(e)?function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return-1^e}(0|t,e,e.length,0):function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t.charCodeAt(a))];return-1^e}(0|t,e,e.length,0):0}},{"./utils":32}],5:[function(e,t,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(e,t,r){"use strict";var n=null;n="undefined"!=typeof Promise?Promise:e("lie"),t.exports={Promise:n}},{lie:37}],7:[function(e,t,r){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,i=e("pako"),s=e("./utils"),a=e("./stream/GenericWorker"),o=n?"uint8array":"array";function h(e,t){a.call(this,"FlateWorker/"+e),this._pako=null,this._pakoAction=e,this._pakoOptions=t,this.meta={}}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(e){this.meta=e.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,e.data),!1)},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},h.prototype._createPako=function(){this._pako=new i[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var t=this;this._pako.onData=function(e){t.push({data:e,meta:t.meta})}},r.compressWorker=function(e){return new h("Deflate",e)},r.uncompressWorker=function(){return new h("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(e,t,r){"use strict";function A(e,t){var r,n="";for(r=0;r>>=8;return n}function n(e,t,r,n,i,s){var a,o,h=e.file,u=e.compression,l=s!==O.utf8encode,f=I.transformTo("string",s(h.name)),c=I.transformTo("string",O.utf8encode(h.name)),d=h.comment,p=I.transformTo("string",s(d)),m=I.transformTo("string",O.utf8encode(d)),_=c.length!==h.name.length,g=m.length!==d.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};t&&!r||(x.crc32=e.crc32,x.compressedSize=e.compressedSize,x.uncompressedSize=e.uncompressedSize);var S=0;t&&(S|=8),l||!_&&!g||(S|=2048);var z=0,C=0;w&&(z|=16),"UNIX"===i?(C=798,z|=function(e,t){var r=e;return e||(r=t?16893:33204),(65535&r)<<16}(h.unixPermissions,w)):(C=20,z|=function(e){return 63&(e||0)}(h.dosPermissions)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(v=A(1,1)+A(B(f),4)+c,b+="up"+A(v.length,2)+v),g&&(y=A(1,1)+A(B(p),4)+m,b+="uc"+A(y.length,2)+y);var E="";return E+="\n\0",E+=A(S,2),E+=u.magic,E+=A(a,2),E+=A(o,2),E+=A(x.crc32,4),E+=A(x.compressedSize,4),E+=A(x.uncompressedSize,4),E+=A(f.length,2),E+=A(b.length,2),{fileRecord:R.LOCAL_FILE_HEADER+E+f+b,dirRecord:R.CENTRAL_FILE_HEADER+A(C,2)+E+A(p.length,2)+"\0\0\0\0"+A(z,4)+A(n,4)+f+b+p}}var I=e("../utils"),i=e("../stream/GenericWorker"),O=e("../utf8"),B=e("../crc32"),R=e("../signature");function s(e,t,r,n){i.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=t,this.zipPlatform=r,this.encodeFileName=n,this.streamFiles=e,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}I.inherits(s,i),s.prototype.push=function(e){var t=e.meta.percent||0,r=this.entriesCount,n=this._sources.length;this.accumulate?this.contentBuffer.push(e):(this.bytesWritten+=e.data.length,i.prototype.push.call(this,{data:e.data,meta:{currentFile:this.currentFile,percent:r?(t+100*(r-n-1))/r:100}}))},s.prototype.openedSource=function(e){this.currentSourceOffset=this.bytesWritten,this.currentFile=e.file.name;var t=this.streamFiles&&!e.file.dir;if(t){var r=n(e,t,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}})}else this.accumulate=!0},s.prototype.closedSource=function(e){this.accumulate=!1;var t=this.streamFiles&&!e.file.dir,r=n(e,t,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(r.dirRecord),t)this.push({data:function(e){return R.DATA_DESCRIPTOR+A(e.crc32,4)+A(e.compressedSize,4)+A(e.uncompressedSize,4)}(e),meta:{percent:100}});else for(this.push({data:r.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},s.prototype.flush=function(){for(var e=this.bytesWritten,t=0;t=this.index;t--)r=(r<<8)+this.byteAt(t);return this.index+=e,r},readString:function(e){return n.transformTo("string",this.readData(e))},readData:function(){},lastIndexOfSignature:function(){},readAndCheckSignature:function(){},readDate:function(){var e=this.readInt(4);return new Date(Date.UTC(1980+(e>>25&127),(e>>21&15)-1,e>>16&31,e>>11&31,e>>5&63,(31&e)<<1))}},t.exports=i},{"../utils":32}],19:[function(e,t,r){"use strict";var n=e("./Uint8ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(e,t,r){"use strict";var n=e("./DataReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.byteAt=function(e){return this.data.charCodeAt(this.zero+e)},i.prototype.lastIndexOfSignature=function(e){return this.data.lastIndexOf(e)-this.zero},i.prototype.readAndCheckSignature=function(e){return e===this.readData(4)},i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./DataReader":18}],21:[function(e,t,r){"use strict";var n=e("./ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){if(this.checkOffset(e),0===e)return new Uint8Array(0);var t=this.data.subarray(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./ArrayReader":17}],22:[function(e,t,r){"use strict";var n=e("../utils"),i=e("../support"),s=e("./ArrayReader"),a=e("./StringReader"),o=e("./NodeBufferReader"),h=e("./Uint8ArrayReader");t.exports=function(e){var t=n.getTypeOf(e);return n.checkSupport(t),"string"!==t||i.uint8array?"nodebuffer"===t?new o(e):i.uint8array?new h(n.transformTo("uint8array",e)):new s(n.transformTo("array",e)):new a(e)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(e,t,r){"use strict";r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b"},{}],24:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../utils");function s(e){n.call(this,"ConvertWorker to "+e),this.destType=e}i.inherits(s,n),s.prototype.processChunk=function(e){this.push({data:i.transformTo(this.destType,e.data),meta:e.meta})},t.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../crc32");function s(){n.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}e("../utils").inherits(s,n),s.prototype.processChunk=function(e){this.streamInfo.crc32=i(e.data,this.streamInfo.crc32||0),this.push(e)},t.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataLengthProbe for "+e),this.propName=e,this.withStreamInfo(e,0)}n.inherits(s,i),s.prototype.processChunk=function(e){if(e){var t=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=t+e.data.length}i.prototype.processChunk.call(this,e)},t.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataWorker");var t=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,e.then(function(e){t.dataIsReady=!0,t.data=e,t.max=e&&e.length||0,t.type=n.getTypeOf(e),t.isPaused||t._tickAndRepeat()},function(e){t.error(e)})}n.inherits(s,i),s.prototype.cleanUp=function(){i.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!i.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,n.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(n.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var e=null,t=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":e=this.data.substring(this.index,t);break;case"uint8array":e=this.data.subarray(this.index,t);break;case"array":case"nodebuffer":e=this.data.slice(this.index,t)}return this.index=t,this.push({data:e,meta:{percent:this.max?this.index/this.max*100:0}})},t.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(e,t,r){"use strict";function n(e){this.name=e||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}n.prototype={push:function(e){this.emit("data",e)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(e){this.emit("error",e)}return!0},error:function(e){return!this.isFinished&&(this.isPaused?this.generatedError=e:(this.isFinished=!0,this.emit("error",e),this.previous&&this.previous.error(e),this.cleanUp()),!0)},on:function(e,t){return this._listeners[e].push(t),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(e,t){if(this._listeners[e])for(var r=0;r "+e:e}},t.exports=n},{}],29:[function(e,t,r){"use strict";var h=e("../utils"),i=e("./ConvertWorker"),s=e("./GenericWorker"),u=e("../base64"),n=e("../support"),a=e("../external"),o=null;if(n.nodestream)try{o=e("../nodejs/NodejsStreamOutputAdapter")}catch(e){}function l(e,o){return new a.Promise(function(t,r){var n=[],i=e._internalType,s=e._outputType,a=e._mimeType;e.on("data",function(e,t){n.push(e),o&&o(t)}).on("error",function(e){n=[],r(e)}).on("end",function(){try{var e=function(e,t,r){switch(e){case"blob":return h.newBlob(h.transformTo("arraybuffer",t),r);case"base64":return u.encode(t);default:return h.transformTo(e,t)}}(s,function(e,t){var r,n=0,i=null,s=0;for(r=0;r>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t}(e)},s.utf8decode=function(e){return h.nodebuffer?o.transformTo("nodebuffer",e).toString("utf-8"):function(e){var t,r,n,i,s=e.length,a=new Array(2*s);for(t=r=0;t>10&1023,a[r++]=56320|1023&n)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(e=o.transformTo(h.uint8array?"uint8array":"array",e))},o.inherits(a,n),a.prototype.processChunk=function(e){var t=o.transformTo(h.uint8array?"uint8array":"array",e.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=t;(t=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),t.set(r,this.leftOver.length)}else t=this.leftOver.concat(t);this.leftOver=null}var n=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}(t),i=t;n!==t.length&&(h.uint8array?(i=t.subarray(0,n),this.leftOver=t.subarray(n,t.length)):(i=t.slice(0,n),this.leftOver=t.slice(n,t.length))),this.push({data:s.utf8decode(i),meta:e.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(l,n),l.prototype.processChunk=function(e){this.push({data:s.utf8encode(e.data),meta:e.meta})},s.Utf8EncodeWorker=l},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(e,t,a){"use strict";var o=e("./support"),h=e("./base64"),r=e("./nodejsUtils"),u=e("./external");function n(e){return e}function l(e,t){for(var r=0;r>8;this.dir=!!(16&this.externalFileAttributes),0==e&&(this.dosPermissions=63&this.externalFileAttributes),3==e&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(){if(this.extraFields[1]){var e=n(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4))}},readExtraFields:function(e){var t,r,n,i=e.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});e.index+4>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t},r.buf2binstring=function(e){return l(e,e.length)},r.binstring2buf=function(e){for(var t=new h.Buf8(e.length),r=0,n=t.length;r>10&1023,o[n++]=56320|1023&i)}return l(o,n)},r.utf8border=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}},{"./common":41}],43:[function(e,t,r){"use strict";t.exports=function(e,t,r,n){for(var i=65535&e|0,s=e>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return-1^e}},{}],46:[function(e,t,r){"use strict";var h,c=e("../utils/common"),u=e("./trees"),d=e("./adler32"),p=e("./crc32"),n=e("./messages"),l=0,f=4,m=0,_=-2,g=-1,b=4,i=2,v=8,y=9,s=286,a=30,o=19,w=2*s+1,k=15,x=3,S=258,z=S+x+1,C=42,E=113,A=1,I=2,O=3,B=4;function R(e,t){return e.msg=n[t],t}function T(e){return(e<<1)-(4e.avail_out&&(r=e.avail_out),0!==r&&(c.arraySet(e.output,t.pending_buf,t.pending_out,r,e.next_out),e.next_out+=r,t.pending_out+=r,e.total_out+=r,e.avail_out-=r,t.pending-=r,0===t.pending&&(t.pending_out=0))}function N(e,t){u._tr_flush_block(e,0<=e.block_start?e.block_start:-1,e.strstart-e.block_start,t),e.block_start=e.strstart,F(e.strm)}function U(e,t){e.pending_buf[e.pending++]=t}function P(e,t){e.pending_buf[e.pending++]=t>>>8&255,e.pending_buf[e.pending++]=255&t}function L(e,t){var r,n,i=e.max_chain_length,s=e.strstart,a=e.prev_length,o=e.nice_match,h=e.strstart>e.w_size-z?e.strstart-(e.w_size-z):0,u=e.window,l=e.w_mask,f=e.prev,c=e.strstart+S,d=u[s+a-1],p=u[s+a];e.prev_length>=e.good_match&&(i>>=2),o>e.lookahead&&(o=e.lookahead);do{if(u[(r=t)+a]===p&&u[r+a-1]===d&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&sh&&0!=--i);return a<=e.lookahead?a:e.lookahead}function j(e){var t,r,n,i,s,a,o,h,u,l,f=e.w_size;do{if(i=e.window_size-e.lookahead-e.strstart,e.strstart>=f+(f-z)){for(c.arraySet(e.window,e.window,f,f,0),e.match_start-=f,e.strstart-=f,e.block_start-=f,t=r=e.hash_size;n=e.head[--t],e.head[t]=f<=n?n-f:0,--r;);for(t=r=f;n=e.prev[--t],e.prev[t]=f<=n?n-f:0,--r;);i+=f}if(0===e.strm.avail_in)break;if(a=e.strm,o=e.window,h=e.strstart+e.lookahead,u=i,l=void 0,l=a.avail_in,u=x)for(s=e.strstart-e.insert,e.ins_h=e.window[s],e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x)if(n=u._tr_tally(e,e.strstart-e.match_start,e.match_length-x),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=x){for(e.match_length--;e.strstart++,e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x&&e.match_length<=e.prev_length){for(i=e.strstart+e.lookahead-x,n=u._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-x),e.lookahead-=e.prev_length-1,e.prev_length-=2;++e.strstart<=i&&(e.ins_h=(e.ins_h<e.pending_buf_size-5&&(r=e.pending_buf_size-5);;){if(e.lookahead<=1){if(j(e),0===e.lookahead&&t===l)return A;if(0===e.lookahead)break}e.strstart+=e.lookahead,e.lookahead=0;var n=e.block_start+r;if((0===e.strstart||e.strstart>=n)&&(e.lookahead=e.strstart-n,e.strstart=n,N(e,!1),0===e.strm.avail_out))return A;if(e.strstart-e.block_start>=e.w_size-z&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):(e.strstart>e.block_start&&(N(e,!1),e.strm.avail_out),A)}),new M(4,4,8,4,Z),new M(4,5,16,8,Z),new M(4,6,32,32,Z),new M(4,4,16,16,W),new M(8,16,32,32,W),new M(8,16,128,128,W),new M(8,32,128,256,W),new M(32,128,258,1024,W),new M(32,258,258,4096,W)],r.deflateInit=function(e,t){return Y(e,t,v,15,8,0)},r.deflateInit2=Y,r.deflateReset=K,r.deflateResetKeep=G,r.deflateSetHeader=function(e,t){return e&&e.state?2!==e.state.wrap?_:(e.state.gzhead=t,m):_},r.deflate=function(e,t){var r,n,i,s;if(!e||!e.state||5>8&255),U(n,n.gzhead.time>>16&255),U(n,n.gzhead.time>>24&255),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,255&n.gzhead.os),n.gzhead.extra&&n.gzhead.extra.length&&(U(n,255&n.gzhead.extra.length),U(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=p(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=69):(U(n,0),U(n,0),U(n,0),U(n,0),U(n,0),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,3),n.status=E);else{var a=v+(n.w_bits-8<<4)<<8;a|=(2<=n.strategy||n.level<2?0:n.level<6?1:6===n.level?2:3)<<6,0!==n.strstart&&(a|=32),a+=31-a%31,n.status=E,P(n,a),0!==n.strstart&&(P(n,e.adler>>>16),P(n,65535&e.adler)),e.adler=1}if(69===n.status)if(n.gzhead.extra){for(i=n.pending;n.gzindex<(65535&n.gzhead.extra.length)&&(n.pending!==n.pending_buf_size||(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending!==n.pending_buf_size));)U(n,255&n.gzhead.extra[n.gzindex]),n.gzindex++;n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=73)}else n.status=73;if(73===n.status)if(n.gzhead.name){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.gzindex=0,n.status=91)}else n.status=91;if(91===n.status)if(n.gzhead.comment){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.status=103)}else n.status=103;if(103===n.status&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&F(e),n.pending+2<=n.pending_buf_size&&(U(n,255&e.adler),U(n,e.adler>>8&255),e.adler=0,n.status=E)):n.status=E),0!==n.pending){if(F(e),0===e.avail_out)return n.last_flush=-1,m}else if(0===e.avail_in&&T(t)<=T(r)&&t!==f)return R(e,-5);if(666===n.status&&0!==e.avail_in)return R(e,-5);if(0!==e.avail_in||0!==n.lookahead||t!==l&&666!==n.status){var o=2===n.strategy?function(e,t){for(var r;;){if(0===e.lookahead&&(j(e),0===e.lookahead)){if(t===l)return A;break}if(e.match_length=0,r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):3===n.strategy?function(e,t){for(var r,n,i,s,a=e.window;;){if(e.lookahead<=S){if(j(e),e.lookahead<=S&&t===l)return A;if(0===e.lookahead)break}if(e.match_length=0,e.lookahead>=x&&0e.lookahead&&(e.match_length=e.lookahead)}if(e.match_length>=x?(r=u._tr_tally(e,1,e.match_length-x),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):h[n.level].func(n,t);if(o!==O&&o!==B||(n.status=666),o===A||o===O)return 0===e.avail_out&&(n.last_flush=-1),m;if(o===I&&(1===t?u._tr_align(n):5!==t&&(u._tr_stored_block(n,0,0,!1),3===t&&(D(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),F(e),0===e.avail_out))return n.last_flush=-1,m}return t!==f?m:n.wrap<=0?1:(2===n.wrap?(U(n,255&e.adler),U(n,e.adler>>8&255),U(n,e.adler>>16&255),U(n,e.adler>>24&255),U(n,255&e.total_in),U(n,e.total_in>>8&255),U(n,e.total_in>>16&255),U(n,e.total_in>>24&255)):(P(n,e.adler>>>16),P(n,65535&e.adler)),F(e),0=r.w_size&&(0===s&&(D(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new c.Buf8(r.w_size),c.arraySet(u,t,l-r.w_size,r.w_size,0),t=u,l=r.w_size),a=e.avail_in,o=e.next_in,h=e.input,e.avail_in=l,e.next_in=0,e.input=t,j(r);r.lookahead>=x;){for(n=r.strstart,i=r.lookahead-(x-1);r.ins_h=(r.ins_h<>>=y=v>>>24,p-=y,0===(y=v>>>16&255))C[s++]=65535&v;else{if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(d&(1<>>=y,p-=y),p<15&&(d+=z[n++]<>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(d&(1<>>=y,p-=y,(y=s-a)>3,d&=(1<<(p-=w<<3))-1,e.next_in=n,e.next_out=s,e.avail_in=n>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=P,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new I.Buf32(n),t.distcode=t.distdyn=new I.Buf32(i),t.sane=1,t.back=-1,N):U}function o(e){var t;return e&&e.state?((t=e.state).wsize=0,t.whave=0,t.wnext=0,a(e)):U}function h(e,t){var r,n;return e&&e.state?(n=e.state,t<0?(r=0,t=-t):(r=1+(t>>4),t<48&&(t&=15)),t&&(t<8||15=s.wsize?(I.arraySet(s.window,t,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(n<(i=s.wsize-s.wnext)&&(i=n),I.arraySet(s.window,t,r-n,i,s.wnext),(n-=i)?(I.arraySet(s.window,t,r-n,n,0),s.wnext=n,s.whave=s.wsize):(s.wnext+=i,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){e.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){e.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){e.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>>8&255,r.check=B(r.check,E,2,0)),l=u=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(d=r.length)&&(d=o),d&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,n,s,d,k)),512&r.flags&&(r.check=B(r.check,n,d,s)),o-=d,s+=d,r.length-=d),r.length))break e;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break e;for(d=0;k=n[s+d++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&d>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break e;o--,u+=n[s++]<>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==t)break;u>>>=2,l-=2;break e;case 2:r.mode=17;break;case 3:e.msg="invalid block type",r.mode=30}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break e;o--,u+=n[s++]<>>16^65535)){e.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===t)break e;case 15:r.mode=16;case 16:if(d=r.length){if(o>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286>>=3,l-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=_,l-=_,r.lens[r.have++]=b;else{if(16===b){for(z=_+2;l>>=_,l-=_,0===r.have){e.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],d=3+(3&u),u>>>=2,l-=2}else if(17===b){for(z=_+3;l>>=_)),u>>>=3,l-=3}else{for(z=_+7;l>>=_)),u>>>=7,l-=7}if(r.have+d>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=30;break}for(;d--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){e.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===t)break e;case 20:r.mode=21;case 21:if(6<=o&&258<=h){e.next_out=a,e.avail_out=h,e.next_in=s,e.avail_in=o,r.hold=u,r.bits=l,R(e,c),a=e.next_out,i=e.output,h=e.avail_out,s=e.next_in,n=e.input,o=e.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){e.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,64&g){e.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break e;if(d=c-h,r.offset>d){if((d=r.offset-d)>r.whave&&r.sane){e.msg="invalid distance too far back",r.mode=30;break}p=d>r.wnext?(d-=r.wnext,r.wsize-d):r.wnext-d,d>r.length&&(d=r.length),m=r.window}else m=i,p=a-r.offset,d=r.length;for(hd?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=t[r+a[v]]}if(k>>7)]}function U(e,t){e.pending_buf[e.pending++]=255&t,e.pending_buf[e.pending++]=t>>>8&255}function P(e,t,r){e.bi_valid>d-r?(e.bi_buf|=t<>d-e.bi_valid,e.bi_valid+=r-d):(e.bi_buf|=t<>>=1,r<<=1,0<--t;);return r>>>1}function Z(e,t,r){var n,i,s=new Array(g+1),a=0;for(n=1;n<=g;n++)s[n]=a=a+r[n-1]<<1;for(i=0;i<=t;i++){var o=e[2*i+1];0!==o&&(e[2*i]=j(s[o]++,o))}}function W(e){var t;for(t=0;t>1;1<=r;r--)G(e,s,r);for(i=h;r=e.heap[1],e.heap[1]=e.heap[e.heap_len--],G(e,s,1),n=e.heap[1],e.heap[--e.heap_max]=r,e.heap[--e.heap_max]=n,s[2*i]=s[2*r]+s[2*n],e.depth[i]=(e.depth[r]>=e.depth[n]?e.depth[r]:e.depth[n])+1,s[2*r+1]=s[2*n+1]=i,e.heap[1]=i++,G(e,s,1),2<=e.heap_len;);e.heap[--e.heap_max]=e.heap[1],function(e,t){var r,n,i,s,a,o,h=t.dyn_tree,u=t.max_code,l=t.stat_desc.static_tree,f=t.stat_desc.has_stree,c=t.stat_desc.extra_bits,d=t.stat_desc.extra_base,p=t.stat_desc.max_length,m=0;for(s=0;s<=g;s++)e.bl_count[s]=0;for(h[2*e.heap[e.heap_max]+1]=0,r=e.heap_max+1;r<_;r++)p<(s=h[2*h[2*(n=e.heap[r])+1]+1]+1)&&(s=p,m++),h[2*n+1]=s,u>=7;n>>=1)if(1&r&&0!==e.dyn_ltree[2*t])return o;if(0!==e.dyn_ltree[18]||0!==e.dyn_ltree[20]||0!==e.dyn_ltree[26])return h;for(t=32;t>>3,(s=e.static_len+3+7>>>3)<=i&&(i=s)):i=s=r+5,r+4<=i&&-1!==t?J(e,t,r,n):4===e.strategy||s===i?(P(e,2+(n?1:0),3),K(e,z,C)):(P(e,4+(n?1:0),3),function(e,t,r,n){var i;for(P(e,t-257,5),P(e,r-1,5),P(e,n-4,4),i=0;i>>8&255,e.pending_buf[e.d_buf+2*e.last_lit+1]=255&t,e.pending_buf[e.l_buf+e.last_lit]=255&r,e.last_lit++,0===t?e.dyn_ltree[2*r]++:(e.matches++,t--,e.dyn_ltree[2*(A[r]+u+1)]++,e.dyn_dtree[2*N(t)]++),e.last_lit===e.lit_bufsize-1},r._tr_align=function(e){P(e,2,3),L(e,m,z),function(e){16===e.bi_valid?(U(e,e.bi_buf),e.bi_buf=0,e.bi_valid=0):8<=e.bi_valid&&(e.pending_buf[e.pending++]=255&e.bi_buf,e.bi_buf>>=8,e.bi_valid-=8)}(e)}},{"../utils/common":41}],53:[function(e,t,r){"use strict";t.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],54:[function(e,t,r){(function(e){!function(r,n){"use strict";if(!r.setImmediate){var i,s,t,a,o=1,h={},u=!1,l=r.document,e=Object.getPrototypeOf&&Object.getPrototypeOf(r);e=e&&e.setTimeout?e:r,i="[object process]"==={}.toString.call(r.process)?function(e){process.nextTick(function(){c(e)})}:function(){if(r.postMessage&&!r.importScripts){var e=!0,t=r.onmessage;return r.onmessage=function(){e=!1},r.postMessage("","*"),r.onmessage=t,e}}()?(a="setImmediate$"+Math.random()+"$",r.addEventListener?r.addEventListener("message",d,!1):r.attachEvent("onmessage",d),function(e){r.postMessage(a+e,"*")}):r.MessageChannel?((t=new MessageChannel).port1.onmessage=function(e){c(e.data)},function(e){t.port2.postMessage(e)}):l&&"onreadystatechange"in l.createElement("script")?(s=l.documentElement,function(e){var t=l.createElement("script");t.onreadystatechange=function(){c(e),t.onreadystatechange=null,s.removeChild(t),t=null},s.appendChild(t)}):function(e){setTimeout(c,0,e)},e.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),r=0;r' + - '
' + item.message + '
' + - ''); - }); + $("#have_read_cb").prop("checked", !$("#have_read_cb").prop("checked")); + if($("#bookDetailsModal").is(":visible")) { + data.forEach(function (item) { + $(".modal-header").after('
' + item.message + '
'); + }); + } else + { + data.forEach(function (item) { + $(".navbar").after('
' + + '
' + item.message + '
' + + '
'); + }); + } } } }); @@ -59,17 +69,20 @@ $("#archived_cb").on("change", function() { ) }; - $("#shelf-actions").on("click", "[data-shelf-action]", function (e) { + $("#add-to-shelves, #remove-from-shelves").on("click", "[data-shelf-action]", function (e) { e.preventDefault(); - - $.get(this.href) + $.ajax({ + url: $(this).data('href'), + method:"post", + data: {csrf_token:$("input[name='csrf_token']").val()}, + }) .done(function() { var $this = $(this); switch ($this.data("shelf-action")) { case "add": $("#remove-from-shelves").append( templates.remove({ - add: this.href, + add: $this.data('href'), remove: $this.data("remove-href"), content: $("
").text(this.textContent).html() }) @@ -79,7 +92,7 @@ $("#archived_cb").on("change", function() { $("#add-to-shelves").append( templates.add({ add: $this.data("add-href"), - remove: this.href, + remove: $this.data('href'), content: $("
").text(this.textContent).html(), }) ); diff --git a/cps/static/js/edit_books.js b/cps/static/js/edit_books.js index 0bfe078cf..c1eb319d4 100644 --- a/cps/static/js/edit_books.js +++ b/cps/static/js/edit_books.js @@ -33,7 +33,7 @@ $(".datepicker").datepicker({ if (results) { pubDate = new Date(results[1], parseInt(results[2], 10) - 1, results[3]) || new Date(this.value); $(this).next('input') - .val(pubDate.toLocaleDateString(language)) + .val(pubDate.toLocaleDateString(language.replaceAll("_","-"))) .removeClass("hidden"); } }).trigger("change"); diff --git a/cps/static/js/get_meta.js b/cps/static/js/get_meta.js index 51ab740d4..43a40fa65 100644 --- a/cps/static/js/get_meta.js +++ b/cps/static/js/get_meta.js @@ -26,21 +26,28 @@ $(function () { ) }; + function getUniqueValues(attribute_name, book){ + var presentArray = $.map($("#"+attribute_name).val().split(","), $.trim); + if ( presentArray.length === 1 && presentArray[0] === "") { + presentArray = []; + } + $.each(book[attribute_name], function(i, el) { + if ($.inArray(el, presentArray) === -1) presentArray.push(el); + }); + return presentArray + } + function populateForm (book) { tinymce.get("description").setContent(book.description); - var uniqueTags = $.map($("#tags").val().split(","), $.trim); - if ( uniqueTags.length == 1 && uniqueTags[0] == "") { - uniqueTags = []; - } - $.each(book.tags, function(i, el) { - if ($.inArray(el, uniqueTags) === -1) uniqueTags.push(el); - }); + var uniqueTags = getUniqueValues('tags', book) + var uniqueLanguages = getUniqueValues('languages', book) var ampSeparatedAuthors = (book.authors || []).join(" & "); $("#bookAuthor").val(ampSeparatedAuthors); $("#book_title").val(book.title); $("#tags").val(uniqueTags.join(", ")); + $("#languages").val(uniqueLanguages.join(", ")); $("#rating").data("rating").setValue(Math.round(book.rating)); - if(book.cover !== null){ + if(book.cover && $("#cover_url").length){ $(".cover img").attr("src", book.cover); $("#cover_url").val(book.cover); } @@ -48,7 +55,32 @@ $(function () { $("#publisher").val(book.publisher); if (typeof book.series !== "undefined") { $("#series").val(book.series); + $("#series_index").val(book.series_index); } + if (typeof book.identifiers !== "undefined") { + populateIdentifiers(book.identifiers) + } + } + + function populateIdentifiers(identifiers){ + for (const property in identifiers) { + console.log(`${property}: ${identifiers[property]}`); + if ($('input[name="identifier-type-'+property+'"]').length) { + $('input[name="identifier-val-'+property+'"]').val(identifiers[property]) + } + else { + addIdentifier(property, identifiers[property]) + } + } + } + + function addIdentifier(name, value){ + var line = ''; + line += ''; + line += ''; + line += ''+_("Remove")+''; + line += ''; + $("#identifier-table").append(line); } function doSearch (keyword) { @@ -60,14 +92,19 @@ $(function () { data: {"query": keyword}, dataType: "json", success: function success(data) { - $("#meta-info").html("
    "); - data.forEach(function(book) { - var $book = $(templates.bookResult(book)); - $book.find("img").on("click", function () { - populateForm(book); + if (data.length) { + $("#meta-info").html("
      "); + data.forEach(function(book) { + var $book = $(templates.bookResult(book)); + $book.find("img").on("click", function () { + populateForm(book); + }); + $("#book-list").append($book); }); - $("#book-list").append($book); - }); + } + else { + $("#meta-info").html("

      " + msg.no_result + "!

      " + $("#meta-info")[0].innerHTML) + } }, error: function error() { $("#meta-info").html("

      " + msg.search_error + "!

      " + $("#meta-info")[0].innerHTML); @@ -128,9 +165,7 @@ $(function () { e.preventDefault(); keyword = $("#keyword").val(); $('.pill').each(function(){ - // console.log($(this).data('control')); $(this).data("initial", $(this).prop('checked')); - // console.log($(this).data('initial')); }); doSearch(keyword); }); diff --git a/cps/static/js/kthoom.js b/cps/static/js/kthoom.js index 7a9de8f4b..d955dfb14 100644 --- a/cps/static/js/kthoom.js +++ b/cps/static/js/kthoom.js @@ -164,6 +164,14 @@ kthoom.ImageFile = function(file) { this.mimeType = undefined; break; } + + // Reset mime type for special files originating from Apple devices + // This folder may contain files having image extensions (for example .jpg) but those files are not actual images + // Trying to view these files cause corrupted/empty pages in the comic reader and files should be ignored + if (this.filename.indexOf("__MACOSX") !== -1) { + this.mimeType = undefined; + } + if ( this.mimeType !== undefined) { this.dataURI = createURLFromArray(file.fileData, this.mimeType); } diff --git a/cps/static/js/libs/Sortable.min.js b/cps/static/js/libs/Sortable.min.js index 4fe7f0c36..17bb16c73 100644 --- a/cps/static/js/libs/Sortable.min.js +++ b/cps/static/js/libs/Sortable.min.js @@ -1,2 +1,2 @@ -/*! Sortable 1.13.0 - MIT | git://github.com/SortableJS/Sortable.git */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Sortable=e()}(this,function(){"use strict";function o(t){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function a(){return(a=Object.assign||function(t){for(var e=1;e"===e[0]&&(e=e.substring(1)),t)try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return!1}return!1}}function P(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"===e[0]?t.parentNode===n&&h(t,e):h(t,e))||o&&t===n)return t;if(t===n)break}while(t=(i=t).host&&i!==document&&i.host.nodeType?i.host:i.parentNode)}var i;return null}var f,p=/\s+/g;function k(t,e,n){if(t&&e)if(t.classList)t.classList[n?"add":"remove"](e);else{var o=(" "+t.className+" ").replace(p," ").replace(" "+e+" "," ");t.className=(o+(n?" "+e:"")).replace(p," ")}}function R(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];e in o||-1!==e.indexOf("webkit")||(e="-webkit-"+e),o[e]=n+("string"==typeof n?"":"px")}}function v(t,e){var n="";if("string"==typeof t)n=t;else do{var o=R(t,"transform");o&&"none"!==o&&(n=o+" "+n)}while(!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function g(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=e.left-n&&r<=e.right+n,i=a>=e.top-n&&a<=e.bottom+n;return n&&o&&i?l=t:void 0}}),l}((t=t.touches?t.touches[0]:t).clientX,t.clientY);if(e){var n={};for(var o in t)t.hasOwnProperty(o)&&(n[o]=t[o]);n.target=n.rootEl=e,n.preventDefault=void 0,n.stopPropagation=void 0,e[j]._onDragOver(n)}}}function kt(t){z&&z.parentNode[j]._isOutsideThisEl(t.target)}function Rt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[j]=this;var n={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return Ot(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Rt.supportPointer&&"PointerEvent"in window&&!u,emptyInsertThreshold:5};for(var o in O.initializePlugins(this,t,n),n)o in e||(e[o]=n[o]);for(var i in Nt(e),this)"_"===i.charAt(0)&&"function"==typeof this[i]&&(this[i]=this[i].bind(this));this.nativeDraggable=!e.forceFallback&&xt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?d(t,"pointerdown",this._onTapStart):(d(t,"mousedown",this._onTapStart),d(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(d(t,"dragover",this),d(t,"dragenter",this)),bt.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,T())}function Xt(t,e,n,o,i,r,a,l){var s,c,u=t[j],d=u.options.onMove;return!window.CustomEvent||w||E?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||X(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),d&&(c=d.call(u,s,a)),c}function Yt(t){t.draggable=!1}function Bt(){Dt=!1}function Ft(t){for(var e=t.tagName+t.className+t.src+t.href+t.textContent,n=e.length,o=0;n--;)o+=e.charCodeAt(n);return o.toString(36)}function Ht(t){return setTimeout(t,0)}function Lt(t){return clearTimeout(t)}Rt.prototype={constructor:Rt,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(ht=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,z):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(function(t){St.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&St.push(o)}}(o),!z&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=P(l,t.draggable,o,!1))&&l.animated||Z===l)){if(J=F(l),et=F(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return W({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),K("filter",n,{evt:e}),void(i&&e.cancelable&&e.preventDefault())}else if(c&&(c=c.split(",").some(function(t){if(t=P(s,t.trim(),o,!1))return W({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),K("filter",n,{evt:e}),!0})))return void(i&&e.cancelable&&e.preventDefault());t.handle&&!P(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;if(n&&!z&&n.parentNode===r){var s=X(n);if(q=r,G=(z=n).parentNode,V=z.nextSibling,Z=n,ot=a.group,rt={target:Rt.dragged=z,clientX:(e||t).clientX,clientY:(e||t).clientY},ct=rt.clientX-s.left,ut=rt.clientY-s.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,z.style["will-change"]="all",o=function(){K("delayEnded",i,{evt:t}),Rt.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!c&&i.nativeDraggable&&(z.draggable=!0),i._triggerDragStart(t,e),W({sortable:i,name:"choose",originalEvent:t}),k(z,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){g(z,t.trim(),Yt)}),d(l,"dragover",Pt),d(l,"mousemove",Pt),d(l,"touchmove",Pt),d(l,"mouseup",i._onDrop),d(l,"touchend",i._onDrop),d(l,"touchcancel",i._onDrop),c&&this.nativeDraggable&&(this.options.touchStartThreshold=4,z.draggable=!0),K("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(E||w))o();else{if(Rt.eventCanceled)return void this._onDrop();d(l,"mouseup",i._disableDelayedDrag),d(l,"touchend",i._disableDelayedDrag),d(l,"touchcancel",i._disableDelayedDrag),d(l,"mousemove",i._delayedDragTouchMoveHandler),d(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&d(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)}}},_delayedDragTouchMoveHandler:function(t){var e=t.touches?t.touches[0]:t;Math.max(Math.abs(e.clientX-this._lastX),Math.abs(e.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){z&&Yt(z),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;s(t,"mouseup",this._disableDelayedDrag),s(t,"touchend",this._disableDelayedDrag),s(t,"touchcancel",this._disableDelayedDrag),s(t,"mousemove",this._delayedDragTouchMoveHandler),s(t,"touchmove",this._delayedDragTouchMoveHandler),s(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?d(document,"pointermove",this._onTouchMove):d(document,e?"touchmove":"mousemove",this._onTouchMove):(d(z,"dragend",this),d(q,"dragstart",this._onDragStart));try{document.selection?Ht(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){if(vt=!1,q&&z){K("dragStarted",this,{evt:e}),this.nativeDraggable&&d(document,"dragover",kt);var n=this.options;t||k(z,n.dragClass,!1),k(z,n.ghostClass,!0),Rt.active=this,t&&this._appendGhost(),W({sortable:this,name:"start",originalEvent:e})}else this._nulling()},_emulateDragOver:function(){if(at){this._lastX=at.clientX,this._lastY=at.clientY,At();for(var t=document.elementFromPoint(at.clientX,at.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(at.clientX,at.clientY))!==e;)e=t;if(z.parentNode[j]._isOutsideThisEl(t),e)do{if(e[j]){if(e[j]._onDragOver({clientX:at.clientX,clientY:at.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}t=e}while(e=e.parentNode);It()}},_onTouchMove:function(t){if(rt){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=U&&v(U,!0),a=U&&r&&r.a,l=U&&r&&r.d,s=Ct&>&&b(gt),c=(i.clientX-rt.clientX+o.x)/(a||1)+(s?s[0]-Et[0]:0)/(a||1),u=(i.clientY-rt.clientY+o.y)/(l||1)+(s?s[1]-Et[1]:0)/(l||1);if(!Rt.active&&!vt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))o.right+10||t.clientX<=o.right&&t.clientY>o.bottom&&t.clientX>=o.left:t.clientX>o.right&&t.clientY>o.top||t.clientX<=o.right&&t.clientY>o.bottom+10}(n,a,this)&&!g.animated){if(g===z)return N(!1);if(g&&l===n.target&&(s=g),s&&(i=X(s)),!1!==Xt(q,l,z,o,s,i,n,!!s))return O(),l.appendChild(z),G=l,A(),N(!0)}else if(s.parentNode===l){i=X(s);var v,m,b,y=z.parentNode!==l,w=!function(t,e,n){var o=n?t.left:t.top,i=n?t.right:t.bottom,r=n?t.width:t.height,a=n?e.left:e.top,l=n?e.right:e.bottom,s=n?e.width:e.height;return o===a||i===l||o+r/2===a+s/2}(z.animated&&z.toRect||o,s.animated&&s.toRect||i,a),E=a?"top":"left",D=Y(s,"top","top")||Y(z,"top","top"),S=D?D.scrollTop:void 0;if(ht!==s&&(m=i[E],yt=!1,wt=!w&&e.invertSwap||y),0!==(v=function(t,e,n,o,i,r,a,l){var s=o?t.clientY:t.clientX,c=o?n.height:n.width,u=o?n.top:n.left,d=o?n.bottom:n.right,h=!1;if(!a)if(l&&ptt.length)&&(e=t.length);for(var n=0,o=new Array(e);n"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}function N(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"!==e[0]||t.parentNode===n)&&p(t,e)||o&&t===n)return t}while(t!==n&&(t=(i=t).host&&i!==document&&i.host.nodeType?i.host:i.parentNode))}var i;return null}var g,m=/\s+/g;function I(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(m," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(m," ")))}function P(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=!(e in o||-1!==e.indexOf("webkit"))?"-webkit-"+e:e]=n+("string"==typeof n?"":"px")}}function v(t,e){var n="";if("string"==typeof t)n=t;else do{var o=P(t,"transform")}while(o&&"none"!==o&&(n=o+" "+n),!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function b(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=n.left-e&&i<=n.right+e,e=r>=n.top-e&&r<=n.bottom+e;return o&&e?a=t:void 0}}),a);if(e){var n,o={};for(n in t)t.hasOwnProperty(n)&&(o[n]=t[n]);o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[j]._onDragOver(o)}}var i,r,a}function Yt(t){q&&q.parentNode[j]._isOutsideThisEl(t.target)}function Bt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[j]=this;var n,o,i={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return It(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Bt.supportPointer&&"PointerEvent"in window&&!u,emptyInsertThreshold:5};for(n in K.initializePlugins(this,t,i),i)n in e||(e[n]=i[n]);for(o in Pt(e),this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));this.nativeDraggable=!e.forceFallback&&Mt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?h(t,"pointerdown",this._onTapStart):(h(t,"mousedown",this._onTapStart),h(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(h(t,"dragover",this),h(t,"dragenter",this)),Et.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,x())}function Ft(t,e,n,o,i,r,a,l){var s,c,u=t[j],d=u.options.onMove;return!window.CustomEvent||y||w?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||k(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),c=d?d.call(u,s,a):c}function jt(t){t.draggable=!1}function Ht(){Ct=!1}function Lt(t){return setTimeout(t,0)}function Kt(t){return clearTimeout(t)}Bt.prototype={constructor:Bt,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(gt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,q):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(!function(t){Tt.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&Tt.push(o)}}(o),!q&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=N(l,t.draggable,o,!1))&&l.animated||J===l)){if(nt=B(l),it=B(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return U({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),z("filter",n,{evt:e}),void(i&&e.cancelable&&e.preventDefault())}else if(c=c&&c.split(",").some(function(t){if(t=N(s,t.trim(),o,!1))return U({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),z("filter",n,{evt:e}),!0}))return void(i&&e.cancelable&&e.preventDefault());t.handle&&!N(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;n&&!q&&n.parentNode===r&&(o=k(n),$=r,V=(q=n).parentNode,Q=q.nextSibling,J=n,at=a.group,st={target:Bt.dragged=q,clientX:(e||t).clientX,clientY:(e||t).clientY},ht=st.clientX-o.left,ft=st.clientY-o.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,q.style["will-change"]="all",o=function(){z("delayEnded",i,{evt:t}),Bt.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!s&&i.nativeDraggable&&(q.draggable=!0),i._triggerDragStart(t,e),U({sortable:i,name:"choose",originalEvent:t}),I(q,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){b(q,t.trim(),jt)}),h(l,"dragover",Xt),h(l,"mousemove",Xt),h(l,"touchmove",Xt),h(l,"mouseup",i._onDrop),h(l,"touchend",i._onDrop),h(l,"touchcancel",i._onDrop),s&&this.nativeDraggable&&(this.options.touchStartThreshold=4,q.draggable=!0),z("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(w||y)?o():Bt.eventCanceled?this._onDrop():(h(l,"mouseup",i._disableDelayedDrag),h(l,"touchend",i._disableDelayedDrag),h(l,"touchcancel",i._disableDelayedDrag),h(l,"mousemove",i._delayedDragTouchMoveHandler),h(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&h(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)))},_delayedDragTouchMoveHandler:function(t){t=t.touches?t.touches[0]:t;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){q&&jt(q),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;f(t,"mouseup",this._disableDelayedDrag),f(t,"touchend",this._disableDelayedDrag),f(t,"touchcancel",this._disableDelayedDrag),f(t,"mousemove",this._delayedDragTouchMoveHandler),f(t,"touchmove",this._delayedDragTouchMoveHandler),f(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?h(document,"pointermove",this._onTouchMove):h(document,e?"touchmove":"mousemove",this._onTouchMove):(h(q,"dragend",this),h($,"dragstart",this._onDragStart));try{document.selection?Lt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){var n;yt=!1,$&&q?(z("dragStarted",this,{evt:e}),this.nativeDraggable&&h(document,"dragover",Yt),n=this.options,t||I(q,n.dragClass,!1),I(q,n.ghostClass,!0),Bt.active=this,t&&this._appendGhost(),U({sortable:this,name:"start",originalEvent:e})):this._nulling()},_emulateDragOver:function(){if(ct){this._lastX=ct.clientX,this._lastY=ct.clientY,kt();for(var t=document.elementFromPoint(ct.clientX,ct.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(ct.clientX,ct.clientY))!==e;)e=t;if(q.parentNode[j]._isOutsideThisEl(t),e)do{if(e[j])if(e[j]._onDragOver({clientX:ct.clientX,clientY:ct.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}while(e=(t=e).parentNode);Rt()}},_onTouchMove:function(t){if(st){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=Z&&v(Z,!0),a=Z&&r&&r.a,l=Z&&r&&r.d,e=Ot&&bt&&E(bt),a=(i.clientX-st.clientX+o.x)/(a||1)+(e?e[0]-_t[0]:0)/(a||1),l=(i.clientY-st.clientY+o.y)/(l||1)+(e?e[1]-_t[1]:0)/(l||1);if(!Bt.active&&!yt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))n.right+10||t.clientX<=n.right&&t.clientY>n.bottom&&t.clientX>=n.left:t.clientX>n.right&&t.clientY>n.top||t.clientX<=n.right&&t.clientY>n.bottom+10}(n,r,this)&&!g.animated){if(g===q)return O(!1);if((l=g&&a===n.target?g:l)&&(w=k(l)),!1!==Ft($,a,q,o,l,w,n,!!l))return x(),g&&g.nextSibling?a.insertBefore(q,g.nextSibling):a.appendChild(q),V=a,A(),O(!0)}else if(g&&function(t,e,n){n=k(X(n.el,0,n.options,!0));return e?t.clientX+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
      "],col:[2,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
      ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,S)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&v(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!y||!y.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ve(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=E)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{if(d.cssSupportsSelector&&!CSS.supports("selector(:is("+c+"))"))throw new Error;return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===E&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[E]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ye(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,S=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.cssSupportsSelector=ce(function(){return CSS.supports("selector(*)")&&C.querySelectorAll(":is(:jqfake)")&&!CSS.supports("selector(:is(*,:jqfake))")}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=E,!C.getElementsByName||!C.getElementsByName(E).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&S)return t.getElementsByClassName(e)},s=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+E+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+E+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),d.cssSupportsSelector||y.push(":has"),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType&&e.documentElement||e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&S&&!N[t+" "]&&(!s||!s.test(t))&&(!y||!y.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:S,!0)),N.test(r[1])&&E.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=S.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,D=E(S);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=S.createDocumentFragment().appendChild(S.createElement("div")),(fe=S.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
      "],col:[2,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],_default:[0,"",""]};function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),S.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;E.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||E.expando+"_"+Ct.guid++;return this[e]=!0,e}}),E.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||E.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?E(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),v.createHTMLDocument=((Ut=S.implementation.createHTMLDocument("").body).innerHTML="
      ",2===Ut.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=S.implementation.createHTMLDocument("")).createElement("base")).href=S.location.href,t.head.appendChild(r)):t=S),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(E.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},E.expr.pseudos.animated=function(t){return E.grep(E.timers,function(e){return t===e.elem}).length},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return B(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=_e(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){E.fn[t]=function(e){return this.on(t,e)}}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0"," ","+","~","preFilter","excess","unquoted","nodeNameSelector","pattern","operator","check","result","what","_argument","simple","forward","ofType","_context","xml","uniqueCache","outerCache","nodeIndex","start","parent","useCache","lastChild","uniqueID","pseudo","args","setFilters","idx","matched","not","matcher","unmatched","has","lang","elemLang","hash","location","root","focus","activeElement","hasFocus","href","tabIndex","enabled","checked","selected","selectedIndex","empty","header","button","_matchIndexes","lt","gt","radio","checkbox","file","password","image","submit","reset","tokens","combinator","base","skip","checkNonElements","doneName","oldCache","newCache","elementMatcher","matchers","condense","newUnmatched","mapped","setMatcher","postFilter","postFinder","postSelector","temp","preMap","postMap","preexisting","contexts","multipleContexts","matcherIn","matcherOut","matcherFromTokens","checkContext","leadingRelative","implicitRelative","matchContext","matchAnyContext","filters","parseOnly","soFar","preFilters","cached","elementMatchers","setMatchers","bySet","byElement","superMatcher","outermost","matchedCount","setMatched","contextBackup","dirrunsUnique","token","compiled","_name","defaultValue","unique","isXMLDoc","escapeSelector","until","truncate","is","siblings","n","rneedsContext","rsingleTag","winnow","qualifier","self","rootjQuery","parseHTML","ready","rparentsprev","guaranteedUnique","children","contents","prev","sibling","targets","l","closest","index","prevAll","add","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","contentDocument","content","reverse","rnothtmlwhite","Identity","v","Thrower","ex","adoptValue","resolve","reject","noValue","method","promise","fail","then","Callbacks","object","_","flag","firing","memory","fired","locked","queue","firingIndex","fire","once","stopOnFalse","remove","disable","lock","fireWith","Deferred","func","tuples","state","always","deferred","catch","pipe","fns","newDefer","tuple","returned","progress","notify","onFulfilled","onRejected","onProgress","maxDepth","depth","special","that","mightThrow","TypeError","notifyWith","resolveWith","process","exceptionHook","stackTrace","rejectWith","getStackHook","setTimeout","stateString","when","singleValue","remaining","resolveContexts","resolveValues","master","updateFunc","rerrorNames","stack","console","warn","message","readyException","readyList","completed","removeEventListener","readyWait","wait","readyState","doScroll","access","chainable","emptyGet","raw","bulk","_key","rmsPrefix","rdashAlpha","fcamelCase","_all","letter","toUpperCase","camelCase","string","acceptData","owner","Data","uid","defineProperty","configurable","set","data","prop","hasData","dataPriv","dataUser","rbrace","rmultiDash","dataAttr","JSON","parse","removeData","_data","_removeData","dequeue","startLength","hooks","_queueHooks","stop","setter","clearQueue","count","defer","pnum","source","rcssNum","cssExpand","isAttached","composed","getRootNode","isHiddenWithinTree","style","display","css","adjustCSS","valueParts","tween","adjusted","scale","maxIterations","currentValue","initial","unit","cssNumber","initialInUnit","defaultDisplayMap","showHide","show","values","body","hide","toggle","div","rcheckableType","rtagName","rscriptType","createDocumentFragment","checkClone","cloneNode","noCloneChecked","option","wrapMap","thead","col","tr","td","_default","getAll","setGlobalEval","refElements","tbody","tfoot","colgroup","caption","th","optgroup","buildFragment","scripts","selection","ignored","wrap","attached","fragment","nodes","htmlPrefilter","createTextNode","rkeyEvent","rmouseEvent","rtypenamespace","returnTrue","returnFalse","expectSync","err","safeActiveElement","on","types","one","origFn","event","off","leverageNative","notAsync","saved","isTrigger","delegateType","stopPropagation","stopImmediatePropagation","preventDefault","trigger","Event","handleObjIn","eventHandle","events","t","handleObj","handlers","namespaces","origType","elemData","create","handle","triggered","dispatch","bindType","delegateCount","setup","mappedTypes","origCount","teardown","removeEvent","nativeEvent","handlerQueue","fix","delegateTarget","preDispatch","isPropagationStopped","currentTarget","isImmediatePropagationStopped","rnamespace","postDispatch","matchedHandlers","matchedSelectors","addProp","hook","enumerable","originalEvent","writable","load","noBubble","click","beforeunload","returnValue","props","isDefaultPrevented","defaultPrevented","relatedTarget","timeStamp","now","isSimulated","altKey","bubbles","cancelable","changedTouches","ctrlKey","detail","eventPhase","metaKey","pageX","pageY","shiftKey","view","char","charCode","keyCode","buttons","clientX","clientY","offsetX","offsetY","pointerId","pointerType","screenX","screenY","targetTouches","toElement","touches","which","blur","mouseenter","mouseleave","pointerenter","pointerleave","orig","related","rnoInnerhtml","rchecked","rcleanScript","manipulationTarget","disableScript","restoreScript","cloneCopyEvent","dest","udataOld","udataCur","domManip","collection","hasScripts","iNoClone","valueIsFunction","html","_evalUrl","keepData","cleanData","dataAndEvents","deepDataAndEvents","srcElements","destElements","inPage","detach","append","prepend","insertBefore","before","after","replaceWith","replaceChild","appendTo","prependTo","insertAfter","replaceAll","original","insert","rnumnonpx","getStyles","opener","getComputedStyle","swap","old","rboxStyle","curCSS","computed","width","minWidth","maxWidth","getPropertyValue","pixelBoxStyles","addGetHookIf","conditionFn","hookFn","computeStyleTests","container","cssText","divStyle","pixelPositionVal","reliableMarginLeftVal","roundPixelMeasures","marginLeft","right","pixelBoxStylesVal","boxSizingReliableVal","position","scrollboxSizeVal","offsetWidth","measure","round","parseFloat","reliableTrDimensionsVal","backgroundClip","clearCloneStyle","boxSizingReliable","pixelPosition","reliableMarginLeft","scrollboxSize","reliableTrDimensions","table","trChild","trStyle","height","parseInt","cssPrefixes","emptyStyle","vendorProps","finalPropName","final","cssProps","capName","vendorPropName","rdisplayswap","rcustomProp","cssShow","visibility","cssNormalTransform","letterSpacing","fontWeight","setPositiveNumber","subtract","max","boxModelAdjustment","dimension","box","isBorderBox","styles","computedVal","extra","delta","ceil","getWidthOrHeight","valueIsBorderBox","offsetProp","getClientRects","Tween","easing","cssHooks","opacity","animationIterationCount","columnCount","fillOpacity","flexGrow","flexShrink","gridArea","gridColumn","gridColumnEnd","gridColumnStart","gridRow","gridRowEnd","gridRowStart","lineHeight","order","orphans","widows","zIndex","zoom","origName","isCustomProp","setProperty","isFinite","getBoundingClientRect","scrollboxSizeBuggy","left","margin","padding","border","prefix","suffix","expand","expanded","parts","propHooks","run","percent","eased","duration","pos","step","fx","scrollTop","scrollLeft","linear","p","swing","cos","PI","fxNow","inProgress","opt","rfxtypes","rrun","schedule","hidden","requestAnimationFrame","interval","tick","createFxNow","genFx","includeWidth","createTween","animation","Animation","tweeners","properties","stopped","prefilters","currentTime","startTime","tweens","opts","specialEasing","originalProperties","originalOptions","gotoEnd","propFilter","bind","complete","timer","anim","*","tweener","oldfire","propTween","restoreDisplay","isBox","dataShow","unqueued","overflow","overflowX","overflowY","prefilter","speed","speeds","fadeTo","to","animate","optall","doAnimation","finish","stopQueue","timers","cssFn","slideDown","slideUp","slideToggle","fadeIn","fadeOut","fadeToggle","slow","fast","delay","time","timeout","clearTimeout","checkOn","optSelected","radioValue","boolHook","removeAttr","nType","attrHooks","attrNames","getter","lowercaseName","rfocusable","rclickable","stripAndCollapse","getClass","classesToArray","removeProp","propFix","tabindex","for","class","addClass","classes","curValue","clazz","finalValue","removeClass","toggleClass","stateVal","isValidValue","classNames","hasClass","rreturn","valHooks","optionSet","focusin","rfocusMorph","stopPropagationCallback","onlyHandlers","bubbleType","ontype","lastElement","eventPath","parentWindow","simulate","triggerHandler","attaches","rquery","parseXML","DOMParser","parseFromString","rbracket","rCRLF","rsubmitterTypes","rsubmittable","buildParams","traditional","param","s","valueOrFunction","encodeURIComponent","serialize","serializeArray","r20","rhash","rantiCache","rheaders","rnoContent","rprotocol","transports","allTypes","originAnchor","addToPrefiltersOrTransports","structure","dataTypeExpression","dataType","dataTypes","inspectPrefiltersOrTransports","jqXHR","inspected","seekingTransport","inspect","prefilterOrFactory","dataTypeOrTransport","ajaxExtend","flatOptions","ajaxSettings","active","lastModified","etag","url","isLocal","protocol","processData","async","contentType","accepts","json","responseFields","converters","* text","text html","text json","text xml","ajaxSetup","settings","ajaxPrefilter","ajaxTransport","ajax","transport","cacheURL","responseHeadersString","responseHeaders","timeoutTimer","urlAnchor","fireGlobals","uncached","callbackContext","globalEventContext","completeDeferred","statusCode","requestHeaders","requestHeadersNames","strAbort","getResponseHeader","getAllResponseHeaders","setRequestHeader","overrideMimeType","mimeType","status","abort","statusText","finalText","crossDomain","host","hasContent","ifModified","headers","beforeSend","success","send","nativeStatusText","responses","isSuccess","response","modified","ct","finalDataType","firstDataType","ajaxHandleResponses","conv2","current","conv","dataFilter","throws","ajaxConvert","getJSON","getScript","text script","wrapAll","firstElementChild","wrapInner","htmlIsFunction","unwrap","visible","offsetHeight","xhr","XMLHttpRequest","xhrSuccessStatus","0","1223","xhrSupported","cors","errorCallback","open","username","xhrFields","onload","onerror","onabort","ontimeout","onreadystatechange","responseType","responseText","binary","scriptAttrs","charset","scriptCharset","evt","oldCallbacks","rjsonp","jsonp","jsonpCallback","originalSettings","callbackName","overwritten","responseContainer","jsonProp","createHTMLDocument","implementation","keepScripts","parsed","params","animated","offset","setOffset","curPosition","curLeft","curCSSTop","curTop","curOffset","curCSSLeft","curElem","using","rect","win","pageYOffset","pageXOffset","offsetParent","parentOffset","scrollTo","Height","Width","","defaultExtra","funcName","unbind","delegate","undelegate","hover","fnOver","fnOut","proxy","holdReady","hold","parseJSON","isNumeric","isNaN","trim","define","amd","_jQuery","_$","$","noConflict"],"mappings":";CAaA,SAAYA,EAAQC,GAEnB,aAEuB,iBAAXC,QAAiD,iBAAnBA,OAAOC,QAShDD,OAAOC,QAAUH,EAAOI,SACvBH,EAASD,GAAQ,GACjB,SAAUK,GACT,IAAMA,EAAED,SACP,MAAM,IAAIE,MAAO,4CAElB,OAAOL,EAASI,IAGlBJ,EAASD,GAtBX,CA0BuB,oBAAXO,OAAyBA,OAASC,KAAM,SAAUD,EAAQE,GAMtE,aAEA,IAAIC,EAAM,GAENC,EAAWC,OAAOC,eAElBC,EAAQJ,EAAII,MAEZC,EAAOL,EAAIK,KAAO,SAAUC,GAC/B,OAAON,EAAIK,KAAKE,KAAMD,IACnB,SAAUA,GACb,OAAON,EAAIQ,OAAOC,MAAO,GAAIH,IAI1BI,EAAOV,EAAIU,KAEXC,EAAUX,EAAIW,QAEdC,EAAa,GAEbC,EAAWD,EAAWC,SAEtBC,EAASF,EAAWG,eAEpBC,EAAaF,EAAOD,SAEpBI,EAAuBD,EAAWT,KAAML,QAExCgB,EAAU,GAEVC,EAAa,SAAqBC,GAMhC,MAAsB,mBAARA,GAA8C,iBAAjBA,EAAIC,UAIjDC,EAAW,SAAmBF,GAChC,OAAc,MAAPA,GAAeA,IAAQA,EAAIvB,QAIhCH,EAAWG,EAAOH,SAIjB6B,EAA4B,CAC/BC,MAAM,EACNC,KAAK,EACLC,OAAO,EACPC,UAAU,GAGX,SAASC,EAASC,EAAMC,EAAMC,GAG7B,IAAIC,EAAGC,EACNC,GAHDH,EAAMA,GAAOrC,GAGCyC,cAAe,UAG7B,GADAD,EAAOE,KAAOP,EACTC,EACJ,IAAME,KAAKT,GAYVU,EAAMH,EAAME,IAAOF,EAAKO,cAAgBP,EAAKO,aAAcL,KAE1DE,EAAOI,aAAcN,EAAGC,GAI3BF,EAAIQ,KAAKC,YAAaN,GAASO,WAAWC,YAAaR,GAIzD,SAASS,EAAQvB,GAChB,OAAY,MAAPA,EACGA,EAAM,GAIQ,iBAARA,GAAmC,mBAARA,EACxCR,EAAYC,EAASN,KAAMa,KAAW,gBAC/BA,EAQT,IACCwB,EAAU,QAGVC,EAAS,SAAUC,EAAUC,GAI5B,OAAO,IAAIF,EAAOG,GAAGC,KAAMH,EAAUC,IA0VvC,SAASG,EAAa9B,GAMrB,IAAI+B,IAAW/B,GAAO,WAAYA,GAAOA,EAAI+B,OAC5C3B,EAAOmB,EAAQvB,GAEhB,OAAKD,EAAYC,KAASE,EAAUF,KAIpB,UAATI,GAA+B,IAAX2B,GACR,iBAAXA,GAAgC,EAATA,GAAgBA,EAAS,KAAO/B,GArWhEyB,EAAOG,GAAKH,EAAOO,UAAY,CAG9BC,OAAQT,EAERU,YAAaT,EAGbM,OAAQ,EAERI,QAAS,WACR,OAAOnD,EAAMG,KAAMT,OAKpB0D,IAAK,SAAUC,GAGd,OAAY,MAAPA,EACGrD,EAAMG,KAAMT,MAIb2D,EAAM,EAAI3D,KAAM2D,EAAM3D,KAAKqD,QAAWrD,KAAM2D,IAKpDC,UAAW,SAAUC,GAGpB,IAAIC,EAAMf,EAAOgB,MAAO/D,KAAKwD,cAAeK,GAM5C,OAHAC,EAAIE,WAAahE,KAGV8D,GAIRG,KAAM,SAAUC,GACf,OAAOnB,EAAOkB,KAAMjE,KAAMkE,IAG3BC,IAAK,SAAUD,GACd,OAAOlE,KAAK4D,UAAWb,EAAOoB,IAAKnE,KAAM,SAAUoE,EAAMlC,GACxD,OAAOgC,EAASzD,KAAM2D,EAAMlC,EAAGkC,OAIjC9D,MAAO,WACN,OAAON,KAAK4D,UAAWtD,EAAMK,MAAOX,KAAMqE,aAG3CC,MAAO,WACN,OAAOtE,KAAKuE,GAAI,IAGjBC,KAAM,WACL,OAAOxE,KAAKuE,IAAK,IAGlBE,KAAM,WACL,OAAOzE,KAAK4D,UAAWb,EAAO2B,KAAM1E,KAAM,SAAU2E,EAAOzC,GAC1D,OAASA,EAAI,GAAM,MAIrB0C,IAAK,WACJ,OAAO5E,KAAK4D,UAAWb,EAAO2B,KAAM1E,KAAM,SAAU2E,EAAOzC,GAC1D,OAAOA,EAAI,MAIbqC,GAAI,SAAUrC,GACb,IAAI2C,EAAM7E,KAAKqD,OACdyB,GAAK5C,GAAMA,EAAI,EAAI2C,EAAM,GAC1B,OAAO7E,KAAK4D,UAAgB,GAALkB,GAAUA,EAAID,EAAM,CAAE7E,KAAM8E,IAAQ,KAG5DC,IAAK,WACJ,OAAO/E,KAAKgE,YAAchE,KAAKwD,eAKhC5C,KAAMA,EACNoE,KAAM9E,EAAI8E,KACVC,OAAQ/E,EAAI+E,QAGblC,EAAOmC,OAASnC,EAAOG,GAAGgC,OAAS,WAClC,IAAIC,EAASC,EAAMzD,EAAK0D,EAAMC,EAAaC,EAC1CC,EAASnB,UAAW,IAAO,GAC3BnC,EAAI,EACJmB,EAASgB,UAAUhB,OACnBoC,GAAO,EAsBR,IAnBuB,kBAAXD,IACXC,EAAOD,EAGPA,EAASnB,UAAWnC,IAAO,GAC3BA,KAIsB,iBAAXsD,GAAwBnE,EAAYmE,KAC/CA,EAAS,IAILtD,IAAMmB,IACVmC,EAASxF,KACTkC,KAGOA,EAAImB,EAAQnB,IAGnB,GAAqC,OAA9BiD,EAAUd,UAAWnC,IAG3B,IAAMkD,KAAQD,EACbE,EAAOF,EAASC,GAIF,cAATA,GAAwBI,IAAWH,IAKnCI,GAAQJ,IAAUtC,EAAO2C,cAAeL,KAC1CC,EAAcK,MAAMC,QAASP,MAC/B1D,EAAM6D,EAAQJ,GAIbG,EADID,IAAgBK,MAAMC,QAASjE,GAC3B,GACI2D,GAAgBvC,EAAO2C,cAAe/D,GAG1CA,EAFA,GAIT2D,GAAc,EAGdE,EAAQJ,GAASrC,EAAOmC,OAAQO,EAAMF,EAAOF,SAGzBQ,IAATR,IACXG,EAAQJ,GAASC,IAOrB,OAAOG,GAGRzC,EAAOmC,OAAQ,CAGdY,QAAS,UAAahD,EAAUiD,KAAKC,UAAWC,QAAS,MAAO,IAGhEC,SAAS,EAETC,MAAO,SAAUC,GAChB,MAAM,IAAItG,MAAOsG,IAGlBC,KAAM,aAENX,cAAe,SAAUpE,GACxB,IAAIgF,EAAOC,EAIX,SAAMjF,GAAgC,oBAAzBP,EAASN,KAAMa,QAI5BgF,EAAQnG,EAAUmB,KASK,mBADvBiF,EAAOvF,EAAOP,KAAM6F,EAAO,gBAAmBA,EAAM9C,cACftC,EAAWT,KAAM8F,KAAWpF,IAGlEqF,cAAe,SAAUlF,GACxB,IAAI8D,EAEJ,IAAMA,KAAQ9D,EACb,OAAO,EAER,OAAO,GAKRmF,WAAY,SAAU1E,EAAMoD,EAASlD,GACpCH,EAASC,EAAM,CAAEH,MAAOuD,GAAWA,EAAQvD,OAASK,IAGrDgC,KAAM,SAAU3C,EAAK4C,GACpB,IAAIb,EAAQnB,EAAI,EAEhB,GAAKkB,EAAa9B,IAEjB,IADA+B,EAAS/B,EAAI+B,OACLnB,EAAImB,EAAQnB,IACnB,IAAgD,IAA3CgC,EAASzD,KAAMa,EAAKY,GAAKA,EAAGZ,EAAKY,IACrC,WAIF,IAAMA,KAAKZ,EACV,IAAgD,IAA3C4C,EAASzD,KAAMa,EAAKY,GAAKA,EAAGZ,EAAKY,IACrC,MAKH,OAAOZ,GAIRoF,UAAW,SAAUxG,EAAKyG,GACzB,IAAI7C,EAAM6C,GAAW,GAarB,OAXY,MAAPzG,IACCkD,EAAahD,OAAQF,IACzB6C,EAAOgB,MAAOD,EACE,iBAAR5D,EACP,CAAEA,GAAQA,GAGXU,EAAKH,KAAMqD,EAAK5D,IAIX4D,GAGR8C,QAAS,SAAUxC,EAAMlE,EAAKgC,GAC7B,OAAc,MAAPhC,GAAe,EAAIW,EAAQJ,KAAMP,EAAKkE,EAAMlC,IAKpD6B,MAAO,SAAUO,EAAOuC,GAKvB,IAJA,IAAIhC,GAAOgC,EAAOxD,OACjByB,EAAI,EACJ5C,EAAIoC,EAAMjB,OAEHyB,EAAID,EAAKC,IAChBR,EAAOpC,KAAQ2E,EAAQ/B,GAKxB,OAFAR,EAAMjB,OAASnB,EAERoC,GAGRI,KAAM,SAAUb,EAAOK,EAAU4C,GAShC,IARA,IACCC,EAAU,GACV7E,EAAI,EACJmB,EAASQ,EAAMR,OACf2D,GAAkBF,EAIX5E,EAAImB,EAAQnB,KACAgC,EAAUL,EAAO3B,GAAKA,KAChB8E,GACxBD,EAAQnG,KAAMiD,EAAO3B,IAIvB,OAAO6E,GAIR5C,IAAK,SAAUN,EAAOK,EAAU+C,GAC/B,IAAI5D,EAAQ6D,EACXhF,EAAI,EACJ4B,EAAM,GAGP,GAAKV,EAAaS,GAEjB,IADAR,EAASQ,EAAMR,OACPnB,EAAImB,EAAQnB,IAGL,OAFdgF,EAAQhD,EAAUL,EAAO3B,GAAKA,EAAG+E,KAGhCnD,EAAIlD,KAAMsG,QAMZ,IAAMhF,KAAK2B,EAGI,OAFdqD,EAAQhD,EAAUL,EAAO3B,GAAKA,EAAG+E,KAGhCnD,EAAIlD,KAAMsG,GAMb,OAAO3G,EAAMuD,IAIdqD,KAAM,EAIN/F,QAASA,IAGa,mBAAXgG,SACXrE,EAAOG,GAAIkE,OAAOC,UAAanH,EAAKkH,OAAOC,WAI5CtE,EAAOkB,KAAM,uEAAuEqD,MAAO,KAC3F,SAAUC,EAAInC,GACbtE,EAAY,WAAasE,EAAO,KAAQA,EAAKoC,gBAmB9C,IAAIC,EAWJ,SAAY1H,GACZ,IAAImC,EACHd,EACAsG,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAGAC,EACAvI,EACAwI,EACAC,EACAC,EACAC,EACAxB,EACAyB,EAGA1C,EAAU,SAAW,EAAI,IAAI2C,KAC7BC,EAAe3I,EAAOH,SACtB+I,EAAU,EACVC,EAAO,EACPC,EAAaC,KACbC,EAAaD,KACbE,EAAgBF,KAChBG,EAAyBH,KACzBI,EAAY,SAAUC,EAAGC,GAIxB,OAHKD,IAAMC,IACVlB,GAAe,GAET,GAIRlH,EAAS,GAAOC,eAChBf,EAAM,GACNmJ,EAAMnJ,EAAImJ,IACVC,EAAapJ,EAAIU,KACjBA,EAAOV,EAAIU,KACXN,EAAQJ,EAAII,MAIZO,EAAU,SAAU0I,EAAMnF,GAGzB,IAFA,IAAIlC,EAAI,EACP2C,EAAM0E,EAAKlG,OACJnB,EAAI2C,EAAK3C,IAChB,GAAKqH,EAAMrH,KAAQkC,EAClB,OAAOlC,EAGT,OAAQ,GAGTsH,EAAW,6HAMXC,EAAa,sBAGbC,EAAa,0BAA4BD,EACxC,0CAGDE,EAAa,MAAQF,EAAa,KAAOC,EAAa,OAASD,EAG9D,gBAAkBA,EAIlB,2DAA6DC,EAAa,OAC1ED,EAAa,OAEdG,EAAU,KAAOF,EAAa,wFAOAC,EAAa,eAO3CE,EAAc,IAAIC,OAAQL,EAAa,IAAK,KAC5CM,EAAQ,IAAID,OAAQ,IAAML,EAAa,8BACtCA,EAAa,KAAM,KAEpBO,EAAS,IAAIF,OAAQ,IAAML,EAAa,KAAOA,EAAa,KAC5DQ,EAAe,IAAIH,OAAQ,IAAML,EAAa,WAAaA,EAAa,IAAMA,EAC7E,KACDS,EAAW,IAAIJ,OAAQL,EAAa,MAEpCU,EAAU,IAAIL,OAAQF,GACtBQ,EAAc,IAAIN,OAAQ,IAAMJ,EAAa,KAE7CW,EAAY,CACXC,GAAM,IAAIR,OAAQ,MAAQJ,EAAa,KACvCa,MAAS,IAAIT,OAAQ,QAAUJ,EAAa,KAC5Cc,IAAO,IAAIV,OAAQ,KAAOJ,EAAa,SACvCe,KAAQ,IAAIX,OAAQ,IAAMH,GAC1Be,OAAU,IAAIZ,OAAQ,IAAMF,GAC5Be,MAAS,IAAIb,OAAQ,yDACpBL,EAAa,+BAAiCA,EAAa,cAC3DA,EAAa,aAAeA,EAAa,SAAU,KACpDmB,KAAQ,IAAId,OAAQ,OAASN,EAAW,KAAM,KAI9CqB,aAAgB,IAAIf,OAAQ,IAAML,EACjC,mDAAqDA,EACrD,mBAAqBA,EAAa,mBAAoB,MAGxDqB,EAAQ,SACRC,EAAU,sCACVC,EAAU,SAEVC,EAAU,yBAGVC,EAAa,mCAEbC,GAAW,OAIXC,GAAY,IAAItB,OAAQ,uBAAyBL,EAAa,uBAAwB,KACtF4B,GAAY,SAAUC,EAAQC,GAC7B,IAAIC,EAAO,KAAOF,EAAOhL,MAAO,GAAM,MAEtC,OAAOiL,IASNC,EAAO,EACNC,OAAOC,aAAcF,EAAO,OAC5BC,OAAOC,aAAcF,GAAQ,GAAK,MAAe,KAAPA,EAAe,SAK5DG,GAAa,sDACbC,GAAa,SAAUC,EAAIC,GAC1B,OAAKA,EAGQ,OAAPD,EACG,SAIDA,EAAGvL,MAAO,GAAI,GAAM,KAC1BuL,EAAGE,WAAYF,EAAGxI,OAAS,GAAItC,SAAU,IAAO,IAI3C,KAAO8K,GAOfG,GAAgB,WACf7D,KAGD8D,GAAqBC,GACpB,SAAU9H,GACT,OAAyB,IAAlBA,EAAK+H,UAAqD,aAAhC/H,EAAKgI,SAAS5E,eAEhD,CAAE6E,IAAK,aAAcC,KAAM,WAI7B,IACC1L,EAAKD,MACFT,EAAMI,EAAMG,KAAMiI,EAAa6D,YACjC7D,EAAa6D,YAMdrM,EAAKwI,EAAa6D,WAAWlJ,QAAS9B,SACrC,MAAQiL,GACT5L,EAAO,CAAED,MAAOT,EAAImD,OAGnB,SAAUmC,EAAQiH,GACjBnD,EAAW3I,MAAO6E,EAAQlF,EAAMG,KAAMgM,KAKvC,SAAUjH,EAAQiH,GACjB,IAAI3H,EAAIU,EAAOnC,OACdnB,EAAI,EAGL,MAAUsD,EAAQV,KAAQ2H,EAAKvK,MAC/BsD,EAAOnC,OAASyB,EAAI,IAKvB,SAAS2C,GAAQzE,EAAUC,EAAS0D,EAAS+F,GAC5C,IAAIC,EAAGzK,EAAGkC,EAAMwI,EAAKC,EAAOC,EAAQC,EACnCC,EAAa/J,GAAWA,EAAQgK,cAGhC1L,EAAW0B,EAAUA,EAAQ1B,SAAW,EAKzC,GAHAoF,EAAUA,GAAW,GAGI,iBAAb3D,IAA0BA,GACxB,IAAbzB,GAA+B,IAAbA,GAA+B,KAAbA,EAEpC,OAAOoF,EAIR,IAAM+F,IACLvE,EAAalF,GACbA,EAAUA,GAAWrD,EAEhByI,GAAiB,CAIrB,GAAkB,KAAb9G,IAAqBsL,EAAQ3B,EAAWgC,KAAMlK,IAGlD,GAAO2J,EAAIE,EAAO,IAGjB,GAAkB,IAAbtL,EAAiB,CACrB,KAAO6C,EAAOnB,EAAQkK,eAAgBR,IAUrC,OAAOhG,EALP,GAAKvC,EAAKgJ,KAAOT,EAEhB,OADAhG,EAAQ/F,KAAMwD,GACPuC,OAYT,GAAKqG,IAAgB5I,EAAO4I,EAAWG,eAAgBR,KACtDnE,EAAUvF,EAASmB,IACnBA,EAAKgJ,KAAOT,EAGZ,OADAhG,EAAQ/F,KAAMwD,GACPuC,MAKH,CAAA,GAAKkG,EAAO,GAElB,OADAjM,EAAKD,MAAOgG,EAAS1D,EAAQoK,qBAAsBrK,IAC5C2D,EAGD,IAAOgG,EAAIE,EAAO,KAASzL,EAAQkM,wBACzCrK,EAAQqK,uBAGR,OADA1M,EAAKD,MAAOgG,EAAS1D,EAAQqK,uBAAwBX,IAC9ChG,EAKT,GAAKvF,EAAQmM,MACXtE,EAAwBjG,EAAW,QACjCsF,IAAcA,EAAUkF,KAAMxK,MAIlB,IAAbzB,GAAqD,WAAnC0B,EAAQmJ,SAAS5E,eAA+B,CAYpE,GAVAuF,EAAc/J,EACdgK,EAAa/J,EASK,IAAb1B,IACF2I,EAASsD,KAAMxK,IAAciH,EAAauD,KAAMxK,IAAe,EAGjEgK,EAAa7B,GAASqC,KAAMxK,IAAcyK,GAAaxK,EAAQN,aAC9DM,KAImBA,GAAY7B,EAAQsM,SAGhCd,EAAM3J,EAAQV,aAAc,OAClCqK,EAAMA,EAAI3G,QAAS0F,GAAYC,IAE/B3I,EAAQT,aAAc,KAAQoK,EAAM9G,IAMtC5D,GADA4K,EAASjF,EAAU7E,IACRK,OACX,MAAQnB,IACP4K,EAAQ5K,IAAQ0K,EAAM,IAAMA,EAAM,UAAa,IAC9Ce,GAAYb,EAAQ5K,IAEtB6K,EAAcD,EAAOc,KAAM,KAG5B,IAIC,OAHAhN,EAAKD,MAAOgG,EACXqG,EAAWa,iBAAkBd,IAEvBpG,EACN,MAAQmH,GACT7E,EAAwBjG,GAAU,GACjC,QACI4J,IAAQ9G,GACZ7C,EAAQ8K,gBAAiB,QAQ9B,OAAOhG,EAAQ/E,EAASiD,QAAS8D,EAAO,MAAQ9G,EAAS0D,EAAS+F,GASnE,SAAS5D,KACR,IAAIkF,EAAO,GAYX,OAVA,SAASC,EAAOC,EAAKhH,GAQpB,OALK8G,EAAKpN,KAAMsN,EAAM,KAAQxG,EAAKyG,oBAG3BF,EAAOD,EAAKI,SAEXH,EAAOC,EAAM,KAAQhH,GAShC,SAASmH,GAAcnL,GAEtB,OADAA,EAAI4C,IAAY,EACT5C,EAOR,SAASoL,GAAQpL,GAChB,IAAIqL,EAAK3O,EAASyC,cAAe,YAEjC,IACC,QAASa,EAAIqL,GACZ,MAAQ/B,GACT,OAAO,EACN,QAGI+B,EAAG5L,YACP4L,EAAG5L,WAAWC,YAAa2L,GAI5BA,EAAK,MASP,SAASC,GAAWC,EAAOC,GAC1B,IAAIxO,EAAMuO,EAAMnH,MAAO,KACtBpF,EAAIhC,EAAImD,OAET,MAAQnB,IACPwF,EAAKiH,WAAYzO,EAAKgC,IAAQwM,EAUhC,SAASE,GAAczF,EAAGC,GACzB,IAAIyF,EAAMzF,GAAKD,EACd2F,EAAOD,GAAsB,IAAf1F,EAAE5H,UAAiC,IAAf6H,EAAE7H,UACnC4H,EAAE4F,YAAc3F,EAAE2F,YAGpB,GAAKD,EACJ,OAAOA,EAIR,GAAKD,EACJ,MAAUA,EAAMA,EAAIG,YACnB,GAAKH,IAAQzF,EACZ,OAAQ,EAKX,OAAOD,EAAI,GAAK,EAOjB,SAAS8F,GAAmBvN,GAC3B,OAAO,SAAU0C,GAEhB,MAAgB,UADLA,EAAKgI,SAAS5E,eACEpD,EAAK1C,OAASA,GAQ3C,SAASwN,GAAoBxN,GAC5B,OAAO,SAAU0C,GAChB,IAAIgB,EAAOhB,EAAKgI,SAAS5E,cACzB,OAAkB,UAATpC,GAA6B,WAATA,IAAuBhB,EAAK1C,OAASA,GAQpE,SAASyN,GAAsBhD,GAG9B,OAAO,SAAU/H,GAKhB,MAAK,SAAUA,EASTA,EAAKzB,aAAgC,IAAlByB,EAAK+H,SAGvB,UAAW/H,EACV,UAAWA,EAAKzB,WACbyB,EAAKzB,WAAWwJ,WAAaA,EAE7B/H,EAAK+H,WAAaA,EAMpB/H,EAAKgL,aAAejD,GAI1B/H,EAAKgL,cAAgBjD,GACrBF,GAAoB7H,KAAW+H,EAG1B/H,EAAK+H,WAAaA,EAKd,UAAW/H,GACfA,EAAK+H,WAAaA,GAY5B,SAASkD,GAAwBnM,GAChC,OAAOmL,GAAc,SAAUiB,GAE9B,OADAA,GAAYA,EACLjB,GAAc,SAAU3B,EAAM3F,GACpC,IAAIjC,EACHyK,EAAerM,EAAI,GAAIwJ,EAAKrJ,OAAQiM,GACpCpN,EAAIqN,EAAalM,OAGlB,MAAQnB,IACFwK,EAAQ5H,EAAIyK,EAAcrN,MAC9BwK,EAAM5H,KAASiC,EAASjC,GAAM4H,EAAM5H,SAYzC,SAAS2I,GAAaxK,GACrB,OAAOA,GAAmD,oBAAjCA,EAAQoK,sBAAwCpK,EAkrC1E,IAAMf,KA9qCNd,EAAUqG,GAAOrG,QAAU,GAO3BwG,EAAQH,GAAOG,MAAQ,SAAUxD,GAChC,IAAIoL,EAAYpL,EAAKqL,aACpBrH,GAAYhE,EAAK6I,eAAiB7I,GAAOsL,gBAK1C,OAAQ5E,EAAM0C,KAAMgC,GAAapH,GAAWA,EAAQgE,UAAY,SAQjEjE,EAAcV,GAAOU,YAAc,SAAUnG,GAC5C,IAAI2N,EAAYC,EACf3N,EAAMD,EAAOA,EAAKiL,eAAiBjL,EAAO0G,EAO3C,OAAKzG,GAAOrC,GAA6B,IAAjBqC,EAAIV,UAAmBU,EAAIyN,kBAMnDtH,GADAxI,EAAWqC,GACQyN,gBACnBrH,GAAkBT,EAAOhI,GAQpB8I,GAAgB9I,IAClBgQ,EAAYhQ,EAASiQ,cAAiBD,EAAUE,MAAQF,IAGrDA,EAAUG,iBACdH,EAAUG,iBAAkB,SAAU/D,IAAe,GAG1C4D,EAAUI,aACrBJ,EAAUI,YAAa,WAAYhE,KASrC5K,EAAQsM,MAAQY,GAAQ,SAAUC,GAEjC,OADAnG,EAAQ1F,YAAa6L,GAAK7L,YAAa9C,EAASyC,cAAe,QACzB,oBAAxBkM,EAAGV,mBACfU,EAAGV,iBAAkB,uBAAwBxK,SAShDjC,EAAQuI,WAAa2E,GAAQ,SAAUC,GAEtC,OADAA,EAAG0B,UAAY,KACP1B,EAAGhM,aAAc,eAO1BnB,EAAQiM,qBAAuBiB,GAAQ,SAAUC,GAEhD,OADAA,EAAG7L,YAAa9C,EAASsQ,cAAe,MAChC3B,EAAGlB,qBAAsB,KAAMhK,SAIxCjC,EAAQkM,uBAAyBrC,EAAQuC,KAAM5N,EAAS0N,wBAMxDlM,EAAQ+O,QAAU7B,GAAQ,SAAUC,GAEnC,OADAnG,EAAQ1F,YAAa6L,GAAKnB,GAAKtH,GACvBlG,EAASwQ,oBAAsBxQ,EAASwQ,kBAAmBtK,GAAUzC,SAIzEjC,EAAQ+O,SACZzI,EAAK2I,OAAa,GAAI,SAAUjD,GAC/B,IAAIkD,EAASlD,EAAGnH,QAASmF,GAAWC,IACpC,OAAO,SAAUjH,GAChB,OAAOA,EAAK7B,aAAc,QAAW+N,IAGvC5I,EAAK6I,KAAW,GAAI,SAAUnD,EAAInK,GACjC,GAAuC,oBAA3BA,EAAQkK,gBAAkC9E,EAAiB,CACtE,IAAIjE,EAAOnB,EAAQkK,eAAgBC,GACnC,OAAOhJ,EAAO,CAAEA,GAAS,OAI3BsD,EAAK2I,OAAa,GAAK,SAAUjD,GAChC,IAAIkD,EAASlD,EAAGnH,QAASmF,GAAWC,IACpC,OAAO,SAAUjH,GAChB,IAAIpC,EAAwC,oBAA1BoC,EAAKoM,kBACtBpM,EAAKoM,iBAAkB,MACxB,OAAOxO,GAAQA,EAAKkF,QAAUoJ,IAMhC5I,EAAK6I,KAAW,GAAI,SAAUnD,EAAInK,GACjC,GAAuC,oBAA3BA,EAAQkK,gBAAkC9E,EAAiB,CACtE,IAAIrG,EAAME,EAAG2B,EACZO,EAAOnB,EAAQkK,eAAgBC,GAEhC,GAAKhJ,EAAO,CAIX,IADApC,EAAOoC,EAAKoM,iBAAkB,QACjBxO,EAAKkF,QAAUkG,EAC3B,MAAO,CAAEhJ,GAIVP,EAAQZ,EAAQmN,kBAAmBhD,GACnClL,EAAI,EACJ,MAAUkC,EAAOP,EAAO3B,KAEvB,IADAF,EAAOoC,EAAKoM,iBAAkB,QACjBxO,EAAKkF,QAAUkG,EAC3B,MAAO,CAAEhJ,GAKZ,MAAO,MAMVsD,EAAK6I,KAAY,IAAInP,EAAQiM,qBAC5B,SAAUoD,EAAKxN,GACd,MAA6C,oBAAjCA,EAAQoK,qBACZpK,EAAQoK,qBAAsBoD,GAG1BrP,EAAQmM,IACZtK,EAAQ4K,iBAAkB4C,QAD3B,GAKR,SAAUA,EAAKxN,GACd,IAAImB,EACHsM,EAAM,GACNxO,EAAI,EAGJyE,EAAU1D,EAAQoK,qBAAsBoD,GAGzC,GAAa,MAARA,EAAc,CAClB,MAAUrM,EAAOuC,EAASzE,KACF,IAAlBkC,EAAK7C,UACTmP,EAAI9P,KAAMwD,GAIZ,OAAOsM,EAER,OAAO/J,GAITe,EAAK6I,KAAc,MAAInP,EAAQkM,wBAA0B,SAAU2C,EAAWhN,GAC7E,GAA+C,oBAAnCA,EAAQqK,wBAA0CjF,EAC7D,OAAOpF,EAAQqK,uBAAwB2C,IAUzC1H,EAAgB,GAOhBD,EAAY,IAELlH,EAAQmM,IAAMtC,EAAQuC,KAAM5N,EAASiO,qBAI3CS,GAAQ,SAAUC,GAEjB,IAAIoC,EAOJvI,EAAQ1F,YAAa6L,GAAKqC,UAAY,UAAY9K,EAAU,qBAC1CA,EAAU,kEAOvByI,EAAGV,iBAAkB,wBAAyBxK,QAClDiF,EAAU1H,KAAM,SAAW6I,EAAa,gBAKnC8E,EAAGV,iBAAkB,cAAexK,QACzCiF,EAAU1H,KAAM,MAAQ6I,EAAa,aAAeD,EAAW,KAI1D+E,EAAGV,iBAAkB,QAAU/H,EAAU,MAAOzC,QACrDiF,EAAU1H,KAAM,OAQjB+P,EAAQ/Q,EAASyC,cAAe,UAC1BG,aAAc,OAAQ,IAC5B+L,EAAG7L,YAAaiO,GACVpC,EAAGV,iBAAkB,aAAcxK,QACxCiF,EAAU1H,KAAM,MAAQ6I,EAAa,QAAUA,EAAa,KAC3DA,EAAa,gBAMT8E,EAAGV,iBAAkB,YAAaxK,QACvCiF,EAAU1H,KAAM,YAMX2N,EAAGV,iBAAkB,KAAO/H,EAAU,MAAOzC,QAClDiF,EAAU1H,KAAM,YAKjB2N,EAAGV,iBAAkB,QACrBvF,EAAU1H,KAAM,iBAGjB0N,GAAQ,SAAUC,GACjBA,EAAGqC,UAAY,oFAKf,IAAID,EAAQ/Q,EAASyC,cAAe,SACpCsO,EAAMnO,aAAc,OAAQ,UAC5B+L,EAAG7L,YAAaiO,GAAQnO,aAAc,OAAQ,KAIzC+L,EAAGV,iBAAkB,YAAaxK,QACtCiF,EAAU1H,KAAM,OAAS6I,EAAa,eAKW,IAA7C8E,EAAGV,iBAAkB,YAAaxK,QACtCiF,EAAU1H,KAAM,WAAY,aAK7BwH,EAAQ1F,YAAa6L,GAAKpC,UAAW,EACc,IAA9CoC,EAAGV,iBAAkB,aAAcxK,QACvCiF,EAAU1H,KAAM,WAAY,aAK7B2N,EAAGV,iBAAkB,QACrBvF,EAAU1H,KAAM,YAIXQ,EAAQyP,gBAAkB5F,EAAQuC,KAAQzG,EAAUqB,EAAQrB,SAClEqB,EAAQ0I,uBACR1I,EAAQ2I,oBACR3I,EAAQ4I,kBACR5I,EAAQ6I,qBAER3C,GAAQ,SAAUC,GAIjBnN,EAAQ8P,kBAAoBnK,EAAQtG,KAAM8N,EAAI,KAI9CxH,EAAQtG,KAAM8N,EAAI,aAClBhG,EAAc3H,KAAM,KAAMgJ,KAI5BtB,EAAYA,EAAUjF,QAAU,IAAIyG,OAAQxB,EAAUsF,KAAM,MAC5DrF,EAAgBA,EAAclF,QAAU,IAAIyG,OAAQvB,EAAcqF,KAAM,MAIxE+B,EAAa1E,EAAQuC,KAAMpF,EAAQ+I,yBAKnC3I,EAAWmH,GAAc1E,EAAQuC,KAAMpF,EAAQI,UAC9C,SAAUW,EAAGC,GACZ,IAAIgI,EAAuB,IAAfjI,EAAE5H,SAAiB4H,EAAEuG,gBAAkBvG,EAClDkI,EAAMjI,GAAKA,EAAEzG,WACd,OAAOwG,IAAMkI,MAAWA,GAAwB,IAAjBA,EAAI9P,YAClC6P,EAAM5I,SACL4I,EAAM5I,SAAU6I,GAChBlI,EAAEgI,yBAA8D,GAAnChI,EAAEgI,wBAAyBE,MAG3D,SAAUlI,EAAGC,GACZ,GAAKA,EACJ,MAAUA,EAAIA,EAAEzG,WACf,GAAKyG,IAAMD,EACV,OAAO,EAIV,OAAO,GAOTD,EAAYyG,EACZ,SAAUxG,EAAGC,GAGZ,GAAKD,IAAMC,EAEV,OADAlB,GAAe,EACR,EAIR,IAAIoJ,GAAWnI,EAAEgI,yBAA2B/H,EAAE+H,wBAC9C,OAAKG,IAgBU,GAPfA,GAAYnI,EAAE8D,eAAiB9D,KAASC,EAAE6D,eAAiB7D,GAC1DD,EAAEgI,wBAAyB/H,GAG3B,KAIGhI,EAAQmQ,cAAgBnI,EAAE+H,wBAAyBhI,KAAQmI,EAOzDnI,GAAKvJ,GAAYuJ,EAAE8D,eAAiBvE,GACxCF,EAAUE,EAAcS,IAChB,EAOJC,GAAKxJ,GAAYwJ,EAAE6D,eAAiBvE,GACxCF,EAAUE,EAAcU,GACjB,EAIDnB,EACJpH,EAASoH,EAAWkB,GAAMtI,EAASoH,EAAWmB,GAChD,EAGe,EAAVkI,GAAe,EAAI,IAE3B,SAAUnI,EAAGC,GAGZ,GAAKD,IAAMC,EAEV,OADAlB,GAAe,EACR,EAGR,IAAI2G,EACH3M,EAAI,EACJsP,EAAMrI,EAAExG,WACR0O,EAAMjI,EAAEzG,WACR8O,EAAK,CAAEtI,GACPuI,EAAK,CAAEtI,GAGR,IAAMoI,IAAQH,EAMb,OAAOlI,GAAKvJ,GAAY,EACvBwJ,GAAKxJ,EAAW,EAEhB4R,GAAO,EACPH,EAAM,EACNpJ,EACEpH,EAASoH,EAAWkB,GAAMtI,EAASoH,EAAWmB,GAChD,EAGK,GAAKoI,IAAQH,EACnB,OAAOzC,GAAczF,EAAGC,GAIzByF,EAAM1F,EACN,MAAU0F,EAAMA,EAAIlM,WACnB8O,EAAGE,QAAS9C,GAEbA,EAAMzF,EACN,MAAUyF,EAAMA,EAAIlM,WACnB+O,EAAGC,QAAS9C,GAIb,MAAQ4C,EAAIvP,KAAQwP,EAAIxP,GACvBA,IAGD,OAAOA,EAGN0M,GAAc6C,EAAIvP,GAAKwP,EAAIxP,IAO3BuP,EAAIvP,IAAOwG,GAAgB,EAC3BgJ,EAAIxP,IAAOwG,EAAe,EAE1B,IAGK9I,GAGR6H,GAAOV,QAAU,SAAU6K,EAAMC,GAChC,OAAOpK,GAAQmK,EAAM,KAAM,KAAMC,IAGlCpK,GAAOoJ,gBAAkB,SAAUzM,EAAMwN,GAGxC,GAFAzJ,EAAa/D,GAERhD,EAAQyP,iBAAmBxI,IAC9BY,EAAwB2I,EAAO,QAC7BrJ,IAAkBA,EAAciF,KAAMoE,OACtCtJ,IAAkBA,EAAUkF,KAAMoE,IAErC,IACC,IAAI9N,EAAMiD,EAAQtG,KAAM2D,EAAMwN,GAG9B,GAAK9N,GAAO1C,EAAQ8P,mBAInB9M,EAAKxE,UAAuC,KAA3BwE,EAAKxE,SAAS2B,SAC/B,OAAOuC,EAEP,MAAQ0I,GACTvD,EAAwB2I,GAAM,GAIhC,OAAyD,EAAlDnK,GAAQmK,EAAMhS,EAAU,KAAM,CAAEwE,IAASf,QAGjDoE,GAAOe,SAAW,SAAUvF,EAASmB,GAUpC,OAHOnB,EAAQgK,eAAiBhK,IAAarD,GAC5CuI,EAAalF,GAEPuF,EAAUvF,EAASmB,IAG3BqD,GAAOqK,KAAO,SAAU1N,EAAMgB,IAOtBhB,EAAK6I,eAAiB7I,IAAUxE,GACtCuI,EAAa/D,GAGd,IAAIlB,EAAKwE,EAAKiH,WAAYvJ,EAAKoC,eAG9BrF,EAAMe,GAAMlC,EAAOP,KAAMiH,EAAKiH,WAAYvJ,EAAKoC,eAC9CtE,EAAIkB,EAAMgB,GAAOiD,QACjBxC,EAEF,YAAeA,IAAR1D,EACNA,EACAf,EAAQuI,aAAetB,EACtBjE,EAAK7B,aAAc6C,IACjBjD,EAAMiC,EAAKoM,iBAAkBpL,KAAYjD,EAAI4P,UAC9C5P,EAAI+E,MACJ,MAGJO,GAAO6D,OAAS,SAAU0G,GACzB,OAASA,EAAM,IAAK/L,QAAS0F,GAAYC,KAG1CnE,GAAOtB,MAAQ,SAAUC,GACxB,MAAM,IAAItG,MAAO,0CAA4CsG,IAO9DqB,GAAOwK,WAAa,SAAUtL,GAC7B,IAAIvC,EACH8N,EAAa,GACbpN,EAAI,EACJ5C,EAAI,EAOL,GAJAgG,GAAgB9G,EAAQ+Q,iBACxBlK,GAAa7G,EAAQgR,YAAczL,EAAQrG,MAAO,GAClDqG,EAAQ3B,KAAMkE,GAEThB,EAAe,CACnB,MAAU9D,EAAOuC,EAASzE,KACpBkC,IAASuC,EAASzE,KACtB4C,EAAIoN,EAAWtR,KAAMsB,IAGvB,MAAQ4C,IACP6B,EAAQ1B,OAAQiN,EAAYpN,GAAK,GAQnC,OAFAmD,EAAY,KAELtB,GAORgB,EAAUF,GAAOE,QAAU,SAAUvD,GACpC,IAAIpC,EACH8B,EAAM,GACN5B,EAAI,EACJX,EAAW6C,EAAK7C,SAEjB,GAAMA,GAQC,GAAkB,IAAbA,GAA+B,IAAbA,GAA+B,KAAbA,EAAkB,CAIjE,GAAiC,iBAArB6C,EAAKiO,YAChB,OAAOjO,EAAKiO,YAIZ,IAAMjO,EAAOA,EAAKkO,WAAYlO,EAAMA,EAAOA,EAAK4K,YAC/ClL,GAAO6D,EAASvD,QAGZ,GAAkB,IAAb7C,GAA+B,IAAbA,EAC7B,OAAO6C,EAAKmO,eAnBZ,MAAUvQ,EAAOoC,EAAMlC,KAGtB4B,GAAO6D,EAAS3F,GAqBlB,OAAO8B,IAGR4D,EAAOD,GAAO+K,UAAY,CAGzBrE,YAAa,GAEbsE,aAAcpE,GAEdxB,MAAOxC,EAEPsE,WAAY,GAEZ4B,KAAM,GAENmC,SAAU,CACTC,IAAK,CAAEtG,IAAK,aAAc/H,OAAO,GACjCsO,IAAK,CAAEvG,IAAK,cACZwG,IAAK,CAAExG,IAAK,kBAAmB/H,OAAO,GACtCwO,IAAK,CAAEzG,IAAK,oBAGb0G,UAAW,CACVtI,KAAQ,SAAUoC,GAWjB,OAVAA,EAAO,GAAMA,EAAO,GAAI5G,QAASmF,GAAWC,IAG5CwB,EAAO,IAAQA,EAAO,IAAOA,EAAO,IACnCA,EAAO,IAAO,IAAK5G,QAASmF,GAAWC,IAEpB,OAAfwB,EAAO,KACXA,EAAO,GAAM,IAAMA,EAAO,GAAM,KAG1BA,EAAMvM,MAAO,EAAG,IAGxBqK,MAAS,SAAUkC,GAiClB,OArBAA,EAAO,GAAMA,EAAO,GAAIrF,cAEU,QAA7BqF,EAAO,GAAIvM,MAAO,EAAG,IAGnBuM,EAAO,IACZpF,GAAOtB,MAAO0G,EAAO,IAKtBA,EAAO,KAASA,EAAO,GACtBA,EAAO,IAAQA,EAAO,IAAO,GAC7B,GAAqB,SAAfA,EAAO,IAAiC,QAAfA,EAAO,KACvCA,EAAO,KAAWA,EAAO,GAAMA,EAAO,IAAwB,QAAfA,EAAO,KAG3CA,EAAO,IAClBpF,GAAOtB,MAAO0G,EAAO,IAGfA,GAGRnC,OAAU,SAAUmC,GACnB,IAAImG,EACHC,GAAYpG,EAAO,IAAOA,EAAO,GAElC,OAAKxC,EAAmB,MAAEmD,KAAMX,EAAO,IAC/B,MAIHA,EAAO,GACXA,EAAO,GAAMA,EAAO,IAAOA,EAAO,IAAO,GAG9BoG,GAAY9I,EAAQqD,KAAMyF,KAGnCD,EAASnL,EAAUoL,GAAU,MAG7BD,EAASC,EAASpS,QAAS,IAAKoS,EAAS5P,OAAS2P,GAAWC,EAAS5P,UAGxEwJ,EAAO,GAAMA,EAAO,GAAIvM,MAAO,EAAG0S,GAClCnG,EAAO,GAAMoG,EAAS3S,MAAO,EAAG0S,IAI1BnG,EAAMvM,MAAO,EAAG,MAIzB+P,OAAQ,CAEP7F,IAAO,SAAU0I,GAChB,IAAI9G,EAAW8G,EAAiBjN,QAASmF,GAAWC,IAAY7D,cAChE,MAA4B,MAArB0L,EACN,WACC,OAAO,GAER,SAAU9O,GACT,OAAOA,EAAKgI,UAAYhI,EAAKgI,SAAS5E,gBAAkB4E,IAI3D7B,MAAS,SAAU0F,GAClB,IAAIkD,EAAUtK,EAAYoH,EAAY,KAEtC,OAAOkD,IACJA,EAAU,IAAIrJ,OAAQ,MAAQL,EAC/B,IAAMwG,EAAY,IAAMxG,EAAa,SAAaZ,EACjDoH,EAAW,SAAU7L,GACpB,OAAO+O,EAAQ3F,KACY,iBAAnBpJ,EAAK6L,WAA0B7L,EAAK6L,WACd,oBAAtB7L,EAAK7B,cACX6B,EAAK7B,aAAc,UACpB,OAKNkI,KAAQ,SAAUrF,EAAMgO,EAAUC,GACjC,OAAO,SAAUjP,GAChB,IAAIkP,EAAS7L,GAAOqK,KAAM1N,EAAMgB,GAEhC,OAAe,MAAVkO,EACgB,OAAbF,GAEFA,IAINE,GAAU,GAIU,MAAbF,EAAmBE,IAAWD,EACvB,OAAbD,EAAoBE,IAAWD,EAClB,OAAbD,EAAoBC,GAAqC,IAA5BC,EAAOzS,QAASwS,GAChC,OAAbD,EAAoBC,IAAoC,EAA3BC,EAAOzS,QAASwS,GAChC,OAAbD,EAAoBC,GAASC,EAAOhT,OAAQ+S,EAAMhQ,UAAagQ,EAClD,OAAbD,GAA2F,GAArE,IAAME,EAAOrN,QAAS4D,EAAa,KAAQ,KAAMhJ,QAASwS,GACnE,OAAbD,IAAoBE,IAAWD,GAASC,EAAOhT,MAAO,EAAG+S,EAAMhQ,OAAS,KAAQgQ,EAAQ,QAO3F1I,MAAS,SAAUjJ,EAAM6R,EAAMC,EAAWlP,EAAOE,GAChD,IAAIiP,EAAgC,QAAvB/R,EAAKpB,MAAO,EAAG,GAC3BoT,EAA+B,SAArBhS,EAAKpB,OAAQ,GACvBqT,EAAkB,YAATJ,EAEV,OAAiB,IAAVjP,GAAwB,IAATE,EAGrB,SAAUJ,GACT,QAASA,EAAKzB,YAGf,SAAUyB,EAAMwP,EAAUC,GACzB,IAAI5F,EAAO6F,EAAaC,EAAY/R,EAAMgS,EAAWC,EACpD5H,EAAMoH,IAAWC,EAAU,cAAgB,kBAC3CQ,EAAS9P,EAAKzB,WACdyC,EAAOuO,GAAUvP,EAAKgI,SAAS5E,cAC/B2M,GAAYN,IAAQF,EACpB7E,GAAO,EAER,GAAKoF,EAAS,CAGb,GAAKT,EAAS,CACb,MAAQpH,EAAM,CACbrK,EAAOoC,EACP,MAAUpC,EAAOA,EAAMqK,GACtB,GAAKsH,EACJ3R,EAAKoK,SAAS5E,gBAAkBpC,EACd,IAAlBpD,EAAKT,SAEL,OAAO,EAKT0S,EAAQ5H,EAAe,SAAT3K,IAAoBuS,GAAS,cAE5C,OAAO,EAMR,GAHAA,EAAQ,CAAEP,EAAUQ,EAAO5B,WAAa4B,EAAOE,WAG1CV,GAAWS,EAAW,CAe1BrF,GADAkF,GADA/F,GAHA6F,GAJAC,GADA/R,EAAOkS,GACYpO,KAAe9D,EAAM8D,GAAY,KAI1B9D,EAAKqS,YAC5BN,EAAY/R,EAAKqS,UAAa,KAEZ3S,IAAU,IACZ,KAAQiH,GAAWsF,EAAO,KACzBA,EAAO,GAC3BjM,EAAOgS,GAAaE,EAAO3H,WAAYyH,GAEvC,MAAUhS,IAASgS,GAAahS,GAAQA,EAAMqK,KAG3CyC,EAAOkF,EAAY,IAAOC,EAAM5K,MAGlC,GAAuB,IAAlBrH,EAAKT,YAAoBuN,GAAQ9M,IAASoC,EAAO,CACrD0P,EAAapS,GAAS,CAAEiH,EAASqL,EAAWlF,GAC5C,YAyBF,GAlBKqF,IAaJrF,EADAkF,GADA/F,GAHA6F,GAJAC,GADA/R,EAAOoC,GACY0B,KAAe9D,EAAM8D,GAAY,KAI1B9D,EAAKqS,YAC5BN,EAAY/R,EAAKqS,UAAa,KAEZ3S,IAAU,IACZ,KAAQiH,GAAWsF,EAAO,KAMhC,IAATa,EAGJ,MAAU9M,IAASgS,GAAahS,GAAQA,EAAMqK,KAC3CyC,EAAOkF,EAAY,IAAOC,EAAM5K,MAElC,IAAOsK,EACN3R,EAAKoK,SAAS5E,gBAAkBpC,EACd,IAAlBpD,EAAKT,aACHuN,IAGGqF,KAMJL,GALAC,EAAa/R,EAAM8D,KAChB9D,EAAM8D,GAAY,KAIK9D,EAAKqS,YAC5BN,EAAY/R,EAAKqS,UAAa,KAEpB3S,GAAS,CAAEiH,EAASmG,IAG7B9M,IAASoC,GACb,MASL,OADA0K,GAAQtK,KACQF,GAAWwK,EAAOxK,GAAU,GAAqB,GAAhBwK,EAAOxK,KAK5DoG,OAAU,SAAU4J,EAAQhF,GAM3B,IAAIiF,EACHrR,EAAKwE,EAAKkC,QAAS0K,IAAY5M,EAAK8M,WAAYF,EAAO9M,gBACtDC,GAAOtB,MAAO,uBAAyBmO,GAKzC,OAAKpR,EAAI4C,GACD5C,EAAIoM,GAIK,EAAZpM,EAAGG,QACPkR,EAAO,CAAED,EAAQA,EAAQ,GAAIhF,GACtB5H,EAAK8M,WAAWvT,eAAgBqT,EAAO9M,eAC7C6G,GAAc,SAAU3B,EAAM3F,GAC7B,IAAI0N,EACHC,EAAUxR,EAAIwJ,EAAM4C,GACpBpN,EAAIwS,EAAQrR,OACb,MAAQnB,IAEPwK,EADA+H,EAAM5T,EAAS6L,EAAMgI,EAASxS,OACb6E,EAAS0N,GAAQC,EAASxS,MAG7C,SAAUkC,GACT,OAAOlB,EAAIkB,EAAM,EAAGmQ,KAIhBrR,IAIT0G,QAAS,CAGR+K,IAAOtG,GAAc,SAAUrL,GAK9B,IAAI2N,EAAQ,GACXhK,EAAU,GACViO,EAAU9M,EAAS9E,EAASiD,QAAS8D,EAAO,OAE7C,OAAO6K,EAAS9O,GACfuI,GAAc,SAAU3B,EAAM3F,EAAS6M,EAAUC,GAChD,IAAIzP,EACHyQ,EAAYD,EAASlI,EAAM,KAAMmH,EAAK,IACtC3R,EAAIwK,EAAKrJ,OAGV,MAAQnB,KACAkC,EAAOyQ,EAAW3S,MACxBwK,EAAMxK,KAAS6E,EAAS7E,GAAMkC,MAIjC,SAAUA,EAAMwP,EAAUC,GAMzB,OALAlD,EAAO,GAAMvM,EACbwQ,EAASjE,EAAO,KAAMkD,EAAKlN,GAG3BgK,EAAO,GAAM,MACLhK,EAAQ0C,SAInByL,IAAOzG,GAAc,SAAUrL,GAC9B,OAAO,SAAUoB,GAChB,OAAyC,EAAlCqD,GAAQzE,EAAUoB,GAAOf,UAIlCmF,SAAY6F,GAAc,SAAU/L,GAEnC,OADAA,EAAOA,EAAK2D,QAASmF,GAAWC,IACzB,SAAUjH,GAChB,OAAkE,GAAzDA,EAAKiO,aAAe1K,EAASvD,IAASvD,QAASyB,MAW1DyS,KAAQ1G,GAAc,SAAU0G,GAO/B,OAJM3K,EAAYoD,KAAMuH,GAAQ,KAC/BtN,GAAOtB,MAAO,qBAAuB4O,GAEtCA,EAAOA,EAAK9O,QAASmF,GAAWC,IAAY7D,cACrC,SAAUpD,GAChB,IAAI4Q,EACJ,GACC,GAAOA,EAAW3M,EACjBjE,EAAK2Q,KACL3Q,EAAK7B,aAAc,aAAgB6B,EAAK7B,aAAc,QAGtD,OADAyS,EAAWA,EAASxN,iBACAuN,GAA2C,IAAnCC,EAASnU,QAASkU,EAAO,YAE3C3Q,EAAOA,EAAKzB,aAAkC,IAAlByB,EAAK7C,UAC7C,OAAO,KAKTiE,OAAU,SAAUpB,GACnB,IAAI6Q,EAAOlV,EAAOmV,UAAYnV,EAAOmV,SAASD,KAC9C,OAAOA,GAAQA,EAAK3U,MAAO,KAAQ8D,EAAKgJ,IAGzC+H,KAAQ,SAAU/Q,GACjB,OAAOA,IAASgE,GAGjBgN,MAAS,SAAUhR,GAClB,OAAOA,IAASxE,EAASyV,iBACrBzV,EAAS0V,UAAY1V,EAAS0V,gBAC7BlR,EAAK1C,MAAQ0C,EAAKmR,OAASnR,EAAKoR,WAItCC,QAAWtG,IAAsB,GACjChD,SAAYgD,IAAsB,GAElCuG,QAAW,SAAUtR,GAIpB,IAAIgI,EAAWhI,EAAKgI,SAAS5E,cAC7B,MAAsB,UAAb4E,KAA0BhI,EAAKsR,SACxB,WAAbtJ,KAA2BhI,EAAKuR,UAGpCA,SAAY,SAAUvR,GASrB,OALKA,EAAKzB,YAETyB,EAAKzB,WAAWiT,eAGQ,IAAlBxR,EAAKuR,UAIbE,MAAS,SAAUzR,GAMlB,IAAMA,EAAOA,EAAKkO,WAAYlO,EAAMA,EAAOA,EAAK4K,YAC/C,GAAK5K,EAAK7C,SAAW,EACpB,OAAO,EAGT,OAAO,GAGR2S,OAAU,SAAU9P,GACnB,OAAQsD,EAAKkC,QAAiB,MAAGxF,IAIlC0R,OAAU,SAAU1R,GACnB,OAAO4G,EAAQwC,KAAMpJ,EAAKgI,WAG3BuE,MAAS,SAAUvM,GAClB,OAAO2G,EAAQyC,KAAMpJ,EAAKgI,WAG3B2J,OAAU,SAAU3R,GACnB,IAAIgB,EAAOhB,EAAKgI,SAAS5E,cACzB,MAAgB,UAATpC,GAAkC,WAAdhB,EAAK1C,MAA8B,WAAT0D,GAGtD9C,KAAQ,SAAU8B,GACjB,IAAI0N,EACJ,MAAuC,UAAhC1N,EAAKgI,SAAS5E,eACN,SAAdpD,EAAK1C,OAIuC,OAAxCoQ,EAAO1N,EAAK7B,aAAc,UACN,SAAvBuP,EAAKtK,gBAIRlD,MAAS+K,GAAwB,WAChC,MAAO,CAAE,KAGV7K,KAAQ6K,GAAwB,SAAU2G,EAAe3S,GACxD,MAAO,CAAEA,EAAS,KAGnBkB,GAAM8K,GAAwB,SAAU2G,EAAe3S,EAAQiM,GAC9D,MAAO,CAAEA,EAAW,EAAIA,EAAWjM,EAASiM,KAG7C7K,KAAQ4K,GAAwB,SAAUE,EAAclM,GAEvD,IADA,IAAInB,EAAI,EACAA,EAAImB,EAAQnB,GAAK,EACxBqN,EAAa3O,KAAMsB,GAEpB,OAAOqN,IAGR3K,IAAOyK,GAAwB,SAAUE,EAAclM,GAEtD,IADA,IAAInB,EAAI,EACAA,EAAImB,EAAQnB,GAAK,EACxBqN,EAAa3O,KAAMsB,GAEpB,OAAOqN,IAGR0G,GAAM5G,GAAwB,SAAUE,EAAclM,EAAQiM,GAM7D,IALA,IAAIpN,EAAIoN,EAAW,EAClBA,EAAWjM,EACAA,EAAXiM,EACCjM,EACAiM,EACa,KAALpN,GACTqN,EAAa3O,KAAMsB,GAEpB,OAAOqN,IAGR2G,GAAM7G,GAAwB,SAAUE,EAAclM,EAAQiM,GAE7D,IADA,IAAIpN,EAAIoN,EAAW,EAAIA,EAAWjM,EAASiM,IACjCpN,EAAImB,GACbkM,EAAa3O,KAAMsB,GAEpB,OAAOqN,OAKL3F,QAAe,IAAIlC,EAAKkC,QAAc,GAGhC,CAAEuM,OAAO,EAAMC,UAAU,EAAMC,MAAM,EAAMC,UAAU,EAAMC,OAAO,GAC5E7O,EAAKkC,QAAS1H,GAAM+M,GAAmB/M,GAExC,IAAMA,IAAK,CAAEsU,QAAQ,EAAMC,OAAO,GACjC/O,EAAKkC,QAAS1H,GAAMgN,GAAoBhN,GAIzC,SAASsS,MA0ET,SAAS7G,GAAY+I,GAIpB,IAHA,IAAIxU,EAAI,EACP2C,EAAM6R,EAAOrT,OACbL,EAAW,GACJd,EAAI2C,EAAK3C,IAChBc,GAAY0T,EAAQxU,GAAIgF,MAEzB,OAAOlE,EAGR,SAASkJ,GAAe0I,EAAS+B,EAAYC,GAC5C,IAAIvK,EAAMsK,EAAWtK,IACpBwK,EAAOF,EAAWrK,KAClB4B,EAAM2I,GAAQxK,EACdyK,EAAmBF,GAAgB,eAAR1I,EAC3B6I,EAAWnO,IAEZ,OAAO+N,EAAWrS,MAGjB,SAAUF,EAAMnB,EAAS4Q,GACxB,MAAUzP,EAAOA,EAAMiI,GACtB,GAAuB,IAAlBjI,EAAK7C,UAAkBuV,EAC3B,OAAOlC,EAASxQ,EAAMnB,EAAS4Q,GAGjC,OAAO,GAIR,SAAUzP,EAAMnB,EAAS4Q,GACxB,IAAImD,EAAUlD,EAAaC,EAC1BkD,EAAW,CAAEtO,EAASoO,GAGvB,GAAKlD,GACJ,MAAUzP,EAAOA,EAAMiI,GACtB,IAAuB,IAAlBjI,EAAK7C,UAAkBuV,IACtBlC,EAASxQ,EAAMnB,EAAS4Q,GAC5B,OAAO,OAKV,MAAUzP,EAAOA,EAAMiI,GACtB,GAAuB,IAAlBjI,EAAK7C,UAAkBuV,EAQ3B,GAHAhD,GAJAC,EAAa3P,EAAM0B,KAAe1B,EAAM0B,GAAY,KAI1B1B,EAAKiQ,YAC5BN,EAAY3P,EAAKiQ,UAAa,IAE5BwC,GAAQA,IAASzS,EAAKgI,SAAS5E,cACnCpD,EAAOA,EAAMiI,IAASjI,MAChB,CAAA,IAAO4S,EAAWlD,EAAa5F,KACrC8I,EAAU,KAAQrO,GAAWqO,EAAU,KAAQD,EAG/C,OAASE,EAAU,GAAMD,EAAU,GAOnC,IAHAlD,EAAa5F,GAAQ+I,GAGJ,GAAMrC,EAASxQ,EAAMnB,EAAS4Q,GAC9C,OAAO,EAMZ,OAAO,GAIV,SAASqD,GAAgBC,GACxB,OAAyB,EAAlBA,EAAS9T,OACf,SAAUe,EAAMnB,EAAS4Q,GACxB,IAAI3R,EAAIiV,EAAS9T,OACjB,MAAQnB,IACP,IAAMiV,EAAUjV,GAAKkC,EAAMnB,EAAS4Q,GACnC,OAAO,EAGT,OAAO,GAERsD,EAAU,GAYZ,SAASC,GAAUvC,EAAW1Q,EAAKkM,EAAQpN,EAAS4Q,GAOnD,IANA,IAAIzP,EACHiT,EAAe,GACfnV,EAAI,EACJ2C,EAAMgQ,EAAUxR,OAChBiU,EAAgB,MAAPnT,EAEFjC,EAAI2C,EAAK3C,KACTkC,EAAOyQ,EAAW3S,MAClBmO,IAAUA,EAAQjM,EAAMnB,EAAS4Q,KACtCwD,EAAazW,KAAMwD,GACdkT,GACJnT,EAAIvD,KAAMsB,KAMd,OAAOmV,EAGR,SAASE,GAAYxE,EAAW/P,EAAU4R,EAAS4C,EAAYC,EAAYC,GAO1E,OANKF,IAAeA,EAAY1R,KAC/B0R,EAAaD,GAAYC,IAErBC,IAAeA,EAAY3R,KAC/B2R,EAAaF,GAAYE,EAAYC,IAE/BrJ,GAAc,SAAU3B,EAAM/F,EAAS1D,EAAS4Q,GACtD,IAAI8D,EAAMzV,EAAGkC,EACZwT,EAAS,GACTC,EAAU,GACVC,EAAcnR,EAAQtD,OAGtBQ,EAAQ6I,GA5CX,SAA2B1J,EAAU+U,EAAUpR,GAG9C,IAFA,IAAIzE,EAAI,EACP2C,EAAMkT,EAAS1U,OACRnB,EAAI2C,EAAK3C,IAChBuF,GAAQzE,EAAU+U,EAAU7V,GAAKyE,GAElC,OAAOA,EAsCWqR,CACfhV,GAAY,IACZC,EAAQ1B,SAAW,CAAE0B,GAAYA,EACjC,IAIDgV,GAAYlF,IAAerG,GAAS1J,EAEnCa,EADAuT,GAAUvT,EAAO+T,EAAQ7E,EAAW9P,EAAS4Q,GAG9CqE,EAAatD,EAGZ6C,IAAgB/K,EAAOqG,EAAY+E,GAAeN,GAGjD,GAGA7Q,EACDsR,EAQF,GALKrD,GACJA,EAASqD,EAAWC,EAAYjV,EAAS4Q,GAIrC2D,EAAa,CACjBG,EAAOP,GAAUc,EAAYL,GAC7BL,EAAYG,EAAM,GAAI1U,EAAS4Q,GAG/B3R,EAAIyV,EAAKtU,OACT,MAAQnB,KACAkC,EAAOuT,EAAMzV,MACnBgW,EAAYL,EAAS3V,MAAW+V,EAAWJ,EAAS3V,IAAQkC,IAK/D,GAAKsI,GACJ,GAAK+K,GAAc1E,EAAY,CAC9B,GAAK0E,EAAa,CAGjBE,EAAO,GACPzV,EAAIgW,EAAW7U,OACf,MAAQnB,KACAkC,EAAO8T,EAAYhW,KAGzByV,EAAK/W,KAAQqX,EAAW/V,GAAMkC,GAGhCqT,EAAY,KAAQS,EAAa,GAAMP,EAAM9D,GAI9C3R,EAAIgW,EAAW7U,OACf,MAAQnB,KACAkC,EAAO8T,EAAYhW,MACsC,GAA7DyV,EAAOF,EAAa5W,EAAS6L,EAAMtI,GAASwT,EAAQ1V,MAEtDwK,EAAMiL,KAAYhR,EAASgR,GAASvT,UAOvC8T,EAAad,GACZc,IAAevR,EACduR,EAAWjT,OAAQ6S,EAAaI,EAAW7U,QAC3C6U,GAEGT,EACJA,EAAY,KAAM9Q,EAASuR,EAAYrE,GAEvCjT,EAAKD,MAAOgG,EAASuR,KAMzB,SAASC,GAAmBzB,GAyB3B,IAxBA,IAAI0B,EAAcxD,EAAS9P,EAC1BD,EAAM6R,EAAOrT,OACbgV,EAAkB3Q,EAAKgL,SAAUgE,EAAQ,GAAIhV,MAC7C4W,EAAmBD,GAAmB3Q,EAAKgL,SAAU,KACrDxQ,EAAImW,EAAkB,EAAI,EAG1BE,EAAerM,GAAe,SAAU9H,GACvC,OAAOA,IAASgU,GACdE,GAAkB,GACrBE,EAAkBtM,GAAe,SAAU9H,GAC1C,OAAwC,EAAjCvD,EAASuX,EAAchU,IAC5BkU,GAAkB,GACrBnB,EAAW,CAAE,SAAU/S,EAAMnB,EAAS4Q,GACrC,IAAI/P,GAASuU,IAAqBxE,GAAO5Q,IAAY+E,MAClDoQ,EAAenV,GAAU1B,SAC1BgX,EAAcnU,EAAMnB,EAAS4Q,GAC7B2E,EAAiBpU,EAAMnB,EAAS4Q,IAIlC,OADAuE,EAAe,KACRtU,IAGD5B,EAAI2C,EAAK3C,IAChB,GAAO0S,EAAUlN,EAAKgL,SAAUgE,EAAQxU,GAAIR,MAC3CyV,EAAW,CAAEjL,GAAegL,GAAgBC,GAAYvC,QAClD,CAIN,IAHAA,EAAUlN,EAAK2I,OAAQqG,EAAQxU,GAAIR,MAAOf,MAAO,KAAM+V,EAAQxU,GAAI6E,UAGrDjB,GAAY,CAIzB,IADAhB,IAAM5C,EACE4C,EAAID,EAAKC,IAChB,GAAK4C,EAAKgL,SAAUgE,EAAQ5R,GAAIpD,MAC/B,MAGF,OAAO6V,GACF,EAAJrV,GAASgV,GAAgBC,GACrB,EAAJjV,GAASyL,GAGT+I,EACEpW,MAAO,EAAG4B,EAAI,GACdxB,OAAQ,CAAEwG,MAAgC,MAAzBwP,EAAQxU,EAAI,GAAIR,KAAe,IAAM,MACtDuE,QAAS8D,EAAO,MAClB6K,EACA1S,EAAI4C,GAAKqT,GAAmBzB,EAAOpW,MAAO4B,EAAG4C,IAC7CA,EAAID,GAAOsT,GAAqBzB,EAASA,EAAOpW,MAAOwE,IACvDA,EAAID,GAAO8I,GAAY+I,IAGzBS,EAASvW,KAAMgU,GAIjB,OAAOsC,GAAgBC,GAoTxB,OAtpBA3C,GAAWlR,UAAYoE,EAAK+Q,QAAU/Q,EAAKkC,QAC3ClC,EAAK8M,WAAa,IAAIA,GAEtB3M,EAAWJ,GAAOI,SAAW,SAAU7E,EAAU0V,GAChD,IAAIhE,EAAS7H,EAAO6J,EAAQhV,EAC3BiX,EAAO7L,EAAQ8L,EACfC,EAAS9P,EAAY/F,EAAW,KAEjC,GAAK6V,EACJ,OAAOH,EAAY,EAAIG,EAAOvY,MAAO,GAGtCqY,EAAQ3V,EACR8J,EAAS,GACT8L,EAAalR,EAAKqL,UAElB,MAAQ4F,EAAQ,CA2Bf,IAAMjX,KAxBAgT,KAAa7H,EAAQ7C,EAAOkD,KAAMyL,MAClC9L,IAGJ8L,EAAQA,EAAMrY,MAAOuM,EAAO,GAAIxJ,SAAYsV,GAE7C7L,EAAOlM,KAAQ8V,EAAS,KAGzBhC,GAAU,GAGH7H,EAAQ5C,EAAaiD,KAAMyL,MACjCjE,EAAU7H,EAAMuB,QAChBsI,EAAO9V,KAAM,CACZsG,MAAOwN,EAGPhT,KAAMmL,EAAO,GAAI5G,QAAS8D,EAAO,OAElC4O,EAAQA,EAAMrY,MAAOoU,EAAQrR,SAIhBqE,EAAK2I,SACXxD,EAAQxC,EAAW3I,GAAOwL,KAAMyL,KAAgBC,EAAYlX,MAChEmL,EAAQ+L,EAAYlX,GAAQmL,MAC9B6H,EAAU7H,EAAMuB,QAChBsI,EAAO9V,KAAM,CACZsG,MAAOwN,EACPhT,KAAMA,EACNqF,QAAS8F,IAEV8L,EAAQA,EAAMrY,MAAOoU,EAAQrR,SAI/B,IAAMqR,EACL,MAOF,OAAOgE,EACNC,EAAMtV,OACNsV,EACClR,GAAOtB,MAAOnD,GAGd+F,EAAY/F,EAAU8J,GAASxM,MAAO,IA4ZzCwH,EAAUL,GAAOK,QAAU,SAAU9E,EAAU6J,GAC9C,IAAI3K,EA9H8B4W,EAAiBC,EAC/CC,EACHC,EACAC,EA4HAH,EAAc,GACdD,EAAkB,GAClBD,EAAS7P,EAAehG,EAAW,KAEpC,IAAM6V,EAAS,CAGRhM,IACLA,EAAQhF,EAAU7E,IAEnBd,EAAI2K,EAAMxJ,OACV,MAAQnB,KACP2W,EAASV,GAAmBtL,EAAO3K,KACtB4D,GACZiT,EAAYnY,KAAMiY,GAElBC,EAAgBlY,KAAMiY,IAKxBA,EAAS7P,EACRhG,GArJgC8V,EAsJNA,EArJxBE,EAA6B,GADkBD,EAsJNA,GArJrB1V,OACvB4V,EAAqC,EAAzBH,EAAgBzV,OAC5B6V,EAAe,SAAUxM,EAAMzJ,EAAS4Q,EAAKlN,EAASwS,GACrD,IAAI/U,EAAMU,EAAG8P,EACZwE,EAAe,EACflX,EAAI,IACJ2S,EAAYnI,GAAQ,GACpB2M,EAAa,GACbC,EAAgBtR,EAGhBnE,EAAQ6I,GAAQuM,GAAavR,EAAK6I,KAAY,IAAG,IAAK4I,GAGtDI,EAAkB5Q,GAA4B,MAAjB2Q,EAAwB,EAAIvT,KAAKC,UAAY,GAC1EnB,EAAMhB,EAAMR,OAcb,IAZK8V,IAMJnR,EAAmB/E,GAAWrD,GAAYqD,GAAWkW,GAM9CjX,IAAM2C,GAAgC,OAAvBT,EAAOP,EAAO3B,IAAeA,IAAM,CACzD,GAAK+W,GAAa7U,EAAO,CACxBU,EAAI,EAME7B,GAAWmB,EAAK6I,eAAiBrN,IACtCuI,EAAa/D,GACbyP,GAAOxL,GAER,MAAUuM,EAAUkE,EAAiBhU,KACpC,GAAK8P,EAASxQ,EAAMnB,GAAWrD,EAAUiU,GAAQ,CAChDlN,EAAQ/F,KAAMwD,GACd,MAGG+U,IACJxQ,EAAU4Q,GAKPP,KAGG5U,GAAQwQ,GAAWxQ,IACzBgV,IAII1M,GACJmI,EAAUjU,KAAMwD,IAgBnB,GATAgV,GAAgBlX,EASX8W,GAAS9W,IAAMkX,EAAe,CAClCtU,EAAI,EACJ,MAAU8P,EAAUmE,EAAajU,KAChC8P,EAASC,EAAWwE,EAAYpW,EAAS4Q,GAG1C,GAAKnH,EAAO,CAGX,GAAoB,EAAf0M,EACJ,MAAQlX,IACC2S,EAAW3S,IAAOmX,EAAYnX,KACrCmX,EAAYnX,GAAMmH,EAAI5I,KAAMkG,IAM/B0S,EAAajC,GAAUiC,GAIxBzY,EAAKD,MAAOgG,EAAS0S,GAGhBF,IAAczM,GAA4B,EAApB2M,EAAWhW,QACG,EAAtC+V,EAAeL,EAAY1V,QAE7BoE,GAAOwK,WAAYtL,GAUrB,OALKwS,IACJxQ,EAAU4Q,EACVvR,EAAmBsR,GAGbzE,GAGFmE,EACN3K,GAAc6K,GACdA,KAgCOlW,SAAWA,EAEnB,OAAO6V,GAYR9Q,EAASN,GAAOM,OAAS,SAAU/E,EAAUC,EAAS0D,EAAS+F,GAC9D,IAAIxK,EAAGwU,EAAQ8C,EAAO9X,EAAM6O,EAC3BkJ,EAA+B,mBAAbzW,GAA2BA,EAC7C6J,GAASH,GAAQ7E,EAAY7E,EAAWyW,EAASzW,UAAYA,GAM9D,GAJA2D,EAAUA,GAAW,GAIC,IAAjBkG,EAAMxJ,OAAe,CAIzB,GAAqB,GADrBqT,EAAS7J,EAAO,GAAMA,EAAO,GAAIvM,MAAO,IAC5B+C,QAA+C,QAA/BmW,EAAQ9C,EAAQ,IAAMhV,MAC5B,IAArBuB,EAAQ1B,UAAkB8G,GAAkBX,EAAKgL,SAAUgE,EAAQ,GAAIhV,MAAS,CAIhF,KAFAuB,GAAYyE,EAAK6I,KAAW,GAAGiJ,EAAMzS,QAAS,GAC5Cd,QAASmF,GAAWC,IAAapI,IAAa,IAAM,IAErD,OAAO0D,EAGI8S,IACXxW,EAAUA,EAAQN,YAGnBK,EAAWA,EAAS1C,MAAOoW,EAAOtI,QAAQlH,MAAM7D,QAIjDnB,EAAImI,EAA0B,aAAEmD,KAAMxK,GAAa,EAAI0T,EAAOrT,OAC9D,MAAQnB,IAAM,CAIb,GAHAsX,EAAQ9C,EAAQxU,GAGXwF,EAAKgL,SAAYhR,EAAO8X,EAAM9X,MAClC,MAED,IAAO6O,EAAO7I,EAAK6I,KAAM7O,MAGjBgL,EAAO6D,EACbiJ,EAAMzS,QAAS,GAAId,QAASmF,GAAWC,IACvCF,GAASqC,KAAMkJ,EAAQ,GAAIhV,OAAU+L,GAAaxK,EAAQN,aACzDM,IACI,CAKL,GAFAyT,EAAOzR,OAAQ/C,EAAG,KAClBc,EAAW0J,EAAKrJ,QAAUsK,GAAY+I,IAGrC,OADA9V,EAAKD,MAAOgG,EAAS+F,GACd/F,EAGR,QAeJ,OAPE8S,GAAY3R,EAAS9E,EAAU6J,IAChCH,EACAzJ,GACCoF,EACD1B,GACC1D,GAAWkI,GAASqC,KAAMxK,IAAcyK,GAAaxK,EAAQN,aAAgBM,GAExE0D,GAMRvF,EAAQgR,WAAatM,EAAQwB,MAAO,IAAKtC,KAAMkE,GAAY0E,KAAM,MAAS9H,EAI1E1E,EAAQ+Q,mBAAqBjK,EAG7BC,IAIA/G,EAAQmQ,aAAejD,GAAQ,SAAUC,GAGxC,OAA4E,EAArEA,EAAG4C,wBAAyBvR,EAASyC,cAAe,eAMtDiM,GAAQ,SAAUC,GAEvB,OADAA,EAAGqC,UAAY,mBACiC,MAAzCrC,EAAG+D,WAAW/P,aAAc,WAEnCiM,GAAW,yBAA0B,SAAUpK,EAAMgB,EAAMwC,GAC1D,IAAMA,EACL,OAAOxD,EAAK7B,aAAc6C,EAA6B,SAAvBA,EAAKoC,cAA2B,EAAI,KAOjEpG,EAAQuI,YAAe2E,GAAQ,SAAUC,GAG9C,OAFAA,EAAGqC,UAAY,WACfrC,EAAG+D,WAAW9P,aAAc,QAAS,IACY,KAA1C+L,EAAG+D,WAAW/P,aAAc,YAEnCiM,GAAW,QAAS,SAAUpK,EAAMsV,EAAO9R,GAC1C,IAAMA,GAAyC,UAAhCxD,EAAKgI,SAAS5E,cAC5B,OAAOpD,EAAKuV,eAOTrL,GAAQ,SAAUC,GACvB,OAAwC,MAAjCA,EAAGhM,aAAc,eAExBiM,GAAWhF,EAAU,SAAUpF,EAAMgB,EAAMwC,GAC1C,IAAIzF,EACJ,IAAMyF,EACL,OAAwB,IAAjBxD,EAAMgB,GAAkBA,EAAKoC,eACjCrF,EAAMiC,EAAKoM,iBAAkBpL,KAAYjD,EAAI4P,UAC9C5P,EAAI+E,MACJ,OAKEO,GA14EP,CA44EK1H,GAILgD,EAAOwN,KAAO9I,EACd1E,EAAO6O,KAAOnK,EAAO+K,UAGrBzP,EAAO6O,KAAM,KAAQ7O,EAAO6O,KAAKhI,QACjC7G,EAAOkP,WAAalP,EAAO6W,OAASnS,EAAOwK,WAC3ClP,EAAOT,KAAOmF,EAAOE,QACrB5E,EAAO8W,SAAWpS,EAAOG,MACzB7E,EAAOyF,SAAWf,EAAOe,SACzBzF,EAAO+W,eAAiBrS,EAAO6D,OAK/B,IAAIe,EAAM,SAAUjI,EAAMiI,EAAK0N,GAC9B,IAAIrF,EAAU,GACbsF,OAAqBnU,IAAVkU,EAEZ,OAAU3V,EAAOA,EAAMiI,KAA6B,IAAlBjI,EAAK7C,SACtC,GAAuB,IAAlB6C,EAAK7C,SAAiB,CAC1B,GAAKyY,GAAYjX,EAAQqB,GAAO6V,GAAIF,GACnC,MAEDrF,EAAQ9T,KAAMwD,GAGhB,OAAOsQ,GAIJwF,EAAW,SAAUC,EAAG/V,GAG3B,IAFA,IAAIsQ,EAAU,GAENyF,EAAGA,EAAIA,EAAEnL,YACI,IAAfmL,EAAE5Y,UAAkB4Y,IAAM/V,GAC9BsQ,EAAQ9T,KAAMuZ,GAIhB,OAAOzF,GAIJ0F,EAAgBrX,EAAO6O,KAAK/E,MAAMhC,aAItC,SAASuB,EAAUhI,EAAMgB,GAEvB,OAAOhB,EAAKgI,UAAYhI,EAAKgI,SAAS5E,gBAAkBpC,EAAKoC,cAG/D,IAAI6S,EAAa,kEAKjB,SAASC,EAAQzI,EAAU0I,EAAW5F,GACrC,OAAKtT,EAAYkZ,GACTxX,EAAO2B,KAAMmN,EAAU,SAAUzN,EAAMlC,GAC7C,QAASqY,EAAU9Z,KAAM2D,EAAMlC,EAAGkC,KAAWuQ,IAK1C4F,EAAUhZ,SACPwB,EAAO2B,KAAMmN,EAAU,SAAUzN,GACvC,OAASA,IAASmW,IAAgB5F,IAKV,iBAAd4F,EACJxX,EAAO2B,KAAMmN,EAAU,SAAUzN,GACvC,OAA4C,EAAnCvD,EAAQJ,KAAM8Z,EAAWnW,KAAkBuQ,IAK/C5R,EAAOsN,OAAQkK,EAAW1I,EAAU8C,GAG5C5R,EAAOsN,OAAS,SAAUuB,EAAM/N,EAAO8Q,GACtC,IAAIvQ,EAAOP,EAAO,GAMlB,OAJK8Q,IACJ/C,EAAO,QAAUA,EAAO,KAGH,IAAjB/N,EAAMR,QAAkC,IAAlBe,EAAK7C,SACxBwB,EAAOwN,KAAKM,gBAAiBzM,EAAMwN,GAAS,CAAExN,GAAS,GAGxDrB,EAAOwN,KAAKxJ,QAAS6K,EAAM7O,EAAO2B,KAAMb,EAAO,SAAUO,GAC/D,OAAyB,IAAlBA,EAAK7C,aAIdwB,EAAOG,GAAGgC,OAAQ,CACjBqL,KAAM,SAAUvN,GACf,IAAId,EAAG4B,EACNe,EAAM7E,KAAKqD,OACXmX,EAAOxa,KAER,GAAyB,iBAAbgD,EACX,OAAOhD,KAAK4D,UAAWb,EAAQC,GAAWqN,OAAQ,WACjD,IAAMnO,EAAI,EAAGA,EAAI2C,EAAK3C,IACrB,GAAKa,EAAOyF,SAAUgS,EAAMtY,GAAKlC,MAChC,OAAO,KAQX,IAFA8D,EAAM9D,KAAK4D,UAAW,IAEhB1B,EAAI,EAAGA,EAAI2C,EAAK3C,IACrBa,EAAOwN,KAAMvN,EAAUwX,EAAMtY,GAAK4B,GAGnC,OAAa,EAANe,EAAU9B,EAAOkP,WAAYnO,GAAQA,GAE7CuM,OAAQ,SAAUrN,GACjB,OAAOhD,KAAK4D,UAAW0W,EAAQta,KAAMgD,GAAY,IAAI,KAEtD2R,IAAK,SAAU3R,GACd,OAAOhD,KAAK4D,UAAW0W,EAAQta,KAAMgD,GAAY,IAAI,KAEtDiX,GAAI,SAAUjX,GACb,QAASsX,EACRta,KAIoB,iBAAbgD,GAAyBoX,EAAc5M,KAAMxK,GACnDD,EAAQC,GACRA,GAAY,IACb,GACCK,UASJ,IAAIoX,EAMHvP,EAAa,uCAENnI,EAAOG,GAAGC,KAAO,SAAUH,EAAUC,EAASkS,GACpD,IAAItI,EAAOzI,EAGX,IAAMpB,EACL,OAAOhD,KAQR,GAHAmV,EAAOA,GAAQsF,EAGU,iBAAbzX,EAAwB,CAanC,KAPC6J,EALsB,MAAlB7J,EAAU,IACsB,MAApCA,EAAUA,EAASK,OAAS,IACT,GAAnBL,EAASK,OAGD,CAAE,KAAML,EAAU,MAGlBkI,EAAWgC,KAAMlK,MAIV6J,EAAO,IAAQ5J,EA6CxB,OAAMA,GAAWA,EAAQM,QACtBN,GAAWkS,GAAO5E,KAAMvN,GAK1BhD,KAAKwD,YAAaP,GAAUsN,KAAMvN,GAhDzC,GAAK6J,EAAO,GAAM,CAYjB,GAXA5J,EAAUA,aAAmBF,EAASE,EAAS,GAAMA,EAIrDF,EAAOgB,MAAO/D,KAAM+C,EAAO2X,UAC1B7N,EAAO,GACP5J,GAAWA,EAAQ1B,SAAW0B,EAAQgK,eAAiBhK,EAAUrD,GACjE,IAIIya,EAAW7M,KAAMX,EAAO,KAAS9J,EAAO2C,cAAezC,GAC3D,IAAM4J,KAAS5J,EAGT5B,EAAYrB,KAAM6M,IACtB7M,KAAM6M,GAAS5J,EAAS4J,IAIxB7M,KAAK8R,KAAMjF,EAAO5J,EAAS4J,IAK9B,OAAO7M,KAYP,OARAoE,EAAOxE,EAASuN,eAAgBN,EAAO,OAKtC7M,KAAM,GAAMoE,EACZpE,KAAKqD,OAAS,GAERrD,KAcH,OAAKgD,EAASzB,UACpBvB,KAAM,GAAMgD,EACZhD,KAAKqD,OAAS,EACPrD,MAIIqB,EAAY2B,QACD6C,IAAfsP,EAAKwF,MACXxF,EAAKwF,MAAO3X,GAGZA,EAAUD,GAGLA,EAAO2D,UAAW1D,EAAUhD,QAIhCsD,UAAYP,EAAOG,GAGxBuX,EAAa1X,EAAQnD,GAGrB,IAAIgb,EAAe,iCAGlBC,EAAmB,CAClBC,UAAU,EACVC,UAAU,EACVzO,MAAM,EACN0O,MAAM,GAoFR,SAASC,EAASpM,EAAKxC,GACtB,OAAUwC,EAAMA,EAAKxC,KAA4B,IAAjBwC,EAAItN,UACpC,OAAOsN,EAnFR9L,EAAOG,GAAGgC,OAAQ,CACjB4P,IAAK,SAAUtP,GACd,IAAI0V,EAAUnY,EAAQyC,EAAQxF,MAC7Bmb,EAAID,EAAQ7X,OAEb,OAAOrD,KAAKqQ,OAAQ,WAEnB,IADA,IAAInO,EAAI,EACAA,EAAIiZ,EAAGjZ,IACd,GAAKa,EAAOyF,SAAUxI,KAAMkb,EAAShZ,IACpC,OAAO,KAMXkZ,QAAS,SAAU5I,EAAWvP,GAC7B,IAAI4L,EACH3M,EAAI,EACJiZ,EAAInb,KAAKqD,OACTqR,EAAU,GACVwG,EAA+B,iBAAd1I,GAA0BzP,EAAQyP,GAGpD,IAAM4H,EAAc5M,KAAMgF,GACzB,KAAQtQ,EAAIiZ,EAAGjZ,IACd,IAAM2M,EAAM7O,KAAMkC,GAAK2M,GAAOA,IAAQ5L,EAAS4L,EAAMA,EAAIlM,WAGxD,GAAKkM,EAAItN,SAAW,KAAQ2Z,GACH,EAAxBA,EAAQG,MAAOxM,GAGE,IAAjBA,EAAItN,UACHwB,EAAOwN,KAAKM,gBAAiBhC,EAAK2D,IAAgB,CAEnDkC,EAAQ9T,KAAMiO,GACd,MAMJ,OAAO7O,KAAK4D,UAA4B,EAAjB8Q,EAAQrR,OAAaN,EAAOkP,WAAYyC,GAAYA,IAI5E2G,MAAO,SAAUjX,GAGhB,OAAMA,EAKe,iBAATA,EACJvD,EAAQJ,KAAMsC,EAAQqB,GAAQpE,KAAM,IAIrCa,EAAQJ,KAAMT,KAGpBoE,EAAKb,OAASa,EAAM,GAAMA,GAZjBpE,KAAM,IAAOA,KAAM,GAAI2C,WAAe3C,KAAKsE,QAAQgX,UAAUjY,QAAU,GAgBlFkY,IAAK,SAAUvY,EAAUC,GACxB,OAAOjD,KAAK4D,UACXb,EAAOkP,WACNlP,EAAOgB,MAAO/D,KAAK0D,MAAOX,EAAQC,EAAUC,OAK/CuY,QAAS,SAAUxY,GAClB,OAAOhD,KAAKub,IAAiB,MAAZvY,EAChBhD,KAAKgE,WAAahE,KAAKgE,WAAWqM,OAAQrN,OAU7CD,EAAOkB,KAAM,CACZiQ,OAAQ,SAAU9P,GACjB,IAAI8P,EAAS9P,EAAKzB,WAClB,OAAOuR,GAA8B,KAApBA,EAAO3S,SAAkB2S,EAAS,MAEpDuH,QAAS,SAAUrX,GAClB,OAAOiI,EAAKjI,EAAM,eAEnBsX,aAAc,SAAUtX,EAAMmD,EAAIwS,GACjC,OAAO1N,EAAKjI,EAAM,aAAc2V,IAEjCzN,KAAM,SAAUlI,GACf,OAAO6W,EAAS7W,EAAM,gBAEvB4W,KAAM,SAAU5W,GACf,OAAO6W,EAAS7W,EAAM,oBAEvBuX,QAAS,SAAUvX,GAClB,OAAOiI,EAAKjI,EAAM,gBAEnBkX,QAAS,SAAUlX,GAClB,OAAOiI,EAAKjI,EAAM,oBAEnBwX,UAAW,SAAUxX,EAAMmD,EAAIwS,GAC9B,OAAO1N,EAAKjI,EAAM,cAAe2V,IAElC8B,UAAW,SAAUzX,EAAMmD,EAAIwS,GAC9B,OAAO1N,EAAKjI,EAAM,kBAAmB2V,IAEtCG,SAAU,SAAU9V,GACnB,OAAO8V,GAAY9V,EAAKzB,YAAc,IAAK2P,WAAYlO,IAExD0W,SAAU,SAAU1W,GACnB,OAAO8V,EAAU9V,EAAKkO,aAEvByI,SAAU,SAAU3W,GACnB,OAA6B,MAAxBA,EAAK0X,iBAKT3b,EAAUiE,EAAK0X,iBAER1X,EAAK0X,iBAMR1P,EAAUhI,EAAM,cACpBA,EAAOA,EAAK2X,SAAW3X,GAGjBrB,EAAOgB,MAAO,GAAIK,EAAKmI,eAE7B,SAAUnH,EAAMlC,GAClBH,EAAOG,GAAIkC,GAAS,SAAU2U,EAAO/W,GACpC,IAAI0R,EAAU3R,EAAOoB,IAAKnE,KAAMkD,EAAI6W,GAuBpC,MArB0B,UAArB3U,EAAK9E,OAAQ,KACjB0C,EAAW+W,GAGP/W,GAAgC,iBAAbA,IACvB0R,EAAU3R,EAAOsN,OAAQrN,EAAU0R,IAGjB,EAAd1U,KAAKqD,SAGHwX,EAAkBzV,IACvBrC,EAAOkP,WAAYyC,GAIfkG,EAAapN,KAAMpI,IACvBsP,EAAQsH,WAIHhc,KAAK4D,UAAW8Q,MAGzB,IAAIuH,EAAgB,oBAsOpB,SAASC,EAAUC,GAClB,OAAOA,EAER,SAASC,EAASC,GACjB,MAAMA,EAGP,SAASC,EAAYpV,EAAOqV,EAASC,EAAQC,GAC5C,IAAIC,EAEJ,IAGMxV,GAAS7F,EAAcqb,EAASxV,EAAMyV,SAC1CD,EAAOjc,KAAMyG,GAAQ0B,KAAM2T,GAAUK,KAAMJ,GAGhCtV,GAAS7F,EAAcqb,EAASxV,EAAM2V,MACjDH,EAAOjc,KAAMyG,EAAOqV,EAASC,GAQ7BD,EAAQ5b,WAAOkF,EAAW,CAAEqB,GAAQ5G,MAAOmc,IAM3C,MAAQvV,GAITsV,EAAO7b,WAAOkF,EAAW,CAAEqB,KAvO7BnE,EAAO+Z,UAAY,SAAU3X,GA9B7B,IAAwBA,EACnB4X,EAiCJ5X,EAA6B,iBAAZA,GAlCMA,EAmCPA,EAlCZ4X,EAAS,GACbha,EAAOkB,KAAMkB,EAAQ0H,MAAOoP,IAAmB,GAAI,SAAUe,EAAGC,GAC/DF,EAAQE,IAAS,IAEXF,GA+BNha,EAAOmC,OAAQ,GAAIC,GAEpB,IACC+X,EAGAC,EAGAC,EAGAC,EAGA9T,EAAO,GAGP+T,EAAQ,GAGRC,GAAe,EAGfC,EAAO,WAQN,IALAH,EAASA,GAAUlY,EAAQsY,KAI3BL,EAAQF,GAAS,EACTI,EAAMja,OAAQka,GAAe,EAAI,CACxCJ,EAASG,EAAMlP,QACf,QAAUmP,EAAchU,EAAKlG,QAGmC,IAA1DkG,EAAMgU,GAAc5c,MAAOwc,EAAQ,GAAKA,EAAQ,KACpDhY,EAAQuY,cAGRH,EAAchU,EAAKlG,OACnB8Z,GAAS,GAMNhY,EAAQgY,SACbA,GAAS,GAGVD,GAAS,EAGJG,IAIH9T,EADI4T,EACG,GAIA,KAMV3C,EAAO,CAGNe,IAAK,WA2BJ,OA1BKhS,IAGC4T,IAAWD,IACfK,EAAchU,EAAKlG,OAAS,EAC5Bia,EAAM1c,KAAMuc,IAGb,SAAW5B,EAAKhH,GACfxR,EAAOkB,KAAMsQ,EAAM,SAAUyI,EAAG/V,GAC1B5F,EAAY4F,GACV9B,EAAQyU,QAAWY,EAAK1F,IAAK7N,IAClCsC,EAAK3I,KAAMqG,GAEDA,GAAOA,EAAI5D,QAA4B,WAAlBR,EAAQoE,IAGxCsU,EAAKtU,KATR,CAYK5C,WAEA8Y,IAAWD,GACfM,KAGKxd,MAIR2d,OAAQ,WAYP,OAXA5a,EAAOkB,KAAMI,UAAW,SAAU2Y,EAAG/V,GACpC,IAAIoU,EACJ,OAA0D,GAAhDA,EAAQtY,EAAO6D,QAASK,EAAKsC,EAAM8R,IAC5C9R,EAAKtE,OAAQoW,EAAO,GAGfA,GAASkC,GACbA,MAIIvd,MAKR8U,IAAK,SAAU5R,GACd,OAAOA,GACwB,EAA9BH,EAAO6D,QAAS1D,EAAIqG,GACN,EAAdA,EAAKlG,QAIPwS,MAAO,WAIN,OAHKtM,IACJA,EAAO,IAEDvJ,MAMR4d,QAAS,WAGR,OAFAP,EAASC,EAAQ,GACjB/T,EAAO4T,EAAS,GACTnd,MAERmM,SAAU,WACT,OAAQ5C,GAMTsU,KAAM,WAKL,OAJAR,EAASC,EAAQ,GACXH,GAAWD,IAChB3T,EAAO4T,EAAS,IAEVnd,MAERqd,OAAQ,WACP,QAASA,GAIVS,SAAU,SAAU7a,EAASsR,GAS5B,OARM8I,IAEL9I,EAAO,CAAEtR,GADTsR,EAAOA,GAAQ,IACQjU,MAAQiU,EAAKjU,QAAUiU,GAC9C+I,EAAM1c,KAAM2T,GACN2I,GACLM,KAGKxd,MAIRwd,KAAM,WAEL,OADAhD,EAAKsD,SAAU9d,KAAMqE,WACdrE,MAIRod,MAAO,WACN,QAASA,IAIZ,OAAO5C,GA4CRzX,EAAOmC,OAAQ,CAEd6Y,SAAU,SAAUC,GACnB,IAAIC,EAAS,CAIX,CAAE,SAAU,WAAYlb,EAAO+Z,UAAW,UACzC/Z,EAAO+Z,UAAW,UAAY,GAC/B,CAAE,UAAW,OAAQ/Z,EAAO+Z,UAAW,eACtC/Z,EAAO+Z,UAAW,eAAiB,EAAG,YACvC,CAAE,SAAU,OAAQ/Z,EAAO+Z,UAAW,eACrC/Z,EAAO+Z,UAAW,eAAiB,EAAG,aAExCoB,EAAQ,UACRvB,EAAU,CACTuB,MAAO,WACN,OAAOA,GAERC,OAAQ,WAEP,OADAC,EAASxV,KAAMvE,WAAYuY,KAAMvY,WAC1BrE,MAERqe,QAAS,SAAUnb,GAClB,OAAOyZ,EAAQE,KAAM,KAAM3Z,IAI5Bob,KAAM,WACL,IAAIC,EAAMla,UAEV,OAAOtB,EAAOgb,SAAU,SAAUS,GACjCzb,EAAOkB,KAAMga,EAAQ,SAAU1W,EAAIkX,GAGlC,IAAIvb,EAAK7B,EAAYkd,EAAKE,EAAO,MAAWF,EAAKE,EAAO,IAKxDL,EAAUK,EAAO,IAAO,WACvB,IAAIC,EAAWxb,GAAMA,EAAGvC,MAAOX,KAAMqE,WAChCqa,GAAYrd,EAAYqd,EAAS/B,SACrC+B,EAAS/B,UACPgC,SAAUH,EAASI,QACnBhW,KAAM4V,EAASjC,SACfK,KAAM4B,EAAShC,QAEjBgC,EAAUC,EAAO,GAAM,QACtBze,KACAkD,EAAK,CAAEwb,GAAara,eAKxBka,EAAM,OACH5B,WAELE,KAAM,SAAUgC,EAAaC,EAAYC,GACxC,IAAIC,EAAW,EACf,SAASzC,EAAS0C,EAAOb,EAAU1P,EAASwQ,GAC3C,OAAO,WACN,IAAIC,EAAOnf,KACVuU,EAAOlQ,UACP+a,EAAa,WACZ,IAAIV,EAAU7B,EAKd,KAAKoC,EAAQD,GAAb,CAQA,IAJAN,EAAWhQ,EAAQ/N,MAAOwe,EAAM5K,MAId6J,EAASzB,UAC1B,MAAM,IAAI0C,UAAW,4BAOtBxC,EAAO6B,IAKgB,iBAAbA,GACY,mBAAbA,IACRA,EAAS7B,KAGLxb,EAAYwb,GAGXqC,EACJrC,EAAKpc,KACJie,EACAnC,EAASyC,EAAUZ,EAAUlC,EAAUgD,GACvC3C,EAASyC,EAAUZ,EAAUhC,EAAS8C,KAOvCF,IAEAnC,EAAKpc,KACJie,EACAnC,EAASyC,EAAUZ,EAAUlC,EAAUgD,GACvC3C,EAASyC,EAAUZ,EAAUhC,EAAS8C,GACtC3C,EAASyC,EAAUZ,EAAUlC,EAC5BkC,EAASkB,eASP5Q,IAAYwN,IAChBiD,OAAOtZ,EACP0O,EAAO,CAAEmK,KAKRQ,GAAWd,EAASmB,aAAeJ,EAAM5K,MAK7CiL,EAAUN,EACTE,EACA,WACC,IACCA,IACC,MAAQ5S,GAEJzJ,EAAOgb,SAAS0B,eACpB1c,EAAOgb,SAAS0B,cAAejT,EAC9BgT,EAAQE,YAMQV,GAAbC,EAAQ,IAIPvQ,IAAY0N,IAChB+C,OAAOtZ,EACP0O,EAAO,CAAE/H,IAGV4R,EAASuB,WAAYR,EAAM5K,MAS3B0K,EACJO,KAKKzc,EAAOgb,SAAS6B,eACpBJ,EAAQE,WAAa3c,EAAOgb,SAAS6B,gBAEtC7f,EAAO8f,WAAYL,KAKtB,OAAOzc,EAAOgb,SAAU,SAAUS,GAGjCP,EAAQ,GAAK,GAAI1C,IAChBgB,EACC,EACAiC,EACAnd,EAAY0d,GACXA,EACA7C,EACDsC,EAASc,aAKXrB,EAAQ,GAAK,GAAI1C,IAChBgB,EACC,EACAiC,EACAnd,EAAYwd,GACXA,EACA3C,IAKH+B,EAAQ,GAAK,GAAI1C,IAChBgB,EACC,EACAiC,EACAnd,EAAYyd,GACXA,EACA1C,MAGAO,WAKLA,QAAS,SAAUrb,GAClB,OAAc,MAAPA,EAAcyB,EAAOmC,OAAQ5D,EAAKqb,GAAYA,IAGvDyB,EAAW,GAkEZ,OA/DArb,EAAOkB,KAAMga,EAAQ,SAAU/b,EAAGuc,GACjC,IAAIlV,EAAOkV,EAAO,GACjBqB,EAAcrB,EAAO,GAKtB9B,EAAS8B,EAAO,IAAQlV,EAAKgS,IAGxBuE,GACJvW,EAAKgS,IACJ,WAIC2C,EAAQ4B,GAKT7B,EAAQ,EAAI/b,GAAK,GAAI0b,QAIrBK,EAAQ,EAAI/b,GAAK,GAAI0b,QAGrBK,EAAQ,GAAK,GAAIJ,KAGjBI,EAAQ,GAAK,GAAIJ,MAOnBtU,EAAKgS,IAAKkD,EAAO,GAAIjB,MAKrBY,EAAUK,EAAO,IAAQ,WAExB,OADAL,EAAUK,EAAO,GAAM,QAAUze,OAASoe,OAAWvY,EAAY7F,KAAMqE,WAChErE,MAMRoe,EAAUK,EAAO,GAAM,QAAWlV,EAAKuU,WAIxCnB,EAAQA,QAASyB,GAGZJ,GACJA,EAAKvd,KAAM2d,EAAUA,GAIfA,GAIR2B,KAAM,SAAUC,GACf,IAGCC,EAAY5b,UAAUhB,OAGtBnB,EAAI+d,EAGJC,EAAkBva,MAAOzD,GACzBie,EAAgB7f,EAAMG,KAAM4D,WAG5B+b,EAASrd,EAAOgb,WAGhBsC,EAAa,SAAUne,GACtB,OAAO,SAAUgF,GAChBgZ,EAAiBhe,GAAMlC,KACvBmgB,EAAeje,GAAyB,EAAnBmC,UAAUhB,OAAa/C,EAAMG,KAAM4D,WAAc6C,IAC5D+Y,GACTG,EAAOb,YAAaW,EAAiBC,KAMzC,GAAKF,GAAa,IACjB3D,EAAY0D,EAAaI,EAAOxX,KAAMyX,EAAYne,IAAMqa,QAAS6D,EAAO5D,QACtEyD,GAGsB,YAAnBG,EAAOlC,SACX7c,EAAY8e,EAAeje,IAAOie,EAAeje,GAAI2a,OAErD,OAAOuD,EAAOvD,OAKhB,MAAQ3a,IACPoa,EAAY6D,EAAeje,GAAKme,EAAYne,GAAKke,EAAO5D,QAGzD,OAAO4D,EAAOzD,aAOhB,IAAI2D,EAAc,yDAElBvd,EAAOgb,SAAS0B,cAAgB,SAAUtZ,EAAOoa,GAI3CxgB,EAAOygB,SAAWzgB,EAAOygB,QAAQC,MAAQta,GAASma,EAAY9S,KAAMrH,EAAMf,OAC9ErF,EAAOygB,QAAQC,KAAM,8BAAgCta,EAAMua,QAASva,EAAMoa,MAAOA,IAOnFxd,EAAO4d,eAAiB,SAAUxa,GACjCpG,EAAO8f,WAAY,WAClB,MAAM1Z,KAQR,IAAIya,EAAY7d,EAAOgb,WAkDvB,SAAS8C,IACRjhB,EAASkhB,oBAAqB,mBAAoBD,GAClD9gB,EAAO+gB,oBAAqB,OAAQD,GACpC9d,EAAO4X,QAnDR5X,EAAOG,GAAGyX,MAAQ,SAAUzX,GAY3B,OAVA0d,EACE/D,KAAM3Z,GAKNmb,SAAO,SAAUlY,GACjBpD,EAAO4d,eAAgBxa,KAGlBnG,MAGR+C,EAAOmC,OAAQ,CAGdgB,SAAS,EAIT6a,UAAW,EAGXpG,MAAO,SAAUqG,KAGF,IAATA,IAAkBje,EAAOge,UAAYhe,EAAOmD,WAKjDnD,EAAOmD,SAAU,KAGZ8a,GAAsC,IAAnBje,EAAOge,WAK/BH,EAAUrB,YAAa3f,EAAU,CAAEmD,OAIrCA,EAAO4X,MAAMkC,KAAO+D,EAAU/D,KAaD,aAAxBjd,EAASqhB,YACa,YAAxBrhB,EAASqhB,aAA6BrhB,EAAS8P,gBAAgBwR,SAGjEnhB,EAAO8f,WAAY9c,EAAO4X,QAK1B/a,EAASmQ,iBAAkB,mBAAoB8Q,GAG/C9gB,EAAOgQ,iBAAkB,OAAQ8Q,IAQlC,IAAIM,EAAS,SAAUtd,EAAOX,EAAIgL,EAAKhH,EAAOka,EAAWC,EAAUC,GAClE,IAAIpf,EAAI,EACP2C,EAAMhB,EAAMR,OACZke,EAAc,MAAPrT,EAGR,GAAuB,WAAlBrL,EAAQqL,GAEZ,IAAMhM,KADNkf,GAAY,EACDlT,EACViT,EAAQtd,EAAOX,EAAIhB,EAAGgM,EAAKhM,IAAK,EAAMmf,EAAUC,QAI3C,QAAezb,IAAVqB,IACXka,GAAY,EAEN/f,EAAY6F,KACjBoa,GAAM,GAGFC,IAGCD,GACJpe,EAAGzC,KAAMoD,EAAOqD,GAChBhE,EAAK,OAILqe,EAAOre,EACPA,EAAK,SAAUkB,EAAMod,EAAMta,GAC1B,OAAOqa,EAAK9gB,KAAMsC,EAAQqB,GAAQ8C,MAKhChE,GACJ,KAAQhB,EAAI2C,EAAK3C,IAChBgB,EACCW,EAAO3B,GAAKgM,EAAKoT,EACjBpa,EACAA,EAAMzG,KAAMoD,EAAO3B,GAAKA,EAAGgB,EAAIW,EAAO3B,GAAKgM,KAM/C,OAAKkT,EACGvd,EAIH0d,EACGre,EAAGzC,KAAMoD,GAGVgB,EAAM3B,EAAIW,EAAO,GAAKqK,GAAQmT,GAKlCI,EAAY,QACfC,EAAa,YAGd,SAASC,EAAYC,EAAMC,GAC1B,OAAOA,EAAOC,cAMf,SAASC,EAAWC,GACnB,OAAOA,EAAO/b,QAASwb,EAAW,OAAQxb,QAASyb,EAAYC,GAEhE,IAAIM,EAAa,SAAUC,GAQ1B,OAA0B,IAAnBA,EAAM3gB,UAAqC,IAAnB2gB,EAAM3gB,YAAsB2gB,EAAM3gB,UAMlE,SAAS4gB,IACRniB,KAAK8F,QAAU/C,EAAO+C,QAAUqc,EAAKC,MAGtCD,EAAKC,IAAM,EAEXD,EAAK7e,UAAY,CAEhB2K,MAAO,SAAUiU,GAGhB,IAAIhb,EAAQgb,EAAOliB,KAAK8F,SA4BxB,OAzBMoB,IACLA,EAAQ,GAKH+a,EAAYC,KAIXA,EAAM3gB,SACV2gB,EAAOliB,KAAK8F,SAAYoB,EAMxB9G,OAAOiiB,eAAgBH,EAAOliB,KAAK8F,QAAS,CAC3CoB,MAAOA,EACPob,cAAc,MAMXpb,GAERqb,IAAK,SAAUL,EAAOM,EAAMtb,GAC3B,IAAIub,EACHxU,EAAQjO,KAAKiO,MAAOiU,GAIrB,GAAqB,iBAATM,EACXvU,EAAO8T,EAAWS,IAAWtb,OAM7B,IAAMub,KAAQD,EACbvU,EAAO8T,EAAWU,IAAWD,EAAMC,GAGrC,OAAOxU,GAERvK,IAAK,SAAUwe,EAAOhU,GACrB,YAAerI,IAARqI,EACNlO,KAAKiO,MAAOiU,GAGZA,EAAOliB,KAAK8F,UAAaoc,EAAOliB,KAAK8F,SAAWic,EAAW7T,KAE7DiT,OAAQ,SAAUe,EAAOhU,EAAKhH,GAa7B,YAAarB,IAARqI,GACCA,GAAsB,iBAARA,QAAgCrI,IAAVqB,EAElClH,KAAK0D,IAAKwe,EAAOhU,IASzBlO,KAAKuiB,IAAKL,EAAOhU,EAAKhH,QAILrB,IAAVqB,EAAsBA,EAAQgH,IAEtCyP,OAAQ,SAAUuE,EAAOhU,GACxB,IAAIhM,EACH+L,EAAQiU,EAAOliB,KAAK8F,SAErB,QAAeD,IAAVoI,EAAL,CAIA,QAAapI,IAARqI,EAAoB,CAkBxBhM,GAXCgM,EAJIvI,MAAMC,QAASsI,GAIbA,EAAI/J,IAAK4d,IAEf7T,EAAM6T,EAAW7T,MAIJD,EACZ,CAAEC,GACAA,EAAIrB,MAAOoP,IAAmB,IAG1B5Y,OAER,MAAQnB,WACA+L,EAAOC,EAAKhM,UAKR2D,IAARqI,GAAqBnL,EAAOyD,cAAeyH,MAM1CiU,EAAM3gB,SACV2gB,EAAOliB,KAAK8F,cAAYD,SAEjBqc,EAAOliB,KAAK8F,YAItB4c,QAAS,SAAUR,GAClB,IAAIjU,EAAQiU,EAAOliB,KAAK8F,SACxB,YAAiBD,IAAVoI,IAAwBlL,EAAOyD,cAAeyH,KAGvD,IAAI0U,EAAW,IAAIR,EAEfS,EAAW,IAAIT,EAcfU,EAAS,gCACZC,EAAa,SA2Bd,SAASC,EAAU3e,EAAM8J,EAAKsU,GAC7B,IAAIpd,EA1Baod,EA8BjB,QAAc3c,IAAT2c,GAAwC,IAAlBpe,EAAK7C,SAI/B,GAHA6D,EAAO,QAAU8I,EAAIjI,QAAS6c,EAAY,OAAQtb,cAG7B,iBAFrBgb,EAAOpe,EAAK7B,aAAc6C,IAEM,CAC/B,IACCod,EAnCW,UADGA,EAoCEA,IA/BL,UAATA,IAIS,SAATA,EACG,KAIHA,KAAUA,EAAO,IACbA,EAGJK,EAAOrV,KAAMgV,GACVQ,KAAKC,MAAOT,GAGbA,GAeH,MAAQhW,IAGVoW,EAASL,IAAKne,EAAM8J,EAAKsU,QAEzBA,OAAO3c,EAGT,OAAO2c,EAGRzf,EAAOmC,OAAQ,CACdwd,QAAS,SAAUte,GAClB,OAAOwe,EAASF,QAASte,IAAUue,EAASD,QAASte,IAGtDoe,KAAM,SAAUpe,EAAMgB,EAAMod,GAC3B,OAAOI,EAASzB,OAAQ/c,EAAMgB,EAAMod,IAGrCU,WAAY,SAAU9e,EAAMgB,GAC3Bwd,EAASjF,OAAQvZ,EAAMgB,IAKxB+d,MAAO,SAAU/e,EAAMgB,EAAMod,GAC5B,OAAOG,EAASxB,OAAQ/c,EAAMgB,EAAMod,IAGrCY,YAAa,SAAUhf,EAAMgB,GAC5Bud,EAAShF,OAAQvZ,EAAMgB,MAIzBrC,EAAOG,GAAGgC,OAAQ,CACjBsd,KAAM,SAAUtU,EAAKhH,GACpB,IAAIhF,EAAGkD,EAAMod,EACZpe,EAAOpE,KAAM,GACbyO,EAAQrK,GAAQA,EAAKuF,WAGtB,QAAa9D,IAARqI,EAAoB,CACxB,GAAKlO,KAAKqD,SACTmf,EAAOI,EAASlf,IAAKU,GAEE,IAAlBA,EAAK7C,WAAmBohB,EAASjf,IAAKU,EAAM,iBAAmB,CACnElC,EAAIuM,EAAMpL,OACV,MAAQnB,IAIFuM,EAAOvM,IAEsB,KADjCkD,EAAOqJ,EAAOvM,GAAIkD,MACRvE,QAAS,WAClBuE,EAAO2c,EAAW3c,EAAK9E,MAAO,IAC9ByiB,EAAU3e,EAAMgB,EAAMod,EAAMpd,KAI/Bud,EAASJ,IAAKne,EAAM,gBAAgB,GAItC,OAAOoe,EAIR,MAAoB,iBAARtU,EACJlO,KAAKiE,KAAM,WACjB2e,EAASL,IAAKviB,KAAMkO,KAIfiT,EAAQnhB,KAAM,SAAUkH,GAC9B,IAAIsb,EAOJ,GAAKpe,QAAkByB,IAAVqB,EAKZ,YAAcrB,KADd2c,EAAOI,EAASlf,IAAKU,EAAM8J,IAEnBsU,OAMM3c,KADd2c,EAAOO,EAAU3e,EAAM8J,IAEfsU,OAIR,EAIDxiB,KAAKiE,KAAM,WAGV2e,EAASL,IAAKviB,KAAMkO,EAAKhH,MAExB,KAAMA,EAA0B,EAAnB7C,UAAUhB,OAAY,MAAM,IAG7C6f,WAAY,SAAUhV,GACrB,OAAOlO,KAAKiE,KAAM,WACjB2e,EAASjF,OAAQ3d,KAAMkO,QAM1BnL,EAAOmC,OAAQ,CACdoY,MAAO,SAAUlZ,EAAM1C,EAAM8gB,GAC5B,IAAIlF,EAEJ,GAAKlZ,EAYJ,OAXA1C,GAASA,GAAQ,MAAS,QAC1B4b,EAAQqF,EAASjf,IAAKU,EAAM1C,GAGvB8gB,KACElF,GAAS3X,MAAMC,QAAS4c,GAC7BlF,EAAQqF,EAASxB,OAAQ/c,EAAM1C,EAAMqB,EAAO2D,UAAW8b,IAEvDlF,EAAM1c,KAAM4hB,IAGPlF,GAAS,IAIlB+F,QAAS,SAAUjf,EAAM1C,GACxBA,EAAOA,GAAQ,KAEf,IAAI4b,EAAQva,EAAOua,MAAOlZ,EAAM1C,GAC/B4hB,EAAchG,EAAMja,OACpBH,EAAKoa,EAAMlP,QACXmV,EAAQxgB,EAAOygB,YAAapf,EAAM1C,GAMvB,eAAPwB,IACJA,EAAKoa,EAAMlP,QACXkV,KAGIpgB,IAIU,OAATxB,GACJ4b,EAAM3L,QAAS,qBAIT4R,EAAME,KACbvgB,EAAGzC,KAAM2D,EApBF,WACNrB,EAAOsgB,QAASjf,EAAM1C,IAmBF6hB,KAGhBD,GAAeC,GACpBA,EAAM1N,MAAM2H,QAKdgG,YAAa,SAAUpf,EAAM1C,GAC5B,IAAIwM,EAAMxM,EAAO,aACjB,OAAOihB,EAASjf,IAAKU,EAAM8J,IAASyU,EAASxB,OAAQ/c,EAAM8J,EAAK,CAC/D2H,MAAO9S,EAAO+Z,UAAW,eAAgBvB,IAAK,WAC7CoH,EAAShF,OAAQvZ,EAAM,CAAE1C,EAAO,QAASwM,WAM7CnL,EAAOG,GAAGgC,OAAQ,CACjBoY,MAAO,SAAU5b,EAAM8gB,GACtB,IAAIkB,EAAS,EAQb,MANqB,iBAAThiB,IACX8gB,EAAO9gB,EACPA,EAAO,KACPgiB,KAGIrf,UAAUhB,OAASqgB,EAChB3gB,EAAOua,MAAOtd,KAAM,GAAK0B,QAGjBmE,IAAT2c,EACNxiB,KACAA,KAAKiE,KAAM,WACV,IAAIqZ,EAAQva,EAAOua,MAAOtd,KAAM0B,EAAM8gB,GAGtCzf,EAAOygB,YAAaxjB,KAAM0B,GAEZ,OAATA,GAAgC,eAAf4b,EAAO,IAC5Bva,EAAOsgB,QAASrjB,KAAM0B,MAI1B2hB,QAAS,SAAU3hB,GAClB,OAAO1B,KAAKiE,KAAM,WACjBlB,EAAOsgB,QAASrjB,KAAM0B,MAGxBiiB,WAAY,SAAUjiB,GACrB,OAAO1B,KAAKsd,MAAO5b,GAAQ,KAAM,KAKlCib,QAAS,SAAUjb,EAAMJ,GACxB,IAAIoP,EACHkT,EAAQ,EACRC,EAAQ9gB,EAAOgb,WACflM,EAAW7R,KACXkC,EAAIlC,KAAKqD,OACTkZ,EAAU,aACCqH,GACTC,EAAMtE,YAAa1N,EAAU,CAAEA,KAIb,iBAATnQ,IACXJ,EAAMI,EACNA,OAAOmE,GAERnE,EAAOA,GAAQ,KAEf,MAAQQ,KACPwO,EAAMiS,EAASjf,IAAKmO,EAAU3P,GAAKR,EAAO,gBAC9BgP,EAAImF,QACf+N,IACAlT,EAAImF,MAAM0F,IAAKgB,IAIjB,OADAA,IACOsH,EAAMlH,QAASrb,MAGxB,IAAIwiB,GAAO,sCAA0CC,OAEjDC,GAAU,IAAIla,OAAQ,iBAAmBga,GAAO,cAAe,KAG/DG,GAAY,CAAE,MAAO,QAAS,SAAU,QAExCvU,GAAkB9P,EAAS8P,gBAI1BwU,GAAa,SAAU9f,GACzB,OAAOrB,EAAOyF,SAAUpE,EAAK6I,cAAe7I,IAE7C+f,GAAW,CAAEA,UAAU,GAOnBzU,GAAgB0U,cACpBF,GAAa,SAAU9f,GACtB,OAAOrB,EAAOyF,SAAUpE,EAAK6I,cAAe7I,IAC3CA,EAAKggB,YAAaD,MAAe/f,EAAK6I,gBAG1C,IAAIoX,GAAqB,SAAUjgB,EAAMmK,GAOvC,MAA8B,UAH9BnK,EAAOmK,GAAMnK,GAGDkgB,MAAMC,SACM,KAAvBngB,EAAKkgB,MAAMC,SAMXL,GAAY9f,IAEsB,SAAlCrB,EAAOyhB,IAAKpgB,EAAM,YAKrB,SAASqgB,GAAWrgB,EAAMqe,EAAMiC,EAAYC,GAC3C,IAAIC,EAAUC,EACbC,EAAgB,GAChBC,EAAeJ,EACd,WACC,OAAOA,EAAM9V,OAEd,WACC,OAAO9L,EAAOyhB,IAAKpgB,EAAMqe,EAAM,KAEjCuC,EAAUD,IACVE,EAAOP,GAAcA,EAAY,KAAS3hB,EAAOmiB,UAAWzC,GAAS,GAAK,MAG1E0C,EAAgB/gB,EAAK7C,WAClBwB,EAAOmiB,UAAWzC,IAAmB,OAATwC,IAAkBD,IAChDhB,GAAQ9W,KAAMnK,EAAOyhB,IAAKpgB,EAAMqe,IAElC,GAAK0C,GAAiBA,EAAe,KAAQF,EAAO,CAInDD,GAAoB,EAGpBC,EAAOA,GAAQE,EAAe,GAG9BA,GAAiBH,GAAW,EAE5B,MAAQF,IAIP/hB,EAAOuhB,MAAOlgB,EAAMqe,EAAM0C,EAAgBF,IACnC,EAAIJ,IAAY,GAAMA,EAAQE,IAAiBC,GAAW,MAAW,IAC3EF,EAAgB,GAEjBK,GAAgCN,EAIjCM,GAAgC,EAChCpiB,EAAOuhB,MAAOlgB,EAAMqe,EAAM0C,EAAgBF,GAG1CP,EAAaA,GAAc,GAgB5B,OAbKA,IACJS,GAAiBA,IAAkBH,GAAW,EAG9CJ,EAAWF,EAAY,GACtBS,GAAkBT,EAAY,GAAM,GAAMA,EAAY,IACrDA,EAAY,GACTC,IACJA,EAAMM,KAAOA,EACbN,EAAM1Q,MAAQkR,EACdR,EAAM5f,IAAM6f,IAGPA,EAIR,IAAIQ,GAAoB,GAyBxB,SAASC,GAAUxT,EAAUyT,GAO5B,IANA,IAAIf,EAASngB,EAxBcA,EACvBuT,EACH1V,EACAmK,EACAmY,EAqBAgB,EAAS,GACTlK,EAAQ,EACRhY,EAASwO,EAASxO,OAGXgY,EAAQhY,EAAQgY,KACvBjX,EAAOyN,EAAUwJ,IACNiJ,QAIXC,EAAUngB,EAAKkgB,MAAMC,QAChBe,GAKa,SAAZf,IACJgB,EAAQlK,GAAUsH,EAASjf,IAAKU,EAAM,YAAe,KAC/CmhB,EAAQlK,KACbjX,EAAKkgB,MAAMC,QAAU,KAGK,KAAvBngB,EAAKkgB,MAAMC,SAAkBF,GAAoBjgB,KACrDmhB,EAAQlK,IA7CVkJ,EAFAtiB,EADG0V,OAAAA,EACH1V,GAF0BmC,EAiDaA,GA/C5B6I,cACXb,EAAWhI,EAAKgI,UAChBmY,EAAUa,GAAmBhZ,MAM9BuL,EAAO1V,EAAIujB,KAAK9iB,YAAaT,EAAII,cAAe+J,IAChDmY,EAAUxhB,EAAOyhB,IAAK7M,EAAM,WAE5BA,EAAKhV,WAAWC,YAAa+U,GAEZ,SAAZ4M,IACJA,EAAU,SAEXa,GAAmBhZ,GAAamY,MAkCb,SAAZA,IACJgB,EAAQlK,GAAU,OAGlBsH,EAASJ,IAAKne,EAAM,UAAWmgB,KAMlC,IAAMlJ,EAAQ,EAAGA,EAAQhY,EAAQgY,IACR,MAAnBkK,EAAQlK,KACZxJ,EAAUwJ,GAAQiJ,MAAMC,QAAUgB,EAAQlK,IAI5C,OAAOxJ,EAGR9O,EAAOG,GAAGgC,OAAQ,CACjBogB,KAAM,WACL,OAAOD,GAAUrlB,MAAM,IAExBylB,KAAM,WACL,OAAOJ,GAAUrlB,OAElB0lB,OAAQ,SAAUxH,GACjB,MAAsB,kBAAVA,EACJA,EAAQle,KAAKslB,OAAStlB,KAAKylB,OAG5BzlB,KAAKiE,KAAM,WACZogB,GAAoBrkB,MACxB+C,EAAQ/C,MAAOslB,OAEfviB,EAAQ/C,MAAOylB,YAKnB,IAUEE,GACAhV,GAXEiV,GAAiB,wBAEjBC,GAAW,iCAEXC,GAAc,qCAMhBH,GADc/lB,EAASmmB,yBACRrjB,YAAa9C,EAASyC,cAAe,SACpDsO,GAAQ/Q,EAASyC,cAAe,UAM3BG,aAAc,OAAQ,SAC5BmO,GAAMnO,aAAc,UAAW,WAC/BmO,GAAMnO,aAAc,OAAQ,KAE5BmjB,GAAIjjB,YAAaiO,IAIjBvP,EAAQ4kB,WAAaL,GAAIM,WAAW,GAAOA,WAAW,GAAO7R,UAAUsB,QAIvEiQ,GAAI/U,UAAY,yBAChBxP,EAAQ8kB,iBAAmBP,GAAIM,WAAW,GAAO7R,UAAUuF,aAK3DgM,GAAI/U,UAAY,oBAChBxP,EAAQ+kB,SAAWR,GAAIvR,UAKxB,IAAIgS,GAAU,CAKbC,MAAO,CAAE,EAAG,UAAW,YACvBC,IAAK,CAAE,EAAG,oBAAqB,uBAC/BC,GAAI,CAAE,EAAG,iBAAkB,oBAC3BC,GAAI,CAAE,EAAG,qBAAsB,yBAE/BC,SAAU,CAAE,EAAG,GAAI,KAYpB,SAASC,GAAQzjB,EAASwN,GAIzB,IAAI3M,EAYJ,OATCA,EAD4C,oBAAjCb,EAAQoK,qBACbpK,EAAQoK,qBAAsBoD,GAAO,KAEI,oBAA7BxN,EAAQ4K,iBACpB5K,EAAQ4K,iBAAkB4C,GAAO,KAGjC,QAGM5K,IAAR4K,GAAqBA,GAAOrE,EAAUnJ,EAASwN,GAC5C1N,EAAOgB,MAAO,CAAEd,GAAWa,GAG5BA,EAKR,SAAS6iB,GAAe9iB,EAAO+iB,GAI9B,IAHA,IAAI1kB,EAAI,EACPiZ,EAAItX,EAAMR,OAEHnB,EAAIiZ,EAAGjZ,IACdygB,EAASJ,IACR1e,EAAO3B,GACP,cACC0kB,GAAejE,EAASjf,IAAKkjB,EAAa1kB,GAAK,eA1CnDkkB,GAAQS,MAAQT,GAAQU,MAAQV,GAAQW,SAAWX,GAAQY,QAAUZ,GAAQC,MAC7ED,GAAQa,GAAKb,GAAQI,GAGfplB,EAAQ+kB,SACbC,GAAQc,SAAWd,GAAQD,OAAS,CAAE,EAAG,+BAAgC,cA2C1E,IAAIrb,GAAQ,YAEZ,SAASqc,GAAetjB,EAAOZ,EAASmkB,EAASC,EAAWC,GAO3D,IANA,IAAIljB,EAAMsM,EAAKD,EAAK8W,EAAMC,EAAU1iB,EACnC2iB,EAAWxkB,EAAQ8iB,yBACnB2B,EAAQ,GACRxlB,EAAI,EACJiZ,EAAItX,EAAMR,OAEHnB,EAAIiZ,EAAGjZ,IAGd,IAFAkC,EAAOP,EAAO3B,KAEQ,IAATkC,EAGZ,GAAwB,WAAnBvB,EAAQuB,GAIZrB,EAAOgB,MAAO2jB,EAAOtjB,EAAK7C,SAAW,CAAE6C,GAASA,QAG1C,GAAM0G,GAAM0C,KAAMpJ,GAIlB,CACNsM,EAAMA,GAAO+W,EAAS/kB,YAAaO,EAAQZ,cAAe,QAG1DoO,GAAQoV,GAAS3Y,KAAM9I,IAAU,CAAE,GAAI,KAAQ,GAAIoD,cACnD+f,EAAOnB,GAAS3V,IAAS2V,GAAQK,SACjC/V,EAAIE,UAAY2W,EAAM,GAAMxkB,EAAO4kB,cAAevjB,GAASmjB,EAAM,GAGjEziB,EAAIyiB,EAAM,GACV,MAAQziB,IACP4L,EAAMA,EAAI0D,UAKXrR,EAAOgB,MAAO2jB,EAAOhX,EAAInE,aAGzBmE,EAAM+W,EAASnV,YAGXD,YAAc,QAzBlBqV,EAAM9mB,KAAMqC,EAAQ2kB,eAAgBxjB,IA+BvCqjB,EAASpV,YAAc,GAEvBnQ,EAAI,EACJ,MAAUkC,EAAOsjB,EAAOxlB,KAGvB,GAAKmlB,IAAkD,EAArCtkB,EAAO6D,QAASxC,EAAMijB,GAClCC,GACJA,EAAQ1mB,KAAMwD,QAgBhB,GAXAojB,EAAWtD,GAAY9f,GAGvBsM,EAAMgW,GAAQe,EAAS/kB,YAAa0B,GAAQ,UAGvCojB,GACJb,GAAejW,GAIX0W,EAAU,CACdtiB,EAAI,EACJ,MAAUV,EAAOsM,EAAK5L,KAChBghB,GAAYtY,KAAMpJ,EAAK1C,MAAQ,KACnC0lB,EAAQxmB,KAAMwD,GAMlB,OAAOqjB,EAIR,IACCI,GAAY,OACZC,GAAc,iDACdC,GAAiB,sBAElB,SAASC,KACR,OAAO,EAGR,SAASC,KACR,OAAO,EASR,SAASC,GAAY9jB,EAAM1C,GAC1B,OAAS0C,IAMV,WACC,IACC,OAAOxE,EAASyV,cACf,MAAQ8S,KATQC,KAAqC,UAAT1mB,GAY/C,SAAS2mB,GAAIjkB,EAAMkkB,EAAOtlB,EAAUwf,EAAMtf,EAAIqlB,GAC7C,IAAIC,EAAQ9mB,EAGZ,GAAsB,iBAAV4mB,EAAqB,CAShC,IAAM5mB,IANmB,iBAAbsB,IAGXwf,EAAOA,GAAQxf,EACfA,OAAW6C,GAEEyiB,EACbD,GAAIjkB,EAAM1C,EAAMsB,EAAUwf,EAAM8F,EAAO5mB,GAAQ6mB,GAEhD,OAAOnkB,EAsBR,GAnBa,MAARoe,GAAsB,MAANtf,GAGpBA,EAAKF,EACLwf,EAAOxf,OAAW6C,GACD,MAAN3C,IACc,iBAAbF,GAGXE,EAAKsf,EACLA,OAAO3c,IAIP3C,EAAKsf,EACLA,EAAOxf,EACPA,OAAW6C,KAGD,IAAP3C,EACJA,EAAK+kB,QACC,IAAM/kB,EACZ,OAAOkB,EAeR,OAZa,IAARmkB,IACJC,EAAStlB,GACTA,EAAK,SAAUulB,GAId,OADA1lB,IAAS2lB,IAAKD,GACPD,EAAO7nB,MAAOX,KAAMqE,aAIzB8C,KAAOqhB,EAAOrhB,OAAUqhB,EAAOrhB,KAAOpE,EAAOoE,SAE1C/C,EAAKH,KAAM,WACjBlB,EAAO0lB,MAAMlN,IAAKvb,KAAMsoB,EAAOplB,EAAIsf,EAAMxf,KA+a3C,SAAS2lB,GAAgBpa,EAAI7M,EAAMwmB,GAG5BA,GAQNvF,EAASJ,IAAKhU,EAAI7M,GAAM,GACxBqB,EAAO0lB,MAAMlN,IAAKhN,EAAI7M,EAAM,CAC3B8N,WAAW,EACXd,QAAS,SAAU+Z,GAClB,IAAIG,EAAUtV,EACbuV,EAAQlG,EAASjf,IAAK1D,KAAM0B,GAE7B,GAAyB,EAAlB+mB,EAAMK,WAAmB9oB,KAAM0B,IAKrC,GAAMmnB,EAAMxlB,QAiCEN,EAAO0lB,MAAMvJ,QAASxd,IAAU,IAAKqnB,cAClDN,EAAMO,uBAfN,GAdAH,EAAQvoB,EAAMG,KAAM4D,WACpBse,EAASJ,IAAKviB,KAAM0B,EAAMmnB,GAK1BD,EAAWV,EAAYloB,KAAM0B,GAC7B1B,KAAM0B,KAEDmnB,KADLvV,EAASqP,EAASjf,IAAK1D,KAAM0B,KACJknB,EACxBjG,EAASJ,IAAKviB,KAAM0B,GAAM,GAE1B4R,EAAS,GAELuV,IAAUvV,EAKd,OAFAmV,EAAMQ,2BACNR,EAAMS,iBACC5V,EAAOpM,WAeL2hB,EAAMxlB,SAGjBsf,EAASJ,IAAKviB,KAAM0B,EAAM,CACzBwF,MAAOnE,EAAO0lB,MAAMU,QAInBpmB,EAAOmC,OAAQ2jB,EAAO,GAAK9lB,EAAOqmB,MAAM9lB,WACxCulB,EAAMvoB,MAAO,GACbN,QAKFyoB,EAAMQ,qCAzE0BpjB,IAA7B8c,EAASjf,IAAK6K,EAAI7M,IACtBqB,EAAO0lB,MAAMlN,IAAKhN,EAAI7M,EAAMsmB,IA5a/BjlB,EAAO0lB,MAAQ,CAEdjpB,OAAQ,GAER+b,IAAK,SAAUnX,EAAMkkB,EAAO5Z,EAAS8T,EAAMxf,GAE1C,IAAIqmB,EAAaC,EAAa5Y,EAC7B6Y,EAAQC,EAAGC,EACXvK,EAASwK,EAAUhoB,EAAMioB,EAAYC,EACrCC,EAAWlH,EAASjf,IAAKU,GAG1B,GAAM6d,EAAY7d,GAAlB,CAKKsK,EAAQA,UAEZA,GADA2a,EAAc3a,GACQA,QACtB1L,EAAWqmB,EAAYrmB,UAKnBA,GACJD,EAAOwN,KAAKM,gBAAiBnB,GAAiB1M,GAIzC0L,EAAQvH,OACbuH,EAAQvH,KAAOpE,EAAOoE,SAIfoiB,EAASM,EAASN,UACzBA,EAASM,EAASN,OAASnpB,OAAO0pB,OAAQ,QAEnCR,EAAcO,EAASE,UAC9BT,EAAcO,EAASE,OAAS,SAAUvd,GAIzC,MAAyB,oBAAXzJ,GAA0BA,EAAO0lB,MAAMuB,YAAcxd,EAAE9K,KACpEqB,EAAO0lB,MAAMwB,SAAStpB,MAAOyD,EAAMC,gBAAcwB,IAMpD2jB,GADAlB,GAAUA,GAAS,IAAKzb,MAAOoP,IAAmB,CAAE,KAC1C5Y,OACV,MAAQmmB,IAEP9nB,EAAOkoB,GADPlZ,EAAMqX,GAAe7a,KAAMob,EAAOkB,KAAS,IACpB,GACvBG,GAAejZ,EAAK,IAAO,IAAKpJ,MAAO,KAAMtC,OAGvCtD,IAKNwd,EAAUnc,EAAO0lB,MAAMvJ,QAASxd,IAAU,GAG1CA,GAASsB,EAAWkc,EAAQ6J,aAAe7J,EAAQgL,WAAcxoB,EAGjEwd,EAAUnc,EAAO0lB,MAAMvJ,QAASxd,IAAU,GAG1C+nB,EAAY1mB,EAAOmC,OAAQ,CAC1BxD,KAAMA,EACNkoB,SAAUA,EACVpH,KAAMA,EACN9T,QAASA,EACTvH,KAAMuH,EAAQvH,KACdnE,SAAUA,EACV6H,aAAc7H,GAAYD,EAAO6O,KAAK/E,MAAMhC,aAAa2C,KAAMxK,GAC/DwM,UAAWma,EAAW/b,KAAM,MAC1Byb,IAGKK,EAAWH,EAAQ7nB,OAC1BgoB,EAAWH,EAAQ7nB,GAAS,IACnByoB,cAAgB,EAGnBjL,EAAQkL,QACiD,IAA9DlL,EAAQkL,MAAM3pB,KAAM2D,EAAMoe,EAAMmH,EAAYL,IAEvCllB,EAAK2L,kBACT3L,EAAK2L,iBAAkBrO,EAAM4nB,IAK3BpK,EAAQ3D,MACZ2D,EAAQ3D,IAAI9a,KAAM2D,EAAMqlB,GAElBA,EAAU/a,QAAQvH,OACvBsiB,EAAU/a,QAAQvH,KAAOuH,EAAQvH,OAK9BnE,EACJ0mB,EAASzkB,OAAQykB,EAASS,gBAAiB,EAAGV,GAE9CC,EAAS9oB,KAAM6oB,GAIhB1mB,EAAO0lB,MAAMjpB,OAAQkC,IAAS,KAMhCic,OAAQ,SAAUvZ,EAAMkkB,EAAO5Z,EAAS1L,EAAUqnB,GAEjD,IAAIvlB,EAAGwlB,EAAW5Z,EACjB6Y,EAAQC,EAAGC,EACXvK,EAASwK,EAAUhoB,EAAMioB,EAAYC,EACrCC,EAAWlH,EAASD,QAASte,IAAUue,EAASjf,IAAKU,GAEtD,GAAMylB,IAAeN,EAASM,EAASN,QAAvC,CAMAC,GADAlB,GAAUA,GAAS,IAAKzb,MAAOoP,IAAmB,CAAE,KAC1C5Y,OACV,MAAQmmB,IAMP,GAJA9nB,EAAOkoB,GADPlZ,EAAMqX,GAAe7a,KAAMob,EAAOkB,KAAS,IACpB,GACvBG,GAAejZ,EAAK,IAAO,IAAKpJ,MAAO,KAAMtC,OAGvCtD,EAAN,CAOAwd,EAAUnc,EAAO0lB,MAAMvJ,QAASxd,IAAU,GAE1CgoB,EAAWH,EADX7nB,GAASsB,EAAWkc,EAAQ6J,aAAe7J,EAAQgL,WAAcxoB,IACpC,GAC7BgP,EAAMA,EAAK,IACV,IAAI5G,OAAQ,UAAY6f,EAAW/b,KAAM,iBAAoB,WAG9D0c,EAAYxlB,EAAI4kB,EAASrmB,OACzB,MAAQyB,IACP2kB,EAAYC,EAAU5kB,IAEfulB,GAAeT,IAAaH,EAAUG,UACzClb,GAAWA,EAAQvH,OAASsiB,EAAUtiB,MACtCuJ,IAAOA,EAAIlD,KAAMic,EAAUja,YAC3BxM,GAAYA,IAAaymB,EAAUzmB,WACxB,OAAbA,IAAqBymB,EAAUzmB,YAChC0mB,EAASzkB,OAAQH,EAAG,GAEf2kB,EAAUzmB,UACd0mB,EAASS,gBAELjL,EAAQvB,QACZuB,EAAQvB,OAAOld,KAAM2D,EAAMqlB,IAOzBa,IAAcZ,EAASrmB,SACrB6b,EAAQqL,WACkD,IAA/DrL,EAAQqL,SAAS9pB,KAAM2D,EAAMulB,EAAYE,EAASE,SAElDhnB,EAAOynB,YAAapmB,EAAM1C,EAAMmoB,EAASE,eAGnCR,EAAQ7nB,SA1Cf,IAAMA,KAAQ6nB,EACbxmB,EAAO0lB,MAAM9K,OAAQvZ,EAAM1C,EAAO4mB,EAAOkB,GAAK9a,EAAS1L,GAAU,GA8C/DD,EAAOyD,cAAe+iB,IAC1B5G,EAAShF,OAAQvZ,EAAM,mBAIzB6lB,SAAU,SAAUQ,GAEnB,IAAIvoB,EAAG4C,EAAGhB,EAAK4Q,EAAS+U,EAAWiB,EAClCnW,EAAO,IAAI5O,MAAOtB,UAAUhB,QAG5BolB,EAAQ1lB,EAAO0lB,MAAMkC,IAAKF,GAE1Bf,GACE/G,EAASjf,IAAK1D,KAAM,WAAcI,OAAO0pB,OAAQ,OAC/CrB,EAAM/mB,OAAU,GACpBwd,EAAUnc,EAAO0lB,MAAMvJ,QAASuJ,EAAM/mB,OAAU,GAKjD,IAFA6S,EAAM,GAAMkU,EAENvmB,EAAI,EAAGA,EAAImC,UAAUhB,OAAQnB,IAClCqS,EAAMrS,GAAMmC,UAAWnC,GAMxB,GAHAumB,EAAMmC,eAAiB5qB,MAGlBkf,EAAQ2L,cAA2D,IAA5C3L,EAAQ2L,YAAYpqB,KAAMT,KAAMyoB,GAA5D,CAKAiC,EAAe3nB,EAAO0lB,MAAMiB,SAASjpB,KAAMT,KAAMyoB,EAAOiB,GAGxDxnB,EAAI,EACJ,OAAUwS,EAAUgW,EAAcxoB,QAAYumB,EAAMqC,uBAAyB,CAC5ErC,EAAMsC,cAAgBrW,EAAQtQ,KAE9BU,EAAI,EACJ,OAAU2kB,EAAY/U,EAAQgV,SAAU5kB,QACtC2jB,EAAMuC,gCAIDvC,EAAMwC,aAAsC,IAAxBxB,EAAUja,YACnCiZ,EAAMwC,WAAWzd,KAAMic,EAAUja,aAEjCiZ,EAAMgB,UAAYA,EAClBhB,EAAMjG,KAAOiH,EAAUjH,UAKV3c,KAHb/B,IAAUf,EAAO0lB,MAAMvJ,QAASuK,EAAUG,WAAc,IAAKG,QAC5DN,EAAU/a,SAAU/N,MAAO+T,EAAQtQ,KAAMmQ,MAGT,KAAzBkU,EAAMnV,OAASxP,KACrB2kB,EAAMS,iBACNT,EAAMO,oBAYX,OAJK9J,EAAQgM,cACZhM,EAAQgM,aAAazqB,KAAMT,KAAMyoB,GAG3BA,EAAMnV,SAGdoW,SAAU,SAAUjB,EAAOiB,GAC1B,IAAIxnB,EAAGunB,EAAWzX,EAAKmZ,EAAiBC,EACvCV,EAAe,GACfP,EAAgBT,EAASS,cACzBtb,EAAM4Z,EAAMjjB,OAGb,GAAK2kB,GAIJtb,EAAItN,YAOc,UAAfknB,EAAM/mB,MAAoC,GAAhB+mB,EAAM1S,QAEnC,KAAQlH,IAAQ7O,KAAM6O,EAAMA,EAAIlM,YAAc3C,KAI7C,GAAsB,IAAjB6O,EAAItN,WAAoC,UAAfknB,EAAM/mB,OAAqC,IAAjBmN,EAAI1C,UAAsB,CAGjF,IAFAgf,EAAkB,GAClBC,EAAmB,GACblpB,EAAI,EAAGA,EAAIioB,EAAejoB,SAME2D,IAA5BulB,EAFLpZ,GAHAyX,EAAYC,EAAUxnB,IAGNc,SAAW,OAG1BooB,EAAkBpZ,GAAQyX,EAAU5e,cACC,EAApC9H,EAAQiP,EAAKhS,MAAOqb,MAAOxM,GAC3B9L,EAAOwN,KAAMyB,EAAKhS,KAAM,KAAM,CAAE6O,IAAQxL,QAErC+nB,EAAkBpZ,IACtBmZ,EAAgBvqB,KAAM6oB,GAGnB0B,EAAgB9nB,QACpBqnB,EAAa9pB,KAAM,CAAEwD,KAAMyK,EAAK6a,SAAUyB,IAY9C,OALAtc,EAAM7O,KACDmqB,EAAgBT,EAASrmB,QAC7BqnB,EAAa9pB,KAAM,CAAEwD,KAAMyK,EAAK6a,SAAUA,EAASppB,MAAO6pB,KAGpDO,GAGRW,QAAS,SAAUjmB,EAAMkmB,GACxBlrB,OAAOiiB,eAAgBtf,EAAOqmB,MAAM9lB,UAAW8B,EAAM,CACpDmmB,YAAY,EACZjJ,cAAc,EAEd5e,IAAKrC,EAAYiqB,GAChB,WACC,GAAKtrB,KAAKwrB,cACR,OAAOF,EAAMtrB,KAAKwrB,gBAGrB,WACC,GAAKxrB,KAAKwrB,cACR,OAAOxrB,KAAKwrB,cAAepmB,IAI/Bmd,IAAK,SAAUrb,GACd9G,OAAOiiB,eAAgBriB,KAAMoF,EAAM,CAClCmmB,YAAY,EACZjJ,cAAc,EACdmJ,UAAU,EACVvkB,MAAOA,QAMXyjB,IAAK,SAAUa,GACd,OAAOA,EAAezoB,EAAO+C,SAC5B0lB,EACA,IAAIzoB,EAAOqmB,MAAOoC,IAGpBtM,QAAS,CACRwM,KAAM,CAGLC,UAAU,GAEXC,MAAO,CAGNxB,MAAO,SAAU5H,GAIhB,IAAIjU,EAAKvO,MAAQwiB,EAWjB,OARKoD,GAAepY,KAAMe,EAAG7M,OAC5B6M,EAAGqd,OAASxf,EAAUmC,EAAI,UAG1Boa,GAAgBpa,EAAI,QAASyZ,KAIvB,GAERmB,QAAS,SAAU3G,GAIlB,IAAIjU,EAAKvO,MAAQwiB,EAUjB,OAPKoD,GAAepY,KAAMe,EAAG7M,OAC5B6M,EAAGqd,OAASxf,EAAUmC,EAAI,UAE1Boa,GAAgBpa,EAAI,UAId,GAKRkY,SAAU,SAAUgC,GACnB,IAAIjjB,EAASijB,EAAMjjB,OACnB,OAAOogB,GAAepY,KAAMhI,EAAO9D,OAClC8D,EAAOomB,OAASxf,EAAU5G,EAAQ,UAClCmd,EAASjf,IAAK8B,EAAQ,UACtB4G,EAAU5G,EAAQ,OAIrBqmB,aAAc,CACbX,aAAc,SAAUzC,QAID5iB,IAAjB4iB,EAAMnV,QAAwBmV,EAAM+C,gBACxC/C,EAAM+C,cAAcM,YAAcrD,EAAMnV,YA8F7CvQ,EAAOynB,YAAc,SAAUpmB,EAAM1C,EAAMqoB,GAGrC3lB,EAAK0c,qBACT1c,EAAK0c,oBAAqBpf,EAAMqoB,IAIlChnB,EAAOqmB,MAAQ,SAAUznB,EAAKoqB,GAG7B,KAAQ/rB,gBAAgB+C,EAAOqmB,OAC9B,OAAO,IAAIrmB,EAAOqmB,MAAOznB,EAAKoqB,GAI1BpqB,GAAOA,EAAID,MACf1B,KAAKwrB,cAAgB7pB,EACrB3B,KAAK0B,KAAOC,EAAID,KAIhB1B,KAAKgsB,mBAAqBrqB,EAAIsqB,uBACHpmB,IAAzBlE,EAAIsqB,mBAGgB,IAApBtqB,EAAImqB,YACL9D,GACAC,GAKDjoB,KAAKwF,OAAW7D,EAAI6D,QAAkC,IAAxB7D,EAAI6D,OAAOjE,SACxCI,EAAI6D,OAAO7C,WACXhB,EAAI6D,OAELxF,KAAK+qB,cAAgBppB,EAAIopB,cACzB/qB,KAAKksB,cAAgBvqB,EAAIuqB,eAIzBlsB,KAAK0B,KAAOC,EAIRoqB,GACJhpB,EAAOmC,OAAQlF,KAAM+rB,GAItB/rB,KAAKmsB,UAAYxqB,GAAOA,EAAIwqB,WAAa1jB,KAAK2jB,MAG9CpsB,KAAM+C,EAAO+C,UAAY,GAK1B/C,EAAOqmB,MAAM9lB,UAAY,CACxBE,YAAaT,EAAOqmB,MACpB4C,mBAAoB/D,GACpB6C,qBAAsB7C,GACtB+C,8BAA+B/C,GAC/BoE,aAAa,EAEbnD,eAAgB,WACf,IAAI1c,EAAIxM,KAAKwrB,cAEbxrB,KAAKgsB,mBAAqBhE,GAErBxb,IAAMxM,KAAKqsB,aACf7f,EAAE0c,kBAGJF,gBAAiB,WAChB,IAAIxc,EAAIxM,KAAKwrB,cAEbxrB,KAAK8qB,qBAAuB9C,GAEvBxb,IAAMxM,KAAKqsB,aACf7f,EAAEwc,mBAGJC,yBAA0B,WACzB,IAAIzc,EAAIxM,KAAKwrB,cAEbxrB,KAAKgrB,8BAAgChD,GAEhCxb,IAAMxM,KAAKqsB,aACf7f,EAAEyc,2BAGHjpB,KAAKgpB,oBAKPjmB,EAAOkB,KAAM,CACZqoB,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,gBAAgB,EAChBC,SAAS,EACTC,QAAQ,EACRC,YAAY,EACZC,SAAS,EACTC,OAAO,EACPC,OAAO,EACPC,UAAU,EACVC,MAAM,EACNC,QAAQ,EACRnrB,MAAM,EACNorB,UAAU,EACVjf,KAAK,EACLkf,SAAS,EACTrX,QAAQ,EACRsX,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,WAAW,EACXC,aAAa,EACbC,SAAS,EACTC,SAAS,EACTC,eAAe,EACfC,WAAW,EACXC,SAAS,EAETC,MAAO,SAAUxF,GAChB,IAAI1S,EAAS0S,EAAM1S,OAGnB,OAAoB,MAAf0S,EAAMwF,OAAiBpG,GAAUra,KAAMib,EAAM/mB,MACxB,MAAlB+mB,EAAM0E,SAAmB1E,EAAM0E,SAAW1E,EAAM2E,SAIlD3E,EAAMwF,YAAoBpoB,IAAXkQ,GAAwB+R,GAAYta,KAAMib,EAAM/mB,MACtD,EAATqU,EACG,EAGM,EAATA,EACG,EAGM,EAATA,EACG,EAGD,EAGD0S,EAAMwF,QAEZlrB,EAAO0lB,MAAM4C,SAEhBtoB,EAAOkB,KAAM,CAAEmR,MAAO,UAAW8Y,KAAM,YAAc,SAAUxsB,EAAMqnB,GACpEhmB,EAAO0lB,MAAMvJ,QAASxd,GAAS,CAG9B0oB,MAAO,WAQN,OAHAzB,GAAgB3oB,KAAM0B,EAAMwmB,KAGrB,GAERiB,QAAS,WAMR,OAHAR,GAAgB3oB,KAAM0B,IAGf,GAGRqnB,aAAcA,KAYhBhmB,EAAOkB,KAAM,CACZkqB,WAAY,YACZC,WAAY,WACZC,aAAc,cACdC,aAAc,cACZ,SAAUC,EAAM5D,GAClB5nB,EAAO0lB,MAAMvJ,QAASqP,GAAS,CAC9BxF,aAAc4B,EACdT,SAAUS,EAEVZ,OAAQ,SAAUtB,GACjB,IAAI3kB,EAEH0qB,EAAU/F,EAAMyD,cAChBzC,EAAYhB,EAAMgB,UASnB,OALM+E,IAAaA,IANTxuB,MAMgC+C,EAAOyF,SANvCxI,KAMyDwuB,MAClE/F,EAAM/mB,KAAO+nB,EAAUG,SACvB9lB,EAAM2lB,EAAU/a,QAAQ/N,MAAOX,KAAMqE,WACrCokB,EAAM/mB,KAAOipB,GAEP7mB,MAKVf,EAAOG,GAAGgC,OAAQ,CAEjBmjB,GAAI,SAAUC,EAAOtlB,EAAUwf,EAAMtf,GACpC,OAAOmlB,GAAIroB,KAAMsoB,EAAOtlB,EAAUwf,EAAMtf,IAEzCqlB,IAAK,SAAUD,EAAOtlB,EAAUwf,EAAMtf,GACrC,OAAOmlB,GAAIroB,KAAMsoB,EAAOtlB,EAAUwf,EAAMtf,EAAI,IAE7CwlB,IAAK,SAAUJ,EAAOtlB,EAAUE,GAC/B,IAAIumB,EAAW/nB,EACf,GAAK4mB,GAASA,EAAMY,gBAAkBZ,EAAMmB,UAW3C,OARAA,EAAYnB,EAAMmB,UAClB1mB,EAAQulB,EAAMsC,gBAAiBlC,IAC9Be,EAAUja,UACTia,EAAUG,SAAW,IAAMH,EAAUja,UACrCia,EAAUG,SACXH,EAAUzmB,SACVymB,EAAU/a,SAEJ1O,KAER,GAAsB,iBAAVsoB,EAAqB,CAGhC,IAAM5mB,KAAQ4mB,EACbtoB,KAAK0oB,IAAKhnB,EAAMsB,EAAUslB,EAAO5mB,IAElC,OAAO1B,KAWR,OATkB,IAAbgD,GAA0C,mBAAbA,IAGjCE,EAAKF,EACLA,OAAW6C,IAEA,IAAP3C,IACJA,EAAK+kB,IAECjoB,KAAKiE,KAAM,WACjBlB,EAAO0lB,MAAM9K,OAAQ3d,KAAMsoB,EAAOplB,EAAIF,QAMzC,IAKCyrB,GAAe,wBAGfC,GAAW,oCACXC,GAAe,2CAGhB,SAASC,GAAoBxqB,EAAM2X,GAClC,OAAK3P,EAAUhI,EAAM,UACpBgI,EAA+B,KAArB2P,EAAQxa,SAAkBwa,EAAUA,EAAQzJ,WAAY,OAE3DvP,EAAQqB,GAAO0W,SAAU,SAAW,IAGrC1W,EAIR,SAASyqB,GAAezqB,GAEvB,OADAA,EAAK1C,MAAyC,OAAhC0C,EAAK7B,aAAc,SAAsB,IAAM6B,EAAK1C,KAC3D0C,EAER,SAAS0qB,GAAe1qB,GAOvB,MAN2C,WAApCA,EAAK1C,MAAQ,IAAKpB,MAAO,EAAG,GAClC8D,EAAK1C,KAAO0C,EAAK1C,KAAKpB,MAAO,GAE7B8D,EAAK2J,gBAAiB,QAGhB3J,EAGR,SAAS2qB,GAAgBptB,EAAKqtB,GAC7B,IAAI9sB,EAAGiZ,EAAGzZ,EAAgButB,EAAUC,EAAU3F,EAE9C,GAAuB,IAAlByF,EAAKztB,SAAV,CAKA,GAAKohB,EAASD,QAAS/gB,KAEtB4nB,EADW5G,EAASjf,IAAK/B,GACP4nB,QAKjB,IAAM7nB,KAFNihB,EAAShF,OAAQqR,EAAM,iBAETzF,EACb,IAAMrnB,EAAI,EAAGiZ,EAAIoO,EAAQ7nB,GAAO2B,OAAQnB,EAAIiZ,EAAGjZ,IAC9Ca,EAAO0lB,MAAMlN,IAAKyT,EAAMttB,EAAM6nB,EAAQ7nB,GAAQQ,IAO7C0gB,EAASF,QAAS/gB,KACtBstB,EAAWrM,EAASzB,OAAQxf,GAC5ButB,EAAWnsB,EAAOmC,OAAQ,GAAI+pB,GAE9BrM,EAASL,IAAKyM,EAAME,KAkBtB,SAASC,GAAUC,EAAY7a,EAAMrQ,EAAUojB,GAG9C/S,EAAOhU,EAAMgU,GAEb,IAAIkT,EAAUnjB,EAAO8iB,EAASiI,EAAYrtB,EAAMC,EAC/CC,EAAI,EACJiZ,EAAIiU,EAAW/rB,OACfisB,EAAWnU,EAAI,EACfjU,EAAQqN,EAAM,GACdgb,EAAkBluB,EAAY6F,GAG/B,GAAKqoB,GACG,EAAJpU,GAA0B,iBAAVjU,IAChB9F,EAAQ4kB,YAAc0I,GAASlhB,KAAMtG,GACxC,OAAOkoB,EAAWnrB,KAAM,SAAUoX,GACjC,IAAIb,EAAO4U,EAAW7qB,GAAI8W,GACrBkU,IACJhb,EAAM,GAAMrN,EAAMzG,KAAMT,KAAMqb,EAAOb,EAAKgV,SAE3CL,GAAU3U,EAAMjG,EAAMrQ,EAAUojB,KAIlC,GAAKnM,IAEJ7W,GADAmjB,EAAWN,GAAe5S,EAAM6a,EAAY,GAAIniB,eAAe,EAAOmiB,EAAY9H,IACjEhV,WAEmB,IAA/BmV,EAASlb,WAAWlJ,SACxBokB,EAAWnjB,GAIPA,GAASgjB,GAAU,CAOvB,IALA+H,GADAjI,EAAUrkB,EAAOoB,IAAKuiB,GAAQe,EAAU,UAAYoH,KAC/BxrB,OAKbnB,EAAIiZ,EAAGjZ,IACdF,EAAOylB,EAEFvlB,IAAMotB,IACVttB,EAAOe,EAAOwC,MAAOvD,GAAM,GAAM,GAG5BqtB,GAIJtsB,EAAOgB,MAAOqjB,EAASV,GAAQ1kB,EAAM,YAIvCkC,EAASzD,KAAM2uB,EAAYltB,GAAKF,EAAME,GAGvC,GAAKmtB,EAOJ,IANAptB,EAAMmlB,EAASA,EAAQ/jB,OAAS,GAAI4J,cAGpClK,EAAOoB,IAAKijB,EAAS0H,IAGf5sB,EAAI,EAAGA,EAAImtB,EAAYntB,IAC5BF,EAAOolB,EAASllB,GACX4jB,GAAYtY,KAAMxL,EAAKN,MAAQ,MAClCihB,EAASxB,OAAQnf,EAAM,eACxBe,EAAOyF,SAAUvG,EAAKD,KAEjBA,EAAKL,KAA8C,YAArCK,EAAKN,MAAQ,IAAK8F,cAG/BzE,EAAO0sB,WAAaztB,EAAKH,UAC7BkB,EAAO0sB,SAAUztB,EAAKL,IAAK,CAC1BC,MAAOI,EAAKJ,OAASI,EAAKO,aAAc,UACtCN,GAGJH,EAASE,EAAKqQ,YAAYpM,QAAS0oB,GAAc,IAAM3sB,EAAMC,IAQnE,OAAOmtB,EAGR,SAASzR,GAAQvZ,EAAMpB,EAAU0sB,GAKhC,IAJA,IAAI1tB,EACH0lB,EAAQ1kB,EAAWD,EAAOsN,OAAQrN,EAAUoB,GAASA,EACrDlC,EAAI,EAE4B,OAAvBF,EAAO0lB,EAAOxlB,IAAeA,IAChCwtB,GAA8B,IAAlB1tB,EAAKT,UACtBwB,EAAO4sB,UAAWjJ,GAAQ1kB,IAGtBA,EAAKW,aACJ+sB,GAAYxL,GAAYliB,IAC5B2kB,GAAeD,GAAQ1kB,EAAM,WAE9BA,EAAKW,WAAWC,YAAaZ,IAI/B,OAAOoC,EAGRrB,EAAOmC,OAAQ,CACdyiB,cAAe,SAAU6H,GACxB,OAAOA,GAGRjqB,MAAO,SAAUnB,EAAMwrB,EAAeC,GACrC,IAAI3tB,EAAGiZ,EAAG2U,EAAaC,EApINpuB,EAAKqtB,EACnB5iB,EAoIF7G,EAAQnB,EAAK6hB,WAAW,GACxB+J,EAAS9L,GAAY9f,GAGtB,KAAMhD,EAAQ8kB,gBAAsC,IAAlB9hB,EAAK7C,UAAoC,KAAlB6C,EAAK7C,UAC3DwB,EAAO8W,SAAUzV,IAMnB,IAHA2rB,EAAerJ,GAAQnhB,GAGjBrD,EAAI,EAAGiZ,GAFb2U,EAAcpJ,GAAQtiB,IAEOf,OAAQnB,EAAIiZ,EAAGjZ,IAhJ5BP,EAiJLmuB,EAAa5tB,GAjJH8sB,EAiJQe,EAAc7tB,QAhJzCkK,EAGc,WAHdA,EAAW4iB,EAAK5iB,SAAS5E,gBAGAoe,GAAepY,KAAM7L,EAAID,MACrDstB,EAAKtZ,QAAU/T,EAAI+T,QAGK,UAAbtJ,GAAqC,aAAbA,IACnC4iB,EAAKrV,aAAehY,EAAIgY,cA6IxB,GAAKiW,EACJ,GAAKC,EAIJ,IAHAC,EAAcA,GAAepJ,GAAQtiB,GACrC2rB,EAAeA,GAAgBrJ,GAAQnhB,GAEjCrD,EAAI,EAAGiZ,EAAI2U,EAAYzsB,OAAQnB,EAAIiZ,EAAGjZ,IAC3C6sB,GAAgBe,EAAa5tB,GAAK6tB,EAAc7tB,SAGjD6sB,GAAgB3qB,EAAMmB,GAWxB,OAL2B,GAD3BwqB,EAAerJ,GAAQnhB,EAAO,WACZlC,QACjBsjB,GAAeoJ,GAAeC,GAAUtJ,GAAQtiB,EAAM,WAIhDmB,GAGRoqB,UAAW,SAAU9rB,GAKpB,IAJA,IAAI2e,EAAMpe,EAAM1C,EACfwd,EAAUnc,EAAO0lB,MAAMvJ,QACvBhd,EAAI,OAE6B2D,KAAxBzB,EAAOP,EAAO3B,IAAqBA,IAC5C,GAAK+f,EAAY7d,GAAS,CACzB,GAAOoe,EAAOpe,EAAMue,EAAS7c,SAAc,CAC1C,GAAK0c,EAAK+G,OACT,IAAM7nB,KAAQ8gB,EAAK+G,OACbrK,EAASxd,GACbqB,EAAO0lB,MAAM9K,OAAQvZ,EAAM1C,GAI3BqB,EAAOynB,YAAapmB,EAAM1C,EAAM8gB,EAAKuH,QAOxC3lB,EAAMue,EAAS7c,cAAYD,EAEvBzB,EAAMwe,EAAS9c,WAInB1B,EAAMwe,EAAS9c,cAAYD,OAOhC9C,EAAOG,GAAGgC,OAAQ,CACjB+qB,OAAQ,SAAUjtB,GACjB,OAAO2a,GAAQ3d,KAAMgD,GAAU,IAGhC2a,OAAQ,SAAU3a,GACjB,OAAO2a,GAAQ3d,KAAMgD,IAGtBV,KAAM,SAAU4E,GACf,OAAOia,EAAQnhB,KAAM,SAAUkH,GAC9B,YAAiBrB,IAAVqB,EACNnE,EAAOT,KAAMtC,MACbA,KAAK6V,QAAQ5R,KAAM,WACK,IAAlBjE,KAAKuB,UAAoC,KAAlBvB,KAAKuB,UAAqC,IAAlBvB,KAAKuB,WACxDvB,KAAKqS,YAAcnL,MAGpB,KAAMA,EAAO7C,UAAUhB,SAG3B6sB,OAAQ,WACP,OAAOf,GAAUnvB,KAAMqE,UAAW,SAAUD,GACpB,IAAlBpE,KAAKuB,UAAoC,KAAlBvB,KAAKuB,UAAqC,IAAlBvB,KAAKuB,UAC3CqtB,GAAoB5uB,KAAMoE,GAChC1B,YAAa0B,MAKvB+rB,QAAS,WACR,OAAOhB,GAAUnvB,KAAMqE,UAAW,SAAUD,GAC3C,GAAuB,IAAlBpE,KAAKuB,UAAoC,KAAlBvB,KAAKuB,UAAqC,IAAlBvB,KAAKuB,SAAiB,CACzE,IAAIiE,EAASopB,GAAoB5uB,KAAMoE,GACvCoB,EAAO4qB,aAAchsB,EAAMoB,EAAO8M,gBAKrC+d,OAAQ,WACP,OAAOlB,GAAUnvB,KAAMqE,UAAW,SAAUD,GACtCpE,KAAK2C,YACT3C,KAAK2C,WAAWytB,aAAchsB,EAAMpE,SAKvCswB,MAAO,WACN,OAAOnB,GAAUnvB,KAAMqE,UAAW,SAAUD,GACtCpE,KAAK2C,YACT3C,KAAK2C,WAAWytB,aAAchsB,EAAMpE,KAAKgP,gBAK5C6G,MAAO,WAIN,IAHA,IAAIzR,EACHlC,EAAI,EAE2B,OAAtBkC,EAAOpE,KAAMkC,IAAeA,IACd,IAAlBkC,EAAK7C,WAGTwB,EAAO4sB,UAAWjJ,GAAQtiB,GAAM,IAGhCA,EAAKiO,YAAc,IAIrB,OAAOrS,MAGRuF,MAAO,SAAUqqB,EAAeC,GAI/B,OAHAD,EAAiC,MAAjBA,GAAgCA,EAChDC,EAAyC,MAArBA,EAA4BD,EAAgBC,EAEzD7vB,KAAKmE,IAAK,WAChB,OAAOpB,EAAOwC,MAAOvF,KAAM4vB,EAAeC,MAI5CL,KAAM,SAAUtoB,GACf,OAAOia,EAAQnhB,KAAM,SAAUkH,GAC9B,IAAI9C,EAAOpE,KAAM,IAAO,GACvBkC,EAAI,EACJiZ,EAAInb,KAAKqD,OAEV,QAAewC,IAAVqB,GAAyC,IAAlB9C,EAAK7C,SAChC,OAAO6C,EAAKwM,UAIb,GAAsB,iBAAV1J,IAAuBunB,GAAajhB,KAAMtG,KACpDkf,IAAWP,GAAS3Y,KAAMhG,IAAW,CAAE,GAAI,KAAQ,GAAIM,eAAkB,CAE1EN,EAAQnE,EAAO4kB,cAAezgB,GAE9B,IACC,KAAQhF,EAAIiZ,EAAGjZ,IAIS,KAHvBkC,EAAOpE,KAAMkC,IAAO,IAGVX,WACTwB,EAAO4sB,UAAWjJ,GAAQtiB,GAAM,IAChCA,EAAKwM,UAAY1J,GAInB9C,EAAO,EAGN,MAAQoI,KAGNpI,GACJpE,KAAK6V,QAAQqa,OAAQhpB,IAEpB,KAAMA,EAAO7C,UAAUhB,SAG3BktB,YAAa,WACZ,IAAIjJ,EAAU,GAGd,OAAO6H,GAAUnvB,KAAMqE,UAAW,SAAUD,GAC3C,IAAI8P,EAASlU,KAAK2C,WAEbI,EAAO6D,QAAS5G,KAAMsnB,GAAY,IACtCvkB,EAAO4sB,UAAWjJ,GAAQ1mB,OACrBkU,GACJA,EAAOsc,aAAcpsB,EAAMpE,QAK3BsnB,MAILvkB,EAAOkB,KAAM,CACZwsB,SAAU,SACVC,UAAW,UACXN,aAAc,SACdO,YAAa,QACbC,WAAY,eACV,SAAUxrB,EAAMyrB,GAClB9tB,EAAOG,GAAIkC,GAAS,SAAUpC,GAO7B,IANA,IAAIa,EACHC,EAAM,GACNgtB,EAAS/tB,EAAQC,GACjBwB,EAAOssB,EAAOztB,OAAS,EACvBnB,EAAI,EAEGA,GAAKsC,EAAMtC,IAClB2B,EAAQ3B,IAAMsC,EAAOxE,KAAOA,KAAKuF,OAAO,GACxCxC,EAAQ+tB,EAAQ5uB,IAAO2uB,GAAYhtB,GAInCjD,EAAKD,MAAOmD,EAAKD,EAAMH,OAGxB,OAAO1D,KAAK4D,UAAWE,MAGzB,IAAIitB,GAAY,IAAIjnB,OAAQ,KAAOga,GAAO,kBAAmB,KAEzDkN,GAAY,SAAU5sB,GAKxB,IAAI6oB,EAAO7oB,EAAK6I,cAAc4C,YAM9B,OAJMod,GAASA,EAAKgE,SACnBhE,EAAOltB,GAGDktB,EAAKiE,iBAAkB9sB,IAG5B+sB,GAAO,SAAU/sB,EAAMe,EAASjB,GACnC,IAAIJ,EAAKsB,EACRgsB,EAAM,GAGP,IAAMhsB,KAAQD,EACbisB,EAAKhsB,GAAShB,EAAKkgB,MAAOlf,GAC1BhB,EAAKkgB,MAAOlf,GAASD,EAASC,GAM/B,IAAMA,KAHNtB,EAAMI,EAASzD,KAAM2D,GAGPe,EACbf,EAAKkgB,MAAOlf,GAASgsB,EAAKhsB,GAG3B,OAAOtB,GAIJutB,GAAY,IAAIvnB,OAAQma,GAAUrW,KAAM,KAAO,KA8HnD,SAAS0jB,GAAQltB,EAAMgB,EAAMmsB,GAC5B,IAAIC,EAAOC,EAAUC,EAAU5tB,EAM9BwgB,EAAQlgB,EAAKkgB,MAqCd,OAnCAiN,EAAWA,GAAYP,GAAW5sB,MAQpB,MAFbN,EAAMytB,EAASI,iBAAkBvsB,IAAUmsB,EAAUnsB,KAEjC8e,GAAY9f,KAC/BN,EAAMf,EAAOuhB,MAAOlgB,EAAMgB,KAQrBhE,EAAQwwB,kBAAoBb,GAAUvjB,KAAM1J,IAASutB,GAAU7jB,KAAMpI,KAG1EosB,EAAQlN,EAAMkN,MACdC,EAAWnN,EAAMmN,SACjBC,EAAWpN,EAAMoN,SAGjBpN,EAAMmN,SAAWnN,EAAMoN,SAAWpN,EAAMkN,MAAQ1tB,EAChDA,EAAMytB,EAASC,MAGflN,EAAMkN,MAAQA,EACdlN,EAAMmN,SAAWA,EACjBnN,EAAMoN,SAAWA,SAIJ7rB,IAAR/B,EAINA,EAAM,GACNA,EAIF,SAAS+tB,GAAcC,EAAaC,GAGnC,MAAO,CACNruB,IAAK,WACJ,IAAKouB,IASL,OAAS9xB,KAAK0D,IAAMquB,GAASpxB,MAAOX,KAAMqE,kBALlCrE,KAAK0D,OAxLhB,WAIC,SAASsuB,IAGR,GAAMrM,EAAN,CAIAsM,EAAU3N,MAAM4N,QAAU,+EAE1BvM,EAAIrB,MAAM4N,QACT,4HAGDxiB,GAAgBhN,YAAauvB,GAAYvvB,YAAaijB,GAEtD,IAAIwM,EAAWpyB,EAAOmxB,iBAAkBvL,GACxCyM,EAAoC,OAAjBD,EAASriB,IAG5BuiB,EAAsE,KAA9CC,EAAoBH,EAASI,YAIrD5M,EAAIrB,MAAMkO,MAAQ,MAClBC,EAA6D,KAAzCH,EAAoBH,EAASK,OAIjDE,EAAgE,KAAzCJ,EAAoBH,EAASX,OAMpD7L,EAAIrB,MAAMqO,SAAW,WACrBC,EAAiE,KAA9CN,EAAoB3M,EAAIkN,YAAc,GAEzDnjB,GAAgB9M,YAAaqvB,GAI7BtM,EAAM,MAGP,SAAS2M,EAAoBQ,GAC5B,OAAO/sB,KAAKgtB,MAAOC,WAAYF,IAGhC,IAAIV,EAAkBM,EAAsBE,EAAkBH,EAC7DQ,EAAyBZ,EACzBJ,EAAYryB,EAASyC,cAAe,OACpCsjB,EAAM/lB,EAASyC,cAAe,OAGzBsjB,EAAIrB,QAMVqB,EAAIrB,MAAM4O,eAAiB,cAC3BvN,EAAIM,WAAW,GAAO3B,MAAM4O,eAAiB,GAC7C9xB,EAAQ+xB,gBAA+C,gBAA7BxN,EAAIrB,MAAM4O,eAEpCnwB,EAAOmC,OAAQ9D,EAAS,CACvBgyB,kBAAmB,WAElB,OADApB,IACOU,GAERd,eAAgB,WAEf,OADAI,IACOS,GAERY,cAAe,WAEd,OADArB,IACOI,GAERkB,mBAAoB,WAEnB,OADAtB,IACOK,GAERkB,cAAe,WAEd,OADAvB,IACOY,GAQRY,qBAAsB,WACrB,IAAIC,EAAOlN,EAAImN,EAASC,EAoBxB,OAnBgC,MAA3BV,IACJQ,EAAQ7zB,EAASyC,cAAe,SAChCkkB,EAAK3mB,EAASyC,cAAe,MAC7BqxB,EAAU9zB,EAASyC,cAAe,OAElCoxB,EAAMnP,MAAM4N,QAAU,kCACtB3L,EAAGjC,MAAMsP,OAAS,MAClBF,EAAQpP,MAAMsP,OAAS,MAEvBlkB,GACEhN,YAAa+wB,GACb/wB,YAAa6jB,GACb7jB,YAAagxB,GAEfC,EAAU5zB,EAAOmxB,iBAAkB3K,GACnC0M,EAAuD,EAA7BY,SAAUF,EAAQC,QAE5ClkB,GAAgB9M,YAAa6wB,IAEvBR,MApHV,GAmMA,IAAIa,GAAc,CAAE,SAAU,MAAO,MACpCC,GAAan0B,EAASyC,cAAe,OAAQiiB,MAC7C0P,GAAc,GAkBf,SAASC,GAAe7uB,GACvB,IAAI8uB,EAAQnxB,EAAOoxB,SAAU/uB,IAAU4uB,GAAa5uB,GAEpD,OAAK8uB,IAGA9uB,KAAQ2uB,GACL3uB,EAED4uB,GAAa5uB,GAxBrB,SAAyBA,GAGxB,IAAIgvB,EAAUhvB,EAAM,GAAI0c,cAAgB1c,EAAK9E,MAAO,GACnD4B,EAAI4xB,GAAYzwB,OAEjB,MAAQnB,IAEP,IADAkD,EAAO0uB,GAAa5xB,GAAMkyB,KACbL,GACZ,OAAO3uB,EAeoBivB,CAAgBjvB,IAAUA,GAIxD,IAKCkvB,GAAe,4BACfC,GAAc,MACdC,GAAU,CAAE7B,SAAU,WAAY8B,WAAY,SAAUlQ,QAAS,SACjEmQ,GAAqB,CACpBC,cAAe,IACfC,WAAY,OAGd,SAASC,GAAmBlwB,EAAOuC,EAAO4tB,GAIzC,IAAI/tB,EAAUid,GAAQ9W,KAAMhG,GAC5B,OAAOH,EAGNhB,KAAKgvB,IAAK,EAAGhuB,EAAS,IAAQ+tB,GAAY,KAAU/tB,EAAS,IAAO,MACpEG,EAGF,SAAS8tB,GAAoB5wB,EAAM6wB,EAAWC,EAAKC,EAAaC,EAAQC,GACvE,IAAInzB,EAAkB,UAAd+yB,EAAwB,EAAI,EACnCK,EAAQ,EACRC,EAAQ,EAGT,GAAKL,KAAUC,EAAc,SAAW,WACvC,OAAO,EAGR,KAAQjzB,EAAI,EAAGA,GAAK,EAGN,WAARgzB,IACJK,GAASxyB,EAAOyhB,IAAKpgB,EAAM8wB,EAAMjR,GAAW/hB,IAAK,EAAMkzB,IAIlDD,GAmBQ,YAARD,IACJK,GAASxyB,EAAOyhB,IAAKpgB,EAAM,UAAY6f,GAAW/hB,IAAK,EAAMkzB,IAIjD,WAARF,IACJK,GAASxyB,EAAOyhB,IAAKpgB,EAAM,SAAW6f,GAAW/hB,GAAM,SAAS,EAAMkzB,MAtBvEG,GAASxyB,EAAOyhB,IAAKpgB,EAAM,UAAY6f,GAAW/hB,IAAK,EAAMkzB,GAGhD,YAARF,EACJK,GAASxyB,EAAOyhB,IAAKpgB,EAAM,SAAW6f,GAAW/hB,GAAM,SAAS,EAAMkzB,GAItEE,GAASvyB,EAAOyhB,IAAKpgB,EAAM,SAAW6f,GAAW/hB,GAAM,SAAS,EAAMkzB,IAoCzE,OAhBMD,GAA8B,GAAfE,IAIpBE,GAASxvB,KAAKgvB,IAAK,EAAGhvB,KAAKyvB,KAC1BpxB,EAAM,SAAW6wB,EAAW,GAAInT,cAAgBmT,EAAU30B,MAAO,IACjE+0B,EACAE,EACAD,EACA,MAIM,GAGDC,EAGR,SAASE,GAAkBrxB,EAAM6wB,EAAWK,GAG3C,IAAIF,EAASpE,GAAW5sB,GAKvB+wB,IADmB/zB,EAAQgyB,qBAAuBkC,IAEE,eAAnDvyB,EAAOyhB,IAAKpgB,EAAM,aAAa,EAAOgxB,GACvCM,EAAmBP,EAEnBhzB,EAAMmvB,GAAQltB,EAAM6wB,EAAWG,GAC/BO,EAAa,SAAWV,EAAW,GAAInT,cAAgBmT,EAAU30B,MAAO,GAIzE,GAAKywB,GAAUvjB,KAAMrL,GAAQ,CAC5B,IAAMmzB,EACL,OAAOnzB,EAERA,EAAM,OAyCP,QAlCQf,EAAQgyB,qBAAuB+B,IAMrC/zB,EAAQoyB,wBAA0BpnB,EAAUhI,EAAM,OAI3C,SAARjC,IAIC6wB,WAAY7wB,IAA0D,WAAjDY,EAAOyhB,IAAKpgB,EAAM,WAAW,EAAOgxB,KAG1DhxB,EAAKwxB,iBAAiBvyB,SAEtB8xB,EAAiE,eAAnDpyB,EAAOyhB,IAAKpgB,EAAM,aAAa,EAAOgxB,IAKpDM,EAAmBC,KAAcvxB,KAEhCjC,EAAMiC,EAAMuxB,MAKdxzB,EAAM6wB,WAAY7wB,IAAS,GAI1B6yB,GACC5wB,EACA6wB,EACAK,IAAWH,EAAc,SAAW,WACpCO,EACAN,EAGAjzB,GAEE,KA+SL,SAAS0zB,GAAOzxB,EAAMe,EAASsd,EAAM1d,EAAK+wB,GACzC,OAAO,IAAID,GAAMvyB,UAAUH,KAAMiB,EAAMe,EAASsd,EAAM1d,EAAK+wB,GA7S5D/yB,EAAOmC,OAAQ,CAId6wB,SAAU,CACTC,QAAS,CACRtyB,IAAK,SAAUU,EAAMmtB,GACpB,GAAKA,EAAW,CAGf,IAAIztB,EAAMwtB,GAAQltB,EAAM,WACxB,MAAe,KAARN,EAAa,IAAMA,MAO9BohB,UAAW,CACV+Q,yBAA2B,EAC3BC,aAAe,EACfC,aAAe,EACfC,UAAY,EACZC,YAAc,EACdzB,YAAc,EACd0B,UAAY,EACZC,YAAc,EACdC,eAAiB,EACjBC,iBAAmB,EACnBC,SAAW,EACXC,YAAc,EACdC,cAAgB,EAChBC,YAAc,EACdb,SAAW,EACXc,OAAS,EACTC,SAAW,EACXC,QAAU,EACVC,QAAU,EACVC,MAAQ,GAKT/C,SAAU,GAGV7P,MAAO,SAAUlgB,EAAMgB,EAAM8B,EAAOouB,GAGnC,GAAMlxB,GAA0B,IAAlBA,EAAK7C,UAAoC,IAAlB6C,EAAK7C,UAAmB6C,EAAKkgB,MAAlE,CAKA,IAAIxgB,EAAKpC,EAAM6hB,EACd4T,EAAWpV,EAAW3c,GACtBgyB,EAAe7C,GAAY/mB,KAAMpI,GACjCkf,EAAQlgB,EAAKkgB,MAad,GARM8S,IACLhyB,EAAO6uB,GAAekD,IAIvB5T,EAAQxgB,EAAOgzB,SAAU3wB,IAAUrC,EAAOgzB,SAAUoB,QAGrCtxB,IAAVqB,EA0CJ,OAAKqc,GAAS,QAASA,QACwB1d,KAA5C/B,EAAMyf,EAAM7f,IAAKU,GAAM,EAAOkxB,IAEzBxxB,EAIDwgB,EAAOlf,GA7CA,YAHd1D,SAAcwF,KAGcpD,EAAMkgB,GAAQ9W,KAAMhG,KAAapD,EAAK,KACjEoD,EAAQud,GAAWrgB,EAAMgB,EAAMtB,GAG/BpC,EAAO,UAIM,MAATwF,GAAiBA,GAAUA,IAOlB,WAATxF,GAAsB01B,IAC1BlwB,GAASpD,GAAOA,EAAK,KAASf,EAAOmiB,UAAWiS,GAAa,GAAK,OAI7D/1B,EAAQ+xB,iBAA6B,KAAVjsB,GAAiD,IAAjC9B,EAAKvE,QAAS,gBAC9DyjB,EAAOlf,GAAS,WAIXme,GAAY,QAASA,QACsB1d,KAA9CqB,EAAQqc,EAAMhB,IAAKne,EAAM8C,EAAOouB,MAE7B8B,EACJ9S,EAAM+S,YAAajyB,EAAM8B,GAEzBod,EAAOlf,GAAS8B,MAkBpBsd,IAAK,SAAUpgB,EAAMgB,EAAMkwB,EAAOF,GACjC,IAAIjzB,EAAKwB,EAAK4f,EACb4T,EAAWpV,EAAW3c,GA6BvB,OA5BgBmvB,GAAY/mB,KAAMpI,KAMjCA,EAAO6uB,GAAekD,KAIvB5T,EAAQxgB,EAAOgzB,SAAU3wB,IAAUrC,EAAOgzB,SAAUoB,KAGtC,QAAS5T,IACtBphB,EAAMohB,EAAM7f,IAAKU,GAAM,EAAMkxB,SAIjBzvB,IAAR1D,IACJA,EAAMmvB,GAAQltB,EAAMgB,EAAMgwB,IAId,WAARjzB,GAAoBiD,KAAQsvB,KAChCvyB,EAAMuyB,GAAoBtvB,IAIZ,KAAVkwB,GAAgBA,GACpB3xB,EAAMqvB,WAAY7wB,IACD,IAAVmzB,GAAkBgC,SAAU3zB,GAAQA,GAAO,EAAIxB,GAGhDA,KAITY,EAAOkB,KAAM,CAAE,SAAU,SAAW,SAAUsD,EAAI0tB,GACjDlyB,EAAOgzB,SAAUd,GAAc,CAC9BvxB,IAAK,SAAUU,EAAMmtB,EAAU+D,GAC9B,GAAK/D,EAIJ,OAAO+C,GAAa9mB,KAAMzK,EAAOyhB,IAAKpgB,EAAM,aAQxCA,EAAKwxB,iBAAiBvyB,QAAWe,EAAKmzB,wBAAwB/F,MAIhEiE,GAAkBrxB,EAAM6wB,EAAWK,GAHnCnE,GAAM/sB,EAAMowB,GAAS,WACpB,OAAOiB,GAAkBrxB,EAAM6wB,EAAWK,MAM/C/S,IAAK,SAAUne,EAAM8C,EAAOouB,GAC3B,IAAIvuB,EACHquB,EAASpE,GAAW5sB,GAIpBozB,GAAsBp2B,EAAQmyB,iBACT,aAApB6B,EAAOzC,SAIRwC,GADkBqC,GAAsBlC,IAEY,eAAnDvyB,EAAOyhB,IAAKpgB,EAAM,aAAa,EAAOgxB,GACvCN,EAAWQ,EACVN,GACC5wB,EACA6wB,EACAK,EACAH,EACAC,GAED,EAqBF,OAjBKD,GAAeqC,IACnB1C,GAAY/uB,KAAKyvB,KAChBpxB,EAAM,SAAW6wB,EAAW,GAAInT,cAAgBmT,EAAU30B,MAAO,IACjE0yB,WAAYoC,EAAQH,IACpBD,GAAoB5wB,EAAM6wB,EAAW,UAAU,EAAOG,GACtD,KAKGN,IAAc/tB,EAAUid,GAAQ9W,KAAMhG,KACb,QAA3BH,EAAS,IAAO,QAElB3C,EAAKkgB,MAAO2Q,GAAc/tB,EAC1BA,EAAQnE,EAAOyhB,IAAKpgB,EAAM6wB,IAGpBJ,GAAmBzwB,EAAM8C,EAAO4tB,OAK1C/xB,EAAOgzB,SAASxD,WAAaV,GAAczwB,EAAQkyB,mBAClD,SAAUlvB,EAAMmtB,GACf,GAAKA,EACJ,OAASyB,WAAY1B,GAAQltB,EAAM,gBAClCA,EAAKmzB,wBAAwBE,KAC5BtG,GAAM/sB,EAAM,CAAEmuB,WAAY,GAAK,WAC9B,OAAOnuB,EAAKmzB,wBAAwBE,QAElC,OAMR10B,EAAOkB,KAAM,CACZyzB,OAAQ,GACRC,QAAS,GACTC,OAAQ,SACN,SAAUC,EAAQC,GACpB/0B,EAAOgzB,SAAU8B,EAASC,GAAW,CACpCC,OAAQ,SAAU7wB,GAOjB,IANA,IAAIhF,EAAI,EACP81B,EAAW,GAGXC,EAAyB,iBAAV/wB,EAAqBA,EAAMI,MAAO,KAAQ,CAAEJ,GAEpDhF,EAAI,EAAGA,IACd81B,EAAUH,EAAS5T,GAAW/hB,GAAM41B,GACnCG,EAAO/1B,IAAO+1B,EAAO/1B,EAAI,IAAO+1B,EAAO,GAGzC,OAAOD,IAIO,WAAXH,IACJ90B,EAAOgzB,SAAU8B,EAASC,GAASvV,IAAMsS,MAI3C9xB,EAAOG,GAAGgC,OAAQ,CACjBsf,IAAK,SAAUpf,EAAM8B,GACpB,OAAOia,EAAQnhB,KAAM,SAAUoE,EAAMgB,EAAM8B,GAC1C,IAAIkuB,EAAQvwB,EACXV,EAAM,GACNjC,EAAI,EAEL,GAAKyD,MAAMC,QAASR,GAAS,CAI5B,IAHAgwB,EAASpE,GAAW5sB,GACpBS,EAAMO,EAAK/B,OAEHnB,EAAI2C,EAAK3C,IAChBiC,EAAKiB,EAAMlD,IAAQa,EAAOyhB,IAAKpgB,EAAMgB,EAAMlD,IAAK,EAAOkzB,GAGxD,OAAOjxB,EAGR,YAAiB0B,IAAVqB,EACNnE,EAAOuhB,MAAOlgB,EAAMgB,EAAM8B,GAC1BnE,EAAOyhB,IAAKpgB,EAAMgB,IACjBA,EAAM8B,EAA0B,EAAnB7C,UAAUhB,aAQ5BN,EAAO8yB,MAAQA,IAETvyB,UAAY,CACjBE,YAAaqyB,GACb1yB,KAAM,SAAUiB,EAAMe,EAASsd,EAAM1d,EAAK+wB,EAAQ7Q,GACjDjlB,KAAKoE,KAAOA,EACZpE,KAAKyiB,KAAOA,EACZziB,KAAK81B,OAASA,GAAU/yB,EAAO+yB,OAAOrP,SACtCzmB,KAAKmF,QAAUA,EACfnF,KAAKiU,MAAQjU,KAAKosB,IAAMpsB,KAAK6O,MAC7B7O,KAAK+E,IAAMA,EACX/E,KAAKilB,KAAOA,IAAUliB,EAAOmiB,UAAWzC,GAAS,GAAK,OAEvD5T,IAAK,WACJ,IAAI0U,EAAQsS,GAAMqC,UAAWl4B,KAAKyiB,MAElC,OAAOc,GAASA,EAAM7f,IACrB6f,EAAM7f,IAAK1D,MACX61B,GAAMqC,UAAUzR,SAAS/iB,IAAK1D,OAEhCm4B,IAAK,SAAUC,GACd,IAAIC,EACH9U,EAAQsS,GAAMqC,UAAWl4B,KAAKyiB,MAoB/B,OAlBKziB,KAAKmF,QAAQmzB,SACjBt4B,KAAKu4B,IAAMF,EAAQt1B,EAAO+yB,OAAQ91B,KAAK81B,QACtCsC,EAASp4B,KAAKmF,QAAQmzB,SAAWF,EAAS,EAAG,EAAGp4B,KAAKmF,QAAQmzB,UAG9Dt4B,KAAKu4B,IAAMF,EAAQD,EAEpBp4B,KAAKosB,KAAQpsB,KAAK+E,IAAM/E,KAAKiU,OAAUokB,EAAQr4B,KAAKiU,MAE/CjU,KAAKmF,QAAQqzB,MACjBx4B,KAAKmF,QAAQqzB,KAAK/3B,KAAMT,KAAKoE,KAAMpE,KAAKosB,IAAKpsB,MAGzCujB,GAASA,EAAMhB,IACnBgB,EAAMhB,IAAKviB,MAEX61B,GAAMqC,UAAUzR,SAASlE,IAAKviB,MAExBA,QAIOmD,KAAKG,UAAYuyB,GAAMvyB,WAEvCuyB,GAAMqC,UAAY,CACjBzR,SAAU,CACT/iB,IAAK,SAAUihB,GACd,IAAIrR,EAIJ,OAA6B,IAAxBqR,EAAMvgB,KAAK7C,UACa,MAA5BojB,EAAMvgB,KAAMugB,EAAMlC,OAAoD,MAAlCkC,EAAMvgB,KAAKkgB,MAAOK,EAAMlC,MACrDkC,EAAMvgB,KAAMugB,EAAMlC,OAO1BnP,EAASvQ,EAAOyhB,IAAKG,EAAMvgB,KAAMugB,EAAMlC,KAAM,MAGhB,SAAXnP,EAAwBA,EAAJ,GAEvCiP,IAAK,SAAUoC,GAKT5hB,EAAO01B,GAAGD,KAAM7T,EAAMlC,MAC1B1f,EAAO01B,GAAGD,KAAM7T,EAAMlC,MAAQkC,GACK,IAAxBA,EAAMvgB,KAAK7C,WACrBwB,EAAOgzB,SAAUpR,EAAMlC,OAC4B,MAAnDkC,EAAMvgB,KAAKkgB,MAAO2P,GAAetP,EAAMlC,OAGxCkC,EAAMvgB,KAAMugB,EAAMlC,MAASkC,EAAMyH,IAFjCrpB,EAAOuhB,MAAOK,EAAMvgB,KAAMugB,EAAMlC,KAAMkC,EAAMyH,IAAMzH,EAAMM,UAU5CyT,UAAY7C,GAAMqC,UAAUS,WAAa,CACxDpW,IAAK,SAAUoC,GACTA,EAAMvgB,KAAK7C,UAAYojB,EAAMvgB,KAAKzB,aACtCgiB,EAAMvgB,KAAMugB,EAAMlC,MAASkC,EAAMyH,OAKpCrpB,EAAO+yB,OAAS,CACf8C,OAAQ,SAAUC,GACjB,OAAOA,GAERC,MAAO,SAAUD,GAChB,MAAO,GAAM9yB,KAAKgzB,IAAKF,EAAI9yB,KAAKizB,IAAO,GAExCvS,SAAU,SAGX1jB,EAAO01B,GAAK5C,GAAMvyB,UAAUH,KAG5BJ,EAAO01B,GAAGD,KAAO,GAKjB,IACCS,GAAOC,GAkrBHvoB,GAEHwoB,GAnrBDC,GAAW,yBACXC,GAAO,cAER,SAASC,KACHJ,MACqB,IAApBt5B,EAAS25B,QAAoBx5B,EAAOy5B,sBACxCz5B,EAAOy5B,sBAAuBF,IAE9Bv5B,EAAO8f,WAAYyZ,GAAUv2B,EAAO01B,GAAGgB,UAGxC12B,EAAO01B,GAAGiB,QAKZ,SAASC,KAIR,OAHA55B,EAAO8f,WAAY,WAClBoZ,QAAQpzB,IAEAozB,GAAQxwB,KAAK2jB,MAIvB,SAASwN,GAAOl4B,EAAMm4B,GACrB,IAAI5L,EACH/rB,EAAI,EACJuM,EAAQ,CAAEmlB,OAAQlyB,GAKnB,IADAm4B,EAAeA,EAAe,EAAI,EAC1B33B,EAAI,EAAGA,GAAK,EAAI23B,EAEvBprB,EAAO,UADPwf,EAAQhK,GAAW/hB,KACSuM,EAAO,UAAYwf,GAAUvsB,EAO1D,OAJKm4B,IACJprB,EAAMunB,QAAUvnB,EAAM+iB,MAAQ9vB,GAGxB+M,EAGR,SAASqrB,GAAa5yB,EAAOub,EAAMsX,GAKlC,IAJA,IAAIpV,EACHyK,GAAe4K,GAAUC,SAAUxX,IAAU,IAAK/hB,OAAQs5B,GAAUC,SAAU,MAC9E5e,EAAQ,EACRhY,EAAS+rB,EAAW/rB,OACbgY,EAAQhY,EAAQgY,IACvB,GAAOsJ,EAAQyK,EAAY/T,GAAQ5a,KAAMs5B,EAAWtX,EAAMvb,GAGzD,OAAOyd,EAsNV,SAASqV,GAAW51B,EAAM81B,EAAY/0B,GACrC,IAAImO,EACH6mB,EACA9e,EAAQ,EACRhY,EAAS22B,GAAUI,WAAW/2B,OAC9B+a,EAAWrb,EAAOgb,WAAWI,OAAQ,kBAG7Bub,EAAKt1B,OAEbs1B,EAAO,WACN,GAAKS,EACJ,OAAO,EAYR,IAVA,IAAIE,EAAcpB,IAASU,KAC1B1Z,EAAYla,KAAKgvB,IAAK,EAAGgF,EAAUO,UAAYP,EAAUzB,SAAW+B,GAKpEjC,EAAU,GADHnY,EAAY8Z,EAAUzB,UAAY,GAEzCjd,EAAQ,EACRhY,EAAS02B,EAAUQ,OAAOl3B,OAEnBgY,EAAQhY,EAAQgY,IACvB0e,EAAUQ,OAAQlf,GAAQ8c,IAAKC,GAMhC,OAHAha,EAASkB,WAAYlb,EAAM,CAAE21B,EAAW3B,EAASnY,IAG5CmY,EAAU,GAAK/0B,EACZ4c,GAIF5c,GACL+a,EAASkB,WAAYlb,EAAM,CAAE21B,EAAW,EAAG,IAI5C3b,EAASmB,YAAanb,EAAM,CAAE21B,KACvB,IAERA,EAAY3b,EAASzB,QAAS,CAC7BvY,KAAMA,EACN2nB,MAAOhpB,EAAOmC,OAAQ,GAAIg1B,GAC1BM,KAAMz3B,EAAOmC,QAAQ,EAAM,CAC1Bu1B,cAAe,GACf3E,OAAQ/yB,EAAO+yB,OAAOrP,UACpBthB,GACHu1B,mBAAoBR,EACpBS,gBAAiBx1B,EACjBm1B,UAAWrB,IAASU,KACpBrB,SAAUnzB,EAAQmzB,SAClBiC,OAAQ,GACRT,YAAa,SAAUrX,EAAM1d,GAC5B,IAAI4f,EAAQ5hB,EAAO8yB,MAAOzxB,EAAM21B,EAAUS,KAAM/X,EAAM1d,EACpDg1B,EAAUS,KAAKC,cAAehY,IAAUsX,EAAUS,KAAK1E,QAEzD,OADAiE,EAAUQ,OAAO35B,KAAM+jB,GAChBA,GAERlB,KAAM,SAAUmX,GACf,IAAIvf,EAAQ,EAIXhY,EAASu3B,EAAUb,EAAUQ,OAAOl3B,OAAS,EAC9C,GAAK82B,EACJ,OAAOn6B,KAGR,IADAm6B,GAAU,EACF9e,EAAQhY,EAAQgY,IACvB0e,EAAUQ,OAAQlf,GAAQ8c,IAAK,GAUhC,OANKyC,GACJxc,EAASkB,WAAYlb,EAAM,CAAE21B,EAAW,EAAG,IAC3C3b,EAASmB,YAAanb,EAAM,CAAE21B,EAAWa,KAEzCxc,EAASuB,WAAYvb,EAAM,CAAE21B,EAAWa,IAElC56B,QAGT+rB,EAAQgO,EAAUhO,MAInB,KA/HD,SAAqBA,EAAO0O,GAC3B,IAAIpf,EAAOjW,EAAM0wB,EAAQ5uB,EAAOqc,EAGhC,IAAMlI,KAAS0Q,EAed,GAbA+J,EAAS2E,EADTr1B,EAAO2c,EAAW1G,IAElBnU,EAAQ6kB,EAAO1Q,GACV1V,MAAMC,QAASsB,KACnB4uB,EAAS5uB,EAAO,GAChBA,EAAQ6kB,EAAO1Q,GAAUnU,EAAO,IAG5BmU,IAAUjW,IACd2mB,EAAO3mB,GAAS8B,SACT6kB,EAAO1Q,KAGfkI,EAAQxgB,EAAOgzB,SAAU3wB,KACX,WAAYme,EAMzB,IAAMlI,KALNnU,EAAQqc,EAAMwU,OAAQ7wB,UACf6kB,EAAO3mB,GAIC8B,EACNmU,KAAS0Q,IAChBA,EAAO1Q,GAAUnU,EAAOmU,GACxBof,EAAepf,GAAUya,QAI3B2E,EAAer1B,GAAS0wB,EA6F1B+E,CAAY9O,EAAOgO,EAAUS,KAAKC,eAE1Bpf,EAAQhY,EAAQgY,IAEvB,GADA/H,EAAS0mB,GAAUI,WAAY/e,GAAQ5a,KAAMs5B,EAAW31B,EAAM2nB,EAAOgO,EAAUS,MAM9E,OAJKn5B,EAAYiS,EAAOmQ,QACvB1gB,EAAOygB,YAAauW,EAAU31B,KAAM21B,EAAUS,KAAKld,OAAQmG,KAC1DnQ,EAAOmQ,KAAKqX,KAAMxnB,IAEbA,EAyBT,OArBAvQ,EAAOoB,IAAK4nB,EAAO+N,GAAaC,GAE3B14B,EAAY04B,EAAUS,KAAKvmB,QAC/B8lB,EAAUS,KAAKvmB,MAAMxT,KAAM2D,EAAM21B,GAIlCA,EACEpb,SAAUob,EAAUS,KAAK7b,UACzB/V,KAAMmxB,EAAUS,KAAK5xB,KAAMmxB,EAAUS,KAAKO,UAC1Cne,KAAMmd,EAAUS,KAAK5d,MACrBuB,OAAQ4b,EAAUS,KAAKrc,QAEzBpb,EAAO01B,GAAGuC,MACTj4B,EAAOmC,OAAQw0B,EAAM,CACpBt1B,KAAMA,EACN62B,KAAMlB,EACNzc,MAAOyc,EAAUS,KAAKld,SAIjByc,EAGRh3B,EAAOi3B,UAAYj3B,EAAOmC,OAAQ80B,GAAW,CAE5CC,SAAU,CACTiB,IAAK,CAAE,SAAUzY,EAAMvb,GACtB,IAAIyd,EAAQ3kB,KAAK85B,YAAarX,EAAMvb,GAEpC,OADAud,GAAWE,EAAMvgB,KAAMqe,EAAMuB,GAAQ9W,KAAMhG,GAASyd,GAC7CA,KAITwW,QAAS,SAAUpP,EAAO7nB,GACpB7C,EAAY0qB,IAChB7nB,EAAW6nB,EACXA,EAAQ,CAAE,MAEVA,EAAQA,EAAMlf,MAAOoP,GAOtB,IAJA,IAAIwG,EACHpH,EAAQ,EACRhY,EAAS0oB,EAAM1oB,OAERgY,EAAQhY,EAAQgY,IACvBoH,EAAOsJ,EAAO1Q,GACd2e,GAAUC,SAAUxX,GAASuX,GAAUC,SAAUxX,IAAU,GAC3DuX,GAAUC,SAAUxX,GAAO9Q,QAASzN,IAItCk2B,WAAY,CA3Wb,SAA2Bh2B,EAAM2nB,EAAOyO,GACvC,IAAI/X,EAAMvb,EAAOwe,EAAQnC,EAAO6X,EAASC,EAAWC,EAAgB/W,EACnEgX,EAAQ,UAAWxP,GAAS,WAAYA,EACxCkP,EAAOj7B,KACPuuB,EAAO,GACPjK,EAAQlgB,EAAKkgB,MACbiV,EAASn1B,EAAK7C,UAAY8iB,GAAoBjgB,GAC9Co3B,EAAW7Y,EAASjf,IAAKU,EAAM,UA6BhC,IAAMqe,KA1BA+X,EAAKld,QAEa,OADvBiG,EAAQxgB,EAAOygB,YAAapf,EAAM,OACvBq3B,WACVlY,EAAMkY,SAAW,EACjBL,EAAU7X,EAAM1N,MAAM2H,KACtB+F,EAAM1N,MAAM2H,KAAO,WACZ+F,EAAMkY,UACXL,MAIH7X,EAAMkY,WAENR,EAAK9c,OAAQ,WAGZ8c,EAAK9c,OAAQ,WACZoF,EAAMkY,WACA14B,EAAOua,MAAOlZ,EAAM,MAAOf,QAChCkgB,EAAM1N,MAAM2H,YAOFuO,EAEb,GADA7kB,EAAQ6kB,EAAOtJ,GACV2W,GAAS5rB,KAAMtG,GAAU,CAG7B,UAFO6kB,EAAOtJ,GACdiD,EAASA,GAAoB,WAAVxe,EACdA,KAAYqyB,EAAS,OAAS,QAAW,CAI7C,GAAe,SAAVryB,IAAoBs0B,QAAiC31B,IAArB21B,EAAU/Y,GAK9C,SAJA8W,GAAS,EAOXhL,EAAM9L,GAAS+Y,GAAYA,EAAU/Y,IAAU1f,EAAOuhB,MAAOlgB,EAAMqe,GAMrE,IADA4Y,GAAat4B,EAAOyD,cAAeulB,MAChBhpB,EAAOyD,cAAe+nB,GA8DzC,IAAM9L,KAzDD8Y,GAA2B,IAAlBn3B,EAAK7C,WAMlBi5B,EAAKkB,SAAW,CAAEpX,EAAMoX,SAAUpX,EAAMqX,UAAWrX,EAAMsX,WAIlC,OADvBN,EAAiBE,GAAYA,EAASjX,WAErC+W,EAAiB3Y,EAASjf,IAAKU,EAAM,YAGrB,UADjBmgB,EAAUxhB,EAAOyhB,IAAKpgB,EAAM,cAEtBk3B,EACJ/W,EAAU+W,GAIVjW,GAAU,CAAEjhB,IAAQ,GACpBk3B,EAAiBl3B,EAAKkgB,MAAMC,SAAW+W,EACvC/W,EAAUxhB,EAAOyhB,IAAKpgB,EAAM,WAC5BihB,GAAU,CAAEjhB,OAKG,WAAZmgB,GAAoC,iBAAZA,GAAgD,MAAlB+W,IACrB,SAAhCv4B,EAAOyhB,IAAKpgB,EAAM,WAGhBi3B,IACLJ,EAAKryB,KAAM,WACV0b,EAAMC,QAAU+W,IAEM,MAAlBA,IACJ/W,EAAUD,EAAMC,QAChB+W,EAA6B,SAAZ/W,EAAqB,GAAKA,IAG7CD,EAAMC,QAAU,iBAKdiW,EAAKkB,WACTpX,EAAMoX,SAAW,SACjBT,EAAK9c,OAAQ,WACZmG,EAAMoX,SAAWlB,EAAKkB,SAAU,GAChCpX,EAAMqX,UAAYnB,EAAKkB,SAAU,GACjCpX,EAAMsX,UAAYpB,EAAKkB,SAAU,MAKnCL,GAAY,EACE9M,EAGP8M,IACAG,EACC,WAAYA,IAChBjC,EAASiC,EAASjC,QAGnBiC,EAAW7Y,EAASxB,OAAQ/c,EAAM,SAAU,CAAEmgB,QAAS+W,IAInD5V,IACJ8V,EAASjC,QAAUA,GAIfA,GACJlU,GAAU,CAAEjhB,IAAQ,GAKrB62B,EAAKryB,KAAM,WASV,IAAM6Z,KAJA8W,GACLlU,GAAU,CAAEjhB,IAEbue,EAAShF,OAAQvZ,EAAM,UACTmqB,EACbxrB,EAAOuhB,MAAOlgB,EAAMqe,EAAM8L,EAAM9L,OAMnC4Y,EAAYvB,GAAaP,EAASiC,EAAU/Y,GAAS,EAAGA,EAAMwY,GACtDxY,KAAQ+Y,IACfA,EAAU/Y,GAAS4Y,EAAUpnB,MACxBslB,IACJ8B,EAAUt2B,IAAMs2B,EAAUpnB,MAC1BonB,EAAUpnB,MAAQ,MAuMrB4nB,UAAW,SAAU33B,EAAUisB,GACzBA,EACJ6J,GAAUI,WAAWzoB,QAASzN,GAE9B81B,GAAUI,WAAWx5B,KAAMsD,MAK9BnB,EAAO+4B,MAAQ,SAAUA,EAAOhG,EAAQ5yB,GACvC,IAAIi2B,EAAM2C,GAA0B,iBAAVA,EAAqB/4B,EAAOmC,OAAQ,GAAI42B,GAAU,CAC3Ef,SAAU73B,IAAOA,GAAM4yB,GACtBz0B,EAAYy6B,IAAWA,EACxBxD,SAAUwD,EACVhG,OAAQ5yB,GAAM4yB,GAAUA,IAAWz0B,EAAYy0B,IAAYA,GAoC5D,OAhCK/yB,EAAO01B,GAAG/P,IACdyQ,EAAIb,SAAW,EAGc,iBAAjBa,EAAIb,WACVa,EAAIb,YAAYv1B,EAAO01B,GAAGsD,OAC9B5C,EAAIb,SAAWv1B,EAAO01B,GAAGsD,OAAQ5C,EAAIb,UAGrCa,EAAIb,SAAWv1B,EAAO01B,GAAGsD,OAAOtV,UAMjB,MAAb0S,EAAI7b,QAA+B,IAAd6b,EAAI7b,QAC7B6b,EAAI7b,MAAQ,MAIb6b,EAAI/H,IAAM+H,EAAI4B,SAEd5B,EAAI4B,SAAW,WACT15B,EAAY83B,EAAI/H,MACpB+H,EAAI/H,IAAI3wB,KAAMT,MAGVm5B,EAAI7b,OACRva,EAAOsgB,QAASrjB,KAAMm5B,EAAI7b,QAIrB6b,GAGRp2B,EAAOG,GAAGgC,OAAQ,CACjB82B,OAAQ,SAAUF,EAAOG,EAAInG,EAAQ5xB,GAGpC,OAAOlE,KAAKqQ,OAAQgU,IAAqBG,IAAK,UAAW,GAAIc,OAG3DvgB,MAAMm3B,QAAS,CAAElG,QAASiG,GAAMH,EAAOhG,EAAQ5xB,IAElDg4B,QAAS,SAAUzZ,EAAMqZ,EAAOhG,EAAQ5xB,GACvC,IAAI2R,EAAQ9S,EAAOyD,cAAeic,GACjC0Z,EAASp5B,EAAO+4B,MAAOA,EAAOhG,EAAQ5xB,GACtCk4B,EAAc,WAGb,IAAInB,EAAOjB,GAAWh6B,KAAM+C,EAAOmC,OAAQ,GAAIud,GAAQ0Z,IAGlDtmB,GAAS8M,EAASjf,IAAK1D,KAAM,YACjCi7B,EAAKxX,MAAM,IAKd,OAFC2Y,EAAYC,OAASD,EAEfvmB,IAA0B,IAAjBsmB,EAAO7e,MACtBtd,KAAKiE,KAAMm4B,GACXp8B,KAAKsd,MAAO6e,EAAO7e,MAAO8e,IAE5B3Y,KAAM,SAAU/hB,EAAMiiB,EAAYiX,GACjC,IAAI0B,EAAY,SAAU/Y,GACzB,IAAIE,EAAOF,EAAME,YACVF,EAAME,KACbA,EAAMmX,IAYP,MATqB,iBAATl5B,IACXk5B,EAAUjX,EACVA,EAAajiB,EACbA,OAAOmE,GAEH8d,GACJ3jB,KAAKsd,MAAO5b,GAAQ,KAAM,IAGpB1B,KAAKiE,KAAM,WACjB,IAAIof,GAAU,EACbhI,EAAgB,MAAR3Z,GAAgBA,EAAO,aAC/B66B,EAASx5B,EAAOw5B,OAChB/Z,EAAOG,EAASjf,IAAK1D,MAEtB,GAAKqb,EACCmH,EAAMnH,IAAWmH,EAAMnH,GAAQoI,MACnC6Y,EAAW9Z,EAAMnH,SAGlB,IAAMA,KAASmH,EACTA,EAAMnH,IAAWmH,EAAMnH,GAAQoI,MAAQ4V,GAAK7rB,KAAM6N,IACtDihB,EAAW9Z,EAAMnH,IAKpB,IAAMA,EAAQkhB,EAAOl5B,OAAQgY,KACvBkhB,EAAQlhB,GAAQjX,OAASpE,MACnB,MAAR0B,GAAgB66B,EAAQlhB,GAAQiC,QAAU5b,IAE5C66B,EAAQlhB,GAAQ4f,KAAKxX,KAAMmX,GAC3BvX,GAAU,EACVkZ,EAAOt3B,OAAQoW,EAAO,KAOnBgI,GAAYuX,GAChB73B,EAAOsgB,QAASrjB,KAAM0B,MAIzB26B,OAAQ,SAAU36B,GAIjB,OAHc,IAATA,IACJA,EAAOA,GAAQ,MAET1B,KAAKiE,KAAM,WACjB,IAAIoX,EACHmH,EAAOG,EAASjf,IAAK1D,MACrBsd,EAAQkF,EAAM9gB,EAAO,SACrB6hB,EAAQf,EAAM9gB,EAAO,cACrB66B,EAASx5B,EAAOw5B,OAChBl5B,EAASia,EAAQA,EAAMja,OAAS,EAajC,IAVAmf,EAAK6Z,QAAS,EAGdt5B,EAAOua,MAAOtd,KAAM0B,EAAM,IAErB6hB,GAASA,EAAME,MACnBF,EAAME,KAAKhjB,KAAMT,MAAM,GAIlBqb,EAAQkhB,EAAOl5B,OAAQgY,KACvBkhB,EAAQlhB,GAAQjX,OAASpE,MAAQu8B,EAAQlhB,GAAQiC,QAAU5b,IAC/D66B,EAAQlhB,GAAQ4f,KAAKxX,MAAM,GAC3B8Y,EAAOt3B,OAAQoW,EAAO,IAKxB,IAAMA,EAAQ,EAAGA,EAAQhY,EAAQgY,IAC3BiC,EAAOjC,IAAWiC,EAAOjC,GAAQghB,QACrC/e,EAAOjC,GAAQghB,OAAO57B,KAAMT,aAKvBwiB,EAAK6Z,YAKft5B,EAAOkB,KAAM,CAAE,SAAU,OAAQ,QAAU,SAAUsD,EAAInC,GACxD,IAAIo3B,EAAQz5B,EAAOG,GAAIkC,GACvBrC,EAAOG,GAAIkC,GAAS,SAAU02B,EAAOhG,EAAQ5xB,GAC5C,OAAgB,MAAT43B,GAAkC,kBAAVA,EAC9BU,EAAM77B,MAAOX,KAAMqE,WACnBrE,KAAKk8B,QAAStC,GAAOx0B,GAAM,GAAQ02B,EAAOhG,EAAQ5xB,MAKrDnB,EAAOkB,KAAM,CACZw4B,UAAW7C,GAAO,QAClB8C,QAAS9C,GAAO,QAChB+C,YAAa/C,GAAO,UACpBgD,OAAQ,CAAE5G,QAAS,QACnB6G,QAAS,CAAE7G,QAAS,QACpB8G,WAAY,CAAE9G,QAAS,WACrB,SAAU5wB,EAAM2mB,GAClBhpB,EAAOG,GAAIkC,GAAS,SAAU02B,EAAOhG,EAAQ5xB,GAC5C,OAAOlE,KAAKk8B,QAASnQ,EAAO+P,EAAOhG,EAAQ5xB,MAI7CnB,EAAOw5B,OAAS,GAChBx5B,EAAO01B,GAAGiB,KAAO,WAChB,IAAIsB,EACH94B,EAAI,EACJq6B,EAASx5B,EAAOw5B,OAIjB,IAFAtD,GAAQxwB,KAAK2jB,MAELlqB,EAAIq6B,EAAOl5B,OAAQnB,KAC1B84B,EAAQuB,EAAQr6B,OAGCq6B,EAAQr6B,KAAQ84B,GAChCuB,EAAOt3B,OAAQ/C,IAAK,GAIhBq6B,EAAOl5B,QACZN,EAAO01B,GAAGhV,OAEXwV,QAAQpzB,GAGT9C,EAAO01B,GAAGuC,MAAQ,SAAUA,GAC3Bj4B,EAAOw5B,OAAO37B,KAAMo6B,GACpBj4B,EAAO01B,GAAGxkB,SAGXlR,EAAO01B,GAAGgB,SAAW,GACrB12B,EAAO01B,GAAGxkB,MAAQ,WACZilB,KAILA,IAAa,EACbI,OAGDv2B,EAAO01B,GAAGhV,KAAO,WAChByV,GAAa,MAGdn2B,EAAO01B,GAAGsD,OAAS,CAClBgB,KAAM,IACNC,KAAM,IAGNvW,SAAU,KAMX1jB,EAAOG,GAAG+5B,MAAQ,SAAUC,EAAMx7B,GAIjC,OAHAw7B,EAAOn6B,EAAO01B,IAAK11B,EAAO01B,GAAGsD,OAAQmB,IAAiBA,EACtDx7B,EAAOA,GAAQ,KAER1B,KAAKsd,MAAO5b,EAAM,SAAU4K,EAAMiX,GACxC,IAAI4Z,EAAUp9B,EAAO8f,WAAYvT,EAAM4wB,GACvC3Z,EAAME,KAAO,WACZ1jB,EAAOq9B,aAAcD,OAOnBxsB,GAAQ/Q,EAASyC,cAAe,SAEnC82B,GADSv5B,EAASyC,cAAe,UACpBK,YAAa9C,EAASyC,cAAe,WAEnDsO,GAAMjP,KAAO,WAIbN,EAAQi8B,QAA0B,KAAhB1sB,GAAMzJ,MAIxB9F,EAAQk8B,YAAcnE,GAAIxjB,UAI1BhF,GAAQ/Q,EAASyC,cAAe,UAC1B6E,MAAQ,IACdyJ,GAAMjP,KAAO,QACbN,EAAQm8B,WAA6B,MAAhB5sB,GAAMzJ,MAI5B,IAAIs2B,GACH7uB,GAAa5L,EAAO6O,KAAKjD,WAE1B5L,EAAOG,GAAGgC,OAAQ,CACjB4M,KAAM,SAAU1M,EAAM8B,GACrB,OAAOia,EAAQnhB,KAAM+C,EAAO+O,KAAM1M,EAAM8B,EAA0B,EAAnB7C,UAAUhB,SAG1Do6B,WAAY,SAAUr4B,GACrB,OAAOpF,KAAKiE,KAAM,WACjBlB,EAAO06B,WAAYz9B,KAAMoF,QAK5BrC,EAAOmC,OAAQ,CACd4M,KAAM,SAAU1N,EAAMgB,EAAM8B,GAC3B,IAAIpD,EAAKyf,EACRma,EAAQt5B,EAAK7C,SAGd,GAAe,IAAVm8B,GAAyB,IAAVA,GAAyB,IAAVA,EAKnC,MAAkC,oBAAtBt5B,EAAK7B,aACTQ,EAAO0f,KAAMre,EAAMgB,EAAM8B,IAKlB,IAAVw2B,GAAgB36B,EAAO8W,SAAUzV,KACrCmf,EAAQxgB,EAAO46B,UAAWv4B,EAAKoC,iBAC5BzE,EAAO6O,KAAK/E,MAAMjC,KAAK4C,KAAMpI,GAASo4B,QAAW33B,SAGtCA,IAAVqB,EACW,OAAVA,OACJnE,EAAO06B,WAAYr5B,EAAMgB,GAIrBme,GAAS,QAASA,QACuB1d,KAA3C/B,EAAMyf,EAAMhB,IAAKne,EAAM8C,EAAO9B,IACzBtB,GAGRM,EAAK5B,aAAc4C,EAAM8B,EAAQ,IAC1BA,GAGHqc,GAAS,QAASA,GAA+C,QAApCzf,EAAMyf,EAAM7f,IAAKU,EAAMgB,IACjDtB,EAMM,OAHdA,EAAMf,EAAOwN,KAAKuB,KAAM1N,EAAMgB,SAGTS,EAAY/B,IAGlC65B,UAAW,CACVj8B,KAAM,CACL6gB,IAAK,SAAUne,EAAM8C,GACpB,IAAM9F,EAAQm8B,YAAwB,UAAVr2B,GAC3BkF,EAAUhI,EAAM,SAAY,CAC5B,IAAIjC,EAAMiC,EAAK8C,MAKf,OAJA9C,EAAK5B,aAAc,OAAQ0E,GACtB/E,IACJiC,EAAK8C,MAAQ/E,GAEP+E,MAMXu2B,WAAY,SAAUr5B,EAAM8C,GAC3B,IAAI9B,EACHlD,EAAI,EAIJ07B,EAAY12B,GAASA,EAAM2F,MAAOoP,GAEnC,GAAK2hB,GAA+B,IAAlBx5B,EAAK7C,SACtB,MAAU6D,EAAOw4B,EAAW17B,KAC3BkC,EAAK2J,gBAAiB3I,MAO1Bo4B,GAAW,CACVjb,IAAK,SAAUne,EAAM8C,EAAO9B,GAQ3B,OAPe,IAAV8B,EAGJnE,EAAO06B,WAAYr5B,EAAMgB,GAEzBhB,EAAK5B,aAAc4C,EAAMA,GAEnBA,IAITrC,EAAOkB,KAAMlB,EAAO6O,KAAK/E,MAAMjC,KAAKmZ,OAAOlX,MAAO,QAAU,SAAUtF,EAAInC,GACzE,IAAIy4B,EAASlvB,GAAYvJ,IAAUrC,EAAOwN,KAAKuB,KAE/CnD,GAAYvJ,GAAS,SAAUhB,EAAMgB,EAAMwC,GAC1C,IAAI9D,EAAKimB,EACR+T,EAAgB14B,EAAKoC,cAYtB,OAVMI,IAGLmiB,EAASpb,GAAYmvB,GACrBnvB,GAAYmvB,GAAkBh6B,EAC9BA,EAAqC,MAA/B+5B,EAAQz5B,EAAMgB,EAAMwC,GACzBk2B,EACA,KACDnvB,GAAYmvB,GAAkB/T,GAExBjmB,KAOT,IAAIi6B,GAAa,sCAChBC,GAAa,gBAyIb,SAASC,GAAkB/2B,GAE1B,OADaA,EAAM2F,MAAOoP,IAAmB,IAC/BrO,KAAM,KAItB,SAASswB,GAAU95B,GAClB,OAAOA,EAAK7B,cAAgB6B,EAAK7B,aAAc,UAAa,GAG7D,SAAS47B,GAAgBj3B,GACxB,OAAKvB,MAAMC,QAASsB,GACZA,EAEc,iBAAVA,GACJA,EAAM2F,MAAOoP,IAEd,GAxJRlZ,EAAOG,GAAGgC,OAAQ,CACjBud,KAAM,SAAUrd,EAAM8B,GACrB,OAAOia,EAAQnhB,KAAM+C,EAAO0f,KAAMrd,EAAM8B,EAA0B,EAAnB7C,UAAUhB,SAG1D+6B,WAAY,SAAUh5B,GACrB,OAAOpF,KAAKiE,KAAM,kBACVjE,KAAM+C,EAAOs7B,QAASj5B,IAAUA,QAK1CrC,EAAOmC,OAAQ,CACdud,KAAM,SAAUre,EAAMgB,EAAM8B,GAC3B,IAAIpD,EAAKyf,EACRma,EAAQt5B,EAAK7C,SAGd,GAAe,IAAVm8B,GAAyB,IAAVA,GAAyB,IAAVA,EAWnC,OAPe,IAAVA,GAAgB36B,EAAO8W,SAAUzV,KAGrCgB,EAAOrC,EAAOs7B,QAASj5B,IAAUA,EACjCme,EAAQxgB,EAAOm1B,UAAW9yB,SAGZS,IAAVqB,EACCqc,GAAS,QAASA,QACuB1d,KAA3C/B,EAAMyf,EAAMhB,IAAKne,EAAM8C,EAAO9B,IACzBtB,EAGCM,EAAMgB,GAAS8B,EAGpBqc,GAAS,QAASA,GAA+C,QAApCzf,EAAMyf,EAAM7f,IAAKU,EAAMgB,IACjDtB,EAGDM,EAAMgB,IAGd8yB,UAAW,CACV1iB,SAAU,CACT9R,IAAK,SAAUU,GAOd,IAAIk6B,EAAWv7B,EAAOwN,KAAKuB,KAAM1N,EAAM,YAEvC,OAAKk6B,EACGzK,SAAUyK,EAAU,IAI3BP,GAAWvwB,KAAMpJ,EAAKgI,WACtB4xB,GAAWxwB,KAAMpJ,EAAKgI,WACtBhI,EAAKmR,KAEE,GAGA,KAKX8oB,QAAS,CACRE,MAAO,UACPC,QAAS,eAYLp9B,EAAQk8B,cACbv6B,EAAOm1B,UAAUviB,SAAW,CAC3BjS,IAAK,SAAUU,GAId,IAAI8P,EAAS9P,EAAKzB,WAIlB,OAHKuR,GAAUA,EAAOvR,YACrBuR,EAAOvR,WAAWiT,cAEZ,MAER2M,IAAK,SAAUne,GAId,IAAI8P,EAAS9P,EAAKzB,WACbuR,IACJA,EAAO0B,cAEF1B,EAAOvR,YACXuR,EAAOvR,WAAWiT,kBAOvB7S,EAAOkB,KAAM,CACZ,WACA,WACA,YACA,cACA,cACA,UACA,UACA,SACA,cACA,mBACE,WACFlB,EAAOs7B,QAASr+B,KAAKwH,eAAkBxH,OA4BxC+C,EAAOG,GAAGgC,OAAQ,CACjBu5B,SAAU,SAAUv3B,GACnB,IAAIw3B,EAASt6B,EAAMyK,EAAK8vB,EAAUC,EAAO95B,EAAG+5B,EAC3C38B,EAAI,EAEL,GAAKb,EAAY6F,GAChB,OAAOlH,KAAKiE,KAAM,SAAUa,GAC3B/B,EAAQ/C,MAAOy+B,SAAUv3B,EAAMzG,KAAMT,KAAM8E,EAAGo5B,GAAUl+B,UAM1D,IAFA0+B,EAAUP,GAAgBj3B,IAEb7D,OACZ,MAAUe,EAAOpE,KAAMkC,KAItB,GAHAy8B,EAAWT,GAAU95B,GACrByK,EAAwB,IAAlBzK,EAAK7C,UAAoB,IAAM08B,GAAkBU,GAAa,IAEzD,CACV75B,EAAI,EACJ,MAAU85B,EAAQF,EAAS55B,KACrB+J,EAAIhO,QAAS,IAAM+9B,EAAQ,KAAQ,IACvC/vB,GAAO+vB,EAAQ,KAMZD,KADLE,EAAaZ,GAAkBpvB,KAE9BzK,EAAK5B,aAAc,QAASq8B,GAMhC,OAAO7+B,MAGR8+B,YAAa,SAAU53B,GACtB,IAAIw3B,EAASt6B,EAAMyK,EAAK8vB,EAAUC,EAAO95B,EAAG+5B,EAC3C38B,EAAI,EAEL,GAAKb,EAAY6F,GAChB,OAAOlH,KAAKiE,KAAM,SAAUa,GAC3B/B,EAAQ/C,MAAO8+B,YAAa53B,EAAMzG,KAAMT,KAAM8E,EAAGo5B,GAAUl+B,UAI7D,IAAMqE,UAAUhB,OACf,OAAOrD,KAAK8R,KAAM,QAAS,IAK5B,IAFA4sB,EAAUP,GAAgBj3B,IAEb7D,OACZ,MAAUe,EAAOpE,KAAMkC,KAMtB,GALAy8B,EAAWT,GAAU95B,GAGrByK,EAAwB,IAAlBzK,EAAK7C,UAAoB,IAAM08B,GAAkBU,GAAa,IAEzD,CACV75B,EAAI,EACJ,MAAU85B,EAAQF,EAAS55B,KAG1B,OAA4C,EAApC+J,EAAIhO,QAAS,IAAM+9B,EAAQ,KAClC/vB,EAAMA,EAAI5I,QAAS,IAAM24B,EAAQ,IAAK,KAMnCD,KADLE,EAAaZ,GAAkBpvB,KAE9BzK,EAAK5B,aAAc,QAASq8B,GAMhC,OAAO7+B,MAGR++B,YAAa,SAAU73B,EAAO83B,GAC7B,IAAIt9B,SAAcwF,EACjB+3B,EAAwB,WAATv9B,GAAqBiE,MAAMC,QAASsB,GAEpD,MAAyB,kBAAb83B,GAA0BC,EAC9BD,EAAWh/B,KAAKy+B,SAAUv3B,GAAUlH,KAAK8+B,YAAa53B,GAGzD7F,EAAY6F,GACTlH,KAAKiE,KAAM,SAAU/B,GAC3Ba,EAAQ/C,MAAO++B,YACd73B,EAAMzG,KAAMT,KAAMkC,EAAGg8B,GAAUl+B,MAAQg/B,GACvCA,KAKIh/B,KAAKiE,KAAM,WACjB,IAAIgM,EAAW/N,EAAGsY,EAAM0kB,EAExB,GAAKD,EAAe,CAGnB/8B,EAAI,EACJsY,EAAOzX,EAAQ/C,MACfk/B,EAAaf,GAAgBj3B,GAE7B,MAAU+I,EAAYivB,EAAYh9B,KAG5BsY,EAAK2kB,SAAUlvB,GACnBuK,EAAKskB,YAAa7uB,GAElBuK,EAAKikB,SAAUxuB,aAKIpK,IAAVqB,GAAgC,YAATxF,KAClCuO,EAAYiuB,GAAUl+B,QAIrB2iB,EAASJ,IAAKviB,KAAM,gBAAiBiQ,GAOjCjQ,KAAKwC,cACTxC,KAAKwC,aAAc,QAClByN,IAAuB,IAAV/I,EACb,GACAyb,EAASjf,IAAK1D,KAAM,kBAAqB,QAO9Cm/B,SAAU,SAAUn8B,GACnB,IAAIiN,EAAW7L,EACdlC,EAAI,EAEL+N,EAAY,IAAMjN,EAAW,IAC7B,MAAUoB,EAAOpE,KAAMkC,KACtB,GAAuB,IAAlBkC,EAAK7C,WACoE,GAA3E,IAAM08B,GAAkBC,GAAU95B,IAAW,KAAMvD,QAASoP,GAC7D,OAAO,EAIV,OAAO,KAOT,IAAImvB,GAAU,MAEdr8B,EAAOG,GAAGgC,OAAQ,CACjB/C,IAAK,SAAU+E,GACd,IAAIqc,EAAOzf,EAAKyrB,EACfnrB,EAAOpE,KAAM,GAEd,OAAMqE,UAAUhB,QA0BhBksB,EAAkBluB,EAAY6F,GAEvBlH,KAAKiE,KAAM,SAAU/B,GAC3B,IAAIC,EAEmB,IAAlBnC,KAAKuB,WAWE,OANXY,EADIotB,EACEroB,EAAMzG,KAAMT,KAAMkC,EAAGa,EAAQ/C,MAAOmC,OAEpC+E,GAKN/E,EAAM,GAEoB,iBAARA,EAClBA,GAAO,GAEIwD,MAAMC,QAASzD,KAC1BA,EAAMY,EAAOoB,IAAKhC,EAAK,SAAU+E,GAChC,OAAgB,MAATA,EAAgB,GAAKA,EAAQ,OAItCqc,EAAQxgB,EAAOs8B,SAAUr/B,KAAK0B,OAAUqB,EAAOs8B,SAAUr/B,KAAKoM,SAAS5E,iBAGrD,QAAS+b,QAA+C1d,IAApC0d,EAAMhB,IAAKviB,KAAMmC,EAAK,WAC3DnC,KAAKkH,MAAQ/E,OAzDTiC,GACJmf,EAAQxgB,EAAOs8B,SAAUj7B,EAAK1C,OAC7BqB,EAAOs8B,SAAUj7B,EAAKgI,SAAS5E,iBAG/B,QAAS+b,QACgC1d,KAAvC/B,EAAMyf,EAAM7f,IAAKU,EAAM,UAElBN,EAMY,iBAHpBA,EAAMM,EAAK8C,OAIHpD,EAAImC,QAASm5B,GAAS,IAIhB,MAAPt7B,EAAc,GAAKA,OAG3B,KAyCHf,EAAOmC,OAAQ,CACdm6B,SAAU,CACTlZ,OAAQ,CACPziB,IAAK,SAAUU,GAEd,IAAIjC,EAAMY,EAAOwN,KAAKuB,KAAM1N,EAAM,SAClC,OAAc,MAAPjC,EACNA,EAMA87B,GAAkBl7B,EAAOT,KAAM8B,MAGlC2D,OAAQ,CACPrE,IAAK,SAAUU,GACd,IAAI8C,EAAOif,EAAQjkB,EAClBiD,EAAUf,EAAKe,QACfkW,EAAQjX,EAAKwR,cACb2S,EAAoB,eAAdnkB,EAAK1C,KACX6jB,EAASgD,EAAM,KAAO,GACtBwM,EAAMxM,EAAMlN,EAAQ,EAAIlW,EAAQ9B,OAUjC,IAPCnB,EADImZ,EAAQ,EACR0Z,EAGAxM,EAAMlN,EAAQ,EAIXnZ,EAAI6yB,EAAK7yB,IAKhB,KAJAikB,EAAShhB,EAASjD,IAIJyT,UAAYzT,IAAMmZ,KAG7B8K,EAAOha,YACLga,EAAOxjB,WAAWwJ,WACnBC,EAAU+Z,EAAOxjB,WAAY,aAAiB,CAMjD,GAHAuE,EAAQnE,EAAQojB,GAAShkB,MAGpBomB,EACJ,OAAOrhB,EAIRqe,EAAO3kB,KAAMsG,GAIf,OAAOqe,GAGRhD,IAAK,SAAUne,EAAM8C,GACpB,IAAIo4B,EAAWnZ,EACdhhB,EAAUf,EAAKe,QACfogB,EAASxiB,EAAO2D,UAAWQ,GAC3BhF,EAAIiD,EAAQ9B,OAEb,MAAQnB,MACPikB,EAAShhB,EAASjD,IAINyT,UACuD,EAAlE5S,EAAO6D,QAAS7D,EAAOs8B,SAASlZ,OAAOziB,IAAKyiB,GAAUZ,MAEtD+Z,GAAY,GAUd,OAHMA,IACLl7B,EAAKwR,eAAiB,GAEhB2P,OAOXxiB,EAAOkB,KAAM,CAAE,QAAS,YAAc,WACrClB,EAAOs8B,SAAUr/B,MAAS,CACzBuiB,IAAK,SAAUne,EAAM8C,GACpB,GAAKvB,MAAMC,QAASsB,GACnB,OAAS9C,EAAKsR,SAA2D,EAAjD3S,EAAO6D,QAAS7D,EAAQqB,GAAOjC,MAAO+E,KAI3D9F,EAAQi8B,UACbt6B,EAAOs8B,SAAUr/B,MAAO0D,IAAM,SAAUU,GACvC,OAAwC,OAAjCA,EAAK7B,aAAc,SAAqB,KAAO6B,EAAK8C,UAW9D9F,EAAQm+B,QAAU,cAAex/B,EAGjC,IAAIy/B,GAAc,kCACjBC,GAA0B,SAAUjzB,GACnCA,EAAEwc,mBAGJjmB,EAAOmC,OAAQnC,EAAO0lB,MAAO,CAE5BU,QAAS,SAAUV,EAAOjG,EAAMpe,EAAMs7B,GAErC,IAAIx9B,EAAG2M,EAAK6B,EAAKivB,EAAYC,EAAQ7V,EAAQ7K,EAAS2gB,EACrDC,EAAY,CAAE17B,GAAQxE,GACtB8B,EAAOV,EAAOP,KAAMgoB,EAAO,QAAWA,EAAM/mB,KAAO+mB,EACnDkB,EAAa3oB,EAAOP,KAAMgoB,EAAO,aAAgBA,EAAMjZ,UAAUlI,MAAO,KAAQ,GAKjF,GAHAuH,EAAMgxB,EAAcnvB,EAAMtM,EAAOA,GAAQxE,EAGlB,IAAlBwE,EAAK7C,UAAoC,IAAlB6C,EAAK7C,WAK5Bi+B,GAAYhyB,KAAM9L,EAAOqB,EAAO0lB,MAAMuB,cAIf,EAAvBtoB,EAAKb,QAAS,OAIlBa,GADAioB,EAAajoB,EAAK4F,MAAO,MACP8G,QAClBub,EAAW3kB,QAEZ46B,EAASl+B,EAAKb,QAAS,KAAQ,GAAK,KAAOa,GAG3C+mB,EAAQA,EAAO1lB,EAAO+C,SACrB2iB,EACA,IAAI1lB,EAAOqmB,MAAO1nB,EAAuB,iBAAV+mB,GAAsBA,IAGhDK,UAAY4W,EAAe,EAAI,EACrCjX,EAAMjZ,UAAYma,EAAW/b,KAAM,KACnC6a,EAAMwC,WAAaxC,EAAMjZ,UACxB,IAAI1F,OAAQ,UAAY6f,EAAW/b,KAAM,iBAAoB,WAC7D,KAGD6a,EAAMnV,YAASzN,EACT4iB,EAAMjjB,SACXijB,EAAMjjB,OAASpB,GAIhBoe,EAAe,MAARA,EACN,CAAEiG,GACF1lB,EAAO2D,UAAW8b,EAAM,CAAEiG,IAG3BvJ,EAAUnc,EAAO0lB,MAAMvJ,QAASxd,IAAU,GACpCg+B,IAAgBxgB,EAAQiK,UAAmD,IAAxCjK,EAAQiK,QAAQxoB,MAAOyD,EAAMoe,IAAtE,CAMA,IAAMkd,IAAiBxgB,EAAQyM,WAAanqB,EAAU4C,GAAS,CAM9D,IAJAu7B,EAAazgB,EAAQ6J,cAAgBrnB,EAC/B89B,GAAYhyB,KAAMmyB,EAAaj+B,KACpCmN,EAAMA,EAAIlM,YAEHkM,EAAKA,EAAMA,EAAIlM,WACtBm9B,EAAUl/B,KAAMiO,GAChB6B,EAAM7B,EAIF6B,KAAUtM,EAAK6I,eAAiBrN,IACpCkgC,EAAUl/B,KAAM8P,EAAIb,aAAea,EAAIqvB,cAAgBhgC,GAKzDmC,EAAI,EACJ,OAAU2M,EAAMixB,EAAW59B,QAAYumB,EAAMqC,uBAC5C+U,EAAchxB,EACd4Z,EAAM/mB,KAAW,EAAJQ,EACZy9B,EACAzgB,EAAQgL,UAAYxoB,GAGrBqoB,GACEpH,EAASjf,IAAKmL,EAAK,WAAczO,OAAO0pB,OAAQ,OAC9CrB,EAAM/mB,OACTihB,EAASjf,IAAKmL,EAAK,YAEnBkb,EAAOppB,MAAOkO,EAAK2T,IAIpBuH,EAAS6V,GAAU/wB,EAAK+wB,KACT7V,EAAOppB,OAASshB,EAAYpT,KAC1C4Z,EAAMnV,OAASyW,EAAOppB,MAAOkO,EAAK2T,IACZ,IAAjBiG,EAAMnV,QACVmV,EAAMS,kBA8CT,OA1CAT,EAAM/mB,KAAOA,EAGPg+B,GAAiBjX,EAAMuD,sBAEpB9M,EAAQuH,WACqC,IAApDvH,EAAQuH,SAAS9lB,MAAOm/B,EAAUz2B,MAAOmZ,KACzCP,EAAY7d,IAIPw7B,GAAUv+B,EAAY+C,EAAM1C,MAAaF,EAAU4C,MAGvDsM,EAAMtM,EAAMw7B,MAGXx7B,EAAMw7B,GAAW,MAIlB78B,EAAO0lB,MAAMuB,UAAYtoB,EAEpB+mB,EAAMqC,wBACV+U,EAAY9vB,iBAAkBrO,EAAM+9B,IAGrCr7B,EAAM1C,KAED+mB,EAAMqC,wBACV+U,EAAY/e,oBAAqBpf,EAAM+9B,IAGxC18B,EAAO0lB,MAAMuB,eAAYnkB,EAEpB6K,IACJtM,EAAMw7B,GAAWlvB,IAMd+X,EAAMnV,SAKd0sB,SAAU,SAAUt+B,EAAM0C,EAAMqkB,GAC/B,IAAIjc,EAAIzJ,EAAOmC,OACd,IAAInC,EAAOqmB,MACXX,EACA,CACC/mB,KAAMA,EACN2qB,aAAa,IAIftpB,EAAO0lB,MAAMU,QAAS3c,EAAG,KAAMpI,MAKjCrB,EAAOG,GAAGgC,OAAQ,CAEjBikB,QAAS,SAAUznB,EAAM8gB,GACxB,OAAOxiB,KAAKiE,KAAM,WACjBlB,EAAO0lB,MAAMU,QAASznB,EAAM8gB,EAAMxiB,SAGpCigC,eAAgB,SAAUv+B,EAAM8gB,GAC/B,IAAIpe,EAAOpE,KAAM,GACjB,GAAKoE,EACJ,OAAOrB,EAAO0lB,MAAMU,QAASznB,EAAM8gB,EAAMpe,GAAM,MAc5ChD,EAAQm+B,SACbx8B,EAAOkB,KAAM,CAAEmR,MAAO,UAAW8Y,KAAM,YAAc,SAAUK,EAAM5D,GAGpE,IAAIjc,EAAU,SAAU+Z,GACvB1lB,EAAO0lB,MAAMuX,SAAUrV,EAAKlC,EAAMjjB,OAAQzC,EAAO0lB,MAAMkC,IAAKlC,KAG7D1lB,EAAO0lB,MAAMvJ,QAASyL,GAAQ,CAC7BP,MAAO,WAIN,IAAInoB,EAAMjC,KAAKiN,eAAiBjN,KAAKJ,UAAYI,KAChDkgC,EAAWvd,EAASxB,OAAQlf,EAAK0oB,GAE5BuV,GACLj+B,EAAI8N,iBAAkBwe,EAAM7f,GAAS,GAEtCiU,EAASxB,OAAQlf,EAAK0oB,GAAOuV,GAAY,GAAM,IAEhD3V,SAAU,WACT,IAAItoB,EAAMjC,KAAKiN,eAAiBjN,KAAKJ,UAAYI,KAChDkgC,EAAWvd,EAASxB,OAAQlf,EAAK0oB,GAAQ,EAEpCuV,EAKLvd,EAASxB,OAAQlf,EAAK0oB,EAAKuV,IAJ3Bj+B,EAAI6e,oBAAqByN,EAAM7f,GAAS,GACxCiU,EAAShF,OAAQ1b,EAAK0oB,QAS3B,IAAIzV,GAAWnV,EAAOmV,SAElBtT,GAAQ,CAAEuF,KAAMsB,KAAK2jB,OAErB+T,GAAS,KAKbp9B,EAAOq9B,SAAW,SAAU5d,GAC3B,IAAI3O,EACJ,IAAM2O,GAAwB,iBAATA,EACpB,OAAO,KAKR,IACC3O,GAAM,IAAM9T,EAAOsgC,WAAcC,gBAAiB9d,EAAM,YACvD,MAAQhW,GACTqH,OAAMhO,EAMP,OAHMgO,IAAOA,EAAIxG,qBAAsB,eAAgBhK,QACtDN,EAAOoD,MAAO,gBAAkBqc,GAE1B3O,GAIR,IACC0sB,GAAW,QACXC,GAAQ,SACRC,GAAkB,wCAClBC,GAAe,qCAEhB,SAASC,GAAa9I,EAAQv2B,EAAKs/B,EAAarlB,GAC/C,IAAInW,EAEJ,GAAKO,MAAMC,QAAStE,GAGnByB,EAAOkB,KAAM3C,EAAK,SAAUY,EAAGia,GACzBykB,GAAeL,GAAS/yB,KAAMqqB,GAGlCtc,EAAKsc,EAAQ1b,GAKbwkB,GACC9I,EAAS,KAAqB,iBAAN1b,GAAuB,MAALA,EAAYja,EAAI,IAAO,IACjEia,EACAykB,EACArlB,UAKG,GAAMqlB,GAAiC,WAAlB/9B,EAAQvB,GAUnCia,EAAKsc,EAAQv2B,QAPb,IAAM8D,KAAQ9D,EACbq/B,GAAa9I,EAAS,IAAMzyB,EAAO,IAAK9D,EAAK8D,GAAQw7B,EAAarlB,GAYrExY,EAAO89B,MAAQ,SAAU13B,EAAGy3B,GAC3B,IAAI/I,EACHiJ,EAAI,GACJvlB,EAAM,SAAUrN,EAAK6yB,GAGpB,IAAI75B,EAAQ7F,EAAY0/B,GACvBA,IACAA,EAEDD,EAAGA,EAAEz9B,QAAW29B,mBAAoB9yB,GAAQ,IAC3C8yB,mBAA6B,MAAT95B,EAAgB,GAAKA,IAG5C,GAAU,MAALiC,EACJ,MAAO,GAIR,GAAKxD,MAAMC,QAASuD,IAASA,EAAE5F,SAAWR,EAAO2C,cAAeyD,GAG/DpG,EAAOkB,KAAMkF,EAAG,WACfoS,EAAKvb,KAAKoF,KAAMpF,KAAKkH,cAOtB,IAAM2wB,KAAU1uB,EACfw3B,GAAa9I,EAAQ1uB,EAAG0uB,GAAU+I,EAAarlB,GAKjD,OAAOulB,EAAElzB,KAAM,MAGhB7K,EAAOG,GAAGgC,OAAQ,CACjB+7B,UAAW,WACV,OAAOl+B,EAAO89B,MAAO7gC,KAAKkhC,mBAE3BA,eAAgB,WACf,OAAOlhC,KAAKmE,IAAK,WAGhB,IAAI0N,EAAW9O,EAAO0f,KAAMziB,KAAM,YAClC,OAAO6R,EAAW9O,EAAO2D,UAAWmL,GAAa7R,OAEjDqQ,OAAQ,WACR,IAAI3O,EAAO1B,KAAK0B,KAGhB,OAAO1B,KAAKoF,OAASrC,EAAQ/C,MAAOia,GAAI,cACvCymB,GAAalzB,KAAMxN,KAAKoM,YAAeq0B,GAAgBjzB,KAAM9L,KAC3D1B,KAAK0V,UAAYkQ,GAAepY,KAAM9L,MAEzCyC,IAAK,SAAUoD,EAAInD,GACnB,IAAIjC,EAAMY,EAAQ/C,MAAOmC,MAEzB,OAAY,MAAPA,EACG,KAGHwD,MAAMC,QAASzD,GACZY,EAAOoB,IAAKhC,EAAK,SAAUA,GACjC,MAAO,CAAEiD,KAAMhB,EAAKgB,KAAM8B,MAAO/E,EAAI8D,QAASu6B,GAAO,WAIhD,CAAEp7B,KAAMhB,EAAKgB,KAAM8B,MAAO/E,EAAI8D,QAASu6B,GAAO,WAClD98B,SAKN,IACCy9B,GAAM,OACNC,GAAQ,OACRC,GAAa,gBACbC,GAAW,6BAIXC,GAAa,iBACbC,GAAY,QAWZpH,GAAa,GAObqH,GAAa,GAGbC,GAAW,KAAKhhC,OAAQ,KAGxBihC,GAAe/hC,EAASyC,cAAe,KAIxC,SAASu/B,GAA6BC,GAGrC,OAAO,SAAUC,EAAoB9jB,GAED,iBAAvB8jB,IACX9jB,EAAO8jB,EACPA,EAAqB,KAGtB,IAAIC,EACH7/B,EAAI,EACJ8/B,EAAYF,EAAmBt6B,cAAcqF,MAAOoP,IAAmB,GAExE,GAAK5a,EAAY2c,GAGhB,MAAU+jB,EAAWC,EAAW9/B,KAGR,MAAlB6/B,EAAU,IACdA,EAAWA,EAASzhC,MAAO,IAAO,KAChCuhC,EAAWE,GAAaF,EAAWE,IAAc,IAAKpwB,QAASqM,KAI/D6jB,EAAWE,GAAaF,EAAWE,IAAc,IAAKnhC,KAAMod,IAQnE,SAASikB,GAA+BJ,EAAW18B,EAASw1B,EAAiBuH,GAE5E,IAAIC,EAAY,GACfC,EAAqBP,IAAcJ,GAEpC,SAASY,EAASN,GACjB,IAAIpsB,EAcJ,OAbAwsB,EAAWJ,IAAa,EACxBh/B,EAAOkB,KAAM49B,EAAWE,IAAc,GAAI,SAAU/kB,EAAGslB,GACtD,IAAIC,EAAsBD,EAAoBn9B,EAASw1B,EAAiBuH,GACxE,MAAoC,iBAAxBK,GACVH,GAAqBD,EAAWI,GAKtBH,IACDzsB,EAAW4sB,QADf,GAHNp9B,EAAQ68B,UAAUrwB,QAAS4wB,GAC3BF,EAASE,IACF,KAKF5sB,EAGR,OAAO0sB,EAASl9B,EAAQ68B,UAAW,MAAUG,EAAW,MAASE,EAAS,KAM3E,SAASG,GAAYh9B,EAAQ7D,GAC5B,IAAIuM,EAAKzI,EACRg9B,EAAc1/B,EAAO2/B,aAAaD,aAAe,GAElD,IAAMv0B,KAAOvM,OACQkE,IAAflE,EAAKuM,MACPu0B,EAAav0B,GAAQ1I,EAAWC,IAAUA,EAAO,KAAUyI,GAAQvM,EAAKuM,IAO5E,OAJKzI,GACJ1C,EAAOmC,QAAQ,EAAMM,EAAQC,GAGvBD,EA/EPm8B,GAAapsB,KAAOL,GAASK,KAgP9BxS,EAAOmC,OAAQ,CAGdy9B,OAAQ,EAGRC,aAAc,GACdC,KAAM,GAENH,aAAc,CACbI,IAAK5tB,GAASK,KACd7T,KAAM,MACNqhC,QAvRgB,4DAuRQv1B,KAAM0H,GAAS8tB,UACvCxjC,QAAQ,EACRyjC,aAAa,EACbC,OAAO,EACPC,YAAa,mDAcbC,QAAS,CACRlI,IAAKwG,GACLp/B,KAAM,aACNktB,KAAM,YACN3b,IAAK,4BACLwvB,KAAM,qCAGPtoB,SAAU,CACTlH,IAAK,UACL2b,KAAM,SACN6T,KAAM,YAGPC,eAAgB,CACfzvB,IAAK,cACLvR,KAAM,eACN+gC,KAAM,gBAKPE,WAAY,CAGXC,SAAU/3B,OAGVg4B,aAAa,EAGbC,YAAa1gB,KAAKC,MAGlB0gB,WAAY5gC,EAAOq9B,UAOpBqC,YAAa,CACZK,KAAK,EACL7/B,SAAS,IAOX2gC,UAAW,SAAUp+B,EAAQq+B,GAC5B,OAAOA,EAGNrB,GAAYA,GAAYh9B,EAAQzC,EAAO2/B,cAAgBmB,GAGvDrB,GAAYz/B,EAAO2/B,aAAcl9B,IAGnCs+B,cAAelC,GAA6BxH,IAC5C2J,cAAenC,GAA6BH,IAG5CuC,KAAM,SAAUlB,EAAK39B,GAGA,iBAAR29B,IACX39B,EAAU29B,EACVA,OAAMj9B,GAIPV,EAAUA,GAAW,GAErB,IAAI8+B,EAGHC,EAGAC,EACAC,EAGAC,EAGAC,EAGAzjB,EAGA0jB,EAGAriC,EAGAsiC,EAGA1D,EAAI/9B,EAAO6gC,UAAW,GAAIz+B,GAG1Bs/B,EAAkB3D,EAAE79B,SAAW69B,EAG/B4D,EAAqB5D,EAAE79B,UACpBwhC,EAAgBljC,UAAYkjC,EAAgBlhC,QAC7CR,EAAQ0hC,GACR1hC,EAAO0lB,MAGTrK,EAAWrb,EAAOgb,WAClB4mB,EAAmB5hC,EAAO+Z,UAAW,eAGrC8nB,EAAa9D,EAAE8D,YAAc,GAG7BC,EAAiB,GACjBC,EAAsB,GAGtBC,EAAW,WAGX7C,EAAQ,CACPjhB,WAAY,EAGZ+jB,kBAAmB,SAAU92B,GAC5B,IAAIrB,EACJ,GAAKgU,EAAY,CAChB,IAAMujB,EAAkB,CACvBA,EAAkB,GAClB,MAAUv3B,EAAQy0B,GAASp0B,KAAMi3B,GAChCC,EAAiBv3B,EAAO,GAAIrF,cAAgB,MACzC48B,EAAiBv3B,EAAO,GAAIrF,cAAgB,MAAS,IACrD9G,OAAQmM,EAAO,IAGpBA,EAAQu3B,EAAiBl2B,EAAI1G,cAAgB,KAE9C,OAAgB,MAATqF,EAAgB,KAAOA,EAAMe,KAAM,OAI3Cq3B,sBAAuB,WACtB,OAAOpkB,EAAYsjB,EAAwB,MAI5Ce,iBAAkB,SAAU9/B,EAAM8B,GAMjC,OALkB,MAAb2Z,IACJzb,EAAO0/B,EAAqB1/B,EAAKoC,eAChCs9B,EAAqB1/B,EAAKoC,gBAAmBpC,EAC9Cy/B,EAAgBz/B,GAAS8B,GAEnBlH,MAIRmlC,iBAAkB,SAAUzjC,GAI3B,OAHkB,MAAbmf,IACJigB,EAAEsE,SAAW1jC,GAEP1B,MAIR4kC,WAAY,SAAUzgC,GACrB,IAAIpC,EACJ,GAAKoC,EACJ,GAAK0c,EAGJqhB,EAAM/jB,OAAQha,EAAK+9B,EAAMmD,cAIzB,IAAMtjC,KAAQoC,EACbygC,EAAY7iC,GAAS,CAAE6iC,EAAY7iC,GAAQoC,EAAKpC,IAInD,OAAO/B,MAIRslC,MAAO,SAAUC,GAChB,IAAIC,EAAYD,GAAcR,EAK9B,OAJKd,GACJA,EAAUqB,MAAOE,GAElB58B,EAAM,EAAG48B,GACFxlC,OAoBV,GAfAoe,EAASzB,QAASulB,GAKlBpB,EAAEgC,MAAUA,GAAOhC,EAAEgC,KAAO5tB,GAASK,MAAS,IAC5CtP,QAASu7B,GAAWtsB,GAAS8tB,SAAW,MAG1ClC,EAAEp/B,KAAOyD,EAAQuX,QAAUvX,EAAQzD,MAAQo/B,EAAEpkB,QAAUokB,EAAEp/B,KAGzDo/B,EAAEkB,WAAclB,EAAEiB,UAAY,KAAMv6B,cAAcqF,MAAOoP,IAAmB,CAAE,IAGxD,MAAjB6kB,EAAE2E,YAAsB,CAC5BnB,EAAY1kC,EAASyC,cAAe,KAKpC,IACCiiC,EAAU/uB,KAAOurB,EAAEgC,IAInBwB,EAAU/uB,KAAO+uB,EAAU/uB,KAC3BurB,EAAE2E,YAAc9D,GAAaqB,SAAW,KAAOrB,GAAa+D,MAC3DpB,EAAUtB,SAAW,KAAOsB,EAAUoB,KACtC,MAAQl5B,GAITs0B,EAAE2E,aAAc,GAalB,GARK3E,EAAEte,MAAQse,EAAEmC,aAAiC,iBAAXnC,EAAEte,OACxCse,EAAEte,KAAOzf,EAAO89B,MAAOC,EAAEte,KAAMse,EAAEF,cAIlCqB,GAA+B7H,GAAY0G,EAAG37B,EAAS+8B,GAGlDrhB,EACJ,OAAOqhB,EA8ER,IAAMhgC,KAzENqiC,EAAcxhC,EAAO0lB,OAASqY,EAAEthC,SAGQ,GAApBuD,EAAO4/B,UAC1B5/B,EAAO0lB,MAAMU,QAAS,aAIvB2X,EAAEp/B,KAAOo/B,EAAEp/B,KAAKogB,cAGhBgf,EAAE6E,YAAcpE,GAAW/zB,KAAMszB,EAAEp/B,MAKnCwiC,EAAWpD,EAAEgC,IAAI78B,QAASm7B,GAAO,IAG3BN,EAAE6E,WAwBI7E,EAAEte,MAAQse,EAAEmC,aACoD,KAAzEnC,EAAEqC,aAAe,IAAKtiC,QAAS,uCACjCigC,EAAEte,KAAOse,EAAEte,KAAKvc,QAASk7B,GAAK,OAvB9BqD,EAAW1D,EAAEgC,IAAIxiC,MAAO4jC,EAAS7gC,QAG5By9B,EAAEte,OAAUse,EAAEmC,aAAiC,iBAAXnC,EAAEte,QAC1C0hB,IAAc/D,GAAO3yB,KAAM02B,GAAa,IAAM,KAAQpD,EAAEte,YAGjDse,EAAEte,OAIO,IAAZse,EAAE7yB,QACNi2B,EAAWA,EAASj+B,QAASo7B,GAAY,MACzCmD,GAAarE,GAAO3yB,KAAM02B,GAAa,IAAM,KAAQ,KAAStiC,GAAMuF,OACnEq9B,GAIF1D,EAAEgC,IAAMoB,EAAWM,GASf1D,EAAE8E,aACD7iC,EAAO6/B,aAAcsB,IACzBhC,EAAMgD,iBAAkB,oBAAqBniC,EAAO6/B,aAAcsB,IAE9DnhC,EAAO8/B,KAAMqB,IACjBhC,EAAMgD,iBAAkB,gBAAiBniC,EAAO8/B,KAAMqB,MAKnDpD,EAAEte,MAAQse,EAAE6E,aAAgC,IAAlB7E,EAAEqC,aAAyBh+B,EAAQg+B,cACjEjB,EAAMgD,iBAAkB,eAAgBpE,EAAEqC,aAI3CjB,EAAMgD,iBACL,SACApE,EAAEkB,UAAW,IAAOlB,EAAEsC,QAAStC,EAAEkB,UAAW,IAC3ClB,EAAEsC,QAAStC,EAAEkB,UAAW,KACA,MAArBlB,EAAEkB,UAAW,GAAc,KAAON,GAAW,WAAa,IAC7DZ,EAAEsC,QAAS,MAIFtC,EAAE+E,QACZ3D,EAAMgD,iBAAkBhjC,EAAG4+B,EAAE+E,QAAS3jC,IAIvC,GAAK4+B,EAAEgF,cAC+C,IAAnDhF,EAAEgF,WAAWrlC,KAAMgkC,EAAiBvC,EAAOpB,IAAiBjgB,GAG9D,OAAOqhB,EAAMoD,QAed,GAXAP,EAAW,QAGXJ,EAAiBppB,IAAKulB,EAAE/F,UACxBmH,EAAMt5B,KAAMk4B,EAAEiF,SACd7D,EAAMtlB,KAAMkkB,EAAE36B,OAGd89B,EAAYhC,GAA+BR,GAAYX,EAAG37B,EAAS+8B,GAK5D,CASN,GARAA,EAAMjhB,WAAa,EAGdsjB,GACJG,EAAmBvb,QAAS,WAAY,CAAE+Y,EAAOpB,IAI7CjgB,EACJ,OAAOqhB,EAIHpB,EAAEoC,OAAqB,EAAZpC,EAAE3D,UACjBkH,EAAetkC,EAAO8f,WAAY,WACjCqiB,EAAMoD,MAAO,YACXxE,EAAE3D,UAGN,IACCtc,GAAY,EACZojB,EAAU+B,KAAMnB,EAAgBj8B,GAC/B,MAAQ4D,GAGT,GAAKqU,EACJ,MAAMrU,EAIP5D,GAAO,EAAG4D,SAhCX5D,GAAO,EAAG,gBAqCX,SAASA,EAAMy8B,EAAQY,EAAkBC,EAAWL,GACnD,IAAIM,EAAWJ,EAAS5/B,EAAOigC,EAAUC,EACxCd,EAAaU,EAGTplB,IAILA,GAAY,EAGPwjB,GACJtkC,EAAOq9B,aAAciH,GAKtBJ,OAAYp+B,EAGZs+B,EAAwB0B,GAAW,GAGnC3D,EAAMjhB,WAAsB,EAATokB,EAAa,EAAI,EAGpCc,EAAsB,KAAVd,GAAiBA,EAAS,KAAkB,MAAXA,EAGxCa,IACJE,EA7lBJ,SAA8BtF,EAAGoB,EAAOgE,GAEvC,IAAII,EAAI5kC,EAAM6kC,EAAeC,EAC5BzrB,EAAW+lB,EAAE/lB,SACbinB,EAAYlB,EAAEkB,UAGf,MAA2B,MAAnBA,EAAW,GAClBA,EAAU5zB,aACEvI,IAAPygC,IACJA,EAAKxF,EAAEsE,UAAYlD,EAAM8C,kBAAmB,iBAK9C,GAAKsB,EACJ,IAAM5kC,KAAQqZ,EACb,GAAKA,EAAUrZ,IAAUqZ,EAAUrZ,GAAO8L,KAAM84B,GAAO,CACtDtE,EAAUrwB,QAASjQ,GACnB,MAMH,GAAKsgC,EAAW,KAAOkE,EACtBK,EAAgBvE,EAAW,OACrB,CAGN,IAAMtgC,KAAQwkC,EAAY,CACzB,IAAMlE,EAAW,IAAOlB,EAAEyC,WAAY7hC,EAAO,IAAMsgC,EAAW,IAAQ,CACrEuE,EAAgB7kC,EAChB,MAEK8kC,IACLA,EAAgB9kC,GAKlB6kC,EAAgBA,GAAiBC,EAMlC,GAAKD,EAIJ,OAHKA,IAAkBvE,EAAW,IACjCA,EAAUrwB,QAAS40B,GAEbL,EAAWK,GA0iBLE,CAAqB3F,EAAGoB,EAAOgE,KAIrCC,IAAwD,EAA3CpjC,EAAO6D,QAAS,SAAUk6B,EAAEkB,aAC9ClB,EAAEyC,WAAY,eAAkB,cAIjC6C,EA5iBH,SAAsBtF,EAAGsF,EAAUlE,EAAOiE,GACzC,IAAIO,EAAOC,EAASC,EAAMl2B,EAAKsK,EAC9BuoB,EAAa,GAGbvB,EAAYlB,EAAEkB,UAAU1hC,QAGzB,GAAK0hC,EAAW,GACf,IAAM4E,KAAQ9F,EAAEyC,WACfA,EAAYqD,EAAKp/B,eAAkBs5B,EAAEyC,WAAYqD,GAInDD,EAAU3E,EAAU5zB,QAGpB,MAAQu4B,EAcP,GAZK7F,EAAEwC,eAAgBqD,KACtBzE,EAAOpB,EAAEwC,eAAgBqD,IAAcP,IAIlCprB,GAAQmrB,GAAarF,EAAE+F,aAC5BT,EAAWtF,EAAE+F,WAAYT,EAAUtF,EAAEiB,WAGtC/mB,EAAO2rB,EACPA,EAAU3E,EAAU5zB,QAKnB,GAAiB,MAAZu4B,EAEJA,EAAU3rB,OAGJ,GAAc,MAATA,GAAgBA,IAAS2rB,EAAU,CAM9C,KAHAC,EAAOrD,EAAYvoB,EAAO,IAAM2rB,IAAapD,EAAY,KAAOoD,IAI/D,IAAMD,KAASnD,EAId,IADA7yB,EAAMg2B,EAAMp/B,MAAO,MACT,KAAQq/B,IAGjBC,EAAOrD,EAAYvoB,EAAO,IAAMtK,EAAK,KACpC6yB,EAAY,KAAO7yB,EAAK,KACb,EAGG,IAATk2B,EACJA,EAAOrD,EAAYmD,IAGgB,IAAxBnD,EAAYmD,KACvBC,EAAUj2B,EAAK,GACfsxB,EAAUrwB,QAASjB,EAAK,KAEzB,MAOJ,IAAc,IAATk2B,EAGJ,GAAKA,GAAQ9F,EAAEgG,UACdV,EAAWQ,EAAMR,QAEjB,IACCA,EAAWQ,EAAMR,GAChB,MAAQ55B,GACT,MAAO,CACN0R,MAAO,cACP/X,MAAOygC,EAAOp6B,EAAI,sBAAwBwO,EAAO,OAAS2rB,IASjE,MAAO,CAAEzoB,MAAO,UAAWsE,KAAM4jB,GA+cpBW,CAAajG,EAAGsF,EAAUlE,EAAOiE,GAGvCA,GAGCrF,EAAE8E,cACNS,EAAWnE,EAAM8C,kBAAmB,oBAEnCjiC,EAAO6/B,aAAcsB,GAAamC,IAEnCA,EAAWnE,EAAM8C,kBAAmB,WAEnCjiC,EAAO8/B,KAAMqB,GAAamC,IAKZ,MAAXhB,GAA6B,SAAXvE,EAAEp/B,KACxB6jC,EAAa,YAGS,MAAXF,EACXE,EAAa,eAIbA,EAAaa,EAASloB,MACtB6nB,EAAUK,EAAS5jB,KAEnB2jB,IADAhgC,EAAQigC,EAASjgC,UAMlBA,EAAQo/B,GACHF,GAAWE,IACfA,EAAa,QACRF,EAAS,IACbA,EAAS,KAMZnD,EAAMmD,OAASA,EACfnD,EAAMqD,YAAeU,GAAoBV,GAAe,GAGnDY,EACJ/nB,EAASmB,YAAaklB,EAAiB,CAAEsB,EAASR,EAAYrD,IAE9D9jB,EAASuB,WAAY8kB,EAAiB,CAAEvC,EAAOqD,EAAYp/B,IAI5D+7B,EAAM0C,WAAYA,GAClBA,OAAa/+B,EAER0+B,GACJG,EAAmBvb,QAASgd,EAAY,cAAgB,YACvD,CAAEjE,EAAOpB,EAAGqF,EAAYJ,EAAU5/B,IAIpCw+B,EAAiB7mB,SAAU2mB,EAAiB,CAAEvC,EAAOqD,IAEhDhB,IACJG,EAAmBvb,QAAS,eAAgB,CAAE+Y,EAAOpB,MAG3C/9B,EAAO4/B,QAChB5/B,EAAO0lB,MAAMU,QAAS,cAKzB,OAAO+Y,GAGR8E,QAAS,SAAUlE,EAAKtgB,EAAMte,GAC7B,OAAOnB,EAAOW,IAAKo/B,EAAKtgB,EAAMte,EAAU,SAGzC+iC,UAAW,SAAUnE,EAAK5+B,GACzB,OAAOnB,EAAOW,IAAKo/B,OAAKj9B,EAAW3B,EAAU,aAI/CnB,EAAOkB,KAAM,CAAE,MAAO,QAAU,SAAUsD,EAAImV,GAC7C3Z,EAAQ2Z,GAAW,SAAUomB,EAAKtgB,EAAMte,EAAUxC,GAUjD,OAPKL,EAAYmhB,KAChB9gB,EAAOA,GAAQwC,EACfA,EAAWse,EACXA,OAAO3c,GAID9C,EAAOihC,KAAMjhC,EAAOmC,OAAQ,CAClC49B,IAAKA,EACLphC,KAAMgb,EACNqlB,SAAUrgC,EACV8gB,KAAMA,EACNujB,QAAS7hC,GACPnB,EAAO2C,cAAeo9B,IAASA,OAIpC//B,EAAO+gC,cAAe,SAAUhD,GAC/B,IAAI5+B,EACJ,IAAMA,KAAK4+B,EAAE+E,QACa,iBAApB3jC,EAAEsF,gBACNs5B,EAAEqC,YAAcrC,EAAE+E,QAAS3jC,IAAO,MAMrCa,EAAO0sB,SAAW,SAAUqT,EAAK39B,EAASlD,GACzC,OAAOc,EAAOihC,KAAM,CACnBlB,IAAKA,EAGLphC,KAAM,MACNqgC,SAAU,SACV9zB,OAAO,EACPi1B,OAAO,EACP1jC,QAAQ,EAKR+jC,WAAY,CACX2D,cAAe,cAEhBL,WAAY,SAAUT,GACrBrjC,EAAO0D,WAAY2/B,EAAUjhC,EAASlD,OAMzCc,EAAOG,GAAGgC,OAAQ,CACjBiiC,QAAS,SAAU3X,GAClB,IAAIjI,EAyBJ,OAvBKvnB,KAAM,KACLqB,EAAYmuB,KAChBA,EAAOA,EAAK/uB,KAAMT,KAAM,KAIzBunB,EAAOxkB,EAAQysB,EAAMxvB,KAAM,GAAIiN,eAAgB1I,GAAI,GAAIgB,OAAO,GAEzDvF,KAAM,GAAI2C,YACd4kB,EAAK6I,aAAcpwB,KAAM,IAG1BunB,EAAKpjB,IAAK,WACT,IAAIC,EAAOpE,KAEX,MAAQoE,EAAKgjC,kBACZhjC,EAAOA,EAAKgjC,kBAGb,OAAOhjC,IACJ8rB,OAAQlwB,OAGNA,MAGRqnC,UAAW,SAAU7X,GACpB,OAAKnuB,EAAYmuB,GACTxvB,KAAKiE,KAAM,SAAU/B,GAC3Ba,EAAQ/C,MAAOqnC,UAAW7X,EAAK/uB,KAAMT,KAAMkC,MAItClC,KAAKiE,KAAM,WACjB,IAAIuW,EAAOzX,EAAQ/C,MAClB+a,EAAWP,EAAKO,WAEZA,EAAS1X,OACb0X,EAASosB,QAAS3X,GAGlBhV,EAAK0V,OAAQV,MAKhBjI,KAAM,SAAUiI,GACf,IAAI8X,EAAiBjmC,EAAYmuB,GAEjC,OAAOxvB,KAAKiE,KAAM,SAAU/B,GAC3Ba,EAAQ/C,MAAOmnC,QAASG,EAAiB9X,EAAK/uB,KAAMT,KAAMkC,GAAMstB,MAIlE+X,OAAQ,SAAUvkC,GAIjB,OAHAhD,KAAKkU,OAAQlR,GAAW2R,IAAK,QAAS1Q,KAAM,WAC3ClB,EAAQ/C,MAAOuwB,YAAavwB,KAAKuM,cAE3BvM,QAKT+C,EAAO6O,KAAKhI,QAAQ2vB,OAAS,SAAUn1B,GACtC,OAAQrB,EAAO6O,KAAKhI,QAAQ49B,QAASpjC,IAEtCrB,EAAO6O,KAAKhI,QAAQ49B,QAAU,SAAUpjC,GACvC,SAAWA,EAAKyuB,aAAezuB,EAAKqjC,cAAgBrjC,EAAKwxB,iBAAiBvyB,SAM3EN,EAAO2/B,aAAagF,IAAM,WACzB,IACC,OAAO,IAAI3nC,EAAO4nC,eACjB,MAAQn7B,MAGX,IAAIo7B,GAAmB,CAGrBC,EAAG,IAIHC,KAAM,KAEPC,GAAehlC,EAAO2/B,aAAagF,MAEpCtmC,EAAQ4mC,OAASD,IAAkB,oBAAqBA,GACxD3mC,EAAQ4iC,KAAO+D,KAAiBA,GAEhChlC,EAAOghC,cAAe,SAAU5+B,GAC/B,IAAIjB,EAAU+jC,EAGd,GAAK7mC,EAAQ4mC,MAAQD,KAAiB5iC,EAAQsgC,YAC7C,MAAO,CACNO,KAAM,SAAUH,EAAS9K,GACxB,IAAI74B,EACHwlC,EAAMviC,EAAQuiC,MAWf,GATAA,EAAIQ,KACH/iC,EAAQzD,KACRyD,EAAQ29B,IACR39B,EAAQ+9B,MACR/9B,EAAQgjC,SACRhjC,EAAQmR,UAIJnR,EAAQijC,UACZ,IAAMlmC,KAAKiD,EAAQijC,UAClBV,EAAKxlC,GAAMiD,EAAQijC,UAAWlmC,GAmBhC,IAAMA,KAdDiD,EAAQigC,UAAYsC,EAAIvC,kBAC5BuC,EAAIvC,iBAAkBhgC,EAAQigC,UAQzBjgC,EAAQsgC,aAAgBI,EAAS,sBACtCA,EAAS,oBAAuB,kBAItBA,EACV6B,EAAIxC,iBAAkBhjC,EAAG2jC,EAAS3jC,IAInCgC,EAAW,SAAUxC,GACpB,OAAO,WACDwC,IACJA,EAAW+jC,EAAgBP,EAAIW,OAC9BX,EAAIY,QAAUZ,EAAIa,QAAUb,EAAIc,UAC/Bd,EAAIe,mBAAqB,KAEb,UAAT/mC,EACJgmC,EAAIpC,QACgB,UAAT5jC,EAKgB,iBAAfgmC,EAAIrC,OACftK,EAAU,EAAG,SAEbA,EAGC2M,EAAIrC,OACJqC,EAAInC,YAINxK,EACC6M,GAAkBF,EAAIrC,SAAYqC,EAAIrC,OACtCqC,EAAInC,WAK+B,UAAjCmC,EAAIgB,cAAgB,SACM,iBAArBhB,EAAIiB,aACV,CAAEC,OAAQlB,EAAItB,UACd,CAAE9jC,KAAMolC,EAAIiB,cACbjB,EAAIzC,4BAQTyC,EAAIW,OAASnkC,IACb+jC,EAAgBP,EAAIY,QAAUZ,EAAIc,UAAYtkC,EAAU,cAKnC2B,IAAhB6hC,EAAIa,QACRb,EAAIa,QAAUN,EAEdP,EAAIe,mBAAqB,WAGA,IAAnBf,EAAIzmB,YAMRlhB,EAAO8f,WAAY,WACb3b,GACJ+jC,OAQL/jC,EAAWA,EAAU,SAErB,IAGCwjC,EAAI1B,KAAM7gC,EAAQwgC,YAAcxgC,EAAQqd,MAAQ,MAC/C,MAAQhW,GAGT,GAAKtI,EACJ,MAAMsI,IAKT84B,MAAO,WACDphC,GACJA,QAWLnB,EAAO+gC,cAAe,SAAUhD,GAC1BA,EAAE2E,cACN3E,EAAE/lB,SAAS3Y,QAAS,KAKtBW,EAAO6gC,UAAW,CACjBR,QAAS,CACRhhC,OAAQ,6FAGT2Y,SAAU,CACT3Y,OAAQ,2BAETmhC,WAAY,CACX2D,cAAe,SAAU5kC,GAExB,OADAS,EAAO0D,WAAYnE,GACZA,MAMVS,EAAO+gC,cAAe,SAAU,SAAUhD,QACxBj7B,IAAZi7B,EAAE7yB,QACN6yB,EAAE7yB,OAAQ,GAEN6yB,EAAE2E,cACN3E,EAAEp/B,KAAO,SAKXqB,EAAOghC,cAAe,SAAU,SAAUjD,GAIxC,IAAI1+B,EAAQ8B,EADb,GAAK48B,EAAE2E,aAAe3E,EAAE+H,YAEvB,MAAO,CACN7C,KAAM,SAAUhpB,EAAG+d,GAClB34B,EAASW,EAAQ,YACf+O,KAAMgvB,EAAE+H,aAAe,IACvBpmB,KAAM,CAAEqmB,QAAShI,EAAEiI,cAAepnC,IAAKm/B,EAAEgC,MACzCza,GAAI,aAAcnkB,EAAW,SAAU8kC,GACvC5mC,EAAOub,SACPzZ,EAAW,KACN8kC,GACJjO,EAAuB,UAAbiO,EAAItnC,KAAmB,IAAM,IAAKsnC,EAAItnC,QAKnD9B,EAAS6C,KAAKC,YAAaN,EAAQ,KAEpCkjC,MAAO,WACDphC,GACJA,QAUL,IAqGKshB,GArGDyjB,GAAe,GAClBC,GAAS,oBAGVnmC,EAAO6gC,UAAW,CACjBuF,MAAO,WACPC,cAAe,WACd,IAAIllC,EAAW+kC,GAAa5/B,OAAWtG,EAAO+C,QAAU,IAAQlE,GAAMuF,OAEtE,OADAnH,KAAMkE,IAAa,EACZA,KAKTnB,EAAO+gC,cAAe,aAAc,SAAUhD,EAAGuI,EAAkBnH,GAElE,IAAIoH,EAAcC,EAAaC,EAC9BC,GAAuB,IAAZ3I,EAAEqI,QAAqBD,GAAO17B,KAAMszB,EAAEgC,KAChD,MACkB,iBAAXhC,EAAEte,MAE6C,KADnDse,EAAEqC,aAAe,IACjBtiC,QAAS,sCACXqoC,GAAO17B,KAAMszB,EAAEte,OAAU,QAI5B,GAAKinB,GAAiC,UAArB3I,EAAEkB,UAAW,GA8D7B,OA3DAsH,EAAexI,EAAEsI,cAAgB/nC,EAAYy/B,EAAEsI,eAC9CtI,EAAEsI,gBACFtI,EAAEsI,cAGEK,EACJ3I,EAAG2I,GAAa3I,EAAG2I,GAAWxjC,QAASijC,GAAQ,KAAOI,IAC/B,IAAZxI,EAAEqI,QACbrI,EAAEgC,MAAS3C,GAAO3yB,KAAMszB,EAAEgC,KAAQ,IAAM,KAAQhC,EAAEqI,MAAQ,IAAMG,GAIjExI,EAAEyC,WAAY,eAAkB,WAI/B,OAHMiG,GACLzmC,EAAOoD,MAAOmjC,EAAe,mBAEvBE,EAAmB,IAI3B1I,EAAEkB,UAAW,GAAM,OAGnBuH,EAAcxpC,EAAQupC,GACtBvpC,EAAQupC,GAAiB,WACxBE,EAAoBnlC,WAIrB69B,EAAM/jB,OAAQ,gBAGQtY,IAAhB0jC,EACJxmC,EAAQhD,GAASq+B,WAAYkL,GAI7BvpC,EAAQupC,GAAiBC,EAIrBzI,EAAGwI,KAGPxI,EAAEsI,cAAgBC,EAAiBD,cAGnCH,GAAaroC,KAAM0oC,IAIfE,GAAqBnoC,EAAYkoC,IACrCA,EAAaC,EAAmB,IAGjCA,EAAoBD,OAAc1jC,IAI5B,WAYTzE,EAAQsoC,qBACHlkB,GAAO5lB,EAAS+pC,eAAeD,mBAAoB,IAAKlkB,MACvD5U,UAAY,6BACiB,IAA3B4U,GAAKjZ,WAAWlJ,QAQxBN,EAAO2X,UAAY,SAAU8H,EAAMvf,EAAS2mC,GAC3C,MAAqB,iBAATpnB,EACJ,IAEgB,kBAAZvf,IACX2mC,EAAc3mC,EACdA,GAAU,GAKLA,IAIA7B,EAAQsoC,qBAMZ9yB,GALA3T,EAAUrD,EAAS+pC,eAAeD,mBAAoB,KAKvCrnC,cAAe,SACzBkT,KAAO3V,EAASsV,SAASK,KAC9BtS,EAAQR,KAAKC,YAAakU,IAE1B3T,EAAUrD,GAKZwnB,GAAWwiB,GAAe,IAD1BC,EAASxvB,EAAWnN,KAAMsV,IAKlB,CAAEvf,EAAQZ,cAAewnC,EAAQ,MAGzCA,EAAS1iB,GAAe,CAAE3E,GAAQvf,EAASmkB,GAEtCA,GAAWA,EAAQ/jB,QACvBN,EAAQqkB,GAAUzJ,SAGZ5a,EAAOgB,MAAO,GAAI8lC,EAAOt9B,cAlChC,IAAIqK,EAAMizB,EAAQziB,GAyCnBrkB,EAAOG,GAAGwoB,KAAO,SAAUoX,EAAKgH,EAAQ5lC,GACvC,IAAIlB,EAAUtB,EAAM0kC,EACnB5rB,EAAOxa,KACP0oB,EAAMoa,EAAIjiC,QAAS,KAsDpB,OApDY,EAAP6nB,IACJ1lB,EAAWi7B,GAAkB6E,EAAIxiC,MAAOooB,IACxCoa,EAAMA,EAAIxiC,MAAO,EAAGooB,IAIhBrnB,EAAYyoC,IAGhB5lC,EAAW4lC,EACXA,OAASjkC,GAGEikC,GAA4B,iBAAXA,IAC5BpoC,EAAO,QAIW,EAAd8Y,EAAKnX,QACTN,EAAOihC,KAAM,CACZlB,IAAKA,EAKLphC,KAAMA,GAAQ,MACdqgC,SAAU,OACVvf,KAAMsnB,IACHlhC,KAAM,SAAU+/B,GAGnBvC,EAAW/hC,UAEXmW,EAAKgV,KAAMxsB,EAIVD,EAAQ,SAAUmtB,OAAQntB,EAAO2X,UAAWiuB,IAAiBp4B,KAAMvN,GAGnE2lC,KAKExqB,OAAQja,GAAY,SAAUg+B,EAAOmD,GACxC7qB,EAAKvW,KAAM,WACVC,EAASvD,MAAOX,KAAMomC,GAAY,CAAElE,EAAMyG,aAActD,EAAQnD,QAK5DliC,MAMR+C,EAAO6O,KAAKhI,QAAQmgC,SAAW,SAAU3lC,GACxC,OAAOrB,EAAO2B,KAAM3B,EAAOw5B,OAAQ,SAAUr5B,GAC5C,OAAOkB,IAASlB,EAAGkB,OAChBf,QAMLN,EAAOinC,OAAS,CACfC,UAAW,SAAU7lC,EAAMe,EAASjD,GACnC,IAAIgoC,EAAaC,EAASC,EAAWC,EAAQC,EAAWC,EACvD5X,EAAW5vB,EAAOyhB,IAAKpgB,EAAM,YAC7BomC,EAAUznC,EAAQqB,GAClB2nB,EAAQ,GAGS,WAAb4G,IACJvuB,EAAKkgB,MAAMqO,SAAW,YAGvB2X,EAAYE,EAAQR,SACpBI,EAAYrnC,EAAOyhB,IAAKpgB,EAAM,OAC9BmmC,EAAaxnC,EAAOyhB,IAAKpgB,EAAM,SACI,aAAbuuB,GAAwC,UAAbA,KACA,GAA9CyX,EAAYG,GAAa1pC,QAAS,SAMpCwpC,GADAH,EAAcM,EAAQ7X,YACD7iB,IACrBq6B,EAAUD,EAAYzS,OAGtB4S,EAASrX,WAAYoX,IAAe,EACpCD,EAAUnX,WAAYuX,IAAgB,GAGlClpC,EAAY8D,KAGhBA,EAAUA,EAAQ1E,KAAM2D,EAAMlC,EAAGa,EAAOmC,OAAQ,GAAIolC,KAGjC,MAAfnlC,EAAQ2K,MACZic,EAAMjc,IAAQ3K,EAAQ2K,IAAMw6B,EAAUx6B,IAAQu6B,GAE1B,MAAhBllC,EAAQsyB,OACZ1L,EAAM0L,KAAStyB,EAAQsyB,KAAO6S,EAAU7S,KAAS0S,GAG7C,UAAWhlC,EACfA,EAAQslC,MAAMhqC,KAAM2D,EAAM2nB,IAGA,iBAAdA,EAAMjc,MACjBic,EAAMjc,KAAO,MAEa,iBAAfic,EAAM0L,OACjB1L,EAAM0L,MAAQ,MAEf+S,EAAQhmB,IAAKuH,MAKhBhpB,EAAOG,GAAGgC,OAAQ,CAGjB8kC,OAAQ,SAAU7kC,GAGjB,GAAKd,UAAUhB,OACd,YAAmBwC,IAAZV,EACNnF,KACAA,KAAKiE,KAAM,SAAU/B,GACpBa,EAAOinC,OAAOC,UAAWjqC,KAAMmF,EAASjD,KAI3C,IAAIwoC,EAAMC,EACTvmC,EAAOpE,KAAM,GAEd,OAAMoE,EAQAA,EAAKwxB,iBAAiBvyB,QAK5BqnC,EAAOtmC,EAAKmzB,wBACZoT,EAAMvmC,EAAK6I,cAAc4C,YAClB,CACNC,IAAK46B,EAAK56B,IAAM66B,EAAIC,YACpBnT,KAAMiT,EAAKjT,KAAOkT,EAAIE,cARf,CAAE/6B,IAAK,EAAG2nB,KAAM,QATxB,GAuBD9E,SAAU,WACT,GAAM3yB,KAAM,GAAZ,CAIA,IAAI8qC,EAAcd,EAAQ/nC,EACzBmC,EAAOpE,KAAM,GACb+qC,EAAe,CAAEj7B,IAAK,EAAG2nB,KAAM,GAGhC,GAAwC,UAAnC10B,EAAOyhB,IAAKpgB,EAAM,YAGtB4lC,EAAS5lC,EAAKmzB,4BAER,CACNyS,EAAShqC,KAAKgqC,SAId/nC,EAAMmC,EAAK6I,cACX69B,EAAe1mC,EAAK0mC,cAAgB7oC,EAAIyN,gBACxC,MAAQo7B,IACLA,IAAiB7oC,EAAIujB,MAAQslB,IAAiB7oC,EAAIyN,kBACT,WAA3C3M,EAAOyhB,IAAKsmB,EAAc,YAE1BA,EAAeA,EAAanoC,WAExBmoC,GAAgBA,IAAiB1mC,GAAkC,IAA1B0mC,EAAavpC,YAG1DwpC,EAAehoC,EAAQ+nC,GAAed,UACzBl6B,KAAO/M,EAAOyhB,IAAKsmB,EAAc,kBAAkB,GAChEC,EAAatT,MAAQ10B,EAAOyhB,IAAKsmB,EAAc,mBAAmB,IAKpE,MAAO,CACNh7B,IAAKk6B,EAAOl6B,IAAMi7B,EAAaj7B,IAAM/M,EAAOyhB,IAAKpgB,EAAM,aAAa,GACpEqzB,KAAMuS,EAAOvS,KAAOsT,EAAatT,KAAO10B,EAAOyhB,IAAKpgB,EAAM,cAAc,MAc1E0mC,aAAc,WACb,OAAO9qC,KAAKmE,IAAK,WAChB,IAAI2mC,EAAe9qC,KAAK8qC,aAExB,MAAQA,GAA2D,WAA3C/nC,EAAOyhB,IAAKsmB,EAAc,YACjDA,EAAeA,EAAaA,aAG7B,OAAOA,GAAgBp7B,QAM1B3M,EAAOkB,KAAM,CAAE00B,WAAY,cAAeD,UAAW,eAAiB,SAAUhc,EAAQ+F,GACvF,IAAI3S,EAAM,gBAAkB2S,EAE5B1f,EAAOG,GAAIwZ,GAAW,SAAUva,GAC/B,OAAOgf,EAAQnhB,KAAM,SAAUoE,EAAMsY,EAAQva,GAG5C,IAAIwoC,EAOJ,GANKnpC,EAAU4C,GACdumC,EAAMvmC,EACuB,IAAlBA,EAAK7C,WAChBopC,EAAMvmC,EAAKyL,kBAGChK,IAAR1D,EACJ,OAAOwoC,EAAMA,EAAKloB,GAASre,EAAMsY,GAG7BiuB,EACJA,EAAIK,SACFl7B,EAAY66B,EAAIE,YAAV1oC,EACP2N,EAAM3N,EAAMwoC,EAAIC,aAIjBxmC,EAAMsY,GAAWva,GAEhBua,EAAQva,EAAKkC,UAAUhB,WAU5BN,EAAOkB,KAAM,CAAE,MAAO,QAAU,SAAUsD,EAAIkb,GAC7C1f,EAAOgzB,SAAUtT,GAASoP,GAAczwB,EAAQiyB,cAC/C,SAAUjvB,EAAMmtB,GACf,GAAKA,EAIJ,OAHAA,EAAWD,GAAQltB,EAAMqe,GAGlBsO,GAAUvjB,KAAM+jB,GACtBxuB,EAAQqB,GAAOuuB,WAAYlQ,GAAS,KACpC8O,MAQLxuB,EAAOkB,KAAM,CAAEgnC,OAAQ,SAAUC,MAAO,SAAW,SAAU9lC,EAAM1D,GAClEqB,EAAOkB,KAAM,CAAE0zB,QAAS,QAAUvyB,EAAM2W,QAASra,EAAMypC,GAAI,QAAU/lC,GACpE,SAAUgmC,EAAcC,GAGxBtoC,EAAOG,GAAImoC,GAAa,SAAU3T,EAAQxwB,GACzC,IAAIka,EAAY/c,UAAUhB,SAAY+nC,GAAkC,kBAAX1T,GAC5DpC,EAAQ8V,KAA6B,IAAX1T,IAA6B,IAAVxwB,EAAiB,SAAW,UAE1E,OAAOia,EAAQnhB,KAAM,SAAUoE,EAAM1C,EAAMwF,GAC1C,IAAIjF,EAEJ,OAAKT,EAAU4C,GAGyB,IAAhCinC,EAASxqC,QAAS,SACxBuD,EAAM,QAAUgB,GAChBhB,EAAKxE,SAAS8P,gBAAiB,SAAWtK,GAIrB,IAAlBhB,EAAK7C,UACTU,EAAMmC,EAAKsL,gBAIJ3J,KAAKgvB,IACX3wB,EAAKohB,KAAM,SAAWpgB,GAAQnD,EAAK,SAAWmD,GAC9ChB,EAAKohB,KAAM,SAAWpgB,GAAQnD,EAAK,SAAWmD,GAC9CnD,EAAK,SAAWmD,UAIDS,IAAVqB,EAGNnE,EAAOyhB,IAAKpgB,EAAM1C,EAAM4zB,GAGxBvyB,EAAOuhB,MAAOlgB,EAAM1C,EAAMwF,EAAOouB,IAChC5zB,EAAM0f,EAAYsW,OAAS7xB,EAAWub,QAM5Cre,EAAOkB,KAAM,CACZ,YACA,WACA,eACA,YACA,cACA,YACE,SAAUsD,EAAI7F,GAChBqB,EAAOG,GAAIxB,GAAS,SAAUwB,GAC7B,OAAOlD,KAAKqoB,GAAI3mB,EAAMwB,MAOxBH,EAAOG,GAAGgC,OAAQ,CAEjB41B,KAAM,SAAUxS,EAAO9F,EAAMtf,GAC5B,OAAOlD,KAAKqoB,GAAIC,EAAO,KAAM9F,EAAMtf,IAEpCooC,OAAQ,SAAUhjB,EAAOplB,GACxB,OAAOlD,KAAK0oB,IAAKJ,EAAO,KAAMplB,IAG/BqoC,SAAU,SAAUvoC,EAAUslB,EAAO9F,EAAMtf,GAC1C,OAAOlD,KAAKqoB,GAAIC,EAAOtlB,EAAUwf,EAAMtf,IAExCsoC,WAAY,SAAUxoC,EAAUslB,EAAOplB,GAGtC,OAA4B,IAArBmB,UAAUhB,OAChBrD,KAAK0oB,IAAK1lB,EAAU,MACpBhD,KAAK0oB,IAAKJ,EAAOtlB,GAAY,KAAME,IAGrCuoC,MAAO,SAAUC,EAAQC,GACxB,OAAO3rC,KAAKmuB,WAAYud,GAAStd,WAAYud,GAASD,MAIxD3oC,EAAOkB,KAAM,wLAEgDqD,MAAO,KACnE,SAAUC,EAAInC,GAGbrC,EAAOG,GAAIkC,GAAS,SAAUod,EAAMtf,GACnC,OAA0B,EAAnBmB,UAAUhB,OAChBrD,KAAKqoB,GAAIjjB,EAAM,KAAMod,EAAMtf,GAC3BlD,KAAKmpB,QAAS/jB,MASlB,IAAI2E,GAAQ,qCAMZhH,EAAO6oC,MAAQ,SAAU1oC,EAAID,GAC5B,IAAIyN,EAAK6D,EAAMq3B,EAUf,GARwB,iBAAZ3oC,IACXyN,EAAMxN,EAAID,GACVA,EAAUC,EACVA,EAAKwN,GAKArP,EAAY6B,GAalB,OARAqR,EAAOjU,EAAMG,KAAM4D,UAAW,IAC9BunC,EAAQ,WACP,OAAO1oC,EAAGvC,MAAOsC,GAAWjD,KAAMuU,EAAK7T,OAAQJ,EAAMG,KAAM4D,eAItD8C,KAAOjE,EAAGiE,KAAOjE,EAAGiE,MAAQpE,EAAOoE,OAElCykC,GAGR7oC,EAAO8oC,UAAY,SAAUC,GACvBA,EACJ/oC,EAAOge,YAEPhe,EAAO4X,OAAO,IAGhB5X,EAAO6C,QAAUD,MAAMC,QACvB7C,EAAOgpC,UAAY/oB,KAAKC,MACxBlgB,EAAOqJ,SAAWA,EAClBrJ,EAAO1B,WAAaA,EACpB0B,EAAOvB,SAAWA,EAClBuB,EAAOgf,UAAYA,EACnBhf,EAAOrB,KAAOmB,EAEdE,EAAOqpB,IAAM3jB,KAAK2jB,IAElBrpB,EAAOipC,UAAY,SAAU1qC,GAK5B,IAAII,EAAOqB,EAAOrB,KAAMJ,GACxB,OAAkB,WAATI,GAA8B,WAATA,KAK5BuqC,MAAO3qC,EAAM0xB,WAAY1xB,KAG5ByB,EAAOmpC,KAAO,SAAU5pC,GACvB,OAAe,MAARA,EACN,IACEA,EAAO,IAAK2D,QAAS8D,GAAO,KAkBT,mBAAXoiC,QAAyBA,OAAOC,KAC3CD,OAAQ,SAAU,GAAI,WACrB,OAAOppC,IAOT,IAGCspC,GAAUtsC,EAAOgD,OAGjBupC,GAAKvsC,EAAOwsC,EAwBb,OAtBAxpC,EAAOypC,WAAa,SAAU/mC,GAS7B,OARK1F,EAAOwsC,IAAMxpC,IACjBhD,EAAOwsC,EAAID,IAGP7mC,GAAQ1F,EAAOgD,SAAWA,IAC9BhD,EAAOgD,OAASspC,IAGVtpC,GAMiB,oBAAb9C,IACXF,EAAOgD,OAAShD,EAAOwsC,EAAIxpC,GAMrBA","file":"jquery-3.5.1.min.js"} \ No newline at end of file +{"version":3,"sources":["jquery-3.6.3.js"],"names":["global","factory","module","exports","document","w","Error","window","this","noGlobal","arr","getProto","Object","getPrototypeOf","slice","flat","array","call","concat","apply","push","indexOf","class2type","toString","hasOwn","hasOwnProperty","fnToString","ObjectFunctionString","support","isFunction","obj","nodeType","item","isWindow","preservedScriptAttributes","type","src","nonce","noModule","DOMEval","code","node","doc","i","val","script","createElement","text","getAttribute","setAttribute","head","appendChild","parentNode","removeChild","toType","version","jQuery","selector","context","fn","init","isArrayLike","length","prototype","jquery","constructor","toArray","get","num","pushStack","elems","ret","merge","prevObject","each","callback","map","elem","arguments","first","eq","last","even","grep","_elem","odd","len","j","end","sort","splice","extend","options","name","copy","copyIsArray","clone","target","deep","isPlainObject","Array","isArray","undefined","expando","Math","random","replace","isReady","error","msg","noop","proto","Ctor","isEmptyObject","globalEval","makeArray","results","inArray","second","invert","matches","callbackExpect","arg","value","guid","Symbol","iterator","split","_i","toLowerCase","Sizzle","Expr","getText","isXML","tokenize","compile","select","outermostContext","sortInput","hasDuplicate","setDocument","docElem","documentIsHTML","rbuggyQSA","rbuggyMatches","contains","Date","preferredDoc","dirruns","done","classCache","createCache","tokenCache","compilerCache","nonnativeSelectorCache","sortOrder","a","b","pop","pushNative","list","booleans","whitespace","identifier","attributes","pseudos","rwhitespace","RegExp","rtrim","rcomma","rcombinators","rdescend","rpseudo","ridentifier","matchExpr","ID","CLASS","TAG","ATTR","PSEUDO","CHILD","bool","needsContext","rhtml","rinputs","rheader","rnative","rquickExpr","rsibling","runescape","funescape","escape","nonHex","high","String","fromCharCode","rcssescape","fcssescape","ch","asCodePoint","charCodeAt","unloadHandler","inDisabledFieldset","addCombinator","disabled","nodeName","dir","next","childNodes","e","els","seed","m","nid","match","groups","newSelector","newContext","ownerDocument","exec","getElementById","id","getElementsByTagName","getElementsByClassName","qsa","test","testContext","scope","toSelector","join","cssSupportsSelector","CSS","supports","querySelectorAll","qsaError","removeAttribute","keys","cache","key","cacheLength","shift","markFunction","assert","el","addHandle","attrs","handler","attrHandle","siblingCheck","cur","diff","sourceIndex","nextSibling","createInputPseudo","createButtonPseudo","createDisabledPseudo","isDisabled","createPositionalPseudo","argument","matchIndexes","namespace","namespaceURI","documentElement","hasCompare","subWindow","defaultView","top","addEventListener","attachEvent","className","createComment","getById","getElementsByName","filter","attrId","find","getAttributeNode","tag","tmp","input","innerHTML","matchesSelector","webkitMatchesSelector","mozMatchesSelector","oMatchesSelector","msMatchesSelector","disconnectedMatch","compareDocumentPosition","adown","bup","compare","sortDetached","aup","ap","bp","unshift","expr","elements","attr","specified","sel","uniqueSort","duplicates","detectDuplicates","sortStable","textContent","firstChild","nodeValue","selectors","createPseudo","relative",">"," ","+","~","preFilter","excess","unquoted","nodeNameSelector","pattern","operator","check","result","what","_argument","simple","forward","ofType","_context","xml","uniqueCache","outerCache","nodeIndex","start","parent","useCache","lastChild","uniqueID","pseudo","args","setFilters","idx","matched","not","matcher","unmatched","has","lang","elemLang","hash","location","root","focus","activeElement","hasFocus","href","tabIndex","enabled","checked","selected","selectedIndex","empty","header","button","_matchIndexes","lt","gt","radio","checkbox","file","password","image","submit","reset","tokens","combinator","base","skip","checkNonElements","doneName","oldCache","newCache","elementMatcher","matchers","condense","newUnmatched","mapped","setMatcher","postFilter","postFinder","postSelector","temp","preMap","postMap","preexisting","contexts","multipleContexts","matcherIn","matcherOut","matcherFromTokens","checkContext","leadingRelative","implicitRelative","matchContext","matchAnyContext","filters","parseOnly","soFar","preFilters","cached","elementMatchers","setMatchers","bySet","byElement","superMatcher","outermost","matchedCount","setMatched","contextBackup","dirrunsUnique","token","compiled","_name","defaultValue","unique","isXMLDoc","escapeSelector","until","truncate","is","siblings","n","rneedsContext","rsingleTag","winnow","qualifier","self","rootjQuery","parseHTML","ready","rparentsprev","guaranteedUnique","children","contents","prev","sibling","targets","l","closest","index","prevAll","add","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","contentDocument","content","reverse","rnothtmlwhite","Identity","v","Thrower","ex","adoptValue","resolve","reject","noValue","method","promise","fail","then","Callbacks","object","_","flag","firing","memory","fired","locked","queue","firingIndex","fire","once","stopOnFalse","remove","disable","lock","fireWith","Deferred","func","tuples","state","always","deferred","catch","pipe","fns","newDefer","tuple","returned","progress","notify","onFulfilled","onRejected","onProgress","maxDepth","depth","special","that","mightThrow","TypeError","notifyWith","resolveWith","process","exceptionHook","stackTrace","rejectWith","getStackHook","setTimeout","stateString","when","singleValue","remaining","resolveContexts","resolveValues","primary","updateFunc","rerrorNames","stack","console","warn","message","readyException","readyList","completed","removeEventListener","readyWait","wait","readyState","doScroll","access","chainable","emptyGet","raw","bulk","_key","rmsPrefix","rdashAlpha","fcamelCase","_all","letter","toUpperCase","camelCase","string","acceptData","owner","Data","uid","defineProperty","configurable","set","data","prop","hasData","dataPriv","dataUser","rbrace","rmultiDash","dataAttr","JSON","parse","removeData","_data","_removeData","dequeue","startLength","hooks","_queueHooks","stop","setter","clearQueue","count","defer","pnum","source","rcssNum","cssExpand","isAttached","composed","getRootNode","isHiddenWithinTree","style","display","css","adjustCSS","valueParts","tween","adjusted","scale","maxIterations","currentValue","initial","unit","cssNumber","initialInUnit","defaultDisplayMap","showHide","show","values","body","hide","toggle","div","rcheckableType","rtagName","rscriptType","createDocumentFragment","checkClone","cloneNode","noCloneChecked","option","wrapMap","thead","col","tr","td","_default","getAll","setGlobalEval","refElements","tbody","tfoot","colgroup","caption","th","optgroup","buildFragment","scripts","selection","ignored","wrap","attached","fragment","nodes","htmlPrefilter","createTextNode","rtypenamespace","returnTrue","returnFalse","expectSync","err","safeActiveElement","on","types","one","origFn","event","off","leverageNative","notAsync","saved","isTrigger","delegateType","stopPropagation","stopImmediatePropagation","preventDefault","trigger","Event","handleObjIn","eventHandle","events","t","handleObj","handlers","namespaces","origType","elemData","create","handle","triggered","dispatch","bindType","delegateCount","setup","mappedTypes","origCount","teardown","removeEvent","nativeEvent","handlerQueue","fix","delegateTarget","preDispatch","isPropagationStopped","currentTarget","isImmediatePropagationStopped","rnamespace","postDispatch","matchedHandlers","matchedSelectors","addProp","hook","enumerable","originalEvent","writable","load","noBubble","click","beforeunload","returnValue","props","isDefaultPrevented","defaultPrevented","relatedTarget","timeStamp","now","isSimulated","altKey","bubbles","cancelable","changedTouches","ctrlKey","detail","eventPhase","metaKey","pageX","pageY","shiftKey","view","char","charCode","keyCode","buttons","clientX","clientY","offsetX","offsetY","pointerId","pointerType","screenX","screenY","targetTouches","toElement","touches","which","blur","mouseenter","mouseleave","pointerenter","pointerleave","orig","related","rnoInnerhtml","rchecked","rcleanScript","manipulationTarget","disableScript","restoreScript","cloneCopyEvent","dest","udataOld","udataCur","domManip","collection","hasScripts","iNoClone","valueIsFunction","html","_evalUrl","keepData","cleanData","dataAndEvents","deepDataAndEvents","srcElements","destElements","inPage","detach","append","prepend","insertBefore","before","after","replaceWith","replaceChild","appendTo","prependTo","insertAfter","replaceAll","original","insert","rnumnonpx","rcustomProp","getStyles","opener","getComputedStyle","swap","old","rboxStyle","rtrimCSS","curCSS","computed","width","minWidth","maxWidth","isCustomProp","getPropertyValue","pixelBoxStyles","addGetHookIf","conditionFn","hookFn","computeStyleTests","container","cssText","divStyle","pixelPositionVal","reliableMarginLeftVal","roundPixelMeasures","marginLeft","right","pixelBoxStylesVal","boxSizingReliableVal","position","scrollboxSizeVal","offsetWidth","measure","round","parseFloat","reliableTrDimensionsVal","backgroundClip","clearCloneStyle","boxSizingReliable","pixelPosition","reliableMarginLeft","scrollboxSize","reliableTrDimensions","table","trChild","trStyle","height","parseInt","borderTopWidth","borderBottomWidth","offsetHeight","cssPrefixes","emptyStyle","vendorProps","finalPropName","final","cssProps","capName","vendorPropName","rdisplayswap","cssShow","visibility","cssNormalTransform","letterSpacing","fontWeight","setPositiveNumber","subtract","max","boxModelAdjustment","dimension","box","isBorderBox","styles","computedVal","extra","delta","ceil","getWidthOrHeight","valueIsBorderBox","offsetProp","getClientRects","Tween","easing","cssHooks","opacity","animationIterationCount","columnCount","fillOpacity","flexGrow","flexShrink","gridArea","gridColumn","gridColumnEnd","gridColumnStart","gridRow","gridRowEnd","gridRowStart","lineHeight","order","orphans","widows","zIndex","zoom","origName","setProperty","isFinite","getBoundingClientRect","scrollboxSizeBuggy","left","margin","padding","border","prefix","suffix","expand","expanded","parts","propHooks","run","percent","eased","duration","pos","step","fx","scrollTop","scrollLeft","linear","p","swing","cos","PI","fxNow","inProgress","opt","rfxtypes","rrun","schedule","hidden","requestAnimationFrame","interval","tick","createFxNow","genFx","includeWidth","createTween","animation","Animation","tweeners","properties","stopped","prefilters","currentTime","startTime","tweens","opts","specialEasing","originalProperties","originalOptions","gotoEnd","propFilter","bind","complete","timer","anim","*","tweener","oldfire","propTween","restoreDisplay","isBox","dataShow","unqueued","overflow","overflowX","overflowY","prefilter","speed","speeds","fadeTo","to","animate","optall","doAnimation","finish","stopQueue","timers","cssFn","slideDown","slideUp","slideToggle","fadeIn","fadeOut","fadeToggle","slow","fast","delay","time","timeout","clearTimeout","checkOn","optSelected","radioValue","boolHook","removeAttr","nType","attrHooks","attrNames","getter","lowercaseName","rfocusable","rclickable","stripAndCollapse","getClass","classesToArray","removeProp","propFix","tabindex","for","class","addClass","classNames","curValue","finalValue","removeClass","toggleClass","stateVal","isValidValue","hasClass","rreturn","valHooks","optionSet","focusin","rfocusMorph","stopPropagationCallback","onlyHandlers","bubbleType","ontype","lastElement","eventPath","parentWindow","simulate","triggerHandler","attaches","rquery","parseXML","parserErrorElem","DOMParser","parseFromString","rbracket","rCRLF","rsubmitterTypes","rsubmittable","buildParams","traditional","param","s","valueOrFunction","encodeURIComponent","serialize","serializeArray","r20","rhash","rantiCache","rheaders","rnoContent","rprotocol","transports","allTypes","originAnchor","addToPrefiltersOrTransports","structure","dataTypeExpression","dataType","dataTypes","inspectPrefiltersOrTransports","jqXHR","inspected","seekingTransport","inspect","prefilterOrFactory","dataTypeOrTransport","ajaxExtend","flatOptions","ajaxSettings","active","lastModified","etag","url","isLocal","protocol","processData","async","contentType","accepts","json","responseFields","converters","* text","text html","text json","text xml","ajaxSetup","settings","ajaxPrefilter","ajaxTransport","ajax","transport","cacheURL","responseHeadersString","responseHeaders","timeoutTimer","urlAnchor","fireGlobals","uncached","callbackContext","globalEventContext","completeDeferred","statusCode","requestHeaders","requestHeadersNames","strAbort","getResponseHeader","getAllResponseHeaders","setRequestHeader","overrideMimeType","mimeType","status","abort","statusText","finalText","crossDomain","host","hasContent","ifModified","headers","beforeSend","success","send","nativeStatusText","responses","isSuccess","response","modified","ct","finalDataType","firstDataType","ajaxHandleResponses","conv2","current","conv","dataFilter","throws","ajaxConvert","getJSON","getScript","text script","wrapAll","firstElementChild","wrapInner","htmlIsFunction","unwrap","visible","xhr","XMLHttpRequest","xhrSuccessStatus","0","1223","xhrSupported","cors","errorCallback","open","username","xhrFields","onload","onerror","onabort","ontimeout","onreadystatechange","responseType","responseText","binary","scriptAttrs","charset","scriptCharset","evt","oldCallbacks","rjsonp","jsonp","jsonpCallback","originalSettings","callbackName","overwritten","responseContainer","jsonProp","createHTMLDocument","implementation","keepScripts","parsed","params","animated","offset","setOffset","curPosition","curLeft","curCSSTop","curTop","curOffset","curCSSLeft","curElem","using","rect","win","pageYOffset","pageXOffset","offsetParent","parentOffset","scrollTo","Height","Width","","defaultExtra","funcName","unbind","delegate","undelegate","hover","fnOver","fnOut","proxy","holdReady","hold","parseJSON","isNumeric","isNaN","trim","define","amd","_jQuery","_$","$","noConflict"],"mappings":";CAaA,SAAYA,EAAQC,GAEnB,aAEuB,iBAAXC,QAAiD,iBAAnBA,OAAOC,QAShDD,OAAOC,QAAUH,EAAOI,SACvBH,EAASD,GAAQ,GACjB,SAAUK,GACT,IAAMA,EAAED,SACP,MAAM,IAAIE,MAAO,4CAElB,OAAOL,EAASI,IAGlBJ,EAASD,GAtBX,CA0BuB,oBAAXO,OAAyBA,OAASC,KAAM,SAAUD,EAAQE,GAMtE,aAEA,IAAIC,EAAM,GAENC,EAAWC,OAAOC,eAElBC,EAAQJ,EAAII,MAEZC,EAAOL,EAAIK,KAAO,SAAUC,GAC/B,OAAON,EAAIK,KAAKE,KAAMD,IACnB,SAAUA,GACb,OAAON,EAAIQ,OAAOC,MAAO,GAAIH,IAI1BI,EAAOV,EAAIU,KAEXC,EAAUX,EAAIW,QAEdC,EAAa,GAEbC,EAAWD,EAAWC,SAEtBC,EAASF,EAAWG,eAEpBC,EAAaF,EAAOD,SAEpBI,EAAuBD,EAAWT,KAAML,QAExCgB,EAAU,GAEVC,EAAa,SAAqBC,GASpC,MAAsB,mBAARA,GAA8C,iBAAjBA,EAAIC,UAC1B,mBAAbD,EAAIE,MAIVC,EAAW,SAAmBH,GAChC,OAAc,MAAPA,GAAeA,IAAQA,EAAIvB,QAIhCH,EAAWG,EAAOH,SAIjB8B,EAA4B,CAC/BC,MAAM,EACNC,KAAK,EACLC,OAAO,EACPC,UAAU,GAGX,SAASC,EAASC,EAAMC,EAAMC,GAG7B,IAAIC,EAAGC,EACNC,GAHDH,EAAMA,GAAOtC,GAGC0C,cAAe,UAG7B,GADAD,EAAOE,KAAOP,EACTC,EACJ,IAAME,KAAKT,GAYVU,EAAMH,EAAME,IAAOF,EAAKO,cAAgBP,EAAKO,aAAcL,KAE1DE,EAAOI,aAAcN,EAAGC,GAI3BF,EAAIQ,KAAKC,YAAaN,GAASO,WAAWC,YAAaR,GAIzD,SAASS,EAAQxB,GAChB,OAAY,MAAPA,EACGA,EAAM,GAIQ,iBAARA,GAAmC,mBAARA,EACxCR,EAAYC,EAASN,KAAMa,KAAW,gBAC/BA,EAQT,IACCyB,EAAU,QAGVC,EAAS,SAAUC,EAAUC,GAI5B,OAAO,IAAIF,EAAOG,GAAGC,KAAMH,EAAUC,IA0VvC,SAASG,EAAa/B,GAMrB,IAAIgC,IAAWhC,GAAO,WAAYA,GAAOA,EAAIgC,OAC5C3B,EAAOmB,EAAQxB,GAEhB,OAAKD,EAAYC,KAASG,EAAUH,KAIpB,UAATK,GAA+B,IAAX2B,GACR,iBAAXA,GAAgC,EAATA,GAAgBA,EAAS,KAAOhC,GArWhE0B,EAAOG,GAAKH,EAAOO,UAAY,CAG9BC,OAAQT,EAERU,YAAaT,EAGbM,OAAQ,EAERI,QAAS,WACR,OAAOpD,EAAMG,KAAMT,OAKpB2D,IAAK,SAAUC,GAGd,OAAY,MAAPA,EACGtD,EAAMG,KAAMT,MAIb4D,EAAM,EAAI5D,KAAM4D,EAAM5D,KAAKsD,QAAWtD,KAAM4D,IAKpDC,UAAW,SAAUC,GAGpB,IAAIC,EAAMf,EAAOgB,MAAOhE,KAAKyD,cAAeK,GAM5C,OAHAC,EAAIE,WAAajE,KAGV+D,GAIRG,KAAM,SAAUC,GACf,OAAOnB,EAAOkB,KAAMlE,KAAMmE,IAG3BC,IAAK,SAAUD,GACd,OAAOnE,KAAK6D,UAAWb,EAAOoB,IAAKpE,KAAM,SAAUqE,EAAMlC,GACxD,OAAOgC,EAAS1D,KAAM4D,EAAMlC,EAAGkC,OAIjC/D,MAAO,WACN,OAAON,KAAK6D,UAAWvD,EAAMK,MAAOX,KAAMsE,aAG3CC,MAAO,WACN,OAAOvE,KAAKwE,GAAI,IAGjBC,KAAM,WACL,OAAOzE,KAAKwE,IAAK,IAGlBE,KAAM,WACL,OAAO1E,KAAK6D,UAAWb,EAAO2B,KAAM3E,KAAM,SAAU4E,EAAOzC,GAC1D,OAASA,EAAI,GAAM,MAIrB0C,IAAK,WACJ,OAAO7E,KAAK6D,UAAWb,EAAO2B,KAAM3E,KAAM,SAAU4E,EAAOzC,GAC1D,OAAOA,EAAI,MAIbqC,GAAI,SAAUrC,GACb,IAAI2C,EAAM9E,KAAKsD,OACdyB,GAAK5C,GAAMA,EAAI,EAAI2C,EAAM,GAC1B,OAAO9E,KAAK6D,UAAgB,GAALkB,GAAUA,EAAID,EAAM,CAAE9E,KAAM+E,IAAQ,KAG5DC,IAAK,WACJ,OAAOhF,KAAKiE,YAAcjE,KAAKyD,eAKhC7C,KAAMA,EACNqE,KAAM/E,EAAI+E,KACVC,OAAQhF,EAAIgF,QAGblC,EAAOmC,OAASnC,EAAOG,GAAGgC,OAAS,WAClC,IAAIC,EAASC,EAAMzD,EAAK0D,EAAMC,EAAaC,EAC1CC,EAASnB,UAAW,IAAO,GAC3BnC,EAAI,EACJmB,EAASgB,UAAUhB,OACnBoC,GAAO,EAsBR,IAnBuB,kBAAXD,IACXC,EAAOD,EAGPA,EAASnB,UAAWnC,IAAO,GAC3BA,KAIsB,iBAAXsD,GAAwBpE,EAAYoE,KAC/CA,EAAS,IAILtD,IAAMmB,IACVmC,EAASzF,KACTmC,KAGOA,EAAImB,EAAQnB,IAGnB,GAAqC,OAA9BiD,EAAUd,UAAWnC,IAG3B,IAAMkD,KAAQD,EACbE,EAAOF,EAASC,GAIF,cAATA,GAAwBI,IAAWH,IAKnCI,GAAQJ,IAAUtC,EAAO2C,cAAeL,KAC1CC,EAAcK,MAAMC,QAASP,MAC/B1D,EAAM6D,EAAQJ,GAIbG,EADID,IAAgBK,MAAMC,QAASjE,GAC3B,GACI2D,GAAgBvC,EAAO2C,cAAe/D,GAG1CA,EAFA,GAIT2D,GAAc,EAGdE,EAAQJ,GAASrC,EAAOmC,OAAQO,EAAMF,EAAOF,SAGzBQ,IAATR,IACXG,EAAQJ,GAASC,IAOrB,OAAOG,GAGRzC,EAAOmC,OAAQ,CAGdY,QAAS,UAAahD,EAAUiD,KAAKC,UAAWC,QAAS,MAAO,IAGhEC,SAAS,EAETC,MAAO,SAAUC,GAChB,MAAM,IAAIvG,MAAOuG,IAGlBC,KAAM,aAENX,cAAe,SAAUrE,GACxB,IAAIiF,EAAOC,EAIX,SAAMlF,GAAgC,oBAAzBP,EAASN,KAAMa,QAI5BiF,EAAQpG,EAAUmB,KASK,mBADvBkF,EAAOxF,EAAOP,KAAM8F,EAAO,gBAAmBA,EAAM9C,cACfvC,EAAWT,KAAM+F,KAAWrF,IAGlEsF,cAAe,SAAUnF,GACxB,IAAI+D,EAEJ,IAAMA,KAAQ/D,EACb,OAAO,EAER,OAAO,GAKRoF,WAAY,SAAU1E,EAAMoD,EAASlD,GACpCH,EAASC,EAAM,CAAEH,MAAOuD,GAAWA,EAAQvD,OAASK,IAGrDgC,KAAM,SAAU5C,EAAK6C,GACpB,IAAIb,EAAQnB,EAAI,EAEhB,GAAKkB,EAAa/B,IAEjB,IADAgC,EAAShC,EAAIgC,OACLnB,EAAImB,EAAQnB,IACnB,IAAgD,IAA3CgC,EAAS1D,KAAMa,EAAKa,GAAKA,EAAGb,EAAKa,IACrC,WAIF,IAAMA,KAAKb,EACV,IAAgD,IAA3C6C,EAAS1D,KAAMa,EAAKa,GAAKA,EAAGb,EAAKa,IACrC,MAKH,OAAOb,GAIRqF,UAAW,SAAUzG,EAAK0G,GACzB,IAAI7C,EAAM6C,GAAW,GAarB,OAXY,MAAP1G,IACCmD,EAAajD,OAAQF,IACzB8C,EAAOgB,MAAOD,EACE,iBAAR7D,EACN,CAAEA,GAAQA,GAGZU,EAAKH,KAAMsD,EAAK7D,IAIX6D,GAGR8C,QAAS,SAAUxC,EAAMnE,EAAKiC,GAC7B,OAAc,MAAPjC,GAAe,EAAIW,EAAQJ,KAAMP,EAAKmE,EAAMlC,IAKpD6B,MAAO,SAAUO,EAAOuC,GAKvB,IAJA,IAAIhC,GAAOgC,EAAOxD,OACjByB,EAAI,EACJ5C,EAAIoC,EAAMjB,OAEHyB,EAAID,EAAKC,IAChBR,EAAOpC,KAAQ2E,EAAQ/B,GAKxB,OAFAR,EAAMjB,OAASnB,EAERoC,GAGRI,KAAM,SAAUb,EAAOK,EAAU4C,GAShC,IARA,IACCC,EAAU,GACV7E,EAAI,EACJmB,EAASQ,EAAMR,OACf2D,GAAkBF,EAIX5E,EAAImB,EAAQnB,KACAgC,EAAUL,EAAO3B,GAAKA,KAChB8E,GACxBD,EAAQpG,KAAMkD,EAAO3B,IAIvB,OAAO6E,GAIR5C,IAAK,SAAUN,EAAOK,EAAU+C,GAC/B,IAAI5D,EAAQ6D,EACXhF,EAAI,EACJ4B,EAAM,GAGP,GAAKV,EAAaS,GAEjB,IADAR,EAASQ,EAAMR,OACPnB,EAAImB,EAAQnB,IAGL,OAFdgF,EAAQhD,EAAUL,EAAO3B,GAAKA,EAAG+E,KAGhCnD,EAAInD,KAAMuG,QAMZ,IAAMhF,KAAK2B,EAGI,OAFdqD,EAAQhD,EAAUL,EAAO3B,GAAKA,EAAG+E,KAGhCnD,EAAInD,KAAMuG,GAMb,OAAO5G,EAAMwD,IAIdqD,KAAM,EAINhG,QAASA,IAGa,mBAAXiG,SACXrE,EAAOG,GAAIkE,OAAOC,UAAapH,EAAKmH,OAAOC,WAI5CtE,EAAOkB,KAAM,uEAAuEqD,MAAO,KAC1F,SAAUC,EAAInC,GACbvE,EAAY,WAAauE,EAAO,KAAQA,EAAKoC,gBAmB/C,IAAIC,EAWJ,SAAY3H,GACZ,IAAIoC,EACHf,EACAuG,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAGAC,EACAxI,EACAyI,EACAC,EACAC,EACAC,EACAxB,EACAyB,EAGA1C,EAAU,SAAW,EAAI,IAAI2C,KAC7BC,EAAe5I,EAAOH,SACtBgJ,EAAU,EACVC,EAAO,EACPC,EAAaC,KACbC,EAAaD,KACbE,EAAgBF,KAChBG,EAAyBH,KACzBI,EAAY,SAAUC,EAAGC,GAIxB,OAHKD,IAAMC,IACVlB,GAAe,GAET,GAIRnH,EAAS,GAAOC,eAChBf,EAAM,GACNoJ,EAAMpJ,EAAIoJ,IACVC,EAAarJ,EAAIU,KACjBA,EAAOV,EAAIU,KACXN,EAAQJ,EAAII,MAIZO,EAAU,SAAU2I,EAAMnF,GAGzB,IAFA,IAAIlC,EAAI,EACP2C,EAAM0E,EAAKlG,OACJnB,EAAI2C,EAAK3C,IAChB,GAAKqH,EAAMrH,KAAQkC,EAClB,OAAOlC,EAGT,OAAQ,GAGTsH,EAAW,6HAMXC,EAAa,sBAGbC,EAAa,0BAA4BD,EACxC,0CAGDE,EAAa,MAAQF,EAAa,KAAOC,EAAa,OAASD,EAG9D,gBAAkBA,EAIlB,2DAA6DC,EAAa,OAC1ED,EAAa,OAEdG,EAAU,KAAOF,EAAa,wFAOAC,EAAa,eAO3CE,EAAc,IAAIC,OAAQL,EAAa,IAAK,KAC5CM,EAAQ,IAAID,OAAQ,IAAML,EAAa,8BACtCA,EAAa,KAAM,KAEpBO,EAAS,IAAIF,OAAQ,IAAML,EAAa,KAAOA,EAAa,KAC5DQ,EAAe,IAAIH,OAAQ,IAAML,EAAa,WAAaA,EAAa,IAAMA,EAC7E,KACDS,EAAW,IAAIJ,OAAQL,EAAa,MAEpCU,EAAU,IAAIL,OAAQF,GACtBQ,EAAc,IAAIN,OAAQ,IAAMJ,EAAa,KAE7CW,EAAY,CACXC,GAAM,IAAIR,OAAQ,MAAQJ,EAAa,KACvCa,MAAS,IAAIT,OAAQ,QAAUJ,EAAa,KAC5Cc,IAAO,IAAIV,OAAQ,KAAOJ,EAAa,SACvCe,KAAQ,IAAIX,OAAQ,IAAMH,GAC1Be,OAAU,IAAIZ,OAAQ,IAAMF,GAC5Be,MAAS,IAAIb,OAAQ,yDACpBL,EAAa,+BAAiCA,EAAa,cAC3DA,EAAa,aAAeA,EAAa,SAAU,KACpDmB,KAAQ,IAAId,OAAQ,OAASN,EAAW,KAAM,KAI9CqB,aAAgB,IAAIf,OAAQ,IAAML,EACjC,mDAAqDA,EACrD,mBAAqBA,EAAa,mBAAoB,MAGxDqB,EAAQ,SACRC,EAAU,sCACVC,EAAU,SAEVC,EAAU,yBAGVC,EAAa,mCAEbC,GAAW,OAIXC,GAAY,IAAItB,OAAQ,uBAAyBL,EAAa,uBAAwB,KACtF4B,GAAY,SAAUC,EAAQC,GAC7B,IAAIC,EAAO,KAAOF,EAAOjL,MAAO,GAAM,MAEtC,OAAOkL,IASNC,EAAO,EACNC,OAAOC,aAAcF,EAAO,OAC5BC,OAAOC,aAAcF,GAAQ,GAAK,MAAe,KAAPA,EAAe,SAK5DG,GAAa,sDACbC,GAAa,SAAUC,EAAIC,GAC1B,OAAKA,EAGQ,OAAPD,EACG,SAIDA,EAAGxL,MAAO,GAAI,GAAM,KAC1BwL,EAAGE,WAAYF,EAAGxI,OAAS,GAAIvC,SAAU,IAAO,IAI3C,KAAO+K,GAOfG,GAAgB,WACf7D,KAGD8D,GAAqBC,GACpB,SAAU9H,GACT,OAAyB,IAAlBA,EAAK+H,UAAqD,aAAhC/H,EAAKgI,SAAS5E,eAEhD,CAAE6E,IAAK,aAAcC,KAAM,WAI7B,IACC3L,EAAKD,MACFT,EAAMI,EAAMG,KAAMkI,EAAa6D,YACjC7D,EAAa6D,YAMdtM,EAAKyI,EAAa6D,WAAWlJ,QAAS/B,SACrC,MAAQkL,GACT7L,EAAO,CAAED,MAAOT,EAAIoD,OAGnB,SAAUmC,EAAQiH,GACjBnD,EAAW5I,MAAO8E,EAAQnF,EAAMG,KAAMiM,KAKvC,SAAUjH,EAAQiH,GACjB,IAAI3H,EAAIU,EAAOnC,OACdnB,EAAI,EAGL,MAAUsD,EAAQV,KAAQ2H,EAAKvK,MAC/BsD,EAAOnC,OAASyB,EAAI,IAKvB,SAAS2C,GAAQzE,EAAUC,EAAS0D,EAAS+F,GAC5C,IAAIC,EAAGzK,EAAGkC,EAAMwI,EAAKC,EAAOC,EAAQC,EACnCC,EAAa/J,GAAWA,EAAQgK,cAGhC3L,EAAW2B,EAAUA,EAAQ3B,SAAW,EAKzC,GAHAqF,EAAUA,GAAW,GAGI,iBAAb3D,IAA0BA,GACxB,IAAb1B,GAA+B,IAAbA,GAA+B,KAAbA,EAEpC,OAAOqF,EAIR,IAAM+F,IACLvE,EAAalF,GACbA,EAAUA,GAAWtD,EAEhB0I,GAAiB,CAIrB,GAAkB,KAAb/G,IAAqBuL,EAAQ3B,EAAWgC,KAAMlK,IAGlD,GAAO2J,EAAIE,EAAO,IAGjB,GAAkB,IAAbvL,EAAiB,CACrB,KAAO8C,EAAOnB,EAAQkK,eAAgBR,IAUrC,OAAOhG,EALP,GAAKvC,EAAKgJ,KAAOT,EAEhB,OADAhG,EAAQhG,KAAMyD,GACPuC,OAYT,GAAKqG,IAAgB5I,EAAO4I,EAAWG,eAAgBR,KACtDnE,EAAUvF,EAASmB,IACnBA,EAAKgJ,KAAOT,EAGZ,OADAhG,EAAQhG,KAAMyD,GACPuC,MAKH,CAAA,GAAKkG,EAAO,GAElB,OADAlM,EAAKD,MAAOiG,EAAS1D,EAAQoK,qBAAsBrK,IAC5C2D,EAGD,IAAOgG,EAAIE,EAAO,KAAS1L,EAAQmM,wBACzCrK,EAAQqK,uBAGR,OADA3M,EAAKD,MAAOiG,EAAS1D,EAAQqK,uBAAwBX,IAC9ChG,EAKT,GAAKxF,EAAQoM,MACXtE,EAAwBjG,EAAW,QACjCsF,IAAcA,EAAUkF,KAAMxK,MAIlB,IAAb1B,GAAqD,WAAnC2B,EAAQmJ,SAAS5E,eAA+B,CAYpE,GAVAuF,EAAc/J,EACdgK,EAAa/J,EASK,IAAb3B,IACF4I,EAASsD,KAAMxK,IAAciH,EAAauD,KAAMxK,IAAe,EAGjEgK,EAAa7B,GAASqC,KAAMxK,IAAcyK,GAAaxK,EAAQN,aAC9DM,KAImBA,GAAY9B,EAAQuM,SAGhCd,EAAM3J,EAAQV,aAAc,OAClCqK,EAAMA,EAAI3G,QAAS0F,GAAYC,IAE/B3I,EAAQT,aAAc,KAAQoK,EAAM9G,IAMtC5D,GADA4K,EAASjF,EAAU7E,IACRK,OACX,MAAQnB,IACP4K,EAAQ5K,IAAQ0K,EAAM,IAAMA,EAAM,UAAa,IAC9Ce,GAAYb,EAAQ5K,IAEtB6K,EAAcD,EAAOc,KAAM,KAG5B,IASC,GAAKzM,EAAQ0M,sBAGXC,IAAIC,SAAU,gBAAkBhB,EAAc,MAO/C,MAAM,IAAIlN,MAMX,OAHAc,EAAKD,MAAOiG,EACXqG,EAAWgB,iBAAkBjB,IAEvBpG,EACN,MAAQsH,GACThF,EAAwBjG,GAAU,GACjC,QACI4J,IAAQ9G,GACZ7C,EAAQiL,gBAAiB,QAQ9B,OAAOnG,EAAQ/E,EAASiD,QAAS8D,EAAO,MAAQ9G,EAAS0D,EAAS+F,GASnE,SAAS5D,KACR,IAAIqF,EAAO,GAYX,OAVA,SAASC,EAAOC,EAAKnH,GAQpB,OALKiH,EAAKxN,KAAM0N,EAAM,KAAQ3G,EAAK4G,oBAG3BF,EAAOD,EAAKI,SAEXH,EAAOC,EAAM,KAAQnH,GAShC,SAASsH,GAActL,GAEtB,OADAA,EAAI4C,IAAY,EACT5C,EAOR,SAASuL,GAAQvL,GAChB,IAAIwL,EAAK/O,EAAS0C,cAAe,YAEjC,IACC,QAASa,EAAIwL,GACZ,MAAQlC,GACT,OAAO,EACN,QAGIkC,EAAG/L,YACP+L,EAAG/L,WAAWC,YAAa8L,GAI5BA,EAAK,MASP,SAASC,GAAWC,EAAOC,GAC1B,IAAI5O,EAAM2O,EAAMtH,MAAO,KACtBpF,EAAIjC,EAAIoD,OAET,MAAQnB,IACPwF,EAAKoH,WAAY7O,EAAKiC,IAAQ2M,EAUhC,SAASE,GAAc5F,EAAGC,GACzB,IAAI4F,EAAM5F,GAAKD,EACd8F,EAAOD,GAAsB,IAAf7F,EAAE7H,UAAiC,IAAf8H,EAAE9H,UACnC6H,EAAE+F,YAAc9F,EAAE8F,YAGpB,GAAKD,EACJ,OAAOA,EAIR,GAAKD,EACJ,MAAUA,EAAMA,EAAIG,YACnB,GAAKH,IAAQ5F,EACZ,OAAQ,EAKX,OAAOD,EAAI,GAAK,EAOjB,SAASiG,GAAmB1N,GAC3B,OAAO,SAAU0C,GAEhB,MAAgB,UADLA,EAAKgI,SAAS5E,eACEpD,EAAK1C,OAASA,GAQ3C,SAAS2N,GAAoB3N,GAC5B,OAAO,SAAU0C,GAChB,IAAIgB,EAAOhB,EAAKgI,SAAS5E,cACzB,OAAkB,UAATpC,GAA6B,WAATA,IAAuBhB,EAAK1C,OAASA,GAQpE,SAAS4N,GAAsBnD,GAG9B,OAAO,SAAU/H,GAKhB,MAAK,SAAUA,EASTA,EAAKzB,aAAgC,IAAlByB,EAAK+H,SAGvB,UAAW/H,EACV,UAAWA,EAAKzB,WACbyB,EAAKzB,WAAWwJ,WAAaA,EAE7B/H,EAAK+H,WAAaA,EAMpB/H,EAAKmL,aAAepD,GAI1B/H,EAAKmL,cAAgBpD,GACrBF,GAAoB7H,KAAW+H,EAG1B/H,EAAK+H,WAAaA,EAKd,UAAW/H,GACfA,EAAK+H,WAAaA,GAY5B,SAASqD,GAAwBtM,GAChC,OAAOsL,GAAc,SAAUiB,GAE9B,OADAA,GAAYA,EACLjB,GAAc,SAAU9B,EAAM3F,GACpC,IAAIjC,EACH4K,EAAexM,EAAI,GAAIwJ,EAAKrJ,OAAQoM,GACpCvN,EAAIwN,EAAarM,OAGlB,MAAQnB,IACFwK,EAAQ5H,EAAI4K,EAAcxN,MAC9BwK,EAAM5H,KAASiC,EAASjC,GAAM4H,EAAM5H,SAYzC,SAAS2I,GAAaxK,GACrB,OAAOA,GAAmD,oBAAjCA,EAAQoK,sBAAwCpK,EA6tC1E,IAAMf,KAztCNf,EAAUsG,GAAOtG,QAAU,GAO3ByG,EAAQH,GAAOG,MAAQ,SAAUxD,GAChC,IAAIuL,EAAYvL,GAAQA,EAAKwL,aAC5BxH,EAAUhE,IAAUA,EAAK6I,eAAiB7I,GAAOyL,gBAKlD,OAAQ/E,EAAM0C,KAAMmC,GAAavH,GAAWA,EAAQgE,UAAY,SAQjEjE,EAAcV,GAAOU,YAAc,SAAUnG,GAC5C,IAAI8N,EAAYC,EACf9N,EAAMD,EAAOA,EAAKiL,eAAiBjL,EAAO0G,EAO3C,OAAKzG,GAAOtC,GAA6B,IAAjBsC,EAAIX,UAAmBW,EAAI4N,kBAMnDzH,GADAzI,EAAWsC,GACQ4N,gBACnBxH,GAAkBT,EAAOjI,GAQpB+I,GAAgB/I,IAClBoQ,EAAYpQ,EAASqQ,cAAiBD,EAAUE,MAAQF,IAGrDA,EAAUG,iBACdH,EAAUG,iBAAkB,SAAUlE,IAAe,GAG1C+D,EAAUI,aACrBJ,EAAUI,YAAa,WAAYnE,KASrC7K,EAAQuM,MAAQe,GAAQ,SAAUC,GAEjC,OADAtG,EAAQ1F,YAAagM,GAAKhM,YAAa/C,EAAS0C,cAAe,QACzB,oBAAxBqM,EAAGV,mBACfU,EAAGV,iBAAkB,uBAAwB3K,SAQhDlC,EAAQ0M,oBAAsBY,GAAQ,WAGrC,OAAOX,IAAIC,SAAU,gBAMpBpO,EAASqO,iBAAkB,kBAM1BF,IAAIC,SAAU,8BAWjB5M,EAAQwI,WAAa8E,GAAQ,SAAUC,GAEtC,OADAA,EAAG0B,UAAY,KACP1B,EAAGnM,aAAc,eAO1BpB,EAAQkM,qBAAuBoB,GAAQ,SAAUC,GAEhD,OADAA,EAAGhM,YAAa/C,EAAS0Q,cAAe,MAChC3B,EAAGrB,qBAAsB,KAAMhK,SAIxClC,EAAQmM,uBAAyBrC,EAAQuC,KAAM7N,EAAS2N,wBAMxDnM,EAAQmP,QAAU7B,GAAQ,SAAUC,GAEnC,OADAtG,EAAQ1F,YAAagM,GAAKtB,GAAKtH,GACvBnG,EAAS4Q,oBAAsB5Q,EAAS4Q,kBAAmBzK,GAAUzC,SAIzElC,EAAQmP,SACZ5I,EAAK8I,OAAa,GAAI,SAAUpD,GAC/B,IAAIqD,EAASrD,EAAGnH,QAASmF,GAAWC,IACpC,OAAO,SAAUjH,GAChB,OAAOA,EAAK7B,aAAc,QAAWkO,IAGvC/I,EAAKgJ,KAAW,GAAI,SAAUtD,EAAInK,GACjC,GAAuC,oBAA3BA,EAAQkK,gBAAkC9E,EAAiB,CACtE,IAAIjE,EAAOnB,EAAQkK,eAAgBC,GACnC,OAAOhJ,EAAO,CAAEA,GAAS,OAI3BsD,EAAK8I,OAAa,GAAK,SAAUpD,GAChC,IAAIqD,EAASrD,EAAGnH,QAASmF,GAAWC,IACpC,OAAO,SAAUjH,GAChB,IAAIpC,EAAwC,oBAA1BoC,EAAKuM,kBACtBvM,EAAKuM,iBAAkB,MACxB,OAAO3O,GAAQA,EAAKkF,QAAUuJ,IAMhC/I,EAAKgJ,KAAW,GAAI,SAAUtD,EAAInK,GACjC,GAAuC,oBAA3BA,EAAQkK,gBAAkC9E,EAAiB,CACtE,IAAIrG,EAAME,EAAG2B,EACZO,EAAOnB,EAAQkK,eAAgBC,GAEhC,GAAKhJ,EAAO,CAIX,IADApC,EAAOoC,EAAKuM,iBAAkB,QACjB3O,EAAKkF,QAAUkG,EAC3B,MAAO,CAAEhJ,GAIVP,EAAQZ,EAAQsN,kBAAmBnD,GACnClL,EAAI,EACJ,MAAUkC,EAAOP,EAAO3B,KAEvB,IADAF,EAAOoC,EAAKuM,iBAAkB,QACjB3O,EAAKkF,QAAUkG,EAC3B,MAAO,CAAEhJ,GAKZ,MAAO,MAMVsD,EAAKgJ,KAAY,IAAIvP,EAAQkM,qBAC5B,SAAUuD,EAAK3N,GACd,MAA6C,oBAAjCA,EAAQoK,qBACZpK,EAAQoK,qBAAsBuD,GAG1BzP,EAAQoM,IACZtK,EAAQ+K,iBAAkB4C,QAD3B,GAKR,SAAUA,EAAK3N,GACd,IAAImB,EACHyM,EAAM,GACN3O,EAAI,EAGJyE,EAAU1D,EAAQoK,qBAAsBuD,GAGzC,GAAa,MAARA,EAAc,CAClB,MAAUxM,EAAOuC,EAASzE,KACF,IAAlBkC,EAAK9C,UACTuP,EAAIlQ,KAAMyD,GAIZ,OAAOyM,EAER,OAAOlK,GAITe,EAAKgJ,KAAc,MAAIvP,EAAQmM,wBAA0B,SAAU8C,EAAWnN,GAC7E,GAA+C,oBAAnCA,EAAQqK,wBAA0CjF,EAC7D,OAAOpF,EAAQqK,uBAAwB8C,IAUzC7H,EAAgB,GAOhBD,EAAY,IAELnH,EAAQoM,IAAMtC,EAAQuC,KAAM7N,EAASqO,qBAI3CS,GAAQ,SAAUC,GAEjB,IAAIoC,EAOJ1I,EAAQ1F,YAAagM,GAAKqC,UAAY,UAAYjL,EAAU,qBAC1CA,EAAU,kEAOvB4I,EAAGV,iBAAkB,wBAAyB3K,QAClDiF,EAAU3H,KAAM,SAAW8I,EAAa,gBAKnCiF,EAAGV,iBAAkB,cAAe3K,QACzCiF,EAAU3H,KAAM,MAAQ8I,EAAa,aAAeD,EAAW,KAI1DkF,EAAGV,iBAAkB,QAAUlI,EAAU,MAAOzC,QACrDiF,EAAU3H,KAAM,OAQjBmQ,EAAQnR,EAAS0C,cAAe,UAC1BG,aAAc,OAAQ,IAC5BkM,EAAGhM,YAAaoO,GACVpC,EAAGV,iBAAkB,aAAc3K,QACxCiF,EAAU3H,KAAM,MAAQ8I,EAAa,QAAUA,EAAa,KAC3DA,EAAa,gBAMTiF,EAAGV,iBAAkB,YAAa3K,QACvCiF,EAAU3H,KAAM,YAMX+N,EAAGV,iBAAkB,KAAOlI,EAAU,MAAOzC,QAClDiF,EAAU3H,KAAM,YAKjB+N,EAAGV,iBAAkB,QACrB1F,EAAU3H,KAAM,iBAGjB8N,GAAQ,SAAUC,GACjBA,EAAGqC,UAAY,oFAKf,IAAID,EAAQnR,EAAS0C,cAAe,SACpCyO,EAAMtO,aAAc,OAAQ,UAC5BkM,EAAGhM,YAAaoO,GAAQtO,aAAc,OAAQ,KAIzCkM,EAAGV,iBAAkB,YAAa3K,QACtCiF,EAAU3H,KAAM,OAAS8I,EAAa,eAKW,IAA7CiF,EAAGV,iBAAkB,YAAa3K,QACtCiF,EAAU3H,KAAM,WAAY,aAK7ByH,EAAQ1F,YAAagM,GAAKvC,UAAW,EACc,IAA9CuC,EAAGV,iBAAkB,aAAc3K,QACvCiF,EAAU3H,KAAM,WAAY,aAK7B+N,EAAGV,iBAAkB,QACrB1F,EAAU3H,KAAM,YAIXQ,EAAQ6P,gBAAkB/F,EAAQuC,KAAQzG,EAAUqB,EAAQrB,SAClEqB,EAAQ6I,uBACR7I,EAAQ8I,oBACR9I,EAAQ+I,kBACR/I,EAAQgJ,qBAER3C,GAAQ,SAAUC,GAIjBvN,EAAQkQ,kBAAoBtK,EAAQvG,KAAMkO,EAAI,KAI9C3H,EAAQvG,KAAMkO,EAAI,aAClBnG,EAAc5H,KAAM,KAAMiJ,KAItBzI,EAAQ0M,qBAQbvF,EAAU3H,KAAM,QAGjB2H,EAAYA,EAAUjF,QAAU,IAAIyG,OAAQxB,EAAUsF,KAAM,MAC5DrF,EAAgBA,EAAclF,QAAU,IAAIyG,OAAQvB,EAAcqF,KAAM,MAIxEkC,EAAa7E,EAAQuC,KAAMpF,EAAQkJ,yBAKnC9I,EAAWsH,GAAc7E,EAAQuC,KAAMpF,EAAQI,UAC9C,SAAUW,EAAGC,GAQZ,IAAImI,EAAuB,IAAfpI,EAAE7H,UAAkB6H,EAAE0G,iBAAmB1G,EACpDqI,EAAMpI,GAAKA,EAAEzG,WACd,OAAOwG,IAAMqI,MAAWA,GAAwB,IAAjBA,EAAIlQ,YAClCiQ,EAAM/I,SACL+I,EAAM/I,SAAUgJ,GAChBrI,EAAEmI,yBAA8D,GAAnCnI,EAAEmI,wBAAyBE,MAG3D,SAAUrI,EAAGC,GACZ,GAAKA,EACJ,MAAUA,EAAIA,EAAEzG,WACf,GAAKyG,IAAMD,EACV,OAAO,EAIV,OAAO,GAOTD,EAAY4G,EACZ,SAAU3G,EAAGC,GAGZ,GAAKD,IAAMC,EAEV,OADAlB,GAAe,EACR,EAIR,IAAIuJ,GAAWtI,EAAEmI,yBAA2BlI,EAAEkI,wBAC9C,OAAKG,IAgBU,GAPfA,GAAYtI,EAAE8D,eAAiB9D,KAASC,EAAE6D,eAAiB7D,GAC1DD,EAAEmI,wBAAyBlI,GAG3B,KAIGjI,EAAQuQ,cAAgBtI,EAAEkI,wBAAyBnI,KAAQsI,EAOzDtI,GAAKxJ,GAAYwJ,EAAE8D,eAAiBvE,GACxCF,EAAUE,EAAcS,IAChB,EAOJC,GAAKzJ,GAAYyJ,EAAE6D,eAAiBvE,GACxCF,EAAUE,EAAcU,GACjB,EAIDnB,EACJrH,EAASqH,EAAWkB,GAAMvI,EAASqH,EAAWmB,GAChD,EAGe,EAAVqI,GAAe,EAAI,IAE3B,SAAUtI,EAAGC,GAGZ,GAAKD,IAAMC,EAEV,OADAlB,GAAe,EACR,EAGR,IAAI8G,EACH9M,EAAI,EACJyP,EAAMxI,EAAExG,WACR6O,EAAMpI,EAAEzG,WACRiP,EAAK,CAAEzI,GACP0I,EAAK,CAAEzI,GAGR,IAAMuI,IAAQH,EAMb,OAAOrI,GAAKxJ,GAAY,EACvByJ,GAAKzJ,EAAW,EAEhBgS,GAAO,EACPH,EAAM,EACNvJ,EACErH,EAASqH,EAAWkB,GAAMvI,EAASqH,EAAWmB,GAChD,EAGK,GAAKuI,IAAQH,EACnB,OAAOzC,GAAc5F,EAAGC,GAIzB4F,EAAM7F,EACN,MAAU6F,EAAMA,EAAIrM,WACnBiP,EAAGE,QAAS9C,GAEbA,EAAM5F,EACN,MAAU4F,EAAMA,EAAIrM,WACnBkP,EAAGC,QAAS9C,GAIb,MAAQ4C,EAAI1P,KAAQ2P,EAAI3P,GACvBA,IAGD,OAAOA,EAGN6M,GAAc6C,EAAI1P,GAAK2P,EAAI3P,IAO3B0P,EAAI1P,IAAOwG,GAAgB,EAC3BmJ,EAAI3P,IAAOwG,EAAe,EAE1B,IAGK/I,GAGR8H,GAAOV,QAAU,SAAUgL,EAAMC,GAChC,OAAOvK,GAAQsK,EAAM,KAAM,KAAMC,IAGlCvK,GAAOuJ,gBAAkB,SAAU5M,EAAM2N,GAGxC,GAFA5J,EAAa/D,GAERjD,EAAQ6P,iBAAmB3I,IAC9BY,EAAwB8I,EAAO,QAC7BxJ,IAAkBA,EAAciF,KAAMuE,OACtCzJ,IAAkBA,EAAUkF,KAAMuE,IAErC,IACC,IAAIjO,EAAMiD,EAAQvG,KAAM4D,EAAM2N,GAG9B,GAAKjO,GAAO3C,EAAQkQ,mBAInBjN,EAAKzE,UAAuC,KAA3ByE,EAAKzE,SAAS2B,SAC/B,OAAOwC,EAEP,MAAQ0I,GACTvD,EAAwB8I,GAAM,GAIhC,OAAyD,EAAlDtK,GAAQsK,EAAMpS,EAAU,KAAM,CAAEyE,IAASf,QAGjDoE,GAAOe,SAAW,SAAUvF,EAASmB,GAUpC,OAHOnB,EAAQgK,eAAiBhK,IAAatD,GAC5CwI,EAAalF,GAEPuF,EAAUvF,EAASmB,IAG3BqD,GAAOwK,KAAO,SAAU7N,EAAMgB,IAOtBhB,EAAK6I,eAAiB7I,IAAUzE,GACtCwI,EAAa/D,GAGd,IAAIlB,EAAKwE,EAAKoH,WAAY1J,EAAKoC,eAG9BrF,EAAMe,GAAMnC,EAAOP,KAAMkH,EAAKoH,WAAY1J,EAAKoC,eAC9CtE,EAAIkB,EAAMgB,GAAOiD,QACjBxC,EAEF,YAAeA,IAAR1D,EACNA,EACAhB,EAAQwI,aAAetB,EACtBjE,EAAK7B,aAAc6C,IACjBjD,EAAMiC,EAAKuM,iBAAkBvL,KAAYjD,EAAI+P,UAC9C/P,EAAI+E,MACJ,MAGJO,GAAO6D,OAAS,SAAU6G,GACzB,OAASA,EAAM,IAAKlM,QAAS0F,GAAYC,KAG1CnE,GAAOtB,MAAQ,SAAUC,GACxB,MAAM,IAAIvG,MAAO,0CAA4CuG,IAO9DqB,GAAO2K,WAAa,SAAUzL,GAC7B,IAAIvC,EACHiO,EAAa,GACbvN,EAAI,EACJ5C,EAAI,EAOL,GAJAgG,GAAgB/G,EAAQmR,iBACxBrK,GAAa9G,EAAQoR,YAAc5L,EAAQtG,MAAO,GAClDsG,EAAQ3B,KAAMkE,GAEThB,EAAe,CACnB,MAAU9D,EAAOuC,EAASzE,KACpBkC,IAASuC,EAASzE,KACtB4C,EAAIuN,EAAW1R,KAAMuB,IAGvB,MAAQ4C,IACP6B,EAAQ1B,OAAQoN,EAAYvN,GAAK,GAQnC,OAFAmD,EAAY,KAELtB,GAORgB,EAAUF,GAAOE,QAAU,SAAUvD,GACpC,IAAIpC,EACH8B,EAAM,GACN5B,EAAI,EACJZ,EAAW8C,EAAK9C,SAEjB,GAAMA,GAQC,GAAkB,IAAbA,GAA+B,IAAbA,GAA+B,KAAbA,EAAkB,CAIjE,GAAiC,iBAArB8C,EAAKoO,YAChB,OAAOpO,EAAKoO,YAIZ,IAAMpO,EAAOA,EAAKqO,WAAYrO,EAAMA,EAAOA,EAAK+K,YAC/CrL,GAAO6D,EAASvD,QAGZ,GAAkB,IAAb9C,GAA+B,IAAbA,EAC7B,OAAO8C,EAAKsO,eAnBZ,MAAU1Q,EAAOoC,EAAMlC,KAGtB4B,GAAO6D,EAAS3F,GAqBlB,OAAO8B,IAGR4D,EAAOD,GAAOkL,UAAY,CAGzBrE,YAAa,GAEbsE,aAAcpE,GAEd3B,MAAOxC,EAEPyE,WAAY,GAEZ4B,KAAM,GAENmC,SAAU,CACTC,IAAK,CAAEzG,IAAK,aAAc/H,OAAO,GACjCyO,IAAK,CAAE1G,IAAK,cACZ2G,IAAK,CAAE3G,IAAK,kBAAmB/H,OAAO,GACtC2O,IAAK,CAAE5G,IAAK,oBAGb6G,UAAW,CACVzI,KAAQ,SAAUoC,GAWjB,OAVAA,EAAO,GAAMA,EAAO,GAAI5G,QAASmF,GAAWC,IAG5CwB,EAAO,IAAQA,EAAO,IAAOA,EAAO,IACnCA,EAAO,IAAO,IAAK5G,QAASmF,GAAWC,IAEpB,OAAfwB,EAAO,KACXA,EAAO,GAAM,IAAMA,EAAO,GAAM,KAG1BA,EAAMxM,MAAO,EAAG,IAGxBsK,MAAS,SAAUkC,GAiClB,OArBAA,EAAO,GAAMA,EAAO,GAAIrF,cAEU,QAA7BqF,EAAO,GAAIxM,MAAO,EAAG,IAGnBwM,EAAO,IACZpF,GAAOtB,MAAO0G,EAAO,IAKtBA,EAAO,KAASA,EAAO,GACtBA,EAAO,IAAQA,EAAO,IAAO,GAC7B,GAAqB,SAAfA,EAAO,IAAiC,QAAfA,EAAO,KACvCA,EAAO,KAAWA,EAAO,GAAMA,EAAO,IAAwB,QAAfA,EAAO,KAG3CA,EAAO,IAClBpF,GAAOtB,MAAO0G,EAAO,IAGfA,GAGRnC,OAAU,SAAUmC,GACnB,IAAIsG,EACHC,GAAYvG,EAAO,IAAOA,EAAO,GAElC,OAAKxC,EAAmB,MAAEmD,KAAMX,EAAO,IAC/B,MAIHA,EAAO,GACXA,EAAO,GAAMA,EAAO,IAAOA,EAAO,IAAO,GAG9BuG,GAAYjJ,EAAQqD,KAAM4F,KAGnCD,EAAStL,EAAUuL,GAAU,MAG7BD,EAASC,EAASxS,QAAS,IAAKwS,EAAS/P,OAAS8P,GAAWC,EAAS/P,UAGxEwJ,EAAO,GAAMA,EAAO,GAAIxM,MAAO,EAAG8S,GAClCtG,EAAO,GAAMuG,EAAS/S,MAAO,EAAG8S,IAI1BtG,EAAMxM,MAAO,EAAG,MAIzBmQ,OAAQ,CAEPhG,IAAO,SAAU6I,GAChB,IAAIjH,EAAWiH,EAAiBpN,QAASmF,GAAWC,IAAY7D,cAChE,MAA4B,MAArB6L,EACN,WACC,OAAO,GAER,SAAUjP,GACT,OAAOA,EAAKgI,UAAYhI,EAAKgI,SAAS5E,gBAAkB4E,IAI3D7B,MAAS,SAAU6F,GAClB,IAAIkD,EAAUzK,EAAYuH,EAAY,KAEtC,OAAOkD,IACJA,EAAU,IAAIxJ,OAAQ,MAAQL,EAC/B,IAAM2G,EAAY,IAAM3G,EAAa,SAAaZ,EACjDuH,EAAW,SAAUhM,GACpB,OAAOkP,EAAQ9F,KACY,iBAAnBpJ,EAAKgM,WAA0BhM,EAAKgM,WACd,oBAAtBhM,EAAK7B,cACX6B,EAAK7B,aAAc,UACpB,OAKNkI,KAAQ,SAAUrF,EAAMmO,EAAUC,GACjC,OAAO,SAAUpP,GAChB,IAAIqP,EAAShM,GAAOwK,KAAM7N,EAAMgB,GAEhC,OAAe,MAAVqO,EACgB,OAAbF,GAEFA,IAINE,GAAU,GAIU,MAAbF,EAAmBE,IAAWD,EACvB,OAAbD,EAAoBE,IAAWD,EAClB,OAAbD,EAAoBC,GAAqC,IAA5BC,EAAO7S,QAAS4S,GAChC,OAAbD,EAAoBC,IAAoC,EAA3BC,EAAO7S,QAAS4S,GAChC,OAAbD,EAAoBC,GAASC,EAAOpT,OAAQmT,EAAMnQ,UAAamQ,EAClD,OAAbD,GAA2F,GAArE,IAAME,EAAOxN,QAAS4D,EAAa,KAAQ,KAAMjJ,QAAS4S,GACnE,OAAbD,IAAoBE,IAAWD,GAASC,EAAOpT,MAAO,EAAGmT,EAAMnQ,OAAS,KAAQmQ,EAAQ,QAO3F7I,MAAS,SAAUjJ,EAAMgS,EAAMC,EAAWrP,EAAOE,GAChD,IAAIoP,EAAgC,QAAvBlS,EAAKrB,MAAO,EAAG,GAC3BwT,EAA+B,SAArBnS,EAAKrB,OAAQ,GACvByT,EAAkB,YAATJ,EAEV,OAAiB,IAAVpP,GAAwB,IAATE,EAGrB,SAAUJ,GACT,QAASA,EAAKzB,YAGf,SAAUyB,EAAM2P,EAAUC,GACzB,IAAI5F,EAAO6F,EAAaC,EAAYlS,EAAMmS,EAAWC,EACpD/H,EAAMuH,IAAWC,EAAU,cAAgB,kBAC3CQ,EAASjQ,EAAKzB,WACdyC,EAAO0O,GAAU1P,EAAKgI,SAAS5E,cAC/B8M,GAAYN,IAAQF,EACpB7E,GAAO,EAER,GAAKoF,EAAS,CAGb,GAAKT,EAAS,CACb,MAAQvH,EAAM,CACbrK,EAAOoC,EACP,MAAUpC,EAAOA,EAAMqK,GACtB,GAAKyH,EACJ9R,EAAKoK,SAAS5E,gBAAkBpC,EACd,IAAlBpD,EAAKV,SAEL,OAAO,EAKT8S,EAAQ/H,EAAe,SAAT3K,IAAoB0S,GAAS,cAE5C,OAAO,EAMR,GAHAA,EAAQ,CAAEP,EAAUQ,EAAO5B,WAAa4B,EAAOE,WAG1CV,GAAWS,EAAW,CAe1BrF,GADAkF,GADA/F,GAHA6F,GAJAC,GADAlS,EAAOqS,GACYvO,KAAe9D,EAAM8D,GAAY,KAI1B9D,EAAKwS,YAC5BN,EAAYlS,EAAKwS,UAAa,KAEZ9S,IAAU,IACZ,KAAQiH,GAAWyF,EAAO,KACzBA,EAAO,GAC3BpM,EAAOmS,GAAaE,EAAO9H,WAAY4H,GAEvC,MAAUnS,IAASmS,GAAanS,GAAQA,EAAMqK,KAG3C4C,EAAOkF,EAAY,IAAOC,EAAM/K,MAGlC,GAAuB,IAAlBrH,EAAKV,YAAoB2N,GAAQjN,IAASoC,EAAO,CACrD6P,EAAavS,GAAS,CAAEiH,EAASwL,EAAWlF,GAC5C,YAyBF,GAlBKqF,IAaJrF,EADAkF,GADA/F,GAHA6F,GAJAC,GADAlS,EAAOoC,GACY0B,KAAe9D,EAAM8D,GAAY,KAI1B9D,EAAKwS,YAC5BN,EAAYlS,EAAKwS,UAAa,KAEZ9S,IAAU,IACZ,KAAQiH,GAAWyF,EAAO,KAMhC,IAATa,EAGJ,MAAUjN,IAASmS,GAAanS,GAAQA,EAAMqK,KAC3C4C,EAAOkF,EAAY,IAAOC,EAAM/K,MAElC,IAAOyK,EACN9R,EAAKoK,SAAS5E,gBAAkBpC,EACd,IAAlBpD,EAAKV,aACH2N,IAGGqF,KAMJL,GALAC,EAAalS,EAAM8D,KAChB9D,EAAM8D,GAAY,KAIK9D,EAAKwS,YAC5BN,EAAYlS,EAAKwS,UAAa,KAEpB9S,GAAS,CAAEiH,EAASsG,IAG7BjN,IAASoC,GACb,MASL,OADA6K,GAAQzK,KACQF,GAAW2K,EAAO3K,GAAU,GAAqB,GAAhB2K,EAAO3K,KAK5DoG,OAAU,SAAU+J,EAAQhF,GAM3B,IAAIiF,EACHxR,EAAKwE,EAAKkC,QAAS6K,IAAY/M,EAAKiN,WAAYF,EAAOjN,gBACtDC,GAAOtB,MAAO,uBAAyBsO,GAKzC,OAAKvR,EAAI4C,GACD5C,EAAIuM,GAIK,EAAZvM,EAAGG,QACPqR,EAAO,CAAED,EAAQA,EAAQ,GAAIhF,GACtB/H,EAAKiN,WAAW3T,eAAgByT,EAAOjN,eAC7CgH,GAAc,SAAU9B,EAAM3F,GAC7B,IAAI6N,EACHC,EAAU3R,EAAIwJ,EAAM+C,GACpBvN,EAAI2S,EAAQxR,OACb,MAAQnB,IAEPwK,EADAkI,EAAMhU,EAAS8L,EAAMmI,EAAS3S,OACb6E,EAAS6N,GAAQC,EAAS3S,MAG7C,SAAUkC,GACT,OAAOlB,EAAIkB,EAAM,EAAGsQ,KAIhBxR,IAIT0G,QAAS,CAGRkL,IAAOtG,GAAc,SAAUxL,GAK9B,IAAI8N,EAAQ,GACXnK,EAAU,GACVoO,EAAUjN,EAAS9E,EAASiD,QAAS8D,EAAO,OAE7C,OAAOgL,EAASjP,GACf0I,GAAc,SAAU9B,EAAM3F,EAASgN,EAAUC,GAChD,IAAI5P,EACH4Q,EAAYD,EAASrI,EAAM,KAAMsH,EAAK,IACtC9R,EAAIwK,EAAKrJ,OAGV,MAAQnB,KACAkC,EAAO4Q,EAAW9S,MACxBwK,EAAMxK,KAAS6E,EAAS7E,GAAMkC,MAIjC,SAAUA,EAAM2P,EAAUC,GAMzB,OALAlD,EAAO,GAAM1M,EACb2Q,EAASjE,EAAO,KAAMkD,EAAKrN,GAG3BmK,EAAO,GAAM,MACLnK,EAAQ0C,SAInB4L,IAAOzG,GAAc,SAAUxL,GAC9B,OAAO,SAAUoB,GAChB,OAAyC,EAAlCqD,GAAQzE,EAAUoB,GAAOf,UAIlCmF,SAAYgG,GAAc,SAAUlM,GAEnC,OADAA,EAAOA,EAAK2D,QAASmF,GAAWC,IACzB,SAAUjH,GAChB,OAAkE,GAAzDA,EAAKoO,aAAe7K,EAASvD,IAASxD,QAAS0B,MAW1D4S,KAAQ1G,GAAc,SAAU0G,GAO/B,OAJM9K,EAAYoD,KAAM0H,GAAQ,KAC/BzN,GAAOtB,MAAO,qBAAuB+O,GAEtCA,EAAOA,EAAKjP,QAASmF,GAAWC,IAAY7D,cACrC,SAAUpD,GAChB,IAAI+Q,EACJ,GACC,GAAOA,EAAW9M,EACjBjE,EAAK8Q,KACL9Q,EAAK7B,aAAc,aAAgB6B,EAAK7B,aAAc,QAGtD,OADA4S,EAAWA,EAAS3N,iBACA0N,GAA2C,IAAnCC,EAASvU,QAASsU,EAAO,YAE3C9Q,EAAOA,EAAKzB,aAAkC,IAAlByB,EAAK9C,UAC7C,OAAO,KAKTkE,OAAU,SAAUpB,GACnB,IAAIgR,EAAOtV,EAAOuV,UAAYvV,EAAOuV,SAASD,KAC9C,OAAOA,GAAQA,EAAK/U,MAAO,KAAQ+D,EAAKgJ,IAGzCkI,KAAQ,SAAUlR,GACjB,OAAOA,IAASgE,GAGjBmN,MAAS,SAAUnR,GAClB,OAAOA,IAASzE,EAAS6V,iBACrB7V,EAAS8V,UAAY9V,EAAS8V,gBAC7BrR,EAAK1C,MAAQ0C,EAAKsR,OAAStR,EAAKuR,WAItCC,QAAWtG,IAAsB,GACjCnD,SAAYmD,IAAsB,GAElCuG,QAAW,SAAUzR,GAIpB,IAAIgI,EAAWhI,EAAKgI,SAAS5E,cAC7B,MAAsB,UAAb4E,KAA0BhI,EAAKyR,SACxB,WAAbzJ,KAA2BhI,EAAK0R,UAGpCA,SAAY,SAAU1R,GASrB,OALKA,EAAKzB,YAETyB,EAAKzB,WAAWoT,eAGQ,IAAlB3R,EAAK0R,UAIbE,MAAS,SAAU5R,GAMlB,IAAMA,EAAOA,EAAKqO,WAAYrO,EAAMA,EAAOA,EAAK+K,YAC/C,GAAK/K,EAAK9C,SAAW,EACpB,OAAO,EAGT,OAAO,GAGR+S,OAAU,SAAUjQ,GACnB,OAAQsD,EAAKkC,QAAiB,MAAGxF,IAIlC6R,OAAU,SAAU7R,GACnB,OAAO4G,EAAQwC,KAAMpJ,EAAKgI,WAG3B0E,MAAS,SAAU1M,GAClB,OAAO2G,EAAQyC,KAAMpJ,EAAKgI,WAG3B8J,OAAU,SAAU9R,GACnB,IAAIgB,EAAOhB,EAAKgI,SAAS5E,cACzB,MAAgB,UAATpC,GAAkC,WAAdhB,EAAK1C,MAA8B,WAAT0D,GAGtD9C,KAAQ,SAAU8B,GACjB,IAAI6N,EACJ,MAAuC,UAAhC7N,EAAKgI,SAAS5E,eACN,SAAdpD,EAAK1C,OAIuC,OAAxCuQ,EAAO7N,EAAK7B,aAAc,UACN,SAAvB0P,EAAKzK,gBAIRlD,MAASkL,GAAwB,WAChC,MAAO,CAAE,KAGVhL,KAAQgL,GAAwB,SAAU2G,EAAe9S,GACxD,MAAO,CAAEA,EAAS,KAGnBkB,GAAMiL,GAAwB,SAAU2G,EAAe9S,EAAQoM,GAC9D,MAAO,CAAEA,EAAW,EAAIA,EAAWpM,EAASoM,KAG7ChL,KAAQ+K,GAAwB,SAAUE,EAAcrM,GAEvD,IADA,IAAInB,EAAI,EACAA,EAAImB,EAAQnB,GAAK,EACxBwN,EAAa/O,KAAMuB,GAEpB,OAAOwN,IAGR9K,IAAO4K,GAAwB,SAAUE,EAAcrM,GAEtD,IADA,IAAInB,EAAI,EACAA,EAAImB,EAAQnB,GAAK,EACxBwN,EAAa/O,KAAMuB,GAEpB,OAAOwN,IAGR0G,GAAM5G,GAAwB,SAAUE,EAAcrM,EAAQoM,GAM7D,IALA,IAAIvN,EAAIuN,EAAW,EAClBA,EAAWpM,EACAA,EAAXoM,EACCpM,EACAoM,EACa,KAALvN,GACTwN,EAAa/O,KAAMuB,GAEpB,OAAOwN,IAGR2G,GAAM7G,GAAwB,SAAUE,EAAcrM,EAAQoM,GAE7D,IADA,IAAIvN,EAAIuN,EAAW,EAAIA,EAAWpM,EAASoM,IACjCvN,EAAImB,GACbqM,EAAa/O,KAAMuB,GAEpB,OAAOwN,OAKL9F,QAAe,IAAIlC,EAAKkC,QAAc,GAGhC,CAAE0M,OAAO,EAAMC,UAAU,EAAMC,MAAM,EAAMC,UAAU,EAAMC,OAAO,GAC5EhP,EAAKkC,QAAS1H,GAAMkN,GAAmBlN,GAExC,IAAMA,IAAK,CAAEyU,QAAQ,EAAMC,OAAO,GACjClP,EAAKkC,QAAS1H,GAAMmN,GAAoBnN,GAIzC,SAASyS,MA0ET,SAAShH,GAAYkJ,GAIpB,IAHA,IAAI3U,EAAI,EACP2C,EAAMgS,EAAOxT,OACbL,EAAW,GACJd,EAAI2C,EAAK3C,IAChBc,GAAY6T,EAAQ3U,GAAIgF,MAEzB,OAAOlE,EAGR,SAASkJ,GAAe6I,EAAS+B,EAAYC,GAC5C,IAAI1K,EAAMyK,EAAWzK,IACpB2K,EAAOF,EAAWxK,KAClB+B,EAAM2I,GAAQ3K,EACd4K,EAAmBF,GAAgB,eAAR1I,EAC3B6I,EAAWtO,IAEZ,OAAOkO,EAAWxS,MAGjB,SAAUF,EAAMnB,EAAS+Q,GACxB,MAAU5P,EAAOA,EAAMiI,GACtB,GAAuB,IAAlBjI,EAAK9C,UAAkB2V,EAC3B,OAAOlC,EAAS3Q,EAAMnB,EAAS+Q,GAGjC,OAAO,GAIR,SAAU5P,EAAMnB,EAAS+Q,GACxB,IAAImD,EAAUlD,EAAaC,EAC1BkD,EAAW,CAAEzO,EAASuO,GAGvB,GAAKlD,GACJ,MAAU5P,EAAOA,EAAMiI,GACtB,IAAuB,IAAlBjI,EAAK9C,UAAkB2V,IACtBlC,EAAS3Q,EAAMnB,EAAS+Q,GAC5B,OAAO,OAKV,MAAU5P,EAAOA,EAAMiI,GACtB,GAAuB,IAAlBjI,EAAK9C,UAAkB2V,EAQ3B,GAHAhD,GAJAC,EAAa9P,EAAM0B,KAAe1B,EAAM0B,GAAY,KAI1B1B,EAAKoQ,YAC5BN,EAAY9P,EAAKoQ,UAAa,IAE5BwC,GAAQA,IAAS5S,EAAKgI,SAAS5E,cACnCpD,EAAOA,EAAMiI,IAASjI,MAChB,CAAA,IAAO+S,EAAWlD,EAAa5F,KACrC8I,EAAU,KAAQxO,GAAWwO,EAAU,KAAQD,EAG/C,OAASE,EAAU,GAAMD,EAAU,GAOnC,IAHAlD,EAAa5F,GAAQ+I,GAGJ,GAAMrC,EAAS3Q,EAAMnB,EAAS+Q,GAC9C,OAAO,EAMZ,OAAO,GAIV,SAASqD,GAAgBC,GACxB,OAAyB,EAAlBA,EAASjU,OACf,SAAUe,EAAMnB,EAAS+Q,GACxB,IAAI9R,EAAIoV,EAASjU,OACjB,MAAQnB,IACP,IAAMoV,EAAUpV,GAAKkC,EAAMnB,EAAS+Q,GACnC,OAAO,EAGT,OAAO,GAERsD,EAAU,GAYZ,SAASC,GAAUvC,EAAW7Q,EAAKqM,EAAQvN,EAAS+Q,GAOnD,IANA,IAAI5P,EACHoT,EAAe,GACftV,EAAI,EACJ2C,EAAMmQ,EAAU3R,OAChBoU,EAAgB,MAAPtT,EAEFjC,EAAI2C,EAAK3C,KACTkC,EAAO4Q,EAAW9S,MAClBsO,IAAUA,EAAQpM,EAAMnB,EAAS+Q,KACtCwD,EAAa7W,KAAMyD,GACdqT,GACJtT,EAAIxD,KAAMuB,KAMd,OAAOsV,EAGR,SAASE,GAAYxE,EAAWlQ,EAAU+R,EAAS4C,EAAYC,EAAYC,GAO1E,OANKF,IAAeA,EAAY7R,KAC/B6R,EAAaD,GAAYC,IAErBC,IAAeA,EAAY9R,KAC/B8R,EAAaF,GAAYE,EAAYC,IAE/BrJ,GAAc,SAAU9B,EAAM/F,EAAS1D,EAAS+Q,GACtD,IAAI8D,EAAM5V,EAAGkC,EACZ2T,EAAS,GACTC,EAAU,GACVC,EAActR,EAAQtD,OAGtBQ,EAAQ6I,GA5CX,SAA2B1J,EAAUkV,EAAUvR,GAG9C,IAFA,IAAIzE,EAAI,EACP2C,EAAMqT,EAAS7U,OACRnB,EAAI2C,EAAK3C,IAChBuF,GAAQzE,EAAUkV,EAAUhW,GAAKyE,GAElC,OAAOA,EAsCWwR,CACfnV,GAAY,IACZC,EAAQ3B,SAAW,CAAE2B,GAAYA,EACjC,IAIDmV,GAAYlF,IAAexG,GAAS1J,EAEnCa,EADA0T,GAAU1T,EAAOkU,EAAQ7E,EAAWjQ,EAAS+Q,GAG9CqE,EAAatD,EAGZ6C,IAAgBlL,EAAOwG,EAAY+E,GAAeN,GAGjD,GAGAhR,EACDyR,EAQF,GALKrD,GACJA,EAASqD,EAAWC,EAAYpV,EAAS+Q,GAIrC2D,EAAa,CACjBG,EAAOP,GAAUc,EAAYL,GAC7BL,EAAYG,EAAM,GAAI7U,EAAS+Q,GAG/B9R,EAAI4V,EAAKzU,OACT,MAAQnB,KACAkC,EAAO0T,EAAM5V,MACnBmW,EAAYL,EAAS9V,MAAWkW,EAAWJ,EAAS9V,IAAQkC,IAK/D,GAAKsI,GACJ,GAAKkL,GAAc1E,EAAY,CAC9B,GAAK0E,EAAa,CAGjBE,EAAO,GACP5V,EAAImW,EAAWhV,OACf,MAAQnB,KACAkC,EAAOiU,EAAYnW,KAGzB4V,EAAKnX,KAAQyX,EAAWlW,GAAMkC,GAGhCwT,EAAY,KAAQS,EAAa,GAAMP,EAAM9D,GAI9C9R,EAAImW,EAAWhV,OACf,MAAQnB,KACAkC,EAAOiU,EAAYnW,MACsC,GAA7D4V,EAAOF,EAAahX,EAAS8L,EAAMtI,GAAS2T,EAAQ7V,MAEtDwK,EAAMoL,KAAYnR,EAASmR,GAAS1T,UAOvCiU,EAAad,GACZc,IAAe1R,EACd0R,EAAWpT,OAAQgT,EAAaI,EAAWhV,QAC3CgV,GAEGT,EACJA,EAAY,KAAMjR,EAAS0R,EAAYrE,GAEvCrT,EAAKD,MAAOiG,EAAS0R,KAMzB,SAASC,GAAmBzB,GAyB3B,IAxBA,IAAI0B,EAAcxD,EAASjQ,EAC1BD,EAAMgS,EAAOxT,OACbmV,EAAkB9Q,EAAKmL,SAAUgE,EAAQ,GAAInV,MAC7C+W,EAAmBD,GAAmB9Q,EAAKmL,SAAU,KACrD3Q,EAAIsW,EAAkB,EAAI,EAG1BE,EAAexM,GAAe,SAAU9H,GACvC,OAAOA,IAASmU,GACdE,GAAkB,GACrBE,EAAkBzM,GAAe,SAAU9H,GAC1C,OAAwC,EAAjCxD,EAAS2X,EAAcnU,IAC5BqU,GAAkB,GACrBnB,EAAW,CAAE,SAAUlT,EAAMnB,EAAS+Q,GACrC,IAAIlQ,GAAS0U,IAAqBxE,GAAO/Q,IAAY+E,MAClDuQ,EAAetV,GAAU3B,SAC1BoX,EAActU,EAAMnB,EAAS+Q,GAC7B2E,EAAiBvU,EAAMnB,EAAS+Q,IAIlC,OADAuE,EAAe,KACRzU,IAGD5B,EAAI2C,EAAK3C,IAChB,GAAO6S,EAAUrN,EAAKmL,SAAUgE,EAAQ3U,GAAIR,MAC3C4V,EAAW,CAAEpL,GAAemL,GAAgBC,GAAYvC,QAClD,CAIN,IAHAA,EAAUrN,EAAK8I,OAAQqG,EAAQ3U,GAAIR,MAAOhB,MAAO,KAAMmW,EAAQ3U,GAAI6E,UAGrDjB,GAAY,CAIzB,IADAhB,IAAM5C,EACE4C,EAAID,EAAKC,IAChB,GAAK4C,EAAKmL,SAAUgE,EAAQ/R,GAAIpD,MAC/B,MAGF,OAAOgW,GACF,EAAJxV,GAASmV,GAAgBC,GACrB,EAAJpV,GAASyL,GAGTkJ,EACExW,MAAO,EAAG6B,EAAI,GACdzB,OAAQ,CAAEyG,MAAgC,MAAzB2P,EAAQ3U,EAAI,GAAIR,KAAe,IAAM,MACtDuE,QAAS8D,EAAO,MAClBgL,EACA7S,EAAI4C,GAAKwT,GAAmBzB,EAAOxW,MAAO6B,EAAG4C,IAC7CA,EAAID,GAAOyT,GAAqBzB,EAASA,EAAOxW,MAAOyE,IACvDA,EAAID,GAAO8I,GAAYkJ,IAGzBS,EAAS3W,KAAMoU,GAIjB,OAAOsC,GAAgBC,GAoTxB,OAtpBA3C,GAAWrR,UAAYoE,EAAKkR,QAAUlR,EAAKkC,QAC3ClC,EAAKiN,WAAa,IAAIA,GAEtB9M,EAAWJ,GAAOI,SAAW,SAAU7E,EAAU6V,GAChD,IAAIhE,EAAShI,EAAOgK,EAAQnV,EAC3BoX,EAAOhM,EAAQiM,EACfC,EAASjQ,EAAY/F,EAAW,KAEjC,GAAKgW,EACJ,OAAOH,EAAY,EAAIG,EAAO3Y,MAAO,GAGtCyY,EAAQ9V,EACR8J,EAAS,GACTiM,EAAarR,EAAKwL,UAElB,MAAQ4F,EAAQ,CA2Bf,IAAMpX,KAxBAmT,KAAahI,EAAQ7C,EAAOkD,KAAM4L,MAClCjM,IAGJiM,EAAQA,EAAMzY,MAAOwM,EAAO,GAAIxJ,SAAYyV,GAE7ChM,EAAOnM,KAAQkW,EAAS,KAGzBhC,GAAU,GAGHhI,EAAQ5C,EAAaiD,KAAM4L,MACjCjE,EAAUhI,EAAM0B,QAChBsI,EAAOlW,KAAM,CACZuG,MAAO2N,EAGPnT,KAAMmL,EAAO,GAAI5G,QAAS8D,EAAO,OAElC+O,EAAQA,EAAMzY,MAAOwU,EAAQxR,SAIhBqE,EAAK8I,SACX3D,EAAQxC,EAAW3I,GAAOwL,KAAM4L,KAAgBC,EAAYrX,MAChEmL,EAAQkM,EAAYrX,GAAQmL,MAC9BgI,EAAUhI,EAAM0B,QAChBsI,EAAOlW,KAAM,CACZuG,MAAO2N,EACPnT,KAAMA,EACNqF,QAAS8F,IAEViM,EAAQA,EAAMzY,MAAOwU,EAAQxR,SAI/B,IAAMwR,EACL,MAOF,OAAOgE,EACNC,EAAMzV,OACNyV,EACCrR,GAAOtB,MAAOnD,GAGd+F,EAAY/F,EAAU8J,GAASzM,MAAO,IA4ZzCyH,EAAUL,GAAOK,QAAU,SAAU9E,EAAU6J,GAC9C,IAAI3K,EA9H8B+W,EAAiBC,EAC/CC,EACHC,EACAC,EA4HAH,EAAc,GACdD,EAAkB,GAClBD,EAAShQ,EAAehG,EAAW,KAEpC,IAAMgW,EAAS,CAGRnM,IACLA,EAAQhF,EAAU7E,IAEnBd,EAAI2K,EAAMxJ,OACV,MAAQnB,KACP8W,EAASV,GAAmBzL,EAAO3K,KACtB4D,GACZoT,EAAYvY,KAAMqY,GAElBC,EAAgBtY,KAAMqY,IAKxBA,EAAShQ,EACRhG,GArJgCiW,EAsJNA,EArJxBE,EAA6B,GADkBD,EAsJNA,GArJrB7V,OACvB+V,EAAqC,EAAzBH,EAAgB5V,OAC5BgW,EAAe,SAAU3M,EAAMzJ,EAAS+Q,EAAKrN,EAAS2S,GACrD,IAAIlV,EAAMU,EAAGiQ,EACZwE,EAAe,EACfrX,EAAI,IACJ8S,EAAYtI,GAAQ,GACpB8M,EAAa,GACbC,EAAgBzR,EAGhBnE,EAAQ6I,GAAQ0M,GAAa1R,EAAKgJ,KAAY,IAAG,IAAK4I,GAGtDI,EAAkB/Q,GAA4B,MAAjB8Q,EAAwB,EAAI1T,KAAKC,UAAY,GAC1EnB,EAAMhB,EAAMR,OAcb,IAZKiW,IAMJtR,EAAmB/E,GAAWtD,GAAYsD,GAAWqW,GAM9CpX,IAAM2C,GAAgC,OAAvBT,EAAOP,EAAO3B,IAAeA,IAAM,CACzD,GAAKkX,GAAahV,EAAO,CACxBU,EAAI,EAME7B,GAAWmB,EAAK6I,eAAiBtN,IACtCwI,EAAa/D,GACb4P,GAAO3L,GAER,MAAU0M,EAAUkE,EAAiBnU,KACpC,GAAKiQ,EAAS3Q,EAAMnB,GAAWtD,EAAUqU,GAAQ,CAChDrN,EAAQhG,KAAMyD,GACd,MAGGkV,IACJ3Q,EAAU+Q,GAKPP,KAGG/U,GAAQ2Q,GAAW3Q,IACzBmV,IAII7M,GACJsI,EAAUrU,KAAMyD,IAgBnB,GATAmV,GAAgBrX,EASXiX,GAASjX,IAAMqX,EAAe,CAClCzU,EAAI,EACJ,MAAUiQ,EAAUmE,EAAapU,KAChCiQ,EAASC,EAAWwE,EAAYvW,EAAS+Q,GAG1C,GAAKtH,EAAO,CAGX,GAAoB,EAAf6M,EACJ,MAAQrX,IACC8S,EAAW9S,IAAOsX,EAAYtX,KACrCsX,EAAYtX,GAAMmH,EAAI7I,KAAMmG,IAM/B6S,EAAajC,GAAUiC,GAIxB7Y,EAAKD,MAAOiG,EAAS6S,GAGhBF,IAAc5M,GAA4B,EAApB8M,EAAWnW,QACG,EAAtCkW,EAAeL,EAAY7V,QAE7BoE,GAAO2K,WAAYzL,GAUrB,OALK2S,IACJ3Q,EAAU+Q,EACV1R,EAAmByR,GAGbzE,GAGFmE,EACN3K,GAAc6K,GACdA,KAgCOrW,SAAWA,EAEnB,OAAOgW,GAYRjR,EAASN,GAAOM,OAAS,SAAU/E,EAAUC,EAAS0D,EAAS+F,GAC9D,IAAIxK,EAAG2U,EAAQ8C,EAAOjY,EAAMgP,EAC3BkJ,EAA+B,mBAAb5W,GAA2BA,EAC7C6J,GAASH,GAAQ7E,EAAY7E,EAAW4W,EAAS5W,UAAYA,GAM9D,GAJA2D,EAAUA,GAAW,GAIC,IAAjBkG,EAAMxJ,OAAe,CAIzB,GAAqB,GADrBwT,EAAShK,EAAO,GAAMA,EAAO,GAAIxM,MAAO,IAC5BgD,QAA+C,QAA/BsW,EAAQ9C,EAAQ,IAAMnV,MAC5B,IAArBuB,EAAQ3B,UAAkB+G,GAAkBX,EAAKmL,SAAUgE,EAAQ,GAAInV,MAAS,CAIhF,KAFAuB,GAAYyE,EAAKgJ,KAAW,GAAGiJ,EAAM5S,QAAS,GAC5Cd,QAASmF,GAAWC,IAAapI,IAAa,IAAM,IAErD,OAAO0D,EAGIiT,IACX3W,EAAUA,EAAQN,YAGnBK,EAAWA,EAAS3C,MAAOwW,EAAOtI,QAAQrH,MAAM7D,QAIjDnB,EAAImI,EAA0B,aAAEmD,KAAMxK,GAAa,EAAI6T,EAAOxT,OAC9D,MAAQnB,IAAM,CAIb,GAHAyX,EAAQ9C,EAAQ3U,GAGXwF,EAAKmL,SAAYnR,EAAOiY,EAAMjY,MAClC,MAED,IAAOgP,EAAOhJ,EAAKgJ,KAAMhP,MAGjBgL,EAAOgE,EACbiJ,EAAM5S,QAAS,GAAId,QAASmF,GAAWC,IACvCF,GAASqC,KAAMqJ,EAAQ,GAAInV,OAAU+L,GAAaxK,EAAQN,aACzDM,IACI,CAKL,GAFA4T,EAAO5R,OAAQ/C,EAAG,KAClBc,EAAW0J,EAAKrJ,QAAUsK,GAAYkJ,IAGrC,OADAlW,EAAKD,MAAOiG,EAAS+F,GACd/F,EAGR,QAeJ,OAPEiT,GAAY9R,EAAS9E,EAAU6J,IAChCH,EACAzJ,GACCoF,EACD1B,GACC1D,GAAWkI,GAASqC,KAAMxK,IAAcyK,GAAaxK,EAAQN,aAAgBM,GAExE0D,GAMRxF,EAAQoR,WAAazM,EAAQwB,MAAO,IAAKtC,KAAMkE,GAAY0E,KAAM,MAAS9H,EAI1E3E,EAAQmR,mBAAqBpK,EAG7BC,IAIAhH,EAAQuQ,aAAejD,GAAQ,SAAUC,GAGxC,OAA4E,EAArEA,EAAG4C,wBAAyB3R,EAAS0C,cAAe,eAMtDoM,GAAQ,SAAUC,GAEvB,OADAA,EAAGqC,UAAY,mBACiC,MAAzCrC,EAAG+D,WAAWlQ,aAAc,WAEnCoM,GAAW,yBAA0B,SAAUvK,EAAMgB,EAAMwC,GAC1D,IAAMA,EACL,OAAOxD,EAAK7B,aAAc6C,EAA6B,SAAvBA,EAAKoC,cAA2B,EAAI,KAOjErG,EAAQwI,YAAe8E,GAAQ,SAAUC,GAG9C,OAFAA,EAAGqC,UAAY,WACfrC,EAAG+D,WAAWjQ,aAAc,QAAS,IACY,KAA1CkM,EAAG+D,WAAWlQ,aAAc,YAEnCoM,GAAW,QAAS,SAAUvK,EAAMyV,EAAOjS,GAC1C,IAAMA,GAAyC,UAAhCxD,EAAKgI,SAAS5E,cAC5B,OAAOpD,EAAK0V,eAOTrL,GAAQ,SAAUC,GACvB,OAAwC,MAAjCA,EAAGnM,aAAc,eAExBoM,GAAWnF,EAAU,SAAUpF,EAAMgB,EAAMwC,GAC1C,IAAIzF,EACJ,IAAMyF,EACL,OAAwB,IAAjBxD,EAAMgB,GAAkBA,EAAKoC,eACjCrF,EAAMiC,EAAKuM,iBAAkBvL,KAAYjD,EAAI+P,UAC9C/P,EAAI+E,MACJ,OAKEO,GA18EP,CA48EK3H,GAILiD,EAAO2N,KAAOjJ,EACd1E,EAAOgP,KAAOtK,EAAOkL,UAGrB5P,EAAOgP,KAAM,KAAQhP,EAAOgP,KAAKnI,QACjC7G,EAAOqP,WAAarP,EAAOgX,OAAStS,EAAO2K,WAC3CrP,EAAOT,KAAOmF,EAAOE,QACrB5E,EAAOiX,SAAWvS,EAAOG,MACzB7E,EAAOyF,SAAWf,EAAOe,SACzBzF,EAAOkX,eAAiBxS,EAAO6D,OAK/B,IAAIe,EAAM,SAAUjI,EAAMiI,EAAK6N,GAC9B,IAAIrF,EAAU,GACbsF,OAAqBtU,IAAVqU,EAEZ,OAAU9V,EAAOA,EAAMiI,KAA6B,IAAlBjI,EAAK9C,SACtC,GAAuB,IAAlB8C,EAAK9C,SAAiB,CAC1B,GAAK6Y,GAAYpX,EAAQqB,GAAOgW,GAAIF,GACnC,MAEDrF,EAAQlU,KAAMyD,GAGhB,OAAOyQ,GAIJwF,EAAW,SAAUC,EAAGlW,GAG3B,IAFA,IAAIyQ,EAAU,GAENyF,EAAGA,EAAIA,EAAEnL,YACI,IAAfmL,EAAEhZ,UAAkBgZ,IAAMlW,GAC9ByQ,EAAQlU,KAAM2Z,GAIhB,OAAOzF,GAIJ0F,EAAgBxX,EAAOgP,KAAKlF,MAAMhC,aAItC,SAASuB,EAAUhI,EAAMgB,GAExB,OAAOhB,EAAKgI,UAAYhI,EAAKgI,SAAS5E,gBAAkBpC,EAAKoC,cAG9D,IAAIgT,EAAa,kEAKjB,SAASC,EAAQzI,EAAU0I,EAAW5F,GACrC,OAAK1T,EAAYsZ,GACT3X,EAAO2B,KAAMsN,EAAU,SAAU5N,EAAMlC,GAC7C,QAASwY,EAAUla,KAAM4D,EAAMlC,EAAGkC,KAAW0Q,IAK1C4F,EAAUpZ,SACPyB,EAAO2B,KAAMsN,EAAU,SAAU5N,GACvC,OAASA,IAASsW,IAAgB5F,IAKV,iBAAd4F,EACJ3X,EAAO2B,KAAMsN,EAAU,SAAU5N,GACvC,OAA4C,EAAnCxD,EAAQJ,KAAMka,EAAWtW,KAAkB0Q,IAK/C/R,EAAOyN,OAAQkK,EAAW1I,EAAU8C,GAG5C/R,EAAOyN,OAAS,SAAUuB,EAAMlO,EAAOiR,GACtC,IAAI1Q,EAAOP,EAAO,GAMlB,OAJKiR,IACJ/C,EAAO,QAAUA,EAAO,KAGH,IAAjBlO,EAAMR,QAAkC,IAAlBe,EAAK9C,SACxByB,EAAO2N,KAAKM,gBAAiB5M,EAAM2N,GAAS,CAAE3N,GAAS,GAGxDrB,EAAO2N,KAAK3J,QAASgL,EAAMhP,EAAO2B,KAAMb,EAAO,SAAUO,GAC/D,OAAyB,IAAlBA,EAAK9C,aAIdyB,EAAOG,GAAGgC,OAAQ,CACjBwL,KAAM,SAAU1N,GACf,IAAId,EAAG4B,EACNe,EAAM9E,KAAKsD,OACXsX,EAAO5a,KAER,GAAyB,iBAAbiD,EACX,OAAOjD,KAAK6D,UAAWb,EAAQC,GAAWwN,OAAQ,WACjD,IAAMtO,EAAI,EAAGA,EAAI2C,EAAK3C,IACrB,GAAKa,EAAOyF,SAAUmS,EAAMzY,GAAKnC,MAChC,OAAO,KAQX,IAFA+D,EAAM/D,KAAK6D,UAAW,IAEhB1B,EAAI,EAAGA,EAAI2C,EAAK3C,IACrBa,EAAO2N,KAAM1N,EAAU2X,EAAMzY,GAAK4B,GAGnC,OAAa,EAANe,EAAU9B,EAAOqP,WAAYtO,GAAQA,GAE7C0M,OAAQ,SAAUxN,GACjB,OAAOjD,KAAK6D,UAAW6W,EAAQ1a,KAAMiD,GAAY,IAAI,KAEtD8R,IAAK,SAAU9R,GACd,OAAOjD,KAAK6D,UAAW6W,EAAQ1a,KAAMiD,GAAY,IAAI,KAEtDoX,GAAI,SAAUpX,GACb,QAASyX,EACR1a,KAIoB,iBAAbiD,GAAyBuX,EAAc/M,KAAMxK,GACnDD,EAAQC,GACRA,GAAY,IACb,GACCK,UASJ,IAAIuX,EAMH1P,EAAa,uCAENnI,EAAOG,GAAGC,KAAO,SAAUH,EAAUC,EAASqS,GACpD,IAAIzI,EAAOzI,EAGX,IAAMpB,EACL,OAAOjD,KAQR,GAHAuV,EAAOA,GAAQsF,EAGU,iBAAb5X,EAAwB,CAanC,KAPC6J,EALsB,MAAlB7J,EAAU,IACsB,MAApCA,EAAUA,EAASK,OAAS,IACT,GAAnBL,EAASK,OAGD,CAAE,KAAML,EAAU,MAGlBkI,EAAWgC,KAAMlK,MAIV6J,EAAO,IAAQ5J,EA6CxB,OAAMA,GAAWA,EAAQM,QACtBN,GAAWqS,GAAO5E,KAAM1N,GAK1BjD,KAAKyD,YAAaP,GAAUyN,KAAM1N,GAhDzC,GAAK6J,EAAO,GAAM,CAYjB,GAXA5J,EAAUA,aAAmBF,EAASE,EAAS,GAAMA,EAIrDF,EAAOgB,MAAOhE,KAAMgD,EAAO8X,UAC1BhO,EAAO,GACP5J,GAAWA,EAAQ3B,SAAW2B,EAAQgK,eAAiBhK,EAAUtD,GACjE,IAII6a,EAAWhN,KAAMX,EAAO,KAAS9J,EAAO2C,cAAezC,GAC3D,IAAM4J,KAAS5J,EAGT7B,EAAYrB,KAAM8M,IACtB9M,KAAM8M,GAAS5J,EAAS4J,IAIxB9M,KAAKkS,KAAMpF,EAAO5J,EAAS4J,IAK9B,OAAO9M,KAYP,OARAqE,EAAOzE,EAASwN,eAAgBN,EAAO,OAKtC9M,KAAM,GAAMqE,EACZrE,KAAKsD,OAAS,GAERtD,KAcH,OAAKiD,EAAS1B,UACpBvB,KAAM,GAAMiD,EACZjD,KAAKsD,OAAS,EACPtD,MAIIqB,EAAY4B,QACD6C,IAAfyP,EAAKwF,MACXxF,EAAKwF,MAAO9X,GAGZA,EAAUD,GAGLA,EAAO2D,UAAW1D,EAAUjD,QAIhCuD,UAAYP,EAAOG,GAGxB0X,EAAa7X,EAAQpD,GAGrB,IAAIob,EAAe,iCAGlBC,EAAmB,CAClBC,UAAU,EACVC,UAAU,EACV5O,MAAM,EACN6O,MAAM,GAoFR,SAASC,EAASpM,EAAK3C,GACtB,OAAU2C,EAAMA,EAAK3C,KAA4B,IAAjB2C,EAAI1N,UACpC,OAAO0N,EAnFRjM,EAAOG,GAAGgC,OAAQ,CACjB+P,IAAK,SAAUzP,GACd,IAAI6V,EAAUtY,EAAQyC,EAAQzF,MAC7Bub,EAAID,EAAQhY,OAEb,OAAOtD,KAAKyQ,OAAQ,WAEnB,IADA,IAAItO,EAAI,EACAA,EAAIoZ,EAAGpZ,IACd,GAAKa,EAAOyF,SAAUzI,KAAMsb,EAASnZ,IACpC,OAAO,KAMXqZ,QAAS,SAAU5I,EAAW1P,GAC7B,IAAI+L,EACH9M,EAAI,EACJoZ,EAAIvb,KAAKsD,OACTwR,EAAU,GACVwG,EAA+B,iBAAd1I,GAA0B5P,EAAQ4P,GAGpD,IAAM4H,EAAc/M,KAAMmF,GACzB,KAAQzQ,EAAIoZ,EAAGpZ,IACd,IAAM8M,EAAMjP,KAAMmC,GAAK8M,GAAOA,IAAQ/L,EAAS+L,EAAMA,EAAIrM,WAGxD,GAAKqM,EAAI1N,SAAW,KAAQ+Z,GACH,EAAxBA,EAAQG,MAAOxM,GAGE,IAAjBA,EAAI1N,UACHyB,EAAO2N,KAAKM,gBAAiBhC,EAAK2D,IAAgB,CAEnDkC,EAAQlU,KAAMqO,GACd,MAMJ,OAAOjP,KAAK6D,UAA4B,EAAjBiR,EAAQxR,OAAaN,EAAOqP,WAAYyC,GAAYA,IAI5E2G,MAAO,SAAUpX,GAGhB,OAAMA,EAKe,iBAATA,EACJxD,EAAQJ,KAAMuC,EAAQqB,GAAQrE,KAAM,IAIrCa,EAAQJ,KAAMT,KAGpBqE,EAAKb,OAASa,EAAM,GAAMA,GAZjBrE,KAAM,IAAOA,KAAM,GAAI4C,WAAe5C,KAAKuE,QAAQmX,UAAUpY,QAAU,GAgBlFqY,IAAK,SAAU1Y,EAAUC,GACxB,OAAOlD,KAAK6D,UACXb,EAAOqP,WACNrP,EAAOgB,MAAOhE,KAAK2D,MAAOX,EAAQC,EAAUC,OAK/C0Y,QAAS,SAAU3Y,GAClB,OAAOjD,KAAK2b,IAAiB,MAAZ1Y,EAChBjD,KAAKiE,WAAajE,KAAKiE,WAAWwM,OAAQxN,OAU7CD,EAAOkB,KAAM,CACZoQ,OAAQ,SAAUjQ,GACjB,IAAIiQ,EAASjQ,EAAKzB,WAClB,OAAO0R,GAA8B,KAApBA,EAAO/S,SAAkB+S,EAAS,MAEpDuH,QAAS,SAAUxX,GAClB,OAAOiI,EAAKjI,EAAM,eAEnByX,aAAc,SAAUzX,EAAMmD,EAAI2S,GACjC,OAAO7N,EAAKjI,EAAM,aAAc8V,IAEjC5N,KAAM,SAAUlI,GACf,OAAOgX,EAAShX,EAAM,gBAEvB+W,KAAM,SAAU/W,GACf,OAAOgX,EAAShX,EAAM,oBAEvB0X,QAAS,SAAU1X,GAClB,OAAOiI,EAAKjI,EAAM,gBAEnBqX,QAAS,SAAUrX,GAClB,OAAOiI,EAAKjI,EAAM,oBAEnB2X,UAAW,SAAU3X,EAAMmD,EAAI2S,GAC9B,OAAO7N,EAAKjI,EAAM,cAAe8V,IAElC8B,UAAW,SAAU5X,EAAMmD,EAAI2S,GAC9B,OAAO7N,EAAKjI,EAAM,kBAAmB8V,IAEtCG,SAAU,SAAUjW,GACnB,OAAOiW,GAAYjW,EAAKzB,YAAc,IAAK8P,WAAYrO,IAExD6W,SAAU,SAAU7W,GACnB,OAAOiW,EAAUjW,EAAKqO,aAEvByI,SAAU,SAAU9W,GACnB,OAA6B,MAAxBA,EAAK6X,iBAKT/b,EAAUkE,EAAK6X,iBAER7X,EAAK6X,iBAMR7P,EAAUhI,EAAM,cACpBA,EAAOA,EAAK8X,SAAW9X,GAGjBrB,EAAOgB,MAAO,GAAIK,EAAKmI,eAE7B,SAAUnH,EAAMlC,GAClBH,EAAOG,GAAIkC,GAAS,SAAU8U,EAAOlX,GACpC,IAAI6R,EAAU9R,EAAOoB,IAAKpE,KAAMmD,EAAIgX,GAuBpC,MArB0B,UAArB9U,EAAK/E,OAAQ,KACjB2C,EAAWkX,GAGPlX,GAAgC,iBAAbA,IACvB6R,EAAU9R,EAAOyN,OAAQxN,EAAU6R,IAGjB,EAAd9U,KAAKsD,SAGH2X,EAAkB5V,IACvBrC,EAAOqP,WAAYyC,GAIfkG,EAAavN,KAAMpI,IACvByP,EAAQsH,WAIHpc,KAAK6D,UAAWiR,MAGzB,IAAIuH,EAAgB,oBAsOpB,SAASC,EAAUC,GAClB,OAAOA,EAER,SAASC,EAASC,GACjB,MAAMA,EAGP,SAASC,EAAYvV,EAAOwV,EAASC,EAAQC,GAC5C,IAAIC,EAEJ,IAGM3V,GAAS9F,EAAcyb,EAAS3V,EAAM4V,SAC1CD,EAAOrc,KAAM0G,GAAQ0B,KAAM8T,GAAUK,KAAMJ,GAGhCzV,GAAS9F,EAAcyb,EAAS3V,EAAM8V,MACjDH,EAAOrc,KAAM0G,EAAOwV,EAASC,GAQ7BD,EAAQhc,WAAOmF,EAAW,CAAEqB,GAAQ7G,MAAOuc,IAM3C,MAAQ1V,GAITyV,EAAOjc,WAAOmF,EAAW,CAAEqB,KAvO7BnE,EAAOka,UAAY,SAAU9X,GA9B7B,IAAwBA,EACnB+X,EAiCJ/X,EAA6B,iBAAZA,GAlCMA,EAmCPA,EAlCZ+X,EAAS,GACbna,EAAOkB,KAAMkB,EAAQ0H,MAAOuP,IAAmB,GAAI,SAAUe,EAAGC,GAC/DF,EAAQE,IAAS,IAEXF,GA+BNna,EAAOmC,OAAQ,GAAIC,GAEpB,IACCkY,EAGAC,EAGAC,EAGAC,EAGAjU,EAAO,GAGPkU,EAAQ,GAGRC,GAAe,EAGfC,EAAO,WAQN,IALAH,EAASA,GAAUrY,EAAQyY,KAI3BL,EAAQF,GAAS,EACTI,EAAMpa,OAAQqa,GAAe,EAAI,CACxCJ,EAASG,EAAMlP,QACf,QAAUmP,EAAcnU,EAAKlG,QAGmC,IAA1DkG,EAAMmU,GAAchd,MAAO4c,EAAQ,GAAKA,EAAQ,KACpDnY,EAAQ0Y,cAGRH,EAAcnU,EAAKlG,OACnBia,GAAS,GAMNnY,EAAQmY,SACbA,GAAS,GAGVD,GAAS,EAGJG,IAIHjU,EADI+T,EACG,GAIA,KAMV3C,EAAO,CAGNe,IAAK,WA2BJ,OA1BKnS,IAGC+T,IAAWD,IACfK,EAAcnU,EAAKlG,OAAS,EAC5Boa,EAAM9c,KAAM2c,IAGb,SAAW5B,EAAKhH,GACf3R,EAAOkB,KAAMyQ,EAAM,SAAUyI,EAAGlW,GAC1B7F,EAAY6F,GACV9B,EAAQ4U,QAAWY,EAAK1F,IAAKhO,IAClCsC,EAAK5I,KAAMsG,GAEDA,GAAOA,EAAI5D,QAA4B,WAAlBR,EAAQoE,IAGxCyU,EAAKzU,KATR,CAYK5C,WAEAiZ,IAAWD,GACfM,KAGK5d,MAIR+d,OAAQ,WAYP,OAXA/a,EAAOkB,KAAMI,UAAW,SAAU8Y,EAAGlW,GACpC,IAAIuU,EACJ,OAA0D,GAAhDA,EAAQzY,EAAO6D,QAASK,EAAKsC,EAAMiS,IAC5CjS,EAAKtE,OAAQuW,EAAO,GAGfA,GAASkC,GACbA,MAII3d,MAKRkV,IAAK,SAAU/R,GACd,OAAOA,GACwB,EAA9BH,EAAO6D,QAAS1D,EAAIqG,GACN,EAAdA,EAAKlG,QAIP2S,MAAO,WAIN,OAHKzM,IACJA,EAAO,IAEDxJ,MAMRge,QAAS,WAGR,OAFAP,EAASC,EAAQ,GACjBlU,EAAO+T,EAAS,GACTvd,MAERoM,SAAU,WACT,OAAQ5C,GAMTyU,KAAM,WAKL,OAJAR,EAASC,EAAQ,GACXH,GAAWD,IAChB9T,EAAO+T,EAAS,IAEVvd,MAERyd,OAAQ,WACP,QAASA,GAIVS,SAAU,SAAUhb,EAASyR,GAS5B,OARM8I,IAEL9I,EAAO,CAAEzR,GADTyR,EAAOA,GAAQ,IACQrU,MAAQqU,EAAKrU,QAAUqU,GAC9C+I,EAAM9c,KAAM+T,GACN2I,GACLM,KAGK5d,MAIR4d,KAAM,WAEL,OADAhD,EAAKsD,SAAUle,KAAMsE,WACdtE,MAIRwd,MAAO,WACN,QAASA,IAIZ,OAAO5C,GA4CR5X,EAAOmC,OAAQ,CAEdgZ,SAAU,SAAUC,GACnB,IAAIC,EAAS,CAIX,CAAE,SAAU,WAAYrb,EAAOka,UAAW,UACzCla,EAAOka,UAAW,UAAY,GAC/B,CAAE,UAAW,OAAQla,EAAOka,UAAW,eACtCla,EAAOka,UAAW,eAAiB,EAAG,YACvC,CAAE,SAAU,OAAQla,EAAOka,UAAW,eACrCla,EAAOka,UAAW,eAAiB,EAAG,aAExCoB,EAAQ,UACRvB,EAAU,CACTuB,MAAO,WACN,OAAOA,GAERC,OAAQ,WAEP,OADAC,EAAS3V,KAAMvE,WAAY0Y,KAAM1Y,WAC1BtE,MAERye,QAAS,SAAUtb,GAClB,OAAO4Z,EAAQE,KAAM,KAAM9Z,IAI5Bub,KAAM,WACL,IAAIC,EAAMra,UAEV,OAAOtB,EAAOmb,SAAU,SAAUS,GACjC5b,EAAOkB,KAAMma,EAAQ,SAAU7W,EAAIqX,GAGlC,IAAI1b,EAAK9B,EAAYsd,EAAKE,EAAO,MAAWF,EAAKE,EAAO,IAKxDL,EAAUK,EAAO,IAAO,WACvB,IAAIC,EAAW3b,GAAMA,EAAGxC,MAAOX,KAAMsE,WAChCwa,GAAYzd,EAAYyd,EAAS/B,SACrC+B,EAAS/B,UACPgC,SAAUH,EAASI,QACnBnW,KAAM+V,EAASjC,SACfK,KAAM4B,EAAShC,QAEjBgC,EAAUC,EAAO,GAAM,QACtB7e,KACAmD,EAAK,CAAE2b,GAAaxa,eAKxBqa,EAAM,OACH5B,WAELE,KAAM,SAAUgC,EAAaC,EAAYC,GACxC,IAAIC,EAAW,EACf,SAASzC,EAAS0C,EAAOb,EAAU1P,EAASwQ,GAC3C,OAAO,WACN,IAAIC,EAAOvf,KACV2U,EAAOrQ,UACPkb,EAAa,WACZ,IAAIV,EAAU7B,EAKd,KAAKoC,EAAQD,GAAb,CAQA,IAJAN,EAAWhQ,EAAQnO,MAAO4e,EAAM5K,MAId6J,EAASzB,UAC1B,MAAM,IAAI0C,UAAW,4BAOtBxC,EAAO6B,IAKgB,iBAAbA,GACY,mBAAbA,IACRA,EAAS7B,KAGL5b,EAAY4b,GAGXqC,EACJrC,EAAKxc,KACJqe,EACAnC,EAASyC,EAAUZ,EAAUlC,EAAUgD,GACvC3C,EAASyC,EAAUZ,EAAUhC,EAAS8C,KAOvCF,IAEAnC,EAAKxc,KACJqe,EACAnC,EAASyC,EAAUZ,EAAUlC,EAAUgD,GACvC3C,EAASyC,EAAUZ,EAAUhC,EAAS8C,GACtC3C,EAASyC,EAAUZ,EAAUlC,EAC5BkC,EAASkB,eASP5Q,IAAYwN,IAChBiD,OAAOzZ,EACP6O,EAAO,CAAEmK,KAKRQ,GAAWd,EAASmB,aAAeJ,EAAM5K,MAK7CiL,EAAUN,EACTE,EACA,WACC,IACCA,IACC,MAAQ/S,GAEJzJ,EAAOmb,SAAS0B,eACpB7c,EAAOmb,SAAS0B,cAAepT,EAC9BmT,EAAQE,YAMQV,GAAbC,EAAQ,IAIPvQ,IAAY0N,IAChB+C,OAAOzZ,EACP6O,EAAO,CAAElI,IAGV+R,EAASuB,WAAYR,EAAM5K,MAS3B0K,EACJO,KAKK5c,EAAOmb,SAAS6B,eACpBJ,EAAQE,WAAa9c,EAAOmb,SAAS6B,gBAEtCjgB,EAAOkgB,WAAYL,KAKtB,OAAO5c,EAAOmb,SAAU,SAAUS,GAGjCP,EAAQ,GAAK,GAAI1C,IAChBgB,EACC,EACAiC,EACAvd,EAAY8d,GACXA,EACA7C,EACDsC,EAASc,aAKXrB,EAAQ,GAAK,GAAI1C,IAChBgB,EACC,EACAiC,EACAvd,EAAY4d,GACXA,EACA3C,IAKH+B,EAAQ,GAAK,GAAI1C,IAChBgB,EACC,EACAiC,EACAvd,EAAY6d,GACXA,EACA1C,MAGAO,WAKLA,QAAS,SAAUzb,GAClB,OAAc,MAAPA,EAAc0B,EAAOmC,OAAQ7D,EAAKyb,GAAYA,IAGvDyB,EAAW,GAkEZ,OA/DAxb,EAAOkB,KAAMma,EAAQ,SAAUlc,EAAG0c,GACjC,IAAIrV,EAAOqV,EAAO,GACjBqB,EAAcrB,EAAO,GAKtB9B,EAAS8B,EAAO,IAAQrV,EAAKmS,IAGxBuE,GACJ1W,EAAKmS,IACJ,WAIC2C,EAAQ4B,GAKT7B,EAAQ,EAAIlc,GAAK,GAAI6b,QAIrBK,EAAQ,EAAIlc,GAAK,GAAI6b,QAGrBK,EAAQ,GAAK,GAAIJ,KAGjBI,EAAQ,GAAK,GAAIJ,MAOnBzU,EAAKmS,IAAKkD,EAAO,GAAIjB,MAKrBY,EAAUK,EAAO,IAAQ,WAExB,OADAL,EAAUK,EAAO,GAAM,QAAU7e,OAASwe,OAAW1Y,EAAY9F,KAAMsE,WAChEtE,MAMRwe,EAAUK,EAAO,GAAM,QAAWrV,EAAK0U,WAIxCnB,EAAQA,QAASyB,GAGZJ,GACJA,EAAK3d,KAAM+d,EAAUA,GAIfA,GAIR2B,KAAM,SAAUC,GACf,IAGCC,EAAY/b,UAAUhB,OAGtBnB,EAAIke,EAGJC,EAAkB1a,MAAOzD,GACzBoe,EAAgBjgB,EAAMG,KAAM6D,WAG5Bkc,EAAUxd,EAAOmb,WAGjBsC,EAAa,SAAUte,GACtB,OAAO,SAAUgF,GAChBmZ,EAAiBne,GAAMnC,KACvBugB,EAAepe,GAAyB,EAAnBmC,UAAUhB,OAAahD,EAAMG,KAAM6D,WAAc6C,IAC5DkZ,GACTG,EAAQb,YAAaW,EAAiBC,KAM1C,GAAKF,GAAa,IACjB3D,EAAY0D,EAAaI,EAAQ3X,KAAM4X,EAAYte,IAAMwa,QAAS6D,EAAQ5D,QACxEyD,GAGuB,YAApBG,EAAQlC,SACZjd,EAAYkf,EAAepe,IAAOoe,EAAepe,GAAI8a,OAErD,OAAOuD,EAAQvD,OAKjB,MAAQ9a,IACPua,EAAY6D,EAAepe,GAAKse,EAAYte,GAAKqe,EAAQ5D,QAG1D,OAAO4D,EAAQzD,aAOjB,IAAI2D,EAAc,yDAElB1d,EAAOmb,SAAS0B,cAAgB,SAAUzZ,EAAOua,GAI3C5gB,EAAO6gB,SAAW7gB,EAAO6gB,QAAQC,MAAQza,GAASsa,EAAYjT,KAAMrH,EAAMf,OAC9EtF,EAAO6gB,QAAQC,KAAM,8BAAgCza,EAAM0a,QAAS1a,EAAMua,MAAOA,IAOnF3d,EAAO+d,eAAiB,SAAU3a,GACjCrG,EAAOkgB,WAAY,WAClB,MAAM7Z,KAQR,IAAI4a,EAAYhe,EAAOmb,WAkDvB,SAAS8C,IACRrhB,EAASshB,oBAAqB,mBAAoBD,GAClDlhB,EAAOmhB,oBAAqB,OAAQD,GACpCje,EAAO+X,QAnDR/X,EAAOG,GAAG4X,MAAQ,SAAU5X,GAY3B,OAVA6d,EACE/D,KAAM9Z,GAKNsb,SAAO,SAAUrY,GACjBpD,EAAO+d,eAAgB3a,KAGlBpG,MAGRgD,EAAOmC,OAAQ,CAGdgB,SAAS,EAITgb,UAAW,EAGXpG,MAAO,SAAUqG,KAGF,IAATA,IAAkBpe,EAAOme,UAAYne,EAAOmD,WAKjDnD,EAAOmD,SAAU,KAGZib,GAAsC,IAAnBpe,EAAOme,WAK/BH,EAAUrB,YAAa/f,EAAU,CAAEoD,OAIrCA,EAAO+X,MAAMkC,KAAO+D,EAAU/D,KAaD,aAAxBrd,EAASyhB,YACa,YAAxBzhB,EAASyhB,aAA6BzhB,EAASkQ,gBAAgBwR,SAGjEvhB,EAAOkgB,WAAYjd,EAAO+X,QAK1Bnb,EAASuQ,iBAAkB,mBAAoB8Q,GAG/ClhB,EAAOoQ,iBAAkB,OAAQ8Q,IAQlC,IAAIM,EAAS,SAAUzd,EAAOX,EAAImL,EAAKnH,EAAOqa,EAAWC,EAAUC,GAClE,IAAIvf,EAAI,EACP2C,EAAMhB,EAAMR,OACZqe,EAAc,MAAPrT,EAGR,GAAuB,WAAlBxL,EAAQwL,GAEZ,IAAMnM,KADNqf,GAAY,EACDlT,EACViT,EAAQzd,EAAOX,EAAIhB,EAAGmM,EAAKnM,IAAK,EAAMsf,EAAUC,QAI3C,QAAe5b,IAAVqB,IACXqa,GAAY,EAENngB,EAAY8F,KACjBua,GAAM,GAGFC,IAGCD,GACJve,EAAG1C,KAAMqD,EAAOqD,GAChBhE,EAAK,OAILwe,EAAOxe,EACPA,EAAK,SAAUkB,EAAMud,EAAMza,GAC1B,OAAOwa,EAAKlhB,KAAMuC,EAAQqB,GAAQ8C,MAKhChE,GACJ,KAAQhB,EAAI2C,EAAK3C,IAChBgB,EACCW,EAAO3B,GAAKmM,EAAKoT,EAChBva,EACAA,EAAM1G,KAAMqD,EAAO3B,GAAKA,EAAGgB,EAAIW,EAAO3B,GAAKmM,KAMhD,OAAKkT,EACG1d,EAIH6d,EACGxe,EAAG1C,KAAMqD,GAGVgB,EAAM3B,EAAIW,EAAO,GAAKwK,GAAQmT,GAKlCI,EAAY,QACfC,EAAa,YAGd,SAASC,EAAYC,EAAMC,GAC1B,OAAOA,EAAOC,cAMf,SAASC,EAAWC,GACnB,OAAOA,EAAOlc,QAAS2b,EAAW,OAAQ3b,QAAS4b,EAAYC,GAEhE,IAAIM,EAAa,SAAUC,GAQ1B,OAA0B,IAAnBA,EAAM/gB,UAAqC,IAAnB+gB,EAAM/gB,YAAsB+gB,EAAM/gB,UAMlE,SAASghB,IACRviB,KAAK+F,QAAU/C,EAAO+C,QAAUwc,EAAKC,MAGtCD,EAAKC,IAAM,EAEXD,EAAKhf,UAAY,CAEhB8K,MAAO,SAAUiU,GAGhB,IAAInb,EAAQmb,EAAOtiB,KAAK+F,SA4BxB,OAzBMoB,IACLA,EAAQ,GAKHkb,EAAYC,KAIXA,EAAM/gB,SACV+gB,EAAOtiB,KAAK+F,SAAYoB,EAMxB/G,OAAOqiB,eAAgBH,EAAOtiB,KAAK+F,QAAS,CAC3CoB,MAAOA,EACPub,cAAc,MAMXvb,GAERwb,IAAK,SAAUL,EAAOM,EAAMzb,GAC3B,IAAI0b,EACHxU,EAAQrO,KAAKqO,MAAOiU,GAIrB,GAAqB,iBAATM,EACXvU,EAAO8T,EAAWS,IAAWzb,OAM7B,IAAM0b,KAAQD,EACbvU,EAAO8T,EAAWU,IAAWD,EAAMC,GAGrC,OAAOxU,GAER1K,IAAK,SAAU2e,EAAOhU,GACrB,YAAexI,IAARwI,EACNtO,KAAKqO,MAAOiU,GAGZA,EAAOtiB,KAAK+F,UAAauc,EAAOtiB,KAAK+F,SAAWoc,EAAW7T,KAE7DiT,OAAQ,SAAUe,EAAOhU,EAAKnH,GAa7B,YAAarB,IAARwI,GACCA,GAAsB,iBAARA,QAAgCxI,IAAVqB,EAElCnH,KAAK2D,IAAK2e,EAAOhU,IASzBtO,KAAK2iB,IAAKL,EAAOhU,EAAKnH,QAILrB,IAAVqB,EAAsBA,EAAQmH,IAEtCyP,OAAQ,SAAUuE,EAAOhU,GACxB,IAAInM,EACHkM,EAAQiU,EAAOtiB,KAAK+F,SAErB,QAAeD,IAAVuI,EAAL,CAIA,QAAavI,IAARwI,EAAoB,CAkBxBnM,GAXCmM,EAJI1I,MAAMC,QAASyI,GAIbA,EAAIlK,IAAK+d,IAEf7T,EAAM6T,EAAW7T,MAIJD,EACZ,CAAEC,GACAA,EAAIxB,MAAOuP,IAAmB,IAG1B/Y,OAER,MAAQnB,WACAkM,EAAOC,EAAKnM,UAKR2D,IAARwI,GAAqBtL,EAAOyD,cAAe4H,MAM1CiU,EAAM/gB,SACV+gB,EAAOtiB,KAAK+F,cAAYD,SAEjBwc,EAAOtiB,KAAK+F,YAItB+c,QAAS,SAAUR,GAClB,IAAIjU,EAAQiU,EAAOtiB,KAAK+F,SACxB,YAAiBD,IAAVuI,IAAwBrL,EAAOyD,cAAe4H,KAGvD,IAAI0U,EAAW,IAAIR,EAEfS,EAAW,IAAIT,EAcfU,EAAS,gCACZC,EAAa,SA2Bd,SAASC,EAAU9e,EAAMiK,EAAKsU,GAC7B,IAAIvd,EA1Baud,EA8BjB,QAAc9c,IAAT8c,GAAwC,IAAlBve,EAAK9C,SAI/B,GAHA8D,EAAO,QAAUiJ,EAAIpI,QAASgd,EAAY,OAAQzb,cAG7B,iBAFrBmb,EAAOve,EAAK7B,aAAc6C,IAEM,CAC/B,IACCud,EAnCW,UADGA,EAoCEA,IA/BL,UAATA,IAIS,SAATA,EACG,KAIHA,KAAUA,EAAO,IACbA,EAGJK,EAAOxV,KAAMmV,GACVQ,KAAKC,MAAOT,GAGbA,GAeH,MAAQnW,IAGVuW,EAASL,IAAKte,EAAMiK,EAAKsU,QAEzBA,OAAO9c,EAGT,OAAO8c,EAGR5f,EAAOmC,OAAQ,CACd2d,QAAS,SAAUze,GAClB,OAAO2e,EAASF,QAASze,IAAU0e,EAASD,QAASze,IAGtDue,KAAM,SAAUve,EAAMgB,EAAMud,GAC3B,OAAOI,EAASzB,OAAQld,EAAMgB,EAAMud,IAGrCU,WAAY,SAAUjf,EAAMgB,GAC3B2d,EAASjF,OAAQ1Z,EAAMgB,IAKxBke,MAAO,SAAUlf,EAAMgB,EAAMud,GAC5B,OAAOG,EAASxB,OAAQld,EAAMgB,EAAMud,IAGrCY,YAAa,SAAUnf,EAAMgB,GAC5B0d,EAAShF,OAAQ1Z,EAAMgB,MAIzBrC,EAAOG,GAAGgC,OAAQ,CACjByd,KAAM,SAAUtU,EAAKnH,GACpB,IAAIhF,EAAGkD,EAAMud,EACZve,EAAOrE,KAAM,GACb6O,EAAQxK,GAAQA,EAAKuF,WAGtB,QAAa9D,IAARwI,EAAoB,CACxB,GAAKtO,KAAKsD,SACTsf,EAAOI,EAASrf,IAAKU,GAEE,IAAlBA,EAAK9C,WAAmBwhB,EAASpf,IAAKU,EAAM,iBAAmB,CACnElC,EAAI0M,EAAMvL,OACV,MAAQnB,IAIF0M,EAAO1M,IAEsB,KADjCkD,EAAOwJ,EAAO1M,GAAIkD,MACRxE,QAAS,WAClBwE,EAAO8c,EAAW9c,EAAK/E,MAAO,IAC9B6iB,EAAU9e,EAAMgB,EAAMud,EAAMvd,KAI/B0d,EAASJ,IAAKte,EAAM,gBAAgB,GAItC,OAAOue,EAIR,MAAoB,iBAARtU,EACJtO,KAAKkE,KAAM,WACjB8e,EAASL,IAAK3iB,KAAMsO,KAIfiT,EAAQvhB,KAAM,SAAUmH,GAC9B,IAAIyb,EAOJ,GAAKve,QAAkByB,IAAVqB,EAKZ,YAAcrB,KADd8c,EAAOI,EAASrf,IAAKU,EAAMiK,IAEnBsU,OAMM9c,KADd8c,EAAOO,EAAU9e,EAAMiK,IAEfsU,OAIR,EAID5iB,KAAKkE,KAAM,WAGV8e,EAASL,IAAK3iB,KAAMsO,EAAKnH,MAExB,KAAMA,EAA0B,EAAnB7C,UAAUhB,OAAY,MAAM,IAG7CggB,WAAY,SAAUhV,GACrB,OAAOtO,KAAKkE,KAAM,WACjB8e,EAASjF,OAAQ/d,KAAMsO,QAM1BtL,EAAOmC,OAAQ,CACduY,MAAO,SAAUrZ,EAAM1C,EAAMihB,GAC5B,IAAIlF,EAEJ,GAAKrZ,EAYJ,OAXA1C,GAASA,GAAQ,MAAS,QAC1B+b,EAAQqF,EAASpf,IAAKU,EAAM1C,GAGvBihB,KACElF,GAAS9X,MAAMC,QAAS+c,GAC7BlF,EAAQqF,EAASxB,OAAQld,EAAM1C,EAAMqB,EAAO2D,UAAWic,IAEvDlF,EAAM9c,KAAMgiB,IAGPlF,GAAS,IAIlB+F,QAAS,SAAUpf,EAAM1C,GACxBA,EAAOA,GAAQ,KAEf,IAAI+b,EAAQ1a,EAAO0a,MAAOrZ,EAAM1C,GAC/B+hB,EAAchG,EAAMpa,OACpBH,EAAKua,EAAMlP,QACXmV,EAAQ3gB,EAAO4gB,YAAavf,EAAM1C,GAMvB,eAAPwB,IACJA,EAAKua,EAAMlP,QACXkV,KAGIvgB,IAIU,OAATxB,GACJ+b,EAAM3L,QAAS,qBAIT4R,EAAME,KACb1gB,EAAG1C,KAAM4D,EApBF,WACNrB,EAAOygB,QAASpf,EAAM1C,IAmBFgiB,KAGhBD,GAAeC,GACpBA,EAAM1N,MAAM2H,QAKdgG,YAAa,SAAUvf,EAAM1C,GAC5B,IAAI2M,EAAM3M,EAAO,aACjB,OAAOohB,EAASpf,IAAKU,EAAMiK,IAASyU,EAASxB,OAAQld,EAAMiK,EAAK,CAC/D2H,MAAOjT,EAAOka,UAAW,eAAgBvB,IAAK,WAC7CoH,EAAShF,OAAQ1Z,EAAM,CAAE1C,EAAO,QAAS2M,WAM7CtL,EAAOG,GAAGgC,OAAQ,CACjBuY,MAAO,SAAU/b,EAAMihB,GACtB,IAAIkB,EAAS,EAQb,MANqB,iBAATniB,IACXihB,EAAOjhB,EACPA,EAAO,KACPmiB,KAGIxf,UAAUhB,OAASwgB,EAChB9gB,EAAO0a,MAAO1d,KAAM,GAAK2B,QAGjBmE,IAAT8c,EACN5iB,KACAA,KAAKkE,KAAM,WACV,IAAIwZ,EAAQ1a,EAAO0a,MAAO1d,KAAM2B,EAAMihB,GAGtC5f,EAAO4gB,YAAa5jB,KAAM2B,GAEZ,OAATA,GAAgC,eAAf+b,EAAO,IAC5B1a,EAAOygB,QAASzjB,KAAM2B,MAI1B8hB,QAAS,SAAU9hB,GAClB,OAAO3B,KAAKkE,KAAM,WACjBlB,EAAOygB,QAASzjB,KAAM2B,MAGxBoiB,WAAY,SAAUpiB,GACrB,OAAO3B,KAAK0d,MAAO/b,GAAQ,KAAM,KAKlCob,QAAS,SAAUpb,EAAML,GACxB,IAAIwP,EACHkT,EAAQ,EACRC,EAAQjhB,EAAOmb,WACflM,EAAWjS,KACXmC,EAAInC,KAAKsD,OACTqZ,EAAU,aACCqH,GACTC,EAAMtE,YAAa1N,EAAU,CAAEA,KAIb,iBAATtQ,IACXL,EAAMK,EACNA,OAAOmE,GAERnE,EAAOA,GAAQ,KAEf,MAAQQ,KACP2O,EAAMiS,EAASpf,IAAKsO,EAAU9P,GAAKR,EAAO,gBAC9BmP,EAAImF,QACf+N,IACAlT,EAAImF,MAAM0F,IAAKgB,IAIjB,OADAA,IACOsH,EAAMlH,QAASzb,MAGxB,IAAI4iB,GAAO,sCAA0CC,OAEjDC,GAAU,IAAIra,OAAQ,iBAAmBma,GAAO,cAAe,KAG/DG,GAAY,CAAE,MAAO,QAAS,SAAU,QAExCvU,GAAkBlQ,EAASkQ,gBAI1BwU,GAAa,SAAUjgB,GACzB,OAAOrB,EAAOyF,SAAUpE,EAAK6I,cAAe7I,IAE7CkgB,GAAW,CAAEA,UAAU,GAOnBzU,GAAgB0U,cACpBF,GAAa,SAAUjgB,GACtB,OAAOrB,EAAOyF,SAAUpE,EAAK6I,cAAe7I,IAC3CA,EAAKmgB,YAAaD,MAAelgB,EAAK6I,gBAG1C,IAAIuX,GAAqB,SAAUpgB,EAAMsK,GAOvC,MAA8B,UAH9BtK,EAAOsK,GAAMtK,GAGDqgB,MAAMC,SACM,KAAvBtgB,EAAKqgB,MAAMC,SAMXL,GAAYjgB,IAEsB,SAAlCrB,EAAO4hB,IAAKvgB,EAAM,YAKrB,SAASwgB,GAAWxgB,EAAMwe,EAAMiC,EAAYC,GAC3C,IAAIC,EAAUC,EACbC,EAAgB,GAChBC,EAAeJ,EACd,WACC,OAAOA,EAAM9V,OAEd,WACC,OAAOjM,EAAO4hB,IAAKvgB,EAAMwe,EAAM,KAEjCuC,EAAUD,IACVE,EAAOP,GAAcA,EAAY,KAAS9hB,EAAOsiB,UAAWzC,GAAS,GAAK,MAG1E0C,EAAgBlhB,EAAK9C,WAClByB,EAAOsiB,UAAWzC,IAAmB,OAATwC,IAAkBD,IAChDhB,GAAQjX,KAAMnK,EAAO4hB,IAAKvgB,EAAMwe,IAElC,GAAK0C,GAAiBA,EAAe,KAAQF,EAAO,CAInDD,GAAoB,EAGpBC,EAAOA,GAAQE,EAAe,GAG9BA,GAAiBH,GAAW,EAE5B,MAAQF,IAIPliB,EAAO0hB,MAAOrgB,EAAMwe,EAAM0C,EAAgBF,IACnC,EAAIJ,IAAY,GAAMA,EAAQE,IAAiBC,GAAW,MAAW,IAC3EF,EAAgB,GAEjBK,GAAgCN,EAIjCM,GAAgC,EAChCviB,EAAO0hB,MAAOrgB,EAAMwe,EAAM0C,EAAgBF,GAG1CP,EAAaA,GAAc,GAgB5B,OAbKA,IACJS,GAAiBA,IAAkBH,GAAW,EAG9CJ,EAAWF,EAAY,GACtBS,GAAkBT,EAAY,GAAM,GAAMA,EAAY,IACrDA,EAAY,GACTC,IACJA,EAAMM,KAAOA,EACbN,EAAM1Q,MAAQkR,EACdR,EAAM/f,IAAMggB,IAGPA,EAIR,IAAIQ,GAAoB,GAyBxB,SAASC,GAAUxT,EAAUyT,GAO5B,IANA,IAAIf,EAAStgB,EAxBcA,EACvB0T,EACH7V,EACAmK,EACAsY,EAqBAgB,EAAS,GACTlK,EAAQ,EACRnY,EAAS2O,EAAS3O,OAGXmY,EAAQnY,EAAQmY,KACvBpX,EAAO4N,EAAUwJ,IACNiJ,QAIXC,EAAUtgB,EAAKqgB,MAAMC,QAChBe,GAKa,SAAZf,IACJgB,EAAQlK,GAAUsH,EAASpf,IAAKU,EAAM,YAAe,KAC/CshB,EAAQlK,KACbpX,EAAKqgB,MAAMC,QAAU,KAGK,KAAvBtgB,EAAKqgB,MAAMC,SAAkBF,GAAoBpgB,KACrDshB,EAAQlK,IA7CVkJ,EAFAziB,EADG6V,OAAAA,EACH7V,GAF0BmC,EAiDaA,GA/C5B6I,cACXb,EAAWhI,EAAKgI,UAChBsY,EAAUa,GAAmBnZ,MAM9B0L,EAAO7V,EAAI0jB,KAAKjjB,YAAaT,EAAII,cAAe+J,IAChDsY,EAAU3hB,EAAO4hB,IAAK7M,EAAM,WAE5BA,EAAKnV,WAAWC,YAAakV,GAEZ,SAAZ4M,IACJA,EAAU,SAEXa,GAAmBnZ,GAAasY,MAkCb,SAAZA,IACJgB,EAAQlK,GAAU,OAGlBsH,EAASJ,IAAKte,EAAM,UAAWsgB,KAMlC,IAAMlJ,EAAQ,EAAGA,EAAQnY,EAAQmY,IACR,MAAnBkK,EAAQlK,KACZxJ,EAAUwJ,GAAQiJ,MAAMC,QAAUgB,EAAQlK,IAI5C,OAAOxJ,EAGRjP,EAAOG,GAAGgC,OAAQ,CACjBugB,KAAM,WACL,OAAOD,GAAUzlB,MAAM,IAExB6lB,KAAM,WACL,OAAOJ,GAAUzlB,OAElB8lB,OAAQ,SAAUxH,GACjB,MAAsB,kBAAVA,EACJA,EAAQte,KAAK0lB,OAAS1lB,KAAK6lB,OAG5B7lB,KAAKkE,KAAM,WACZugB,GAAoBzkB,MACxBgD,EAAQhD,MAAO0lB,OAEf1iB,EAAQhD,MAAO6lB,YAKnB,IAUEE,GACAhV,GAXEiV,GAAiB,wBAEjBC,GAAW,iCAEXC,GAAc,qCAMhBH,GADcnmB,EAASumB,yBACRxjB,YAAa/C,EAAS0C,cAAe,SACpDyO,GAAQnR,EAAS0C,cAAe,UAM3BG,aAAc,OAAQ,SAC5BsO,GAAMtO,aAAc,UAAW,WAC/BsO,GAAMtO,aAAc,OAAQ,KAE5BsjB,GAAIpjB,YAAaoO,IAIjB3P,EAAQglB,WAAaL,GAAIM,WAAW,GAAOA,WAAW,GAAO7R,UAAUsB,QAIvEiQ,GAAI/U,UAAY,yBAChB5P,EAAQklB,iBAAmBP,GAAIM,WAAW,GAAO7R,UAAUuF,aAK3DgM,GAAI/U,UAAY,oBAChB5P,EAAQmlB,SAAWR,GAAIvR,UAKxB,IAAIgS,GAAU,CAKbC,MAAO,CAAE,EAAG,UAAW,YACvBC,IAAK,CAAE,EAAG,oBAAqB,uBAC/BC,GAAI,CAAE,EAAG,iBAAkB,oBAC3BC,GAAI,CAAE,EAAG,qBAAsB,yBAE/BC,SAAU,CAAE,EAAG,GAAI,KAYpB,SAASC,GAAQ5jB,EAAS2N,GAIzB,IAAI9M,EAYJ,OATCA,EAD4C,oBAAjCb,EAAQoK,qBACbpK,EAAQoK,qBAAsBuD,GAAO,KAEI,oBAA7B3N,EAAQ+K,iBACpB/K,EAAQ+K,iBAAkB4C,GAAO,KAGjC,QAGM/K,IAAR+K,GAAqBA,GAAOxE,EAAUnJ,EAAS2N,GAC5C7N,EAAOgB,MAAO,CAAEd,GAAWa,GAG5BA,EAKR,SAASgjB,GAAejjB,EAAOkjB,GAI9B,IAHA,IAAI7kB,EAAI,EACPoZ,EAAIzX,EAAMR,OAEHnB,EAAIoZ,EAAGpZ,IACd4gB,EAASJ,IACR7e,EAAO3B,GACP,cACC6kB,GAAejE,EAASpf,IAAKqjB,EAAa7kB,GAAK,eA1CnDqkB,GAAQS,MAAQT,GAAQU,MAAQV,GAAQW,SAAWX,GAAQY,QAAUZ,GAAQC,MAC7ED,GAAQa,GAAKb,GAAQI,GAGfxlB,EAAQmlB,SACbC,GAAQc,SAAWd,GAAQD,OAAS,CAAE,EAAG,+BAAgC,cA2C1E,IAAIxb,GAAQ,YAEZ,SAASwc,GAAezjB,EAAOZ,EAASskB,EAASC,EAAWC,GAO3D,IANA,IAAIrjB,EAAMyM,EAAKD,EAAK8W,EAAMC,EAAU7iB,EACnC8iB,EAAW3kB,EAAQijB,yBACnB2B,EAAQ,GACR3lB,EAAI,EACJoZ,EAAIzX,EAAMR,OAEHnB,EAAIoZ,EAAGpZ,IAGd,IAFAkC,EAAOP,EAAO3B,KAEQ,IAATkC,EAGZ,GAAwB,WAAnBvB,EAAQuB,GAIZrB,EAAOgB,MAAO8jB,EAAOzjB,EAAK9C,SAAW,CAAE8C,GAASA,QAG1C,GAAM0G,GAAM0C,KAAMpJ,GAIlB,CACNyM,EAAMA,GAAO+W,EAASllB,YAAaO,EAAQZ,cAAe,QAG1DuO,GAAQoV,GAAS9Y,KAAM9I,IAAU,CAAE,GAAI,KAAQ,GAAIoD,cACnDkgB,EAAOnB,GAAS3V,IAAS2V,GAAQK,SACjC/V,EAAIE,UAAY2W,EAAM,GAAM3kB,EAAO+kB,cAAe1jB,GAASsjB,EAAM,GAGjE5iB,EAAI4iB,EAAM,GACV,MAAQ5iB,IACP+L,EAAMA,EAAI0D,UAKXxR,EAAOgB,MAAO8jB,EAAOhX,EAAItE,aAGzBsE,EAAM+W,EAASnV,YAGXD,YAAc,QAzBlBqV,EAAMlnB,KAAMsC,EAAQ8kB,eAAgB3jB,IA+BvCwjB,EAASpV,YAAc,GAEvBtQ,EAAI,EACJ,MAAUkC,EAAOyjB,EAAO3lB,KAGvB,GAAKslB,IAAkD,EAArCzkB,EAAO6D,QAASxC,EAAMojB,GAClCC,GACJA,EAAQ9mB,KAAMyD,QAgBhB,GAXAujB,EAAWtD,GAAYjgB,GAGvByM,EAAMgW,GAAQe,EAASllB,YAAa0B,GAAQ,UAGvCujB,GACJb,GAAejW,GAIX0W,EAAU,CACdziB,EAAI,EACJ,MAAUV,EAAOyM,EAAK/L,KAChBmhB,GAAYzY,KAAMpJ,EAAK1C,MAAQ,KACnC6lB,EAAQ5mB,KAAMyD,GAMlB,OAAOwjB,EAIR,IAAII,GAAiB,sBAErB,SAASC,KACR,OAAO,EAGR,SAASC,KACR,OAAO,EASR,SAASC,GAAY/jB,EAAM1C,GAC1B,OAAS0C,IAMV,WACC,IACC,OAAOzE,EAAS6V,cACf,MAAQ4S,KATQC,KAAqC,UAAT3mB,GAY/C,SAAS4mB,GAAIlkB,EAAMmkB,EAAOvlB,EAAU2f,EAAMzf,EAAIslB,GAC7C,IAAIC,EAAQ/mB,EAGZ,GAAsB,iBAAV6mB,EAAqB,CAShC,IAAM7mB,IANmB,iBAAbsB,IAGX2f,EAAOA,GAAQ3f,EACfA,OAAW6C,GAEE0iB,EACbD,GAAIlkB,EAAM1C,EAAMsB,EAAU2f,EAAM4F,EAAO7mB,GAAQ8mB,GAEhD,OAAOpkB,EAsBR,GAnBa,MAARue,GAAsB,MAANzf,GAGpBA,EAAKF,EACL2f,EAAO3f,OAAW6C,GACD,MAAN3C,IACc,iBAAbF,GAGXE,EAAKyf,EACLA,OAAO9c,IAIP3C,EAAKyf,EACLA,EAAO3f,EACPA,OAAW6C,KAGD,IAAP3C,EACJA,EAAKglB,QACC,IAAMhlB,EACZ,OAAOkB,EAeR,OAZa,IAARokB,IACJC,EAASvlB,GACTA,EAAK,SAAUwlB,GAId,OADA3lB,IAAS4lB,IAAKD,GACPD,EAAO/nB,MAAOX,KAAMsE,aAIzB8C,KAAOshB,EAAOthB,OAAUshB,EAAOthB,KAAOpE,EAAOoE,SAE1C/C,EAAKH,KAAM,WACjBlB,EAAO2lB,MAAMhN,IAAK3b,KAAMwoB,EAAOrlB,EAAIyf,EAAM3f,KA+a3C,SAAS4lB,GAAgBla,EAAIhN,EAAMymB,GAG5BA,GAQNrF,EAASJ,IAAKhU,EAAIhN,GAAM,GACxBqB,EAAO2lB,MAAMhN,IAAKhN,EAAIhN,EAAM,CAC3BiO,WAAW,EACXd,QAAS,SAAU6Z,GAClB,IAAIG,EAAUpV,EACbqV,EAAQhG,EAASpf,IAAK3D,KAAM2B,GAE7B,GAAyB,EAAlBgnB,EAAMK,WAAmBhpB,KAAM2B,IAKrC,GAAMonB,EAAMzlB,QAuCEN,EAAO2lB,MAAMrJ,QAAS3d,IAAU,IAAKsnB,cAClDN,EAAMO,uBArBN,GAdAH,EAAQzoB,EAAMG,KAAM6D,WACpBye,EAASJ,IAAK3iB,KAAM2B,EAAMonB,GAK1BD,EAAWV,EAAYpoB,KAAM2B,GAC7B3B,KAAM2B,KAEDonB,KADLrV,EAASqP,EAASpf,IAAK3D,KAAM2B,KACJmnB,EACxB/F,EAASJ,IAAK3iB,KAAM2B,GAAM,GAE1B+R,EAAS,GAELqV,IAAUrV,EAWd,OARAiV,EAAMQ,2BACNR,EAAMS,iBAOC1V,GAAUA,EAAOvM,WAef4hB,EAAMzlB,SAGjByf,EAASJ,IAAK3iB,KAAM2B,EAAM,CACzBwF,MAAOnE,EAAO2lB,MAAMU,QAInBrmB,EAAOmC,OAAQ4jB,EAAO,GAAK/lB,EAAOsmB,MAAM/lB,WACxCwlB,EAAMzoB,MAAO,GACbN,QAKF2oB,EAAMQ,qCA/E0BrjB,IAA7Bid,EAASpf,IAAKgL,EAAIhN,IACtBqB,EAAO2lB,MAAMhN,IAAKhN,EAAIhN,EAAMumB,IA5a/BllB,EAAO2lB,MAAQ,CAEdnpB,OAAQ,GAERmc,IAAK,SAAUtX,EAAMmkB,EAAO1Z,EAAS8T,EAAM3f,GAE1C,IAAIsmB,EAAaC,EAAa1Y,EAC7B2Y,EAAQC,EAAGC,EACXrK,EAASsK,EAAUjoB,EAAMkoB,EAAYC,EACrCC,EAAWhH,EAASpf,IAAKU,GAG1B,GAAMge,EAAYhe,GAAlB,CAKKyK,EAAQA,UAEZA,GADAya,EAAcza,GACQA,QACtB7L,EAAWsmB,EAAYtmB,UAKnBA,GACJD,EAAO2N,KAAKM,gBAAiBnB,GAAiB7M,GAIzC6L,EAAQ1H,OACb0H,EAAQ1H,KAAOpE,EAAOoE,SAIfqiB,EAASM,EAASN,UACzBA,EAASM,EAASN,OAASrpB,OAAO4pB,OAAQ,QAEnCR,EAAcO,EAASE,UAC9BT,EAAcO,EAASE,OAAS,SAAUxd,GAIzC,MAAyB,oBAAXzJ,GAA0BA,EAAO2lB,MAAMuB,YAAczd,EAAE9K,KACpEqB,EAAO2lB,MAAMwB,SAASxpB,MAAO0D,EAAMC,gBAAcwB,IAMpD4jB,GADAlB,GAAUA,GAAS,IAAK1b,MAAOuP,IAAmB,CAAE,KAC1C/Y,OACV,MAAQomB,IAEP/nB,EAAOmoB,GADPhZ,EAAMmX,GAAe9a,KAAMqb,EAAOkB,KAAS,IACpB,GACvBG,GAAe/Y,EAAK,IAAO,IAAKvJ,MAAO,KAAMtC,OAGvCtD,IAKN2d,EAAUtc,EAAO2lB,MAAMrJ,QAAS3d,IAAU,GAG1CA,GAASsB,EAAWqc,EAAQ2J,aAAe3J,EAAQ8K,WAAczoB,EAGjE2d,EAAUtc,EAAO2lB,MAAMrJ,QAAS3d,IAAU,GAG1CgoB,EAAY3mB,EAAOmC,OAAQ,CAC1BxD,KAAMA,EACNmoB,SAAUA,EACVlH,KAAMA,EACN9T,QAASA,EACT1H,KAAM0H,EAAQ1H,KACdnE,SAAUA,EACV6H,aAAc7H,GAAYD,EAAOgP,KAAKlF,MAAMhC,aAAa2C,KAAMxK,GAC/D2M,UAAWia,EAAWhc,KAAM,MAC1B0b,IAGKK,EAAWH,EAAQ9nB,OAC1BioB,EAAWH,EAAQ9nB,GAAS,IACnB0oB,cAAgB,EAGnB/K,EAAQgL,QACiD,IAA9DhL,EAAQgL,MAAM7pB,KAAM4D,EAAMue,EAAMiH,EAAYL,IAEvCnlB,EAAK8L,kBACT9L,EAAK8L,iBAAkBxO,EAAM6nB,IAK3BlK,EAAQ3D,MACZ2D,EAAQ3D,IAAIlb,KAAM4D,EAAMslB,GAElBA,EAAU7a,QAAQ1H,OACvBuiB,EAAU7a,QAAQ1H,KAAO0H,EAAQ1H,OAK9BnE,EACJ2mB,EAAS1kB,OAAQ0kB,EAASS,gBAAiB,EAAGV,GAE9CC,EAAShpB,KAAM+oB,GAIhB3mB,EAAO2lB,MAAMnpB,OAAQmC,IAAS,KAMhCoc,OAAQ,SAAU1Z,EAAMmkB,EAAO1Z,EAAS7L,EAAUsnB,GAEjD,IAAIxlB,EAAGylB,EAAW1Z,EACjB2Y,EAAQC,EAAGC,EACXrK,EAASsK,EAAUjoB,EAAMkoB,EAAYC,EACrCC,EAAWhH,EAASD,QAASze,IAAU0e,EAASpf,IAAKU,GAEtD,GAAM0lB,IAAeN,EAASM,EAASN,QAAvC,CAMAC,GADAlB,GAAUA,GAAS,IAAK1b,MAAOuP,IAAmB,CAAE,KAC1C/Y,OACV,MAAQomB,IAMP,GAJA/nB,EAAOmoB,GADPhZ,EAAMmX,GAAe9a,KAAMqb,EAAOkB,KAAS,IACpB,GACvBG,GAAe/Y,EAAK,IAAO,IAAKvJ,MAAO,KAAMtC,OAGvCtD,EAAN,CAOA2d,EAAUtc,EAAO2lB,MAAMrJ,QAAS3d,IAAU,GAE1CioB,EAAWH,EADX9nB,GAASsB,EAAWqc,EAAQ2J,aAAe3J,EAAQ8K,WAAczoB,IACpC,GAC7BmP,EAAMA,EAAK,IACV,IAAI/G,OAAQ,UAAY8f,EAAWhc,KAAM,iBAAoB,WAG9D2c,EAAYzlB,EAAI6kB,EAAStmB,OACzB,MAAQyB,IACP4kB,EAAYC,EAAU7kB,IAEfwlB,GAAeT,IAAaH,EAAUG,UACzChb,GAAWA,EAAQ1H,OAASuiB,EAAUviB,MACtC0J,IAAOA,EAAIrD,KAAMkc,EAAU/Z,YAC3B3M,GAAYA,IAAa0mB,EAAU1mB,WACxB,OAAbA,IAAqB0mB,EAAU1mB,YAChC2mB,EAAS1kB,OAAQH,EAAG,GAEf4kB,EAAU1mB,UACd2mB,EAASS,gBAEL/K,EAAQvB,QACZuB,EAAQvB,OAAOtd,KAAM4D,EAAMslB,IAOzBa,IAAcZ,EAAStmB,SACrBgc,EAAQmL,WACkD,IAA/DnL,EAAQmL,SAAShqB,KAAM4D,EAAMwlB,EAAYE,EAASE,SAElDjnB,EAAO0nB,YAAarmB,EAAM1C,EAAMooB,EAASE,eAGnCR,EAAQ9nB,SA1Cf,IAAMA,KAAQ8nB,EACbzmB,EAAO2lB,MAAM5K,OAAQ1Z,EAAM1C,EAAO6mB,EAAOkB,GAAK5a,EAAS7L,GAAU,GA8C/DD,EAAOyD,cAAegjB,IAC1B1G,EAAShF,OAAQ1Z,EAAM,mBAIzB8lB,SAAU,SAAUQ,GAEnB,IAAIxoB,EAAG4C,EAAGhB,EAAK+Q,EAAS6U,EAAWiB,EAClCjW,EAAO,IAAI/O,MAAOtB,UAAUhB,QAG5BqlB,EAAQ3lB,EAAO2lB,MAAMkC,IAAKF,GAE1Bf,GACC7G,EAASpf,IAAK3D,KAAM,WAAcI,OAAO4pB,OAAQ,OAC/CrB,EAAMhnB,OAAU,GACnB2d,EAAUtc,EAAO2lB,MAAMrJ,QAASqJ,EAAMhnB,OAAU,GAKjD,IAFAgT,EAAM,GAAMgU,EAENxmB,EAAI,EAAGA,EAAImC,UAAUhB,OAAQnB,IAClCwS,EAAMxS,GAAMmC,UAAWnC,GAMxB,GAHAwmB,EAAMmC,eAAiB9qB,MAGlBsf,EAAQyL,cAA2D,IAA5CzL,EAAQyL,YAAYtqB,KAAMT,KAAM2oB,GAA5D,CAKAiC,EAAe5nB,EAAO2lB,MAAMiB,SAASnpB,KAAMT,KAAM2oB,EAAOiB,GAGxDznB,EAAI,EACJ,OAAU2S,EAAU8V,EAAczoB,QAAYwmB,EAAMqC,uBAAyB,CAC5ErC,EAAMsC,cAAgBnW,EAAQzQ,KAE9BU,EAAI,EACJ,OAAU4kB,EAAY7U,EAAQ8U,SAAU7kB,QACtC4jB,EAAMuC,gCAIDvC,EAAMwC,aAAsC,IAAxBxB,EAAU/Z,YACnC+Y,EAAMwC,WAAW1d,KAAMkc,EAAU/Z,aAEjC+Y,EAAMgB,UAAYA,EAClBhB,EAAM/F,KAAO+G,EAAU/G,UAKV9c,KAHb/B,IAAUf,EAAO2lB,MAAMrJ,QAASqK,EAAUG,WAAc,IAAKG,QAC5DN,EAAU7a,SAAUnO,MAAOmU,EAAQzQ,KAAMsQ,MAGT,KAAzBgU,EAAMjV,OAAS3P,KACrB4kB,EAAMS,iBACNT,EAAMO,oBAYX,OAJK5J,EAAQ8L,cACZ9L,EAAQ8L,aAAa3qB,KAAMT,KAAM2oB,GAG3BA,EAAMjV,SAGdkW,SAAU,SAAUjB,EAAOiB,GAC1B,IAAIznB,EAAGwnB,EAAWvX,EAAKiZ,EAAiBC,EACvCV,EAAe,GACfP,EAAgBT,EAASS,cACzBpb,EAAM0Z,EAAMljB,OAGb,GAAK4kB,GAIJpb,EAAI1N,YAOc,UAAfonB,EAAMhnB,MAAoC,GAAhBgnB,EAAMxS,QAEnC,KAAQlH,IAAQjP,KAAMiP,EAAMA,EAAIrM,YAAc5C,KAI7C,GAAsB,IAAjBiP,EAAI1N,WAAoC,UAAfonB,EAAMhnB,OAAqC,IAAjBsN,EAAI7C,UAAsB,CAGjF,IAFAif,EAAkB,GAClBC,EAAmB,GACbnpB,EAAI,EAAGA,EAAIkoB,EAAeloB,SAME2D,IAA5BwlB,EAFLlZ,GAHAuX,EAAYC,EAAUznB,IAGNc,SAAW,OAG1BqoB,EAAkBlZ,GAAQuX,EAAU7e,cACC,EAApC9H,EAAQoP,EAAKpS,MAAOyb,MAAOxM,GAC3BjM,EAAO2N,KAAMyB,EAAKpS,KAAM,KAAM,CAAEiP,IAAQ3L,QAErCgoB,EAAkBlZ,IACtBiZ,EAAgBzqB,KAAM+oB,GAGnB0B,EAAgB/nB,QACpBsnB,EAAahqB,KAAM,CAAEyD,KAAM4K,EAAK2a,SAAUyB,IAY9C,OALApc,EAAMjP,KACDqqB,EAAgBT,EAAStmB,QAC7BsnB,EAAahqB,KAAM,CAAEyD,KAAM4K,EAAK2a,SAAUA,EAAStpB,MAAO+pB,KAGpDO,GAGRW,QAAS,SAAUlmB,EAAMmmB,GACxBprB,OAAOqiB,eAAgBzf,EAAOsmB,MAAM/lB,UAAW8B,EAAM,CACpDomB,YAAY,EACZ/I,cAAc,EAEd/e,IAAKtC,EAAYmqB,GAChB,WACC,GAAKxrB,KAAK0rB,cACT,OAAOF,EAAMxrB,KAAK0rB,gBAGpB,WACC,GAAK1rB,KAAK0rB,cACT,OAAO1rB,KAAK0rB,cAAermB,IAI9Bsd,IAAK,SAAUxb,GACd/G,OAAOqiB,eAAgBziB,KAAMqF,EAAM,CAClComB,YAAY,EACZ/I,cAAc,EACdiJ,UAAU,EACVxkB,MAAOA,QAMX0jB,IAAK,SAAUa,GACd,OAAOA,EAAe1oB,EAAO+C,SAC5B2lB,EACA,IAAI1oB,EAAOsmB,MAAOoC,IAGpBpM,QAAS,CACRsM,KAAM,CAGLC,UAAU,GAEXC,MAAO,CAGNxB,MAAO,SAAU1H,GAIhB,IAAIjU,EAAK3O,MAAQ4iB,EAWjB,OARKoD,GAAevY,KAAMkB,EAAGhN,OAC5BgN,EAAGmd,OAASzf,EAAUsC,EAAI,UAG1Bka,GAAgBla,EAAI,QAASuZ,KAIvB,GAERmB,QAAS,SAAUzG,GAIlB,IAAIjU,EAAK3O,MAAQ4iB,EAUjB,OAPKoD,GAAevY,KAAMkB,EAAGhN,OAC5BgN,EAAGmd,OAASzf,EAAUsC,EAAI,UAE1Bka,GAAgBla,EAAI,UAId,GAKRkY,SAAU,SAAU8B,GACnB,IAAIljB,EAASkjB,EAAMljB,OACnB,OAAOugB,GAAevY,KAAMhI,EAAO9D,OAClC8D,EAAOqmB,OAASzf,EAAU5G,EAAQ,UAClCsd,EAASpf,IAAK8B,EAAQ,UACtB4G,EAAU5G,EAAQ,OAIrBsmB,aAAc,CACbX,aAAc,SAAUzC,QAID7iB,IAAjB6iB,EAAMjV,QAAwBiV,EAAM+C,gBACxC/C,EAAM+C,cAAcM,YAAcrD,EAAMjV,YAoG7C1Q,EAAO0nB,YAAc,SAAUrmB,EAAM1C,EAAMsoB,GAGrC5lB,EAAK6c,qBACT7c,EAAK6c,oBAAqBvf,EAAMsoB,IAIlCjnB,EAAOsmB,MAAQ,SAAU1nB,EAAKqqB,GAG7B,KAAQjsB,gBAAgBgD,EAAOsmB,OAC9B,OAAO,IAAItmB,EAAOsmB,MAAO1nB,EAAKqqB,GAI1BrqB,GAAOA,EAAID,MACf3B,KAAK0rB,cAAgB9pB,EACrB5B,KAAK2B,KAAOC,EAAID,KAIhB3B,KAAKksB,mBAAqBtqB,EAAIuqB,uBACHrmB,IAAzBlE,EAAIuqB,mBAGgB,IAApBvqB,EAAIoqB,YACL9D,GACAC,GAKDnoB,KAAKyF,OAAW7D,EAAI6D,QAAkC,IAAxB7D,EAAI6D,OAAOlE,SACxCK,EAAI6D,OAAO7C,WACXhB,EAAI6D,OAELzF,KAAKirB,cAAgBrpB,EAAIqpB,cACzBjrB,KAAKosB,cAAgBxqB,EAAIwqB,eAIzBpsB,KAAK2B,KAAOC,EAIRqqB,GACJjpB,EAAOmC,OAAQnF,KAAMisB,GAItBjsB,KAAKqsB,UAAYzqB,GAAOA,EAAIyqB,WAAa3jB,KAAK4jB,MAG9CtsB,KAAMgD,EAAO+C,UAAY,GAK1B/C,EAAOsmB,MAAM/lB,UAAY,CACxBE,YAAaT,EAAOsmB,MACpB4C,mBAAoB/D,GACpB6C,qBAAsB7C,GACtB+C,8BAA+B/C,GAC/BoE,aAAa,EAEbnD,eAAgB,WACf,IAAI3c,EAAIzM,KAAK0rB,cAEb1rB,KAAKksB,mBAAqBhE,GAErBzb,IAAMzM,KAAKusB,aACf9f,EAAE2c,kBAGJF,gBAAiB,WAChB,IAAIzc,EAAIzM,KAAK0rB,cAEb1rB,KAAKgrB,qBAAuB9C,GAEvBzb,IAAMzM,KAAKusB,aACf9f,EAAEyc,mBAGJC,yBAA0B,WACzB,IAAI1c,EAAIzM,KAAK0rB,cAEb1rB,KAAKkrB,8BAAgChD,GAEhCzb,IAAMzM,KAAKusB,aACf9f,EAAE0c,2BAGHnpB,KAAKkpB,oBAKPlmB,EAAOkB,KAAM,CACZsoB,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,gBAAgB,EAChBC,SAAS,EACTC,QAAQ,EACRC,YAAY,EACZC,SAAS,EACTC,OAAO,EACPC,OAAO,EACPC,UAAU,EACVC,MAAM,EACNC,QAAQ,EACRprB,MAAM,EACNqrB,UAAU,EACV/e,KAAK,EACLgf,SAAS,EACTnX,QAAQ,EACRoX,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,WAAW,EACXC,aAAa,EACbC,SAAS,EACTC,SAAS,EACTC,eAAe,EACfC,WAAW,EACXC,SAAS,EACTC,OAAO,GACLnrB,EAAO2lB,MAAM4C,SAEhBvoB,EAAOkB,KAAM,CAAEsR,MAAO,UAAW4Y,KAAM,YAAc,SAAUzsB,EAAMsnB,GACpEjmB,EAAO2lB,MAAMrJ,QAAS3d,GAAS,CAG9B2oB,MAAO,WAQN,OAHAzB,GAAgB7oB,KAAM2B,EAAMymB,KAGrB,GAERiB,QAAS,WAMR,OAHAR,GAAgB7oB,KAAM2B,IAGf,GAKRklB,SAAU,SAAU8B,GACnB,OAAO5F,EAASpf,IAAKglB,EAAMljB,OAAQ9D,IAGpCsnB,aAAcA,KAYhBjmB,EAAOkB,KAAM,CACZmqB,WAAY,YACZC,WAAY,WACZC,aAAc,cACdC,aAAc,cACZ,SAAUC,EAAM5D,GAClB7nB,EAAO2lB,MAAMrJ,QAASmP,GAAS,CAC9BxF,aAAc4B,EACdT,SAAUS,EAEVZ,OAAQ,SAAUtB,GACjB,IAAI5kB,EAEH2qB,EAAU/F,EAAMyD,cAChBzC,EAAYhB,EAAMgB,UASnB,OALM+E,IAAaA,IANT1uB,MAMgCgD,EAAOyF,SANvCzI,KAMyD0uB,MAClE/F,EAAMhnB,KAAOgoB,EAAUG,SACvB/lB,EAAM4lB,EAAU7a,QAAQnO,MAAOX,KAAMsE,WACrCqkB,EAAMhnB,KAAOkpB,GAEP9mB,MAKVf,EAAOG,GAAGgC,OAAQ,CAEjBojB,GAAI,SAAUC,EAAOvlB,EAAU2f,EAAMzf,GACpC,OAAOolB,GAAIvoB,KAAMwoB,EAAOvlB,EAAU2f,EAAMzf,IAEzCslB,IAAK,SAAUD,EAAOvlB,EAAU2f,EAAMzf,GACrC,OAAOolB,GAAIvoB,KAAMwoB,EAAOvlB,EAAU2f,EAAMzf,EAAI,IAE7CylB,IAAK,SAAUJ,EAAOvlB,EAAUE,GAC/B,IAAIwmB,EAAWhoB,EACf,GAAK6mB,GAASA,EAAMY,gBAAkBZ,EAAMmB,UAW3C,OARAA,EAAYnB,EAAMmB,UAClB3mB,EAAQwlB,EAAMsC,gBAAiBlC,IAC9Be,EAAU/Z,UACT+Z,EAAUG,SAAW,IAAMH,EAAU/Z,UACrC+Z,EAAUG,SACXH,EAAU1mB,SACV0mB,EAAU7a,SAEJ9O,KAER,GAAsB,iBAAVwoB,EAAqB,CAGhC,IAAM7mB,KAAQ6mB,EACbxoB,KAAK4oB,IAAKjnB,EAAMsB,EAAUulB,EAAO7mB,IAElC,OAAO3B,KAWR,OATkB,IAAbiD,GAA0C,mBAAbA,IAGjCE,EAAKF,EACLA,OAAW6C,IAEA,IAAP3C,IACJA,EAAKglB,IAECnoB,KAAKkE,KAAM,WACjBlB,EAAO2lB,MAAM5K,OAAQ/d,KAAMwoB,EAAOrlB,EAAIF,QAMzC,IAKC0rB,GAAe,wBAGfC,GAAW,oCAEXC,GAAe,6BAGhB,SAASC,GAAoBzqB,EAAM8X,GAClC,OAAK9P,EAAUhI,EAAM,UACpBgI,EAA+B,KAArB8P,EAAQ5a,SAAkB4a,EAAUA,EAAQzJ,WAAY,OAE3D1P,EAAQqB,GAAO6W,SAAU,SAAW,IAGrC7W,EAIR,SAAS0qB,GAAe1qB,GAEvB,OADAA,EAAK1C,MAAyC,OAAhC0C,EAAK7B,aAAc,SAAsB,IAAM6B,EAAK1C,KAC3D0C,EAER,SAAS2qB,GAAe3qB,GAOvB,MAN2C,WAApCA,EAAK1C,MAAQ,IAAKrB,MAAO,EAAG,GAClC+D,EAAK1C,KAAO0C,EAAK1C,KAAKrB,MAAO,GAE7B+D,EAAK8J,gBAAiB,QAGhB9J,EAGR,SAAS4qB,GAAgBrtB,EAAKstB,GAC7B,IAAI/sB,EAAGoZ,EAAG5Z,EAAgBwtB,EAAUC,EAAU3F,EAE9C,GAAuB,IAAlByF,EAAK3tB,SAAV,CAKA,GAAKwhB,EAASD,QAASlhB,KAEtB6nB,EADW1G,EAASpf,IAAK/B,GACP6nB,QAKjB,IAAM9nB,KAFNohB,EAAShF,OAAQmR,EAAM,iBAETzF,EACb,IAAMtnB,EAAI,EAAGoZ,EAAIkO,EAAQ9nB,GAAO2B,OAAQnB,EAAIoZ,EAAGpZ,IAC9Ca,EAAO2lB,MAAMhN,IAAKuT,EAAMvtB,EAAM8nB,EAAQ9nB,GAAQQ,IAO7C6gB,EAASF,QAASlhB,KACtButB,EAAWnM,EAASzB,OAAQ3f,GAC5BwtB,EAAWpsB,EAAOmC,OAAQ,GAAIgqB,GAE9BnM,EAASL,IAAKuM,EAAME,KAkBtB,SAASC,GAAUC,EAAY3a,EAAMxQ,EAAUujB,GAG9C/S,EAAOpU,EAAMoU,GAEb,IAAIkT,EAAUtjB,EAAOijB,EAAS+H,EAAYttB,EAAMC,EAC/CC,EAAI,EACJoZ,EAAI+T,EAAWhsB,OACfksB,EAAWjU,EAAI,EACfpU,EAAQwN,EAAM,GACd8a,EAAkBpuB,EAAY8F,GAG/B,GAAKsoB,GACG,EAAJlU,GAA0B,iBAAVpU,IAChB/F,EAAQglB,YAAcwI,GAASnhB,KAAMtG,GACxC,OAAOmoB,EAAWprB,KAAM,SAAUuX,GACjC,IAAIb,EAAO0U,EAAW9qB,GAAIiX,GACrBgU,IACJ9a,EAAM,GAAMxN,EAAM1G,KAAMT,KAAMyb,EAAOb,EAAK8U,SAE3CL,GAAUzU,EAAMjG,EAAMxQ,EAAUujB,KAIlC,GAAKnM,IAEJhX,GADAsjB,EAAWN,GAAe5S,EAAM2a,EAAY,GAAIpiB,eAAe,EAAOoiB,EAAY5H,IACjEhV,WAEmB,IAA/BmV,EAASrb,WAAWlJ,SACxBukB,EAAWtjB,GAIPA,GAASmjB,GAAU,CAOvB,IALA6H,GADA/H,EAAUxkB,EAAOoB,IAAK0iB,GAAQe,EAAU,UAAYkH,KAC/BzrB,OAKbnB,EAAIoZ,EAAGpZ,IACdF,EAAO4lB,EAEF1lB,IAAMqtB,IACVvtB,EAAOe,EAAOwC,MAAOvD,GAAM,GAAM,GAG5BstB,GAIJvsB,EAAOgB,MAAOwjB,EAASV,GAAQ7kB,EAAM,YAIvCkC,EAAS1D,KAAM6uB,EAAYntB,GAAKF,EAAME,GAGvC,GAAKotB,EAOJ,IANArtB,EAAMslB,EAASA,EAAQlkB,OAAS,GAAI4J,cAGpClK,EAAOoB,IAAKojB,EAASwH,IAGf7sB,EAAI,EAAGA,EAAIotB,EAAYptB,IAC5BF,EAAOulB,EAASrlB,GACX+jB,GAAYzY,KAAMxL,EAAKN,MAAQ,MAClCohB,EAASxB,OAAQtf,EAAM,eACxBe,EAAOyF,SAAUvG,EAAKD,KAEjBA,EAAKL,KAA8C,YAArCK,EAAKN,MAAQ,IAAK8F,cAG/BzE,EAAO2sB,WAAa1tB,EAAKH,UAC7BkB,EAAO2sB,SAAU1tB,EAAKL,IAAK,CAC1BC,MAAOI,EAAKJ,OAASI,EAAKO,aAAc,UACtCN,GASJH,EAASE,EAAKwQ,YAAYvM,QAAS2oB,GAAc,IAAM5sB,EAAMC,IAQnE,OAAOotB,EAGR,SAASvR,GAAQ1Z,EAAMpB,EAAU2sB,GAKhC,IAJA,IAAI3tB,EACH6lB,EAAQ7kB,EAAWD,EAAOyN,OAAQxN,EAAUoB,GAASA,EACrDlC,EAAI,EAE4B,OAAvBF,EAAO6lB,EAAO3lB,IAAeA,IAChCytB,GAA8B,IAAlB3tB,EAAKV,UACtByB,EAAO6sB,UAAW/I,GAAQ7kB,IAGtBA,EAAKW,aACJgtB,GAAYtL,GAAYriB,IAC5B8kB,GAAeD,GAAQ7kB,EAAM,WAE9BA,EAAKW,WAAWC,YAAaZ,IAI/B,OAAOoC,EAGRrB,EAAOmC,OAAQ,CACd4iB,cAAe,SAAU2H,GACxB,OAAOA,GAGRlqB,MAAO,SAAUnB,EAAMyrB,EAAeC,GACrC,IAAI5tB,EAAGoZ,EAAGyU,EAAaC,EA1INruB,EAAKstB,EACnB7iB,EA0IF7G,EAAQnB,EAAKgiB,WAAW,GACxB6J,EAAS5L,GAAYjgB,GAGtB,KAAMjD,EAAQklB,gBAAsC,IAAlBjiB,EAAK9C,UAAoC,KAAlB8C,EAAK9C,UAC3DyB,EAAOiX,SAAU5V,IAMnB,IAHA4rB,EAAenJ,GAAQthB,GAGjBrD,EAAI,EAAGoZ,GAFbyU,EAAclJ,GAAQziB,IAEOf,OAAQnB,EAAIoZ,EAAGpZ,IAtJ5BP,EAuJLouB,EAAa7tB,GAvJH+sB,EAuJQe,EAAc9tB,QAtJzCkK,EAGc,WAHdA,EAAW6iB,EAAK7iB,SAAS5E,gBAGAue,GAAevY,KAAM7L,EAAID,MACrDutB,EAAKpZ,QAAUlU,EAAIkU,QAGK,UAAbzJ,GAAqC,aAAbA,IACnC6iB,EAAKnV,aAAenY,EAAImY,cAmJxB,GAAK+V,EACJ,GAAKC,EAIJ,IAHAC,EAAcA,GAAelJ,GAAQziB,GACrC4rB,EAAeA,GAAgBnJ,GAAQthB,GAEjCrD,EAAI,EAAGoZ,EAAIyU,EAAY1sB,OAAQnB,EAAIoZ,EAAGpZ,IAC3C8sB,GAAgBe,EAAa7tB,GAAK8tB,EAAc9tB,SAGjD8sB,GAAgB5qB,EAAMmB,GAWxB,OAL2B,GAD3ByqB,EAAenJ,GAAQthB,EAAO,WACZlC,QACjByjB,GAAekJ,GAAeC,GAAUpJ,GAAQziB,EAAM,WAIhDmB,GAGRqqB,UAAW,SAAU/rB,GAKpB,IAJA,IAAI8e,EAAMve,EAAM1C,EACf2d,EAAUtc,EAAO2lB,MAAMrJ,QACvBnd,EAAI,OAE6B2D,KAAxBzB,EAAOP,EAAO3B,IAAqBA,IAC5C,GAAKkgB,EAAYhe,GAAS,CACzB,GAAOue,EAAOve,EAAM0e,EAAShd,SAAc,CAC1C,GAAK6c,EAAK6G,OACT,IAAM9nB,KAAQihB,EAAK6G,OACbnK,EAAS3d,GACbqB,EAAO2lB,MAAM5K,OAAQ1Z,EAAM1C,GAI3BqB,EAAO0nB,YAAarmB,EAAM1C,EAAMihB,EAAKqH,QAOxC5lB,EAAM0e,EAAShd,cAAYD,EAEvBzB,EAAM2e,EAASjd,WAInB1B,EAAM2e,EAASjd,cAAYD,OAOhC9C,EAAOG,GAAGgC,OAAQ,CACjBgrB,OAAQ,SAAUltB,GACjB,OAAO8a,GAAQ/d,KAAMiD,GAAU,IAGhC8a,OAAQ,SAAU9a,GACjB,OAAO8a,GAAQ/d,KAAMiD,IAGtBV,KAAM,SAAU4E,GACf,OAAOoa,EAAQvhB,KAAM,SAAUmH,GAC9B,YAAiBrB,IAAVqB,EACNnE,EAAOT,KAAMvC,MACbA,KAAKiW,QAAQ/R,KAAM,WACK,IAAlBlE,KAAKuB,UAAoC,KAAlBvB,KAAKuB,UAAqC,IAAlBvB,KAAKuB,WACxDvB,KAAKyS,YAActL,MAGpB,KAAMA,EAAO7C,UAAUhB,SAG3B8sB,OAAQ,WACP,OAAOf,GAAUrvB,KAAMsE,UAAW,SAAUD,GACpB,IAAlBrE,KAAKuB,UAAoC,KAAlBvB,KAAKuB,UAAqC,IAAlBvB,KAAKuB,UAC3CutB,GAAoB9uB,KAAMqE,GAChC1B,YAAa0B,MAKvBgsB,QAAS,WACR,OAAOhB,GAAUrvB,KAAMsE,UAAW,SAAUD,GAC3C,GAAuB,IAAlBrE,KAAKuB,UAAoC,KAAlBvB,KAAKuB,UAAqC,IAAlBvB,KAAKuB,SAAiB,CACzE,IAAIkE,EAASqpB,GAAoB9uB,KAAMqE,GACvCoB,EAAO6qB,aAAcjsB,EAAMoB,EAAOiN,gBAKrC6d,OAAQ,WACP,OAAOlB,GAAUrvB,KAAMsE,UAAW,SAAUD,GACtCrE,KAAK4C,YACT5C,KAAK4C,WAAW0tB,aAAcjsB,EAAMrE,SAKvCwwB,MAAO,WACN,OAAOnB,GAAUrvB,KAAMsE,UAAW,SAAUD,GACtCrE,KAAK4C,YACT5C,KAAK4C,WAAW0tB,aAAcjsB,EAAMrE,KAAKoP,gBAK5C6G,MAAO,WAIN,IAHA,IAAI5R,EACHlC,EAAI,EAE2B,OAAtBkC,EAAOrE,KAAMmC,IAAeA,IACd,IAAlBkC,EAAK9C,WAGTyB,EAAO6sB,UAAW/I,GAAQziB,GAAM,IAGhCA,EAAKoO,YAAc,IAIrB,OAAOzS,MAGRwF,MAAO,SAAUsqB,EAAeC,GAI/B,OAHAD,EAAiC,MAAjBA,GAAgCA,EAChDC,EAAyC,MAArBA,EAA4BD,EAAgBC,EAEzD/vB,KAAKoE,IAAK,WAChB,OAAOpB,EAAOwC,MAAOxF,KAAM8vB,EAAeC,MAI5CL,KAAM,SAAUvoB,GACf,OAAOoa,EAAQvhB,KAAM,SAAUmH,GAC9B,IAAI9C,EAAOrE,KAAM,IAAO,GACvBmC,EAAI,EACJoZ,EAAIvb,KAAKsD,OAEV,QAAewC,IAAVqB,GAAyC,IAAlB9C,EAAK9C,SAChC,OAAO8C,EAAK2M,UAIb,GAAsB,iBAAV7J,IAAuBwnB,GAAalhB,KAAMtG,KACpDqf,IAAWP,GAAS9Y,KAAMhG,IAAW,CAAE,GAAI,KAAQ,GAAIM,eAAkB,CAE1EN,EAAQnE,EAAO+kB,cAAe5gB,GAE9B,IACC,KAAQhF,EAAIoZ,EAAGpZ,IAIS,KAHvBkC,EAAOrE,KAAMmC,IAAO,IAGVZ,WACTyB,EAAO6sB,UAAW/I,GAAQziB,GAAM,IAChCA,EAAK2M,UAAY7J,GAInB9C,EAAO,EAGN,MAAQoI,KAGNpI,GACJrE,KAAKiW,QAAQma,OAAQjpB,IAEpB,KAAMA,EAAO7C,UAAUhB,SAG3BmtB,YAAa,WACZ,IAAI/I,EAAU,GAGd,OAAO2H,GAAUrvB,KAAMsE,UAAW,SAAUD,GAC3C,IAAIiQ,EAAStU,KAAK4C,WAEbI,EAAO6D,QAAS7G,KAAM0nB,GAAY,IACtC1kB,EAAO6sB,UAAW/I,GAAQ9mB,OACrBsU,GACJA,EAAOoc,aAAcrsB,EAAMrE,QAK3B0nB,MAIL1kB,EAAOkB,KAAM,CACZysB,SAAU,SACVC,UAAW,UACXN,aAAc,SACdO,YAAa,QACbC,WAAY,eACV,SAAUzrB,EAAM0rB,GAClB/tB,EAAOG,GAAIkC,GAAS,SAAUpC,GAO7B,IANA,IAAIa,EACHC,EAAM,GACNitB,EAAShuB,EAAQC,GACjBwB,EAAOusB,EAAO1tB,OAAS,EACvBnB,EAAI,EAEGA,GAAKsC,EAAMtC,IAClB2B,EAAQ3B,IAAMsC,EAAOzE,KAAOA,KAAKwF,OAAO,GACxCxC,EAAQguB,EAAQ7uB,IAAO4uB,GAAYjtB,GAInClD,EAAKD,MAAOoD,EAAKD,EAAMH,OAGxB,OAAO3D,KAAK6D,UAAWE,MAGzB,IAAIktB,GAAY,IAAIlnB,OAAQ,KAAOma,GAAO,kBAAmB,KAEzDgN,GAAc,MAGdC,GAAY,SAAU9sB,GAKxB,IAAI8oB,EAAO9oB,EAAK6I,cAAc+C,YAM9B,OAJMkd,GAASA,EAAKiE,SACnBjE,EAAOptB,GAGDotB,EAAKkE,iBAAkBhtB,IAG5BitB,GAAO,SAAUjtB,EAAMe,EAASjB,GACnC,IAAIJ,EAAKsB,EACRksB,EAAM,GAGP,IAAMlsB,KAAQD,EACbmsB,EAAKlsB,GAAShB,EAAKqgB,MAAOrf,GAC1BhB,EAAKqgB,MAAOrf,GAASD,EAASC,GAM/B,IAAMA,KAHNtB,EAAMI,EAAS1D,KAAM4D,GAGPe,EACbf,EAAKqgB,MAAOrf,GAASksB,EAAKlsB,GAG3B,OAAOtB,GAIJytB,GAAY,IAAIznB,OAAQsa,GAAUxW,KAAM,KAAO,KAE/CnE,GAAa,sBAGb+nB,GAAW,IAAI1nB,OAClB,IAAML,GAAa,8BAAgCA,GAAa,KAChE,KAmJD,SAASgoB,GAAQrtB,EAAMgB,EAAMssB,GAC5B,IAAIC,EAAOC,EAAUC,EAAU/tB,EAC9BguB,EAAeb,GAAYzjB,KAAMpI,GAMjCqf,EAAQrgB,EAAKqgB,MAoEd,OAlEAiN,EAAWA,GAAYR,GAAW9sB,MAgBjCN,EAAM4tB,EAASK,iBAAkB3sB,IAAUssB,EAAUtsB,GAEhD0sB,GAAgBhuB,IAkBpBA,EAAMA,EAAImC,QAASurB,GAAU,YAAU3rB,GAG3B,KAAR/B,GAAeugB,GAAYjgB,KAC/BN,EAAMf,EAAO0hB,MAAOrgB,EAAMgB,KAQrBjE,EAAQ6wB,kBAAoBhB,GAAUxjB,KAAM1J,IAASytB,GAAU/jB,KAAMpI,KAG1EusB,EAAQlN,EAAMkN,MACdC,EAAWnN,EAAMmN,SACjBC,EAAWpN,EAAMoN,SAGjBpN,EAAMmN,SAAWnN,EAAMoN,SAAWpN,EAAMkN,MAAQ7tB,EAChDA,EAAM4tB,EAASC,MAGflN,EAAMkN,MAAQA,EACdlN,EAAMmN,SAAWA,EACjBnN,EAAMoN,SAAWA,SAIJhsB,IAAR/B,EAINA,EAAM,GACNA,EAIF,SAASmuB,GAAcC,EAAaC,GAGnC,MAAO,CACNzuB,IAAK,WACJ,IAAKwuB,IASL,OAASnyB,KAAK2D,IAAMyuB,GAASzxB,MAAOX,KAAMsE,kBALlCtE,KAAK2D,OA3OhB,WAIC,SAAS0uB,IAGR,GAAMtM,EAAN,CAIAuM,EAAU5N,MAAM6N,QAAU,+EAE1BxM,EAAIrB,MAAM6N,QACT,4HAGDziB,GAAgBnN,YAAa2vB,GAAY3vB,YAAaojB,GAEtD,IAAIyM,EAAWzyB,EAAOsxB,iBAAkBtL,GACxC0M,EAAoC,OAAjBD,EAAStiB,IAG5BwiB,EAAsE,KAA9CC,EAAoBH,EAASI,YAIrD7M,EAAIrB,MAAMmO,MAAQ,MAClBC,EAA6D,KAAzCH,EAAoBH,EAASK,OAIjDE,EAAgE,KAAzCJ,EAAoBH,EAASZ,OAMpD7L,EAAIrB,MAAMsO,SAAW,WACrBC,EAAiE,KAA9CN,EAAoB5M,EAAImN,YAAc,GAEzDpjB,GAAgBjN,YAAayvB,GAI7BvM,EAAM,MAGP,SAAS4M,EAAoBQ,GAC5B,OAAOntB,KAAKotB,MAAOC,WAAYF,IAGhC,IAAIV,EAAkBM,EAAsBE,EAAkBH,EAC7DQ,EAAyBZ,EACzBJ,EAAY1yB,EAAS0C,cAAe,OACpCyjB,EAAMnmB,EAAS0C,cAAe,OAGzByjB,EAAIrB,QAMVqB,EAAIrB,MAAM6O,eAAiB,cAC3BxN,EAAIM,WAAW,GAAO3B,MAAM6O,eAAiB,GAC7CnyB,EAAQoyB,gBAA+C,gBAA7BzN,EAAIrB,MAAM6O,eAEpCvwB,EAAOmC,OAAQ/D,EAAS,CACvBqyB,kBAAmB,WAElB,OADApB,IACOU,GAERd,eAAgB,WAEf,OADAI,IACOS,GAERY,cAAe,WAEd,OADArB,IACOI,GAERkB,mBAAoB,WAEnB,OADAtB,IACOK,GAERkB,cAAe,WAEd,OADAvB,IACOY,GAYRY,qBAAsB,WACrB,IAAIC,EAAOnN,EAAIoN,EAASC,EAmCxB,OAlCgC,MAA3BV,IACJQ,EAAQl0B,EAAS0C,cAAe,SAChCqkB,EAAK/mB,EAAS0C,cAAe,MAC7ByxB,EAAUn0B,EAAS0C,cAAe,OAElCwxB,EAAMpP,MAAM6N,QAAU,2DACtB5L,EAAGjC,MAAM6N,QAAU,mBAKnB5L,EAAGjC,MAAMuP,OAAS,MAClBF,EAAQrP,MAAMuP,OAAS,MAQvBF,EAAQrP,MAAMC,QAAU,QAExB7U,GACEnN,YAAamxB,GACbnxB,YAAagkB,GACbhkB,YAAaoxB,GAEfC,EAAUj0B,EAAOsxB,iBAAkB1K,GACnC2M,EAA4BY,SAAUF,EAAQC,OAAQ,IACrDC,SAAUF,EAAQG,eAAgB,IAClCD,SAAUF,EAAQI,kBAAmB,MAAWzN,EAAG0N,aAEpDvkB,GAAgBjN,YAAaixB,IAEvBR,MAvIV,GAsPA,IAAIgB,GAAc,CAAE,SAAU,MAAO,MACpCC,GAAa30B,EAAS0C,cAAe,OAAQoiB,MAC7C8P,GAAc,GAkBf,SAASC,GAAepvB,GACvB,IAAIqvB,EAAQ1xB,EAAO2xB,SAAUtvB,IAAUmvB,GAAanvB,GAEpD,OAAKqvB,IAGArvB,KAAQkvB,GACLlvB,EAEDmvB,GAAanvB,GAxBrB,SAAyBA,GAGxB,IAAIuvB,EAAUvvB,EAAM,GAAI6c,cAAgB7c,EAAK/E,MAAO,GACnD6B,EAAImyB,GAAYhxB,OAEjB,MAAQnB,IAEP,IADAkD,EAAOivB,GAAanyB,GAAMyyB,KACbL,GACZ,OAAOlvB,EAeoBwvB,CAAgBxvB,IAAUA,GAIxD,IAKCyvB,GAAe,4BACfC,GAAU,CAAE/B,SAAU,WAAYgC,WAAY,SAAUrQ,QAAS,SACjEsQ,GAAqB,CACpBC,cAAe,IACfC,WAAY,OAGd,SAASC,GAAmBxwB,EAAOuC,EAAOkuB,GAIzC,IAAIruB,EAAUod,GAAQjX,KAAMhG,GAC5B,OAAOH,EAGNhB,KAAKsvB,IAAK,EAAGtuB,EAAS,IAAQquB,GAAY,KAAUruB,EAAS,IAAO,MACpEG,EAGF,SAASouB,GAAoBlxB,EAAMmxB,EAAWC,EAAKC,EAAaC,EAAQC,GACvE,IAAIzzB,EAAkB,UAAdqzB,EAAwB,EAAI,EACnCK,EAAQ,EACRC,EAAQ,EAGT,GAAKL,KAAUC,EAAc,SAAW,WACvC,OAAO,EAGR,KAAQvzB,EAAI,EAAGA,GAAK,EAGN,WAARszB,IACJK,GAAS9yB,EAAO4hB,IAAKvgB,EAAMoxB,EAAMpR,GAAWliB,IAAK,EAAMwzB,IAIlDD,GAmBQ,YAARD,IACJK,GAAS9yB,EAAO4hB,IAAKvgB,EAAM,UAAYggB,GAAWliB,IAAK,EAAMwzB,IAIjD,WAARF,IACJK,GAAS9yB,EAAO4hB,IAAKvgB,EAAM,SAAWggB,GAAWliB,GAAM,SAAS,EAAMwzB,MAtBvEG,GAAS9yB,EAAO4hB,IAAKvgB,EAAM,UAAYggB,GAAWliB,IAAK,EAAMwzB,GAGhD,YAARF,EACJK,GAAS9yB,EAAO4hB,IAAKvgB,EAAM,SAAWggB,GAAWliB,GAAM,SAAS,EAAMwzB,GAItEE,GAAS7yB,EAAO4hB,IAAKvgB,EAAM,SAAWggB,GAAWliB,GAAM,SAAS,EAAMwzB,IAoCzE,OAhBMD,GAA8B,GAAfE,IAIpBE,GAAS9vB,KAAKsvB,IAAK,EAAGtvB,KAAK+vB,KAC1B1xB,EAAM,SAAWmxB,EAAW,GAAItT,cAAgBsT,EAAUl1B,MAAO,IACjEs1B,EACAE,EACAD,EACA,MAIM,GAGDC,EAGR,SAASE,GAAkB3xB,EAAMmxB,EAAWK,GAG3C,IAAIF,EAASxE,GAAW9sB,GAKvBqxB,IADmBt0B,EAAQqyB,qBAAuBoC,IAEE,eAAnD7yB,EAAO4hB,IAAKvgB,EAAM,aAAa,EAAOsxB,GACvCM,EAAmBP,EAEnBtzB,EAAMsvB,GAAQrtB,EAAMmxB,EAAWG,GAC/BO,EAAa,SAAWV,EAAW,GAAItT,cAAgBsT,EAAUl1B,MAAO,GAIzE,GAAK2wB,GAAUxjB,KAAMrL,GAAQ,CAC5B,IAAMyzB,EACL,OAAOzzB,EAERA,EAAM,OAyCP,QAlCQhB,EAAQqyB,qBAAuBiC,IAMrCt0B,EAAQyyB,wBAA0BxnB,EAAUhI,EAAM,OAI3C,SAARjC,IAICixB,WAAYjxB,IAA0D,WAAjDY,EAAO4hB,IAAKvgB,EAAM,WAAW,EAAOsxB,KAG1DtxB,EAAK8xB,iBAAiB7yB,SAEtBoyB,EAAiE,eAAnD1yB,EAAO4hB,IAAKvgB,EAAM,aAAa,EAAOsxB,IAKpDM,EAAmBC,KAAc7xB,KAEhCjC,EAAMiC,EAAM6xB,MAKd9zB,EAAMixB,WAAYjxB,IAAS,GAI1BmzB,GACClxB,EACAmxB,EACAK,IAAWH,EAAc,SAAW,WACpCO,EACAN,EAGAvzB,GAEE,KA+SL,SAASg0B,GAAO/xB,EAAMe,EAASyd,EAAM7d,EAAKqxB,GACzC,OAAO,IAAID,GAAM7yB,UAAUH,KAAMiB,EAAMe,EAASyd,EAAM7d,EAAKqxB,GA7S5DrzB,EAAOmC,OAAQ,CAIdmxB,SAAU,CACTC,QAAS,CACR5yB,IAAK,SAAUU,EAAMstB,GACpB,GAAKA,EAAW,CAGf,IAAI5tB,EAAM2tB,GAAQrtB,EAAM,WACxB,MAAe,KAARN,EAAa,IAAMA,MAO9BuhB,UAAW,CACVkR,yBAA2B,EAC3BC,aAAe,EACfC,aAAe,EACfC,UAAY,EACZC,YAAc,EACdzB,YAAc,EACd0B,UAAY,EACZC,YAAc,EACdC,eAAiB,EACjBC,iBAAmB,EACnBC,SAAW,EACXC,YAAc,EACdC,cAAgB,EAChBC,YAAc,EACdb,SAAW,EACXc,OAAS,EACTC,SAAW,EACXC,QAAU,EACVC,QAAU,EACVC,MAAQ,GAKT9C,SAAU,GAGVjQ,MAAO,SAAUrgB,EAAMgB,EAAM8B,EAAO0uB,GAGnC,GAAMxxB,GAA0B,IAAlBA,EAAK9C,UAAoC,IAAlB8C,EAAK9C,UAAmB8C,EAAKqgB,MAAlE,CAKA,IAAI3gB,EAAKpC,EAAMgiB,EACd+T,EAAWvV,EAAW9c,GACtB0sB,EAAeb,GAAYzjB,KAAMpI,GACjCqf,EAAQrgB,EAAKqgB,MAad,GARMqN,IACL1sB,EAAOovB,GAAeiD,IAIvB/T,EAAQ3gB,EAAOszB,SAAUjxB,IAAUrC,EAAOszB,SAAUoB,QAGrC5xB,IAAVqB,EA0CJ,OAAKwc,GAAS,QAASA,QACwB7d,KAA5C/B,EAAM4f,EAAMhgB,IAAKU,GAAM,EAAOwxB,IAEzB9xB,EAID2gB,EAAOrf,GA7CA,YAHd1D,SAAcwF,KAGcpD,EAAMqgB,GAAQjX,KAAMhG,KAAapD,EAAK,KACjEoD,EAAQ0d,GAAWxgB,EAAMgB,EAAMtB,GAG/BpC,EAAO,UAIM,MAATwF,GAAiBA,GAAUA,IAOlB,WAATxF,GAAsBowB,IAC1B5qB,GAASpD,GAAOA,EAAK,KAASf,EAAOsiB,UAAWoS,GAAa,GAAK,OAI7Dt2B,EAAQoyB,iBAA6B,KAAVrsB,GAAiD,IAAjC9B,EAAKxE,QAAS,gBAC9D6jB,EAAOrf,GAAS,WAIXse,GAAY,QAASA,QACsB7d,KAA9CqB,EAAQwc,EAAMhB,IAAKte,EAAM8C,EAAO0uB,MAE7B9D,EACJrN,EAAMiT,YAAatyB,EAAM8B,GAEzBud,EAAOrf,GAAS8B,MAkBpByd,IAAK,SAAUvgB,EAAMgB,EAAMwwB,EAAOF,GACjC,IAAIvzB,EAAKwB,EAAK+f,EACb+T,EAAWvV,EAAW9c,GA6BvB,OA5BgB6rB,GAAYzjB,KAAMpI,KAMjCA,EAAOovB,GAAeiD,KAIvB/T,EAAQ3gB,EAAOszB,SAAUjxB,IAAUrC,EAAOszB,SAAUoB,KAGtC,QAAS/T,IACtBvhB,EAAMuhB,EAAMhgB,IAAKU,GAAM,EAAMwxB,SAIjB/vB,IAAR1D,IACJA,EAAMsvB,GAAQrtB,EAAMgB,EAAMswB,IAId,WAARvzB,GAAoBiD,KAAQ4vB,KAChC7yB,EAAM6yB,GAAoB5vB,IAIZ,KAAVwwB,GAAgBA,GACpBjyB,EAAMyvB,WAAYjxB,IACD,IAAVyzB,GAAkB+B,SAAUh0B,GAAQA,GAAO,EAAIxB,GAGhDA,KAITY,EAAOkB,KAAM,CAAE,SAAU,SAAW,SAAUsD,EAAIguB,GACjDxyB,EAAOszB,SAAUd,GAAc,CAC9B7xB,IAAK,SAAUU,EAAMstB,EAAUkE,GAC9B,GAAKlE,EAIJ,OAAOmD,GAAarnB,KAAMzK,EAAO4hB,IAAKvgB,EAAM,aAQxCA,EAAK8xB,iBAAiB7yB,QAAWe,EAAKwzB,wBAAwBjG,MAIjEoE,GAAkB3xB,EAAMmxB,EAAWK,GAHnCvE,GAAMjtB,EAAM0wB,GAAS,WACpB,OAAOiB,GAAkB3xB,EAAMmxB,EAAWK,MAM9ClT,IAAK,SAAUte,EAAM8C,EAAO0uB,GAC3B,IAAI7uB,EACH2uB,EAASxE,GAAW9sB,GAIpByzB,GAAsB12B,EAAQwyB,iBACT,aAApB+B,EAAO3C,SAIR0C,GADkBoC,GAAsBjC,IAEY,eAAnD7yB,EAAO4hB,IAAKvgB,EAAM,aAAa,EAAOsxB,GACvCN,EAAWQ,EACVN,GACClxB,EACAmxB,EACAK,EACAH,EACAC,GAED,EAqBF,OAjBKD,GAAeoC,IACnBzC,GAAYrvB,KAAK+vB,KAChB1xB,EAAM,SAAWmxB,EAAW,GAAItT,cAAgBsT,EAAUl1B,MAAO,IACjE+yB,WAAYsC,EAAQH,IACpBD,GAAoBlxB,EAAMmxB,EAAW,UAAU,EAAOG,GACtD,KAKGN,IAAcruB,EAAUod,GAAQjX,KAAMhG,KACb,QAA3BH,EAAS,IAAO,QAElB3C,EAAKqgB,MAAO8Q,GAAcruB,EAC1BA,EAAQnE,EAAO4hB,IAAKvgB,EAAMmxB,IAGpBJ,GAAmB/wB,EAAM8C,EAAOkuB,OAK1CryB,EAAOszB,SAAS1D,WAAaV,GAAc9wB,EAAQuyB,mBAClD,SAAUtvB,EAAMstB,GACf,GAAKA,EACJ,OAAS0B,WAAY3B,GAAQrtB,EAAM,gBAClCA,EAAKwzB,wBAAwBE,KAC5BzG,GAAMjtB,EAAM,CAAEuuB,WAAY,GAAK,WAC9B,OAAOvuB,EAAKwzB,wBAAwBE,QAEnC,OAMP/0B,EAAOkB,KAAM,CACZ8zB,OAAQ,GACRC,QAAS,GACTC,OAAQ,SACN,SAAUC,EAAQC,GACpBp1B,EAAOszB,SAAU6B,EAASC,GAAW,CACpCC,OAAQ,SAAUlxB,GAOjB,IANA,IAAIhF,EAAI,EACPm2B,EAAW,GAGXC,EAAyB,iBAAVpxB,EAAqBA,EAAMI,MAAO,KAAQ,CAAEJ,GAEpDhF,EAAI,EAAGA,IACdm2B,EAAUH,EAAS9T,GAAWliB,GAAMi2B,GACnCG,EAAOp2B,IAAOo2B,EAAOp2B,EAAI,IAAOo2B,EAAO,GAGzC,OAAOD,IAIO,WAAXH,IACJn1B,EAAOszB,SAAU6B,EAASC,GAASzV,IAAMyS,MAI3CpyB,EAAOG,GAAGgC,OAAQ,CACjByf,IAAK,SAAUvf,EAAM8B,GACpB,OAAOoa,EAAQvhB,KAAM,SAAUqE,EAAMgB,EAAM8B,GAC1C,IAAIwuB,EAAQ7wB,EACXV,EAAM,GACNjC,EAAI,EAEL,GAAKyD,MAAMC,QAASR,GAAS,CAI5B,IAHAswB,EAASxE,GAAW9sB,GACpBS,EAAMO,EAAK/B,OAEHnB,EAAI2C,EAAK3C,IAChBiC,EAAKiB,EAAMlD,IAAQa,EAAO4hB,IAAKvgB,EAAMgB,EAAMlD,IAAK,EAAOwzB,GAGxD,OAAOvxB,EAGR,YAAiB0B,IAAVqB,EACNnE,EAAO0hB,MAAOrgB,EAAMgB,EAAM8B,GAC1BnE,EAAO4hB,IAAKvgB,EAAMgB,IACjBA,EAAM8B,EAA0B,EAAnB7C,UAAUhB,aAQ5BN,EAAOozB,MAAQA,IAET7yB,UAAY,CACjBE,YAAa2yB,GACbhzB,KAAM,SAAUiB,EAAMe,EAASyd,EAAM7d,EAAKqxB,EAAQhR,GACjDrlB,KAAKqE,KAAOA,EACZrE,KAAK6iB,KAAOA,EACZ7iB,KAAKq2B,OAASA,GAAUrzB,EAAOqzB,OAAOxP,SACtC7mB,KAAKoF,QAAUA,EACfpF,KAAKqU,MAAQrU,KAAKssB,IAAMtsB,KAAKiP,MAC7BjP,KAAKgF,IAAMA,EACXhF,KAAKqlB,KAAOA,IAAUriB,EAAOsiB,UAAWzC,GAAS,GAAK,OAEvD5T,IAAK,WACJ,IAAI0U,EAAQyS,GAAMoC,UAAWx4B,KAAK6iB,MAElC,OAAOc,GAASA,EAAMhgB,IACrBggB,EAAMhgB,IAAK3D,MACXo2B,GAAMoC,UAAU3R,SAASljB,IAAK3D,OAEhCy4B,IAAK,SAAUC,GACd,IAAIC,EACHhV,EAAQyS,GAAMoC,UAAWx4B,KAAK6iB,MAoB/B,OAlBK7iB,KAAKoF,QAAQwzB,SACjB54B,KAAK64B,IAAMF,EAAQ31B,EAAOqzB,OAAQr2B,KAAKq2B,QACtCqC,EAAS14B,KAAKoF,QAAQwzB,SAAWF,EAAS,EAAG,EAAG14B,KAAKoF,QAAQwzB,UAG9D54B,KAAK64B,IAAMF,EAAQD,EAEpB14B,KAAKssB,KAAQtsB,KAAKgF,IAAMhF,KAAKqU,OAAUskB,EAAQ34B,KAAKqU,MAE/CrU,KAAKoF,QAAQ0zB,MACjB94B,KAAKoF,QAAQ0zB,KAAKr4B,KAAMT,KAAKqE,KAAMrE,KAAKssB,IAAKtsB,MAGzC2jB,GAASA,EAAMhB,IACnBgB,EAAMhB,IAAK3iB,MAEXo2B,GAAMoC,UAAU3R,SAASlE,IAAK3iB,MAExBA,QAIOoD,KAAKG,UAAY6yB,GAAM7yB,WAEvC6yB,GAAMoC,UAAY,CACjB3R,SAAU,CACTljB,IAAK,SAAUohB,GACd,IAAIrR,EAIJ,OAA6B,IAAxBqR,EAAM1gB,KAAK9C,UACa,MAA5BwjB,EAAM1gB,KAAM0gB,EAAMlC,OAAoD,MAAlCkC,EAAM1gB,KAAKqgB,MAAOK,EAAMlC,MACrDkC,EAAM1gB,KAAM0gB,EAAMlC,OAO1BnP,EAAS1Q,EAAO4hB,IAAKG,EAAM1gB,KAAM0gB,EAAMlC,KAAM,MAGhB,SAAXnP,EAAwBA,EAAJ,GAEvCiP,IAAK,SAAUoC,GAKT/hB,EAAO+1B,GAAGD,KAAM/T,EAAMlC,MAC1B7f,EAAO+1B,GAAGD,KAAM/T,EAAMlC,MAAQkC,GACK,IAAxBA,EAAM1gB,KAAK9C,WACtByB,EAAOszB,SAAUvR,EAAMlC,OAC6B,MAAnDkC,EAAM1gB,KAAKqgB,MAAO+P,GAAe1P,EAAMlC,OAGxCkC,EAAM1gB,KAAM0gB,EAAMlC,MAASkC,EAAMuH,IAFjCtpB,EAAO0hB,MAAOK,EAAM1gB,KAAM0gB,EAAMlC,KAAMkC,EAAMuH,IAAMvH,EAAMM,UAU5C2T,UAAY5C,GAAMoC,UAAUS,WAAa,CACxDtW,IAAK,SAAUoC,GACTA,EAAM1gB,KAAK9C,UAAYwjB,EAAM1gB,KAAKzB,aACtCmiB,EAAM1gB,KAAM0gB,EAAMlC,MAASkC,EAAMuH,OAKpCtpB,EAAOqzB,OAAS,CACf6C,OAAQ,SAAUC,GACjB,OAAOA,GAERC,MAAO,SAAUD,GAChB,MAAO,GAAMnzB,KAAKqzB,IAAKF,EAAInzB,KAAKszB,IAAO,GAExCzS,SAAU,SAGX7jB,EAAO+1B,GAAK3C,GAAM7yB,UAAUH,KAG5BJ,EAAO+1B,GAAGD,KAAO,GAKjB,IACCS,GAAOC,GAkrBHzoB,GAEH0oB,GAnrBDC,GAAW,yBACXC,GAAO,cAER,SAASC,KACHJ,MACqB,IAApB55B,EAASi6B,QAAoB95B,EAAO+5B,sBACxC/5B,EAAO+5B,sBAAuBF,IAE9B75B,EAAOkgB,WAAY2Z,GAAU52B,EAAO+1B,GAAGgB,UAGxC/2B,EAAO+1B,GAAGiB,QAKZ,SAASC,KAIR,OAHAl6B,EAAOkgB,WAAY,WAClBsZ,QAAQzzB,IAEAyzB,GAAQ7wB,KAAK4jB,MAIvB,SAAS4N,GAAOv4B,EAAMw4B,GACrB,IAAIhM,EACHhsB,EAAI,EACJ0M,EAAQ,CAAEolB,OAAQtyB,GAKnB,IADAw4B,EAAeA,EAAe,EAAI,EAC1Bh4B,EAAI,EAAGA,GAAK,EAAIg4B,EAEvBtrB,EAAO,UADPsf,EAAQ9J,GAAWliB,KACS0M,EAAO,UAAYsf,GAAUxsB,EAO1D,OAJKw4B,IACJtrB,EAAM0nB,QAAU1nB,EAAM+iB,MAAQjwB,GAGxBkN,EAGR,SAASurB,GAAajzB,EAAO0b,EAAMwX,GAKlC,IAJA,IAAItV,EACHuK,GAAegL,GAAUC,SAAU1X,IAAU,IAAKniB,OAAQ45B,GAAUC,SAAU,MAC9E9e,EAAQ,EACRnY,EAASgsB,EAAWhsB,OACbmY,EAAQnY,EAAQmY,IACvB,GAAOsJ,EAAQuK,EAAY7T,GAAQhb,KAAM45B,EAAWxX,EAAM1b,GAGzD,OAAO4d,EAsNV,SAASuV,GAAWj2B,EAAMm2B,EAAYp1B,GACrC,IAAIsO,EACH+mB,EACAhf,EAAQ,EACRnY,EAASg3B,GAAUI,WAAWp3B,OAC9Bkb,EAAWxb,EAAOmb,WAAWI,OAAQ,kBAG7Byb,EAAK31B,OAEb21B,EAAO,WACN,GAAKS,EACJ,OAAO,EAYR,IAVA,IAAIE,EAAcpB,IAASU,KAC1B5Z,EAAYra,KAAKsvB,IAAK,EAAG+E,EAAUO,UAAYP,EAAUzB,SAAW+B,GAKpEjC,EAAU,GADHrY,EAAYga,EAAUzB,UAAY,GAEzCnd,EAAQ,EACRnY,EAAS+2B,EAAUQ,OAAOv3B,OAEnBmY,EAAQnY,EAAQmY,IACvB4e,EAAUQ,OAAQpf,GAAQgd,IAAKC,GAMhC,OAHAla,EAASkB,WAAYrb,EAAM,CAAEg2B,EAAW3B,EAASrY,IAG5CqY,EAAU,GAAKp1B,EACZ+c,GAIF/c,GACLkb,EAASkB,WAAYrb,EAAM,CAAEg2B,EAAW,EAAG,IAI5C7b,EAASmB,YAAatb,EAAM,CAAEg2B,KACvB,IAERA,EAAY7b,EAASzB,QAAS,CAC7B1Y,KAAMA,EACN4nB,MAAOjpB,EAAOmC,OAAQ,GAAIq1B,GAC1BM,KAAM93B,EAAOmC,QAAQ,EAAM,CAC1B41B,cAAe,GACf1E,OAAQrzB,EAAOqzB,OAAOxP,UACpBzhB,GACH41B,mBAAoBR,EACpBS,gBAAiB71B,EACjBw1B,UAAWrB,IAASU,KACpBrB,SAAUxzB,EAAQwzB,SAClBiC,OAAQ,GACRT,YAAa,SAAUvX,EAAM7d,GAC5B,IAAI+f,EAAQ/hB,EAAOozB,MAAO/xB,EAAMg2B,EAAUS,KAAMjY,EAAM7d,EACrDq1B,EAAUS,KAAKC,cAAelY,IAAUwX,EAAUS,KAAKzE,QAExD,OADAgE,EAAUQ,OAAOj6B,KAAMmkB,GAChBA,GAERlB,KAAM,SAAUqX,GACf,IAAIzf,EAAQ,EAIXnY,EAAS43B,EAAUb,EAAUQ,OAAOv3B,OAAS,EAC9C,GAAKm3B,EACJ,OAAOz6B,KAGR,IADAy6B,GAAU,EACFhf,EAAQnY,EAAQmY,IACvB4e,EAAUQ,OAAQpf,GAAQgd,IAAK,GAUhC,OANKyC,GACJ1c,EAASkB,WAAYrb,EAAM,CAAEg2B,EAAW,EAAG,IAC3C7b,EAASmB,YAAatb,EAAM,CAAEg2B,EAAWa,KAEzC1c,EAASuB,WAAY1b,EAAM,CAAEg2B,EAAWa,IAElCl7B,QAGTisB,EAAQoO,EAAUpO,MAInB,KA/HD,SAAqBA,EAAO8O,GAC3B,IAAItf,EAAOpW,EAAMgxB,EAAQlvB,EAAOwc,EAGhC,IAAMlI,KAASwQ,EAed,GAbAoK,EAAS0E,EADT11B,EAAO8c,EAAW1G,IAElBtU,EAAQ8kB,EAAOxQ,GACV7V,MAAMC,QAASsB,KACnBkvB,EAASlvB,EAAO,GAChBA,EAAQ8kB,EAAOxQ,GAAUtU,EAAO,IAG5BsU,IAAUpW,IACd4mB,EAAO5mB,GAAS8B,SACT8kB,EAAOxQ,KAGfkI,EAAQ3gB,EAAOszB,SAAUjxB,KACX,WAAYse,EAMzB,IAAMlI,KALNtU,EAAQwc,EAAM0U,OAAQlxB,UACf8kB,EAAO5mB,GAIC8B,EACNsU,KAASwQ,IAChBA,EAAOxQ,GAAUtU,EAAOsU,GACxBsf,EAAetf,GAAU4a,QAI3B0E,EAAe11B,GAASgxB,EA6F1B8E,CAAYlP,EAAOoO,EAAUS,KAAKC,eAE1Btf,EAAQnY,EAAQmY,IAEvB,GADA/H,EAAS4mB,GAAUI,WAAYjf,GAAQhb,KAAM45B,EAAWh2B,EAAM4nB,EAAOoO,EAAUS,MAM9E,OAJKz5B,EAAYqS,EAAOmQ,QACvB7gB,EAAO4gB,YAAayW,EAAUh2B,KAAMg2B,EAAUS,KAAKpd,OAAQmG,KAC1DnQ,EAAOmQ,KAAKuX,KAAM1nB,IAEbA,EAyBT,OArBA1Q,EAAOoB,IAAK6nB,EAAOmO,GAAaC,GAE3Bh5B,EAAYg5B,EAAUS,KAAKzmB,QAC/BgmB,EAAUS,KAAKzmB,MAAM5T,KAAM4D,EAAMg2B,GAIlCA,EACEtb,SAAUsb,EAAUS,KAAK/b,UACzBlW,KAAMwxB,EAAUS,KAAKjyB,KAAMwxB,EAAUS,KAAKO,UAC1Cre,KAAMqd,EAAUS,KAAK9d,MACrBuB,OAAQ8b,EAAUS,KAAKvc,QAEzBvb,EAAO+1B,GAAGuC,MACTt4B,EAAOmC,OAAQ60B,EAAM,CACpB31B,KAAMA,EACNk3B,KAAMlB,EACN3c,MAAO2c,EAAUS,KAAKpd,SAIjB2c,EAGRr3B,EAAOs3B,UAAYt3B,EAAOmC,OAAQm1B,GAAW,CAE5CC,SAAU,CACTiB,IAAK,CAAE,SAAU3Y,EAAM1b,GACtB,IAAI4d,EAAQ/kB,KAAKo6B,YAAavX,EAAM1b,GAEpC,OADA0d,GAAWE,EAAM1gB,KAAMwe,EAAMuB,GAAQjX,KAAMhG,GAAS4d,GAC7CA,KAIT0W,QAAS,SAAUxP,EAAO9nB,GACpB9C,EAAY4qB,IAChB9nB,EAAW8nB,EACXA,EAAQ,CAAE,MAEVA,EAAQA,EAAMnf,MAAOuP,GAOtB,IAJA,IAAIwG,EACHpH,EAAQ,EACRnY,EAAS2oB,EAAM3oB,OAERmY,EAAQnY,EAAQmY,IACvBoH,EAAOoJ,EAAOxQ,GACd6e,GAAUC,SAAU1X,GAASyX,GAAUC,SAAU1X,IAAU,GAC3DyX,GAAUC,SAAU1X,GAAO9Q,QAAS5N,IAItCu2B,WAAY,CA3Wb,SAA2Br2B,EAAM4nB,EAAO6O,GACvC,IAAIjY,EAAM1b,EAAO2e,EAAQnC,EAAO+X,EAASC,EAAWC,EAAgBjX,EACnEkX,EAAQ,UAAW5P,GAAS,WAAYA,EACxCsP,EAAOv7B,KACPyuB,EAAO,GACP/J,EAAQrgB,EAAKqgB,MACbmV,EAASx1B,EAAK9C,UAAYkjB,GAAoBpgB,GAC9Cy3B,EAAW/Y,EAASpf,IAAKU,EAAM,UA6BhC,IAAMwe,KA1BAiY,EAAKpd,QAEa,OADvBiG,EAAQ3gB,EAAO4gB,YAAavf,EAAM,OACvB03B,WACVpY,EAAMoY,SAAW,EACjBL,EAAU/X,EAAM1N,MAAM2H,KACtB+F,EAAM1N,MAAM2H,KAAO,WACZ+F,EAAMoY,UACXL,MAIH/X,EAAMoY,WAENR,EAAKhd,OAAQ,WAGZgd,EAAKhd,OAAQ,WACZoF,EAAMoY,WACA/4B,EAAO0a,MAAOrZ,EAAM,MAAOf,QAChCqgB,EAAM1N,MAAM2H,YAOFqO,EAEb,GADA9kB,EAAQ8kB,EAAOpJ,GACV6W,GAASjsB,KAAMtG,GAAU,CAG7B,UAFO8kB,EAAOpJ,GACdiD,EAASA,GAAoB,WAAV3e,EACdA,KAAY0yB,EAAS,OAAS,QAAW,CAI7C,GAAe,SAAV1yB,IAAoB20B,QAAiCh2B,IAArBg2B,EAAUjZ,GAK9C,SAJAgX,GAAS,EAOXpL,EAAM5L,GAASiZ,GAAYA,EAAUjZ,IAAU7f,EAAO0hB,MAAOrgB,EAAMwe,GAMrE,IADA8Y,GAAa34B,EAAOyD,cAAewlB,MAChBjpB,EAAOyD,cAAegoB,GA8DzC,IAAM5L,KAzDDgZ,GAA2B,IAAlBx3B,EAAK9C,WAMlBu5B,EAAKkB,SAAW,CAAEtX,EAAMsX,SAAUtX,EAAMuX,UAAWvX,EAAMwX,WAIlC,OADvBN,EAAiBE,GAAYA,EAASnX,WAErCiX,EAAiB7Y,EAASpf,IAAKU,EAAM,YAGrB,UADjBsgB,EAAU3hB,EAAO4hB,IAAKvgB,EAAM,cAEtBu3B,EACJjX,EAAUiX,GAIVnW,GAAU,CAAEphB,IAAQ,GACpBu3B,EAAiBv3B,EAAKqgB,MAAMC,SAAWiX,EACvCjX,EAAU3hB,EAAO4hB,IAAKvgB,EAAM,WAC5BohB,GAAU,CAAEphB,OAKG,WAAZsgB,GAAoC,iBAAZA,GAAgD,MAAlBiX,IACrB,SAAhC54B,EAAO4hB,IAAKvgB,EAAM,WAGhBs3B,IACLJ,EAAK1yB,KAAM,WACV6b,EAAMC,QAAUiX,IAEM,MAAlBA,IACJjX,EAAUD,EAAMC,QAChBiX,EAA6B,SAAZjX,EAAqB,GAAKA,IAG7CD,EAAMC,QAAU,iBAKdmW,EAAKkB,WACTtX,EAAMsX,SAAW,SACjBT,EAAKhd,OAAQ,WACZmG,EAAMsX,SAAWlB,EAAKkB,SAAU,GAChCtX,EAAMuX,UAAYnB,EAAKkB,SAAU,GACjCtX,EAAMwX,UAAYpB,EAAKkB,SAAU,MAKnCL,GAAY,EACElN,EAGPkN,IACAG,EACC,WAAYA,IAChBjC,EAASiC,EAASjC,QAGnBiC,EAAW/Y,EAASxB,OAAQld,EAAM,SAAU,CAAEsgB,QAASiX,IAInD9V,IACJgW,EAASjC,QAAUA,GAIfA,GACJpU,GAAU,CAAEphB,IAAQ,GAKrBk3B,EAAK1yB,KAAM,WASV,IAAMga,KAJAgX,GACLpU,GAAU,CAAEphB,IAEb0e,EAAShF,OAAQ1Z,EAAM,UACToqB,EACbzrB,EAAO0hB,MAAOrgB,EAAMwe,EAAM4L,EAAM5L,OAMnC8Y,EAAYvB,GAAaP,EAASiC,EAAUjZ,GAAS,EAAGA,EAAM0Y,GACtD1Y,KAAQiZ,IACfA,EAAUjZ,GAAS8Y,EAAUtnB,MACxBwlB,IACJ8B,EAAU32B,IAAM22B,EAAUtnB,MAC1BsnB,EAAUtnB,MAAQ,MAuMrB8nB,UAAW,SAAUh4B,EAAUksB,GACzBA,EACJiK,GAAUI,WAAW3oB,QAAS5N,GAE9Bm2B,GAAUI,WAAW95B,KAAMuD,MAK9BnB,EAAOo5B,MAAQ,SAAUA,EAAO/F,EAAQlzB,GACvC,IAAIs2B,EAAM2C,GAA0B,iBAAVA,EAAqBp5B,EAAOmC,OAAQ,GAAIi3B,GAAU,CAC3Ef,SAAUl4B,IAAOA,GAAMkzB,GACtBh1B,EAAY+6B,IAAWA,EACxBxD,SAAUwD,EACV/F,OAAQlzB,GAAMkzB,GAAUA,IAAWh1B,EAAYg1B,IAAYA,GAoC5D,OAhCKrzB,EAAO+1B,GAAGnQ,IACd6Q,EAAIb,SAAW,EAGc,iBAAjBa,EAAIb,WACVa,EAAIb,YAAY51B,EAAO+1B,GAAGsD,OAC9B5C,EAAIb,SAAW51B,EAAO+1B,GAAGsD,OAAQ5C,EAAIb,UAGrCa,EAAIb,SAAW51B,EAAO+1B,GAAGsD,OAAOxV,UAMjB,MAAb4S,EAAI/b,QAA+B,IAAd+b,EAAI/b,QAC7B+b,EAAI/b,MAAQ,MAIb+b,EAAIlI,IAAMkI,EAAI4B,SAEd5B,EAAI4B,SAAW,WACTh6B,EAAYo4B,EAAIlI,MACpBkI,EAAIlI,IAAI9wB,KAAMT,MAGVy5B,EAAI/b,OACR1a,EAAOygB,QAASzjB,KAAMy5B,EAAI/b,QAIrB+b,GAGRz2B,EAAOG,GAAGgC,OAAQ,CACjBm3B,OAAQ,SAAUF,EAAOG,EAAIlG,EAAQlyB,GAGpC,OAAOnE,KAAKyQ,OAAQgU,IAAqBG,IAAK,UAAW,GAAIc,OAG3D1gB,MAAMw3B,QAAS,CAAEjG,QAASgG,GAAMH,EAAO/F,EAAQlyB,IAElDq4B,QAAS,SAAU3Z,EAAMuZ,EAAO/F,EAAQlyB,GACvC,IAAI8R,EAAQjT,EAAOyD,cAAeoc,GACjC4Z,EAASz5B,EAAOo5B,MAAOA,EAAO/F,EAAQlyB,GACtCu4B,EAAc,WAGb,IAAInB,EAAOjB,GAAWt6B,KAAMgD,EAAOmC,OAAQ,GAAI0d,GAAQ4Z,IAGlDxmB,GAAS8M,EAASpf,IAAK3D,KAAM,YACjCu7B,EAAK1X,MAAM,IAMd,OAFA6Y,EAAYC,OAASD,EAEdzmB,IAA0B,IAAjBwmB,EAAO/e,MACtB1d,KAAKkE,KAAMw4B,GACX18B,KAAK0d,MAAO+e,EAAO/e,MAAOgf,IAE5B7Y,KAAM,SAAUliB,EAAMoiB,EAAYmX,GACjC,IAAI0B,EAAY,SAAUjZ,GACzB,IAAIE,EAAOF,EAAME,YACVF,EAAME,KACbA,EAAMqX,IAYP,MATqB,iBAATv5B,IACXu5B,EAAUnX,EACVA,EAAapiB,EACbA,OAAOmE,GAEHie,GACJ/jB,KAAK0d,MAAO/b,GAAQ,KAAM,IAGpB3B,KAAKkE,KAAM,WACjB,IAAIuf,GAAU,EACbhI,EAAgB,MAAR9Z,GAAgBA,EAAO,aAC/Bk7B,EAAS75B,EAAO65B,OAChBja,EAAOG,EAASpf,IAAK3D,MAEtB,GAAKyb,EACCmH,EAAMnH,IAAWmH,EAAMnH,GAAQoI,MACnC+Y,EAAWha,EAAMnH,SAGlB,IAAMA,KAASmH,EACTA,EAAMnH,IAAWmH,EAAMnH,GAAQoI,MAAQ8V,GAAKlsB,KAAMgO,IACtDmhB,EAAWha,EAAMnH,IAKpB,IAAMA,EAAQohB,EAAOv5B,OAAQmY,KACvBohB,EAAQphB,GAAQpX,OAASrE,MACnB,MAAR2B,GAAgBk7B,EAAQphB,GAAQiC,QAAU/b,IAE5Ck7B,EAAQphB,GAAQ8f,KAAK1X,KAAMqX,GAC3BzX,GAAU,EACVoZ,EAAO33B,OAAQuW,EAAO,KAOnBgI,GAAYyX,GAChBl4B,EAAOygB,QAASzjB,KAAM2B,MAIzBg7B,OAAQ,SAAUh7B,GAIjB,OAHc,IAATA,IACJA,EAAOA,GAAQ,MAET3B,KAAKkE,KAAM,WACjB,IAAIuX,EACHmH,EAAOG,EAASpf,IAAK3D,MACrB0d,EAAQkF,EAAMjhB,EAAO,SACrBgiB,EAAQf,EAAMjhB,EAAO,cACrBk7B,EAAS75B,EAAO65B,OAChBv5B,EAASoa,EAAQA,EAAMpa,OAAS,EAajC,IAVAsf,EAAK+Z,QAAS,EAGd35B,EAAO0a,MAAO1d,KAAM2B,EAAM,IAErBgiB,GAASA,EAAME,MACnBF,EAAME,KAAKpjB,KAAMT,MAAM,GAIlByb,EAAQohB,EAAOv5B,OAAQmY,KACvBohB,EAAQphB,GAAQpX,OAASrE,MAAQ68B,EAAQphB,GAAQiC,QAAU/b,IAC/Dk7B,EAAQphB,GAAQ8f,KAAK1X,MAAM,GAC3BgZ,EAAO33B,OAAQuW,EAAO,IAKxB,IAAMA,EAAQ,EAAGA,EAAQnY,EAAQmY,IAC3BiC,EAAOjC,IAAWiC,EAAOjC,GAAQkhB,QACrCjf,EAAOjC,GAAQkhB,OAAOl8B,KAAMT,aAKvB4iB,EAAK+Z,YAKf35B,EAAOkB,KAAM,CAAE,SAAU,OAAQ,QAAU,SAAUsD,EAAInC,GACxD,IAAIy3B,EAAQ95B,EAAOG,GAAIkC,GACvBrC,EAAOG,GAAIkC,GAAS,SAAU+2B,EAAO/F,EAAQlyB,GAC5C,OAAgB,MAATi4B,GAAkC,kBAAVA,EAC9BU,EAAMn8B,MAAOX,KAAMsE,WACnBtE,KAAKw8B,QAAStC,GAAO70B,GAAM,GAAQ+2B,EAAO/F,EAAQlyB,MAKrDnB,EAAOkB,KAAM,CACZ64B,UAAW7C,GAAO,QAClB8C,QAAS9C,GAAO,QAChB+C,YAAa/C,GAAO,UACpBgD,OAAQ,CAAE3G,QAAS,QACnB4G,QAAS,CAAE5G,QAAS,QACpB6G,WAAY,CAAE7G,QAAS,WACrB,SAAUlxB,EAAM4mB,GAClBjpB,EAAOG,GAAIkC,GAAS,SAAU+2B,EAAO/F,EAAQlyB,GAC5C,OAAOnE,KAAKw8B,QAASvQ,EAAOmQ,EAAO/F,EAAQlyB,MAI7CnB,EAAO65B,OAAS,GAChB75B,EAAO+1B,GAAGiB,KAAO,WAChB,IAAIsB,EACHn5B,EAAI,EACJ06B,EAAS75B,EAAO65B,OAIjB,IAFAtD,GAAQ7wB,KAAK4jB,MAELnqB,EAAI06B,EAAOv5B,OAAQnB,KAC1Bm5B,EAAQuB,EAAQ16B,OAGC06B,EAAQ16B,KAAQm5B,GAChCuB,EAAO33B,OAAQ/C,IAAK,GAIhB06B,EAAOv5B,QACZN,EAAO+1B,GAAGlV,OAEX0V,QAAQzzB,GAGT9C,EAAO+1B,GAAGuC,MAAQ,SAAUA,GAC3Bt4B,EAAO65B,OAAOj8B,KAAM06B,GACpBt4B,EAAO+1B,GAAG1kB,SAGXrR,EAAO+1B,GAAGgB,SAAW,GACrB/2B,EAAO+1B,GAAG1kB,MAAQ,WACZmlB,KAILA,IAAa,EACbI,OAGD52B,EAAO+1B,GAAGlV,KAAO,WAChB2V,GAAa,MAGdx2B,EAAO+1B,GAAGsD,OAAS,CAClBgB,KAAM,IACNC,KAAM,IAGNzW,SAAU,KAKX7jB,EAAOG,GAAGo6B,MAAQ,SAAUC,EAAM77B,GAIjC,OAHA67B,EAAOx6B,EAAO+1B,IAAK/1B,EAAO+1B,GAAGsD,OAAQmB,IAAiBA,EACtD77B,EAAOA,GAAQ,KAER3B,KAAK0d,MAAO/b,EAAM,SAAU4K,EAAMoX,GACxC,IAAI8Z,EAAU19B,EAAOkgB,WAAY1T,EAAMixB,GACvC7Z,EAAME,KAAO,WACZ9jB,EAAO29B,aAAcD,OAOnB1sB,GAAQnR,EAAS0C,cAAe,SAEnCm3B,GADS75B,EAAS0C,cAAe,UACpBK,YAAa/C,EAAS0C,cAAe,WAEnDyO,GAAMpP,KAAO,WAIbP,EAAQu8B,QAA0B,KAAhB5sB,GAAM5J,MAIxB/F,EAAQw8B,YAAcnE,GAAI1jB,UAI1BhF,GAAQnR,EAAS0C,cAAe,UAC1B6E,MAAQ,IACd4J,GAAMpP,KAAO,QACbP,EAAQy8B,WAA6B,MAAhB9sB,GAAM5J,MAI5B,IAAI22B,GACH/uB,GAAa/L,EAAOgP,KAAKjD,WAE1B/L,EAAOG,GAAGgC,OAAQ,CACjB+M,KAAM,SAAU7M,EAAM8B,GACrB,OAAOoa,EAAQvhB,KAAMgD,EAAOkP,KAAM7M,EAAM8B,EAA0B,EAAnB7C,UAAUhB,SAG1Dy6B,WAAY,SAAU14B,GACrB,OAAOrF,KAAKkE,KAAM,WACjBlB,EAAO+6B,WAAY/9B,KAAMqF,QAK5BrC,EAAOmC,OAAQ,CACd+M,KAAM,SAAU7N,EAAMgB,EAAM8B,GAC3B,IAAIpD,EAAK4f,EACRqa,EAAQ35B,EAAK9C,SAGd,GAAe,IAAVy8B,GAAyB,IAAVA,GAAyB,IAAVA,EAKnC,MAAkC,oBAAtB35B,EAAK7B,aACTQ,EAAO6f,KAAMxe,EAAMgB,EAAM8B,IAKlB,IAAV62B,GAAgBh7B,EAAOiX,SAAU5V,KACrCsf,EAAQ3gB,EAAOi7B,UAAW54B,EAAKoC,iBAC5BzE,EAAOgP,KAAKlF,MAAMjC,KAAK4C,KAAMpI,GAASy4B,QAAWh4B,SAGtCA,IAAVqB,EACW,OAAVA,OACJnE,EAAO+6B,WAAY15B,EAAMgB,GAIrBse,GAAS,QAASA,QACuB7d,KAA3C/B,EAAM4f,EAAMhB,IAAKte,EAAM8C,EAAO9B,IACzBtB,GAGRM,EAAK5B,aAAc4C,EAAM8B,EAAQ,IAC1BA,GAGHwc,GAAS,QAASA,GAA+C,QAApC5f,EAAM4f,EAAMhgB,IAAKU,EAAMgB,IACjDtB,EAMM,OAHdA,EAAMf,EAAO2N,KAAKuB,KAAM7N,EAAMgB,SAGTS,EAAY/B,IAGlCk6B,UAAW,CACVt8B,KAAM,CACLghB,IAAK,SAAUte,EAAM8C,GACpB,IAAM/F,EAAQy8B,YAAwB,UAAV12B,GAC3BkF,EAAUhI,EAAM,SAAY,CAC5B,IAAIjC,EAAMiC,EAAK8C,MAKf,OAJA9C,EAAK5B,aAAc,OAAQ0E,GACtB/E,IACJiC,EAAK8C,MAAQ/E,GAEP+E,MAMX42B,WAAY,SAAU15B,EAAM8C,GAC3B,IAAI9B,EACHlD,EAAI,EAIJ+7B,EAAY/2B,GAASA,EAAM2F,MAAOuP,GAEnC,GAAK6hB,GAA+B,IAAlB75B,EAAK9C,SACtB,MAAU8D,EAAO64B,EAAW/7B,KAC3BkC,EAAK8J,gBAAiB9I,MAO1By4B,GAAW,CACVnb,IAAK,SAAUte,EAAM8C,EAAO9B,GAQ3B,OAPe,IAAV8B,EAGJnE,EAAO+6B,WAAY15B,EAAMgB,GAEzBhB,EAAK5B,aAAc4C,EAAMA,GAEnBA,IAITrC,EAAOkB,KAAMlB,EAAOgP,KAAKlF,MAAMjC,KAAKsZ,OAAOrX,MAAO,QAAU,SAAUtF,EAAInC,GACzE,IAAI84B,EAASpvB,GAAY1J,IAAUrC,EAAO2N,KAAKuB,KAE/CnD,GAAY1J,GAAS,SAAUhB,EAAMgB,EAAMwC,GAC1C,IAAI9D,EAAKkmB,EACRmU,EAAgB/4B,EAAKoC,cAYtB,OAVMI,IAGLoiB,EAASlb,GAAYqvB,GACrBrvB,GAAYqvB,GAAkBr6B,EAC9BA,EAAqC,MAA/Bo6B,EAAQ95B,EAAMgB,EAAMwC,GACzBu2B,EACA,KACDrvB,GAAYqvB,GAAkBnU,GAExBlmB,KAOT,IAAIs6B,GAAa,sCAChBC,GAAa,gBAwIb,SAASC,GAAkBp3B,GAE1B,OADaA,EAAM2F,MAAOuP,IAAmB,IAC/BxO,KAAM,KAItB,SAAS2wB,GAAUn6B,GAClB,OAAOA,EAAK7B,cAAgB6B,EAAK7B,aAAc,UAAa,GAG7D,SAASi8B,GAAgBt3B,GACxB,OAAKvB,MAAMC,QAASsB,GACZA,EAEc,iBAAVA,GACJA,EAAM2F,MAAOuP,IAEd,GAvJRrZ,EAAOG,GAAGgC,OAAQ,CACjB0d,KAAM,SAAUxd,EAAM8B,GACrB,OAAOoa,EAAQvhB,KAAMgD,EAAO6f,KAAMxd,EAAM8B,EAA0B,EAAnB7C,UAAUhB,SAG1Do7B,WAAY,SAAUr5B,GACrB,OAAOrF,KAAKkE,KAAM,kBACVlE,KAAMgD,EAAO27B,QAASt5B,IAAUA,QAK1CrC,EAAOmC,OAAQ,CACd0d,KAAM,SAAUxe,EAAMgB,EAAM8B,GAC3B,IAAIpD,EAAK4f,EACRqa,EAAQ35B,EAAK9C,SAGd,GAAe,IAAVy8B,GAAyB,IAAVA,GAAyB,IAAVA,EAWnC,OAPe,IAAVA,GAAgBh7B,EAAOiX,SAAU5V,KAGrCgB,EAAOrC,EAAO27B,QAASt5B,IAAUA,EACjCse,EAAQ3gB,EAAOw1B,UAAWnzB,SAGZS,IAAVqB,EACCwc,GAAS,QAASA,QACuB7d,KAA3C/B,EAAM4f,EAAMhB,IAAKte,EAAM8C,EAAO9B,IACzBtB,EAGCM,EAAMgB,GAAS8B,EAGpBwc,GAAS,QAASA,GAA+C,QAApC5f,EAAM4f,EAAMhgB,IAAKU,EAAMgB,IACjDtB,EAGDM,EAAMgB,IAGdmzB,UAAW,CACV5iB,SAAU,CACTjS,IAAK,SAAUU,GAMd,IAAIu6B,EAAW57B,EAAO2N,KAAKuB,KAAM7N,EAAM,YAEvC,OAAKu6B,EACG1K,SAAU0K,EAAU,IAI3BP,GAAW5wB,KAAMpJ,EAAKgI,WACtBiyB,GAAW7wB,KAAMpJ,EAAKgI,WACtBhI,EAAKsR,KAEE,GAGA,KAKXgpB,QAAS,CACRE,MAAO,UACPC,QAAS,eAYL19B,EAAQw8B,cACb56B,EAAOw1B,UAAUziB,SAAW,CAC3BpS,IAAK,SAAUU,GAId,IAAIiQ,EAASjQ,EAAKzB,WAIlB,OAHK0R,GAAUA,EAAO1R,YACrB0R,EAAO1R,WAAWoT,cAEZ,MAER2M,IAAK,SAAUte,GAId,IAAIiQ,EAASjQ,EAAKzB,WACb0R,IACJA,EAAO0B,cAEF1B,EAAO1R,YACX0R,EAAO1R,WAAWoT,kBAOvBhT,EAAOkB,KAAM,CACZ,WACA,WACA,YACA,cACA,cACA,UACA,UACA,SACA,cACA,mBACE,WACFlB,EAAO27B,QAAS3+B,KAAKyH,eAAkBzH,OA4BxCgD,EAAOG,GAAGgC,OAAQ,CACjB45B,SAAU,SAAU53B,GACnB,IAAI63B,EAAY/vB,EAAKgwB,EAAU5uB,EAAWlO,EAAG+8B,EAE7C,OAAK79B,EAAY8F,GACTnH,KAAKkE,KAAM,SAAUa,GAC3B/B,EAAQhD,MAAO++B,SAAU53B,EAAM1G,KAAMT,KAAM+E,EAAGy5B,GAAUx+B,WAI1Dg/B,EAAaP,GAAgBt3B,IAEb7D,OACRtD,KAAKkE,KAAM,WAIjB,GAHA+6B,EAAWT,GAAUx+B,MACrBiP,EAAwB,IAAlBjP,KAAKuB,UAAoB,IAAMg9B,GAAkBU,GAAa,IAEzD,CACV,IAAM98B,EAAI,EAAGA,EAAI68B,EAAW17B,OAAQnB,IACnCkO,EAAY2uB,EAAY78B,GACnB8M,EAAIpO,QAAS,IAAMwP,EAAY,KAAQ,IAC3CpB,GAAOoB,EAAY,KAKrB6uB,EAAaX,GAAkBtvB,GAC1BgwB,IAAaC,GACjBl/B,KAAKyC,aAAc,QAASy8B,MAMzBl/B,MAGRm/B,YAAa,SAAUh4B,GACtB,IAAI63B,EAAY/vB,EAAKgwB,EAAU5uB,EAAWlO,EAAG+8B,EAE7C,OAAK79B,EAAY8F,GACTnH,KAAKkE,KAAM,SAAUa,GAC3B/B,EAAQhD,MAAOm/B,YAAah4B,EAAM1G,KAAMT,KAAM+E,EAAGy5B,GAAUx+B,UAIvDsE,UAAUhB,QAIhB07B,EAAaP,GAAgBt3B,IAEb7D,OACRtD,KAAKkE,KAAM,WAMjB,GALA+6B,EAAWT,GAAUx+B,MAGrBiP,EAAwB,IAAlBjP,KAAKuB,UAAoB,IAAMg9B,GAAkBU,GAAa,IAEzD,CACV,IAAM98B,EAAI,EAAGA,EAAI68B,EAAW17B,OAAQnB,IAAM,CACzCkO,EAAY2uB,EAAY78B,GAGxB,OAAgD,EAAxC8M,EAAIpO,QAAS,IAAMwP,EAAY,KACtCpB,EAAMA,EAAI/I,QAAS,IAAMmK,EAAY,IAAK,KAK5C6uB,EAAaX,GAAkBtvB,GAC1BgwB,IAAaC,GACjBl/B,KAAKyC,aAAc,QAASy8B,MAMzBl/B,KA/BCA,KAAKkS,KAAM,QAAS,KAkC7BktB,YAAa,SAAUj4B,EAAOk4B,GAC7B,IAAIL,EAAY3uB,EAAWlO,EAAGyY,EAC7BjZ,SAAcwF,EACdm4B,EAAwB,WAAT39B,GAAqBiE,MAAMC,QAASsB,GAEpD,OAAK9F,EAAY8F,GACTnH,KAAKkE,KAAM,SAAU/B,GAC3Ba,EAAQhD,MAAOo/B,YACdj4B,EAAM1G,KAAMT,KAAMmC,EAAGq8B,GAAUx+B,MAAQq/B,GACvCA,KAKsB,kBAAbA,GAA0BC,EAC9BD,EAAWr/B,KAAK++B,SAAU53B,GAAUnH,KAAKm/B,YAAah4B,IAG9D63B,EAAaP,GAAgBt3B,GAEtBnH,KAAKkE,KAAM,WACjB,GAAKo7B,EAKJ,IAFA1kB,EAAO5X,EAAQhD,MAETmC,EAAI,EAAGA,EAAI68B,EAAW17B,OAAQnB,IACnCkO,EAAY2uB,EAAY78B,GAGnByY,EAAK2kB,SAAUlvB,GACnBuK,EAAKukB,YAAa9uB,GAElBuK,EAAKmkB,SAAU1uB,aAKIvK,IAAVqB,GAAgC,YAATxF,KAClC0O,EAAYmuB,GAAUx+B,QAIrB+iB,EAASJ,IAAK3iB,KAAM,gBAAiBqQ,GAOjCrQ,KAAKyC,cACTzC,KAAKyC,aAAc,QAClB4N,IAAuB,IAAVlJ,EACZ,GACA4b,EAASpf,IAAK3D,KAAM,kBAAqB,SAO/Cu/B,SAAU,SAAUt8B,GACnB,IAAIoN,EAAWhM,EACdlC,EAAI,EAELkO,EAAY,IAAMpN,EAAW,IAC7B,MAAUoB,EAAOrE,KAAMmC,KACtB,GAAuB,IAAlBkC,EAAK9C,WACoE,GAA3E,IAAMg9B,GAAkBC,GAAUn6B,IAAW,KAAMxD,QAASwP,GAC9D,OAAO,EAIT,OAAO,KAOT,IAAImvB,GAAU,MAEdx8B,EAAOG,GAAGgC,OAAQ,CACjB/C,IAAK,SAAU+E,GACd,IAAIwc,EAAO5f,EAAK0rB,EACfprB,EAAOrE,KAAM,GAEd,OAAMsE,UAAUhB,QA0BhBmsB,EAAkBpuB,EAAY8F,GAEvBnH,KAAKkE,KAAM,SAAU/B,GAC3B,IAAIC,EAEmB,IAAlBpC,KAAKuB,WAWE,OANXa,EADIqtB,EACEtoB,EAAM1G,KAAMT,KAAMmC,EAAGa,EAAQhD,MAAOoC,OAEpC+E,GAKN/E,EAAM,GAEoB,iBAARA,EAClBA,GAAO,GAEIwD,MAAMC,QAASzD,KAC1BA,EAAMY,EAAOoB,IAAKhC,EAAK,SAAU+E,GAChC,OAAgB,MAATA,EAAgB,GAAKA,EAAQ,OAItCwc,EAAQ3gB,EAAOy8B,SAAUz/B,KAAK2B,OAAUqB,EAAOy8B,SAAUz/B,KAAKqM,SAAS5E,iBAGrD,QAASkc,QAA+C7d,IAApC6d,EAAMhB,IAAK3iB,KAAMoC,EAAK,WAC3DpC,KAAKmH,MAAQ/E,OAzDTiC,GACJsf,EAAQ3gB,EAAOy8B,SAAUp7B,EAAK1C,OAC7BqB,EAAOy8B,SAAUp7B,EAAKgI,SAAS5E,iBAG/B,QAASkc,QACgC7d,KAAvC/B,EAAM4f,EAAMhgB,IAAKU,EAAM,UAElBN,EAMY,iBAHpBA,EAAMM,EAAK8C,OAIHpD,EAAImC,QAASs5B,GAAS,IAIhB,MAAPz7B,EAAc,GAAKA,OAG3B,KAyCHf,EAAOmC,OAAQ,CACds6B,SAAU,CACTlZ,OAAQ,CACP5iB,IAAK,SAAUU,GAEd,IAAIjC,EAAMY,EAAO2N,KAAKuB,KAAM7N,EAAM,SAClC,OAAc,MAAPjC,EACNA,EAMAm8B,GAAkBv7B,EAAOT,KAAM8B,MAGlC2D,OAAQ,CACPrE,IAAK,SAAUU,GACd,IAAI8C,EAAOof,EAAQpkB,EAClBiD,EAAUf,EAAKe,QACfqW,EAAQpX,EAAK2R,cACbyS,EAAoB,eAAdpkB,EAAK1C,KACXgkB,EAAS8C,EAAM,KAAO,GACtB6M,EAAM7M,EAAMhN,EAAQ,EAAIrW,EAAQ9B,OAUjC,IAPCnB,EADIsZ,EAAQ,EACR6Z,EAGA7M,EAAMhN,EAAQ,EAIXtZ,EAAImzB,EAAKnzB,IAKhB,KAJAokB,EAASnhB,EAASjD,IAIJ4T,UAAY5T,IAAMsZ,KAG7B8K,EAAOna,YACLma,EAAO3jB,WAAWwJ,WACnBC,EAAUka,EAAO3jB,WAAY,aAAiB,CAMjD,GAHAuE,EAAQnE,EAAQujB,GAASnkB,MAGpBqmB,EACJ,OAAOthB,EAIRwe,EAAO/kB,KAAMuG,GAIf,OAAOwe,GAGRhD,IAAK,SAAUte,EAAM8C,GACpB,IAAIu4B,EAAWnZ,EACdnhB,EAAUf,EAAKe,QACfugB,EAAS3iB,EAAO2D,UAAWQ,GAC3BhF,EAAIiD,EAAQ9B,OAEb,MAAQnB,MACPokB,EAASnhB,EAASjD,IAIN4T,UACuD,EAAlE/S,EAAO6D,QAAS7D,EAAOy8B,SAASlZ,OAAO5iB,IAAK4iB,GAAUZ,MAEtD+Z,GAAY,GAUd,OAHMA,IACLr7B,EAAK2R,eAAiB,GAEhB2P,OAOX3iB,EAAOkB,KAAM,CAAE,QAAS,YAAc,WACrClB,EAAOy8B,SAAUz/B,MAAS,CACzB2iB,IAAK,SAAUte,EAAM8C,GACpB,GAAKvB,MAAMC,QAASsB,GACnB,OAAS9C,EAAKyR,SAA2D,EAAjD9S,EAAO6D,QAAS7D,EAAQqB,GAAOjC,MAAO+E,KAI3D/F,EAAQu8B,UACb36B,EAAOy8B,SAAUz/B,MAAO2D,IAAM,SAAUU,GACvC,OAAwC,OAAjCA,EAAK7B,aAAc,SAAqB,KAAO6B,EAAK8C,UAW9D/F,EAAQu+B,QAAU,cAAe5/B,EAGjC,IAAI6/B,GAAc,kCACjBC,GAA0B,SAAUpzB,GACnCA,EAAEyc,mBAGJlmB,EAAOmC,OAAQnC,EAAO2lB,MAAO,CAE5BU,QAAS,SAAUV,EAAO/F,EAAMve,EAAMy7B,GAErC,IAAI39B,EAAG8M,EAAK6B,EAAKivB,EAAYC,EAAQ/V,EAAQ3K,EAAS2gB,EACrDC,EAAY,CAAE77B,GAAQzE,GACtB+B,EAAOX,EAAOP,KAAMkoB,EAAO,QAAWA,EAAMhnB,KAAOgnB,EACnDkB,EAAa7oB,EAAOP,KAAMkoB,EAAO,aAAgBA,EAAM/Y,UAAUrI,MAAO,KAAQ,GAKjF,GAHA0H,EAAMgxB,EAAcnvB,EAAMzM,EAAOA,GAAQzE,EAGlB,IAAlByE,EAAK9C,UAAoC,IAAlB8C,EAAK9C,WAK5Bq+B,GAAYnyB,KAAM9L,EAAOqB,EAAO2lB,MAAMuB,cAIf,EAAvBvoB,EAAKd,QAAS,OAIlBc,GADAkoB,EAAaloB,EAAK4F,MAAO,MACPiH,QAClBqb,EAAW5kB,QAEZ+6B,EAASr+B,EAAKd,QAAS,KAAQ,GAAK,KAAOc,GAG3CgnB,EAAQA,EAAO3lB,EAAO+C,SACrB4iB,EACA,IAAI3lB,EAAOsmB,MAAO3nB,EAAuB,iBAAVgnB,GAAsBA,IAGhDK,UAAY8W,EAAe,EAAI,EACrCnX,EAAM/Y,UAAYia,EAAWhc,KAAM,KACnC8a,EAAMwC,WAAaxC,EAAM/Y,UACxB,IAAI7F,OAAQ,UAAY8f,EAAWhc,KAAM,iBAAoB,WAC7D,KAGD8a,EAAMjV,YAAS5N,EACT6iB,EAAMljB,SACXkjB,EAAMljB,OAASpB,GAIhBue,EAAe,MAARA,EACN,CAAE+F,GACF3lB,EAAO2D,UAAWic,EAAM,CAAE+F,IAG3BrJ,EAAUtc,EAAO2lB,MAAMrJ,QAAS3d,IAAU,GACpCm+B,IAAgBxgB,EAAQ+J,UAAmD,IAAxC/J,EAAQ+J,QAAQ1oB,MAAO0D,EAAMue,IAAtE,CAMA,IAAMkd,IAAiBxgB,EAAQuM,WAAapqB,EAAU4C,GAAS,CAM9D,IAJA07B,EAAazgB,EAAQ2J,cAAgBtnB,EAC/Bi+B,GAAYnyB,KAAMsyB,EAAap+B,KACpCsN,EAAMA,EAAIrM,YAEHqM,EAAKA,EAAMA,EAAIrM,WACtBs9B,EAAUt/B,KAAMqO,GAChB6B,EAAM7B,EAIF6B,KAAUzM,EAAK6I,eAAiBtN,IACpCsgC,EAAUt/B,KAAMkQ,EAAIb,aAAea,EAAIqvB,cAAgBpgC,GAKzDoC,EAAI,EACJ,OAAU8M,EAAMixB,EAAW/9B,QAAYwmB,EAAMqC,uBAC5CiV,EAAchxB,EACd0Z,EAAMhnB,KAAW,EAAJQ,EACZ49B,EACAzgB,EAAQ8K,UAAYzoB,GAGrBsoB,GAAWlH,EAASpf,IAAKsL,EAAK,WAAc7O,OAAO4pB,OAAQ,OAAUrB,EAAMhnB,OAC1EohB,EAASpf,IAAKsL,EAAK,YAEnBgb,EAAOtpB,MAAOsO,EAAK2T,IAIpBqH,EAAS+V,GAAU/wB,EAAK+wB,KACT/V,EAAOtpB,OAAS0hB,EAAYpT,KAC1C0Z,EAAMjV,OAASuW,EAAOtpB,MAAOsO,EAAK2T,IACZ,IAAjB+F,EAAMjV,QACViV,EAAMS,kBA8CT,OA1CAT,EAAMhnB,KAAOA,EAGPm+B,GAAiBnX,EAAMuD,sBAEpB5M,EAAQuH,WACqC,IAApDvH,EAAQuH,SAASlmB,MAAOu/B,EAAU52B,MAAOsZ,KACzCP,EAAYhe,IAIP27B,GAAU3+B,EAAYgD,EAAM1C,MAAaF,EAAU4C,MAGvDyM,EAAMzM,EAAM27B,MAGX37B,EAAM27B,GAAW,MAIlBh9B,EAAO2lB,MAAMuB,UAAYvoB,EAEpBgnB,EAAMqC,wBACViV,EAAY9vB,iBAAkBxO,EAAMk+B,IAGrCx7B,EAAM1C,KAEDgnB,EAAMqC,wBACViV,EAAY/e,oBAAqBvf,EAAMk+B,IAGxC78B,EAAO2lB,MAAMuB,eAAYpkB,EAEpBgL,IACJzM,EAAM27B,GAAWlvB,IAMd6X,EAAMjV,SAKd0sB,SAAU,SAAUz+B,EAAM0C,EAAMskB,GAC/B,IAAIlc,EAAIzJ,EAAOmC,OACd,IAAInC,EAAOsmB,MACXX,EACA,CACChnB,KAAMA,EACN4qB,aAAa,IAIfvpB,EAAO2lB,MAAMU,QAAS5c,EAAG,KAAMpI,MAKjCrB,EAAOG,GAAGgC,OAAQ,CAEjBkkB,QAAS,SAAU1nB,EAAMihB,GACxB,OAAO5iB,KAAKkE,KAAM,WACjBlB,EAAO2lB,MAAMU,QAAS1nB,EAAMihB,EAAM5iB,SAGpCqgC,eAAgB,SAAU1+B,EAAMihB,GAC/B,IAAIve,EAAOrE,KAAM,GACjB,GAAKqE,EACJ,OAAOrB,EAAO2lB,MAAMU,QAAS1nB,EAAMihB,EAAMve,GAAM,MAc5CjD,EAAQu+B,SACb38B,EAAOkB,KAAM,CAAEsR,MAAO,UAAW4Y,KAAM,YAAc,SAAUK,EAAM5D,GAGpE,IAAI/b,EAAU,SAAU6Z,GACvB3lB,EAAO2lB,MAAMyX,SAAUvV,EAAKlC,EAAMljB,OAAQzC,EAAO2lB,MAAMkC,IAAKlC,KAG7D3lB,EAAO2lB,MAAMrJ,QAASuL,GAAQ,CAC7BP,MAAO,WAIN,IAAIpoB,EAAMlC,KAAKkN,eAAiBlN,KAAKJ,UAAYI,KAChDsgC,EAAWvd,EAASxB,OAAQrf,EAAK2oB,GAE5ByV,GACLp+B,EAAIiO,iBAAkBse,EAAM3f,GAAS,GAEtCiU,EAASxB,OAAQrf,EAAK2oB,GAAOyV,GAAY,GAAM,IAEhD7V,SAAU,WACT,IAAIvoB,EAAMlC,KAAKkN,eAAiBlN,KAAKJ,UAAYI,KAChDsgC,EAAWvd,EAASxB,OAAQrf,EAAK2oB,GAAQ,EAEpCyV,EAKLvd,EAASxB,OAAQrf,EAAK2oB,EAAKyV,IAJ3Bp+B,EAAIgf,oBAAqBuN,EAAM3f,GAAS,GACxCiU,EAAShF,OAAQ7b,EAAK2oB,QAS3B,IAAIvV,GAAWvV,EAAOuV,SAElBzT,GAAQ,CAAEuF,KAAMsB,KAAK4jB,OAErBiU,GAAS,KAKbv9B,EAAOw9B,SAAW,SAAU5d,GAC3B,IAAI3O,EAAKwsB,EACT,IAAM7d,GAAwB,iBAATA,EACpB,OAAO,KAKR,IACC3O,GAAM,IAAMlU,EAAO2gC,WAAcC,gBAAiB/d,EAAM,YACvD,MAAQnW,IAYV,OAVAg0B,EAAkBxsB,GAAOA,EAAI3G,qBAAsB,eAAiB,GAC9D2G,IAAOwsB,GACZz9B,EAAOoD,MAAO,iBACbq6B,EACCz9B,EAAOoB,IAAKq8B,EAAgBj0B,WAAY,SAAUmC,GACjD,OAAOA,EAAG8D,cACP5E,KAAM,MACV+U,IAGI3O,GAIR,IACC2sB,GAAW,QACXC,GAAQ,SACRC,GAAkB,wCAClBC,GAAe,qCAEhB,SAASC,GAAa7I,EAAQ72B,EAAK2/B,EAAatlB,GAC/C,IAAItW,EAEJ,GAAKO,MAAMC,QAASvE,GAGnB0B,EAAOkB,KAAM5C,EAAK,SAAUa,EAAGoa,GACzB0kB,GAAeL,GAASnzB,KAAM0qB,GAGlCxc,EAAKwc,EAAQ5b,GAKbykB,GACC7I,EAAS,KAAqB,iBAAN5b,GAAuB,MAALA,EAAYpa,EAAI,IAAO,IACjEoa,EACA0kB,EACAtlB,UAKG,GAAMslB,GAAiC,WAAlBn+B,EAAQxB,GAUnCqa,EAAKwc,EAAQ72B,QAPb,IAAM+D,KAAQ/D,EACb0/B,GAAa7I,EAAS,IAAM9yB,EAAO,IAAK/D,EAAK+D,GAAQ47B,EAAatlB,GAYrE3Y,EAAOk+B,MAAQ,SAAU93B,EAAG63B,GAC3B,IAAI9I,EACHgJ,EAAI,GACJxlB,EAAM,SAAUrN,EAAK8yB,GAGpB,IAAIj6B,EAAQ9F,EAAY+/B,GACvBA,IACAA,EAEDD,EAAGA,EAAE79B,QAAW+9B,mBAAoB/yB,GAAQ,IAC3C+yB,mBAA6B,MAATl6B,EAAgB,GAAKA,IAG5C,GAAU,MAALiC,EACJ,MAAO,GAIR,GAAKxD,MAAMC,QAASuD,IAASA,EAAE5F,SAAWR,EAAO2C,cAAeyD,GAG/DpG,EAAOkB,KAAMkF,EAAG,WACfuS,EAAK3b,KAAKqF,KAAMrF,KAAKmH,cAOtB,IAAMgxB,KAAU/uB,EACf43B,GAAa7I,EAAQ/uB,EAAG+uB,GAAU8I,EAAatlB,GAKjD,OAAOwlB,EAAEtzB,KAAM,MAGhB7K,EAAOG,GAAGgC,OAAQ,CACjBm8B,UAAW,WACV,OAAOt+B,EAAOk+B,MAAOlhC,KAAKuhC,mBAE3BA,eAAgB,WACf,OAAOvhC,KAAKoE,IAAK,WAGhB,IAAI6N,EAAWjP,EAAO6f,KAAM7iB,KAAM,YAClC,OAAOiS,EAAWjP,EAAO2D,UAAWsL,GAAajS,OAC9CyQ,OAAQ,WACX,IAAI9O,EAAO3B,KAAK2B,KAGhB,OAAO3B,KAAKqF,OAASrC,EAAQhD,MAAOqa,GAAI,cACvC0mB,GAAatzB,KAAMzN,KAAKqM,YAAey0B,GAAgBrzB,KAAM9L,KAC3D3B,KAAK8V,UAAYkQ,GAAevY,KAAM9L,MACtCyC,IAAK,SAAUoD,EAAInD,GACtB,IAAIjC,EAAMY,EAAQhD,MAAOoC,MAEzB,OAAY,MAAPA,EACG,KAGHwD,MAAMC,QAASzD,GACZY,EAAOoB,IAAKhC,EAAK,SAAUA,GACjC,MAAO,CAAEiD,KAAMhB,EAAKgB,KAAM8B,MAAO/E,EAAI8D,QAAS26B,GAAO,WAIhD,CAAEx7B,KAAMhB,EAAKgB,KAAM8B,MAAO/E,EAAI8D,QAAS26B,GAAO,WAClDl9B,SAKN,IACC69B,GAAM,OACNC,GAAQ,OACRC,GAAa,gBACbC,GAAW,6BAIXC,GAAa,iBACbC,GAAY,QAWZnH,GAAa,GAOboH,GAAa,GAGbC,GAAW,KAAKrhC,OAAQ,KAGxBshC,GAAepiC,EAAS0C,cAAe,KAKxC,SAAS2/B,GAA6BC,GAGrC,OAAO,SAAUC,EAAoB/jB,GAED,iBAAvB+jB,IACX/jB,EAAO+jB,EACPA,EAAqB,KAGtB,IAAIC,EACHjgC,EAAI,EACJkgC,EAAYF,EAAmB16B,cAAcqF,MAAOuP,IAAmB,GAExE,GAAKhb,EAAY+c,GAGhB,MAAUgkB,EAAWC,EAAWlgC,KAGR,MAAlBigC,EAAU,IACdA,EAAWA,EAAS9hC,MAAO,IAAO,KAChC4hC,EAAWE,GAAaF,EAAWE,IAAc,IAAKrwB,QAASqM,KAI/D8jB,EAAWE,GAAaF,EAAWE,IAAc,IAAKxhC,KAAMwd,IAQnE,SAASkkB,GAA+BJ,EAAW98B,EAAS61B,EAAiBsH,GAE5E,IAAIC,EAAY,GACfC,EAAqBP,IAAcJ,GAEpC,SAASY,EAASN,GACjB,IAAIrsB,EAcJ,OAbAysB,EAAWJ,IAAa,EACxBp/B,EAAOkB,KAAMg+B,EAAWE,IAAc,GAAI,SAAUhlB,EAAGulB,GACtD,IAAIC,EAAsBD,EAAoBv9B,EAAS61B,EAAiBsH,GACxE,MAAoC,iBAAxBK,GACVH,GAAqBD,EAAWI,GAKtBH,IACD1sB,EAAW6sB,QADf,GAHNx9B,EAAQi9B,UAAUtwB,QAAS6wB,GAC3BF,EAASE,IACF,KAKF7sB,EAGR,OAAO2sB,EAASt9B,EAAQi9B,UAAW,MAAUG,EAAW,MAASE,EAAS,KAM3E,SAASG,GAAYp9B,EAAQ7D,GAC5B,IAAI0M,EAAK5I,EACRo9B,EAAc9/B,EAAO+/B,aAAaD,aAAe,GAElD,IAAMx0B,KAAO1M,OACQkE,IAAflE,EAAK0M,MACPw0B,EAAax0B,GAAQ7I,EAAWC,IAAUA,EAAO,KAAU4I,GAAQ1M,EAAK0M,IAO5E,OAJK5I,GACJ1C,EAAOmC,QAAQ,EAAMM,EAAQC,GAGvBD,EA/ERu8B,GAAarsB,KAAOL,GAASK,KAgP7B3S,EAAOmC,OAAQ,CAGd69B,OAAQ,EAGRC,aAAc,GACdC,KAAM,GAENH,aAAc,CACbI,IAAK7tB,GAASK,KACdhU,KAAM,MACNyhC,QAxRgB,4DAwRQ31B,KAAM6H,GAAS+tB,UACvC7jC,QAAQ,EACR8jC,aAAa,EACbC,OAAO,EACPC,YAAa,mDAcbC,QAAS,CACRjI,IAAKuG,GACLx/B,KAAM,aACNmtB,KAAM,YACNzb,IAAK,4BACLyvB,KAAM,qCAGPvoB,SAAU,CACTlH,IAAK,UACLyb,KAAM,SACNgU,KAAM,YAGPC,eAAgB,CACf1vB,IAAK,cACL1R,KAAM,eACNmhC,KAAM,gBAKPE,WAAY,CAGXC,SAAUn4B,OAGVo4B,aAAa,EAGbC,YAAa3gB,KAAKC,MAGlB2gB,WAAYhhC,EAAOw9B,UAOpBsC,YAAa,CACZK,KAAK,EACLjgC,SAAS,IAOX+gC,UAAW,SAAUx+B,EAAQy+B,GAC5B,OAAOA,EAGNrB,GAAYA,GAAYp9B,EAAQzC,EAAO+/B,cAAgBmB,GAGvDrB,GAAY7/B,EAAO+/B,aAAct9B,IAGnC0+B,cAAelC,GAA6BvH,IAC5C0J,cAAenC,GAA6BH,IAG5CuC,KAAM,SAAUlB,EAAK/9B,GAGA,iBAAR+9B,IACX/9B,EAAU+9B,EACVA,OAAMr9B,GAIPV,EAAUA,GAAW,GAErB,IAAIk/B,EAGHC,EAGAC,EACAC,EAGAC,EAGAC,EAGA1jB,EAGA2jB,EAGAziC,EAGA0iC,EAGA1D,EAAIn+B,EAAOihC,UAAW,GAAI7+B,GAG1B0/B,EAAkB3D,EAAEj+B,SAAWi+B,EAG/B4D,EAAqB5D,EAAEj+B,UACpB4hC,EAAgBvjC,UAAYujC,EAAgBthC,QAC9CR,EAAQ8hC,GACR9hC,EAAO2lB,MAGRnK,EAAWxb,EAAOmb,WAClB6mB,EAAmBhiC,EAAOka,UAAW,eAGrC+nB,EAAa9D,EAAE8D,YAAc,GAG7BC,EAAiB,GACjBC,EAAsB,GAGtBC,EAAW,WAGX7C,EAAQ,CACPlhB,WAAY,EAGZgkB,kBAAmB,SAAU/2B,GAC5B,IAAIxB,EACJ,GAAKmU,EAAY,CAChB,IAAMwjB,EAAkB,CACvBA,EAAkB,GAClB,MAAU33B,EAAQ60B,GAASx0B,KAAMq3B,GAChCC,EAAiB33B,EAAO,GAAIrF,cAAgB,MACzCg9B,EAAiB33B,EAAO,GAAIrF,cAAgB,MAAS,IACrD/G,OAAQoM,EAAO,IAGpBA,EAAQ23B,EAAiBn2B,EAAI7G,cAAgB,KAE9C,OAAgB,MAATqF,EAAgB,KAAOA,EAAMe,KAAM,OAI3Cy3B,sBAAuB,WACtB,OAAOrkB,EAAYujB,EAAwB,MAI5Ce,iBAAkB,SAAUlgC,EAAM8B,GAMjC,OALkB,MAAb8Z,IACJ5b,EAAO8/B,EAAqB9/B,EAAKoC,eAChC09B,EAAqB9/B,EAAKoC,gBAAmBpC,EAC9C6/B,EAAgB7/B,GAAS8B,GAEnBnH,MAIRwlC,iBAAkB,SAAU7jC,GAI3B,OAHkB,MAAbsf,IACJkgB,EAAEsE,SAAW9jC,GAEP3B,MAIRilC,WAAY,SAAU7gC,GACrB,IAAIpC,EACJ,GAAKoC,EACJ,GAAK6c,EAGJshB,EAAMhkB,OAAQna,EAAKm+B,EAAMmD,cAIzB,IAAM1jC,KAAQoC,EACb6gC,EAAYjjC,GAAS,CAAEijC,EAAYjjC,GAAQoC,EAAKpC,IAInD,OAAOhC,MAIR2lC,MAAO,SAAUC,GAChB,IAAIC,EAAYD,GAAcR,EAK9B,OAJKd,GACJA,EAAUqB,MAAOE,GAElBh9B,EAAM,EAAGg9B,GACF7lC,OAoBV,GAfAwe,EAASzB,QAASwlB,GAKlBpB,EAAEgC,MAAUA,GAAOhC,EAAEgC,KAAO7tB,GAASK,MAAS,IAC5CzP,QAAS27B,GAAWvsB,GAAS+tB,SAAW,MAG1ClC,EAAEx/B,KAAOyD,EAAQ0X,QAAU1X,EAAQzD,MAAQw/B,EAAErkB,QAAUqkB,EAAEx/B,KAGzDw/B,EAAEkB,WAAclB,EAAEiB,UAAY,KAAM36B,cAAcqF,MAAOuP,IAAmB,CAAE,IAGxD,MAAjB8kB,EAAE2E,YAAsB,CAC5BnB,EAAY/kC,EAAS0C,cAAe,KAKpC,IACCqiC,EAAUhvB,KAAOwrB,EAAEgC,IAInBwB,EAAUhvB,KAAOgvB,EAAUhvB,KAC3BwrB,EAAE2E,YAAc9D,GAAaqB,SAAW,KAAOrB,GAAa+D,MAC3DpB,EAAUtB,SAAW,KAAOsB,EAAUoB,KACtC,MAAQt5B,GAIT00B,EAAE2E,aAAc,GAalB,GARK3E,EAAEve,MAAQue,EAAEmC,aAAiC,iBAAXnC,EAAEve,OACxCue,EAAEve,KAAO5f,EAAOk+B,MAAOC,EAAEve,KAAMue,EAAEF,cAIlCqB,GAA+B5H,GAAYyG,EAAG/7B,EAASm9B,GAGlDthB,EACJ,OAAOshB,EA8ER,IAAMpgC,KAzENyiC,EAAc5hC,EAAO2lB,OAASwY,EAAE3hC,SAGQ,GAApBwD,EAAOggC,UAC1BhgC,EAAO2lB,MAAMU,QAAS,aAIvB8X,EAAEx/B,KAAOw/B,EAAEx/B,KAAKugB,cAGhBif,EAAE6E,YAAcpE,GAAWn0B,KAAM0zB,EAAEx/B,MAKnC4iC,EAAWpD,EAAEgC,IAAIj9B,QAASu7B,GAAO,IAG3BN,EAAE6E,WAwBI7E,EAAEve,MAAQue,EAAEmC,aACoD,KAAzEnC,EAAEqC,aAAe,IAAK3iC,QAAS,uCACjCsgC,EAAEve,KAAOue,EAAEve,KAAK1c,QAASs7B,GAAK,OAvB9BqD,EAAW1D,EAAEgC,IAAI7iC,MAAOikC,EAASjhC,QAG5B69B,EAAEve,OAAUue,EAAEmC,aAAiC,iBAAXnC,EAAEve,QAC1C2hB,IAAchE,GAAO9yB,KAAM82B,GAAa,IAAM,KAAQpD,EAAEve,YAGjDue,EAAEve,OAIO,IAAZue,EAAE9yB,QACNk2B,EAAWA,EAASr+B,QAASw7B,GAAY,MACzCmD,GAAatE,GAAO9yB,KAAM82B,GAAa,IAAM,KAAQ,KAAS1iC,GAAMuF,OACnEy9B,GAIF1D,EAAEgC,IAAMoB,EAAWM,GASf1D,EAAE8E,aACDjjC,EAAOigC,aAAcsB,IACzBhC,EAAMgD,iBAAkB,oBAAqBviC,EAAOigC,aAAcsB,IAE9DvhC,EAAOkgC,KAAMqB,IACjBhC,EAAMgD,iBAAkB,gBAAiBviC,EAAOkgC,KAAMqB,MAKnDpD,EAAEve,MAAQue,EAAE6E,aAAgC,IAAlB7E,EAAEqC,aAAyBp+B,EAAQo+B,cACjEjB,EAAMgD,iBAAkB,eAAgBpE,EAAEqC,aAI3CjB,EAAMgD,iBACL,SACApE,EAAEkB,UAAW,IAAOlB,EAAEsC,QAAStC,EAAEkB,UAAW,IAC3ClB,EAAEsC,QAAStC,EAAEkB,UAAW,KACA,MAArBlB,EAAEkB,UAAW,GAAc,KAAON,GAAW,WAAa,IAC7DZ,EAAEsC,QAAS,MAIFtC,EAAE+E,QACZ3D,EAAMgD,iBAAkBpjC,EAAGg/B,EAAE+E,QAAS/jC,IAIvC,GAAKg/B,EAAEgF,cAC+C,IAAnDhF,EAAEgF,WAAW1lC,KAAMqkC,EAAiBvC,EAAOpB,IAAiBlgB,GAG9D,OAAOshB,EAAMoD,QAed,GAXAP,EAAW,QAGXJ,EAAiBrpB,IAAKwlB,EAAE9F,UACxBkH,EAAM15B,KAAMs4B,EAAEiF,SACd7D,EAAMvlB,KAAMmkB,EAAE/6B,OAGdk+B,EAAYhC,GAA+BR,GAAYX,EAAG/7B,EAASm9B,GAK5D,CASN,GARAA,EAAMlhB,WAAa,EAGdujB,GACJG,EAAmB1b,QAAS,WAAY,CAAEkZ,EAAOpB,IAI7ClgB,EACJ,OAAOshB,EAIHpB,EAAEoC,OAAqB,EAAZpC,EAAE1D,UACjBiH,EAAe3kC,EAAOkgB,WAAY,WACjCsiB,EAAMoD,MAAO,YACXxE,EAAE1D,UAGN,IACCxc,GAAY,EACZqjB,EAAU+B,KAAMnB,EAAgBr8B,GAC/B,MAAQ4D,GAGT,GAAKwU,EACJ,MAAMxU,EAIP5D,GAAO,EAAG4D,SAhCX5D,GAAO,EAAG,gBAqCX,SAASA,EAAM68B,EAAQY,EAAkBC,EAAWL,GACnD,IAAIM,EAAWJ,EAAShgC,EAAOqgC,EAAUC,EACxCd,EAAaU,EAGTrlB,IAILA,GAAY,EAGPyjB,GACJ3kC,EAAO29B,aAAcgH,GAKtBJ,OAAYx+B,EAGZ0+B,EAAwB0B,GAAW,GAGnC3D,EAAMlhB,WAAsB,EAATqkB,EAAa,EAAI,EAGpCc,EAAsB,KAAVd,GAAiBA,EAAS,KAAkB,MAAXA,EAGxCa,IACJE,EA7lBJ,SAA8BtF,EAAGoB,EAAOgE,GAEvC,IAAII,EAAIhlC,EAAMilC,EAAeC,EAC5B1rB,EAAWgmB,EAAEhmB,SACbknB,EAAYlB,EAAEkB,UAGf,MAA2B,MAAnBA,EAAW,GAClBA,EAAU7zB,aACE1I,IAAP6gC,IACJA,EAAKxF,EAAEsE,UAAYlD,EAAM8C,kBAAmB,iBAK9C,GAAKsB,EACJ,IAAMhlC,KAAQwZ,EACb,GAAKA,EAAUxZ,IAAUwZ,EAAUxZ,GAAO8L,KAAMk5B,GAAO,CACtDtE,EAAUtwB,QAASpQ,GACnB,MAMH,GAAK0gC,EAAW,KAAOkE,EACtBK,EAAgBvE,EAAW,OACrB,CAGN,IAAM1gC,KAAQ4kC,EAAY,CACzB,IAAMlE,EAAW,IAAOlB,EAAEyC,WAAYjiC,EAAO,IAAM0gC,EAAW,IAAQ,CACrEuE,EAAgBjlC,EAChB,MAEKklC,IACLA,EAAgBllC,GAKlBilC,EAAgBA,GAAiBC,EAMlC,GAAKD,EAIJ,OAHKA,IAAkBvE,EAAW,IACjCA,EAAUtwB,QAAS60B,GAEbL,EAAWK,GA0iBLE,CAAqB3F,EAAGoB,EAAOgE,KAIrCC,IACsC,EAA3CxjC,EAAO6D,QAAS,SAAUs6B,EAAEkB,YAC5Br/B,EAAO6D,QAAS,OAAQs6B,EAAEkB,WAAc,IACxClB,EAAEyC,WAAY,eAAkB,cAIjC6C,EA9iBH,SAAsBtF,EAAGsF,EAAUlE,EAAOiE,GACzC,IAAIO,EAAOC,EAASC,EAAMn2B,EAAKsK,EAC9BwoB,EAAa,GAGbvB,EAAYlB,EAAEkB,UAAU/hC,QAGzB,GAAK+hC,EAAW,GACf,IAAM4E,KAAQ9F,EAAEyC,WACfA,EAAYqD,EAAKx/B,eAAkB05B,EAAEyC,WAAYqD,GAInDD,EAAU3E,EAAU7zB,QAGpB,MAAQw4B,EAcP,GAZK7F,EAAEwC,eAAgBqD,KACtBzE,EAAOpB,EAAEwC,eAAgBqD,IAAcP,IAIlCrrB,GAAQorB,GAAarF,EAAE+F,aAC5BT,EAAWtF,EAAE+F,WAAYT,EAAUtF,EAAEiB,WAGtChnB,EAAO4rB,EACPA,EAAU3E,EAAU7zB,QAKnB,GAAiB,MAAZw4B,EAEJA,EAAU5rB,OAGJ,GAAc,MAATA,GAAgBA,IAAS4rB,EAAU,CAM9C,KAHAC,EAAOrD,EAAYxoB,EAAO,IAAM4rB,IAAapD,EAAY,KAAOoD,IAI/D,IAAMD,KAASnD,EAId,IADA9yB,EAAMi2B,EAAMx/B,MAAO,MACT,KAAQy/B,IAGjBC,EAAOrD,EAAYxoB,EAAO,IAAMtK,EAAK,KACpC8yB,EAAY,KAAO9yB,EAAK,KACb,EAGG,IAATm2B,EACJA,EAAOrD,EAAYmD,IAGgB,IAAxBnD,EAAYmD,KACvBC,EAAUl2B,EAAK,GACfuxB,EAAUtwB,QAASjB,EAAK,KAEzB,MAOJ,IAAc,IAATm2B,EAGJ,GAAKA,GAAQ9F,EAAEgG,UACdV,EAAWQ,EAAMR,QAEjB,IACCA,EAAWQ,EAAMR,GAChB,MAAQh6B,GACT,MAAO,CACN6R,MAAO,cACPlY,MAAO6gC,EAAOx6B,EAAI,sBAAwB2O,EAAO,OAAS4rB,IASjE,MAAO,CAAE1oB,MAAO,UAAWsE,KAAM6jB,GAidpBW,CAAajG,EAAGsF,EAAUlE,EAAOiE,GAGvCA,GAGCrF,EAAE8E,cACNS,EAAWnE,EAAM8C,kBAAmB,oBAEnCriC,EAAOigC,aAAcsB,GAAamC,IAEnCA,EAAWnE,EAAM8C,kBAAmB,WAEnCriC,EAAOkgC,KAAMqB,GAAamC,IAKZ,MAAXhB,GAA6B,SAAXvE,EAAEx/B,KACxBikC,EAAa,YAGS,MAAXF,EACXE,EAAa,eAIbA,EAAaa,EAASnoB,MACtB8nB,EAAUK,EAAS7jB,KAEnB4jB,IADApgC,EAAQqgC,EAASrgC,UAMlBA,EAAQw/B,GACHF,GAAWE,IACfA,EAAa,QACRF,EAAS,IACbA,EAAS,KAMZnD,EAAMmD,OAASA,EACfnD,EAAMqD,YAAeU,GAAoBV,GAAe,GAGnDY,EACJhoB,EAASmB,YAAamlB,EAAiB,CAAEsB,EAASR,EAAYrD,IAE9D/jB,EAASuB,WAAY+kB,EAAiB,CAAEvC,EAAOqD,EAAYx/B,IAI5Dm8B,EAAM0C,WAAYA,GAClBA,OAAan/B,EAER8+B,GACJG,EAAmB1b,QAASmd,EAAY,cAAgB,YACvD,CAAEjE,EAAOpB,EAAGqF,EAAYJ,EAAUhgC,IAIpC4+B,EAAiB9mB,SAAU4mB,EAAiB,CAAEvC,EAAOqD,IAEhDhB,IACJG,EAAmB1b,QAAS,eAAgB,CAAEkZ,EAAOpB,MAG3Cn+B,EAAOggC,QAChBhgC,EAAO2lB,MAAMU,QAAS,cAKzB,OAAOkZ,GAGR8E,QAAS,SAAUlE,EAAKvgB,EAAMze,GAC7B,OAAOnB,EAAOW,IAAKw/B,EAAKvgB,EAAMze,EAAU,SAGzCmjC,UAAW,SAAUnE,EAAKh/B,GACzB,OAAOnB,EAAOW,IAAKw/B,OAAKr9B,EAAW3B,EAAU,aAI/CnB,EAAOkB,KAAM,CAAE,MAAO,QAAU,SAAUsD,EAAIsV,GAC7C9Z,EAAQ8Z,GAAW,SAAUqmB,EAAKvgB,EAAMze,EAAUxC,GAUjD,OAPKN,EAAYuhB,KAChBjhB,EAAOA,GAAQwC,EACfA,EAAWye,EACXA,OAAO9c,GAID9C,EAAOqhC,KAAMrhC,EAAOmC,OAAQ,CAClCg+B,IAAKA,EACLxhC,KAAMmb,EACNslB,SAAUzgC,EACVihB,KAAMA,EACNwjB,QAASjiC,GACPnB,EAAO2C,cAAew9B,IAASA,OAIpCngC,EAAOmhC,cAAe,SAAUhD,GAC/B,IAAIh/B,EACJ,IAAMA,KAAKg/B,EAAE+E,QACa,iBAApB/jC,EAAEsF,gBACN05B,EAAEqC,YAAcrC,EAAE+E,QAAS/jC,IAAO,MAMrCa,EAAO2sB,SAAW,SAAUwT,EAAK/9B,EAASlD,GACzC,OAAOc,EAAOqhC,KAAM,CACnBlB,IAAKA,EAGLxhC,KAAM,MACNygC,SAAU,SACV/zB,OAAO,EACPk1B,OAAO,EACP/jC,QAAQ,EAKRokC,WAAY,CACX2D,cAAe,cAEhBL,WAAY,SAAUT,GACrBzjC,EAAO0D,WAAY+/B,EAAUrhC,EAASlD,OAMzCc,EAAOG,GAAGgC,OAAQ,CACjBqiC,QAAS,SAAU9X,GAClB,IAAI/H,EAyBJ,OAvBK3nB,KAAM,KACLqB,EAAYquB,KAChBA,EAAOA,EAAKjvB,KAAMT,KAAM,KAIzB2nB,EAAO3kB,EAAQ0sB,EAAM1vB,KAAM,GAAIkN,eAAgB1I,GAAI,GAAIgB,OAAO,GAEzDxF,KAAM,GAAI4C,YACd+kB,EAAK2I,aAActwB,KAAM,IAG1B2nB,EAAKvjB,IAAK,WACT,IAAIC,EAAOrE,KAEX,MAAQqE,EAAKojC,kBACZpjC,EAAOA,EAAKojC,kBAGb,OAAOpjC,IACJ+rB,OAAQpwB,OAGNA,MAGR0nC,UAAW,SAAUhY,GACpB,OAAKruB,EAAYquB,GACT1vB,KAAKkE,KAAM,SAAU/B,GAC3Ba,EAAQhD,MAAO0nC,UAAWhY,EAAKjvB,KAAMT,KAAMmC,MAItCnC,KAAKkE,KAAM,WACjB,IAAI0W,EAAO5X,EAAQhD,MAClBmb,EAAWP,EAAKO,WAEZA,EAAS7X,OACb6X,EAASqsB,QAAS9X,GAGlB9U,EAAKwV,OAAQV,MAKhB/H,KAAM,SAAU+H,GACf,IAAIiY,EAAiBtmC,EAAYquB,GAEjC,OAAO1vB,KAAKkE,KAAM,SAAU/B,GAC3Ba,EAAQhD,MAAOwnC,QAASG,EAAiBjY,EAAKjvB,KAAMT,KAAMmC,GAAMutB,MAIlEkY,OAAQ,SAAU3kC,GAIjB,OAHAjD,KAAKsU,OAAQrR,GAAW8R,IAAK,QAAS7Q,KAAM,WAC3ClB,EAAQhD,MAAOywB,YAAazwB,KAAKwM,cAE3BxM,QAKTgD,EAAOgP,KAAKnI,QAAQgwB,OAAS,SAAUx1B,GACtC,OAAQrB,EAAOgP,KAAKnI,QAAQg+B,QAASxjC,IAEtCrB,EAAOgP,KAAKnI,QAAQg+B,QAAU,SAAUxjC,GACvC,SAAWA,EAAK6uB,aAAe7uB,EAAKgwB,cAAgBhwB,EAAK8xB,iBAAiB7yB,SAM3EN,EAAO+/B,aAAa+E,IAAM,WACzB,IACC,OAAO,IAAI/nC,EAAOgoC,eACjB,MAAQt7B,MAGX,IAAIu7B,GAAmB,CAGrBC,EAAG,IAIHC,KAAM,KAEPC,GAAenlC,EAAO+/B,aAAa+E,MAEpC1mC,EAAQgnC,OAASD,IAAkB,oBAAqBA,GACxD/mC,EAAQijC,KAAO8D,KAAiBA,GAEhCnlC,EAAOohC,cAAe,SAAUh/B,GAC/B,IAAIjB,EAAUkkC,EAGd,GAAKjnC,EAAQgnC,MAAQD,KAAiB/iC,EAAQ0gC,YAC7C,MAAO,CACNO,KAAM,SAAUH,EAAS7K,GACxB,IAAIl5B,EACH2lC,EAAM1iC,EAAQ0iC,MAWf,GATAA,EAAIQ,KACHljC,EAAQzD,KACRyD,EAAQ+9B,IACR/9B,EAAQm+B,MACRn+B,EAAQmjC,SACRnjC,EAAQsR,UAIJtR,EAAQojC,UACZ,IAAMrmC,KAAKiD,EAAQojC,UAClBV,EAAK3lC,GAAMiD,EAAQojC,UAAWrmC,GAmBhC,IAAMA,KAdDiD,EAAQqgC,UAAYqC,EAAItC,kBAC5BsC,EAAItC,iBAAkBpgC,EAAQqgC,UAQzBrgC,EAAQ0gC,aAAgBI,EAAS,sBACtCA,EAAS,oBAAuB,kBAItBA,EACV4B,EAAIvC,iBAAkBpjC,EAAG+jC,EAAS/jC,IAInCgC,EAAW,SAAUxC,GACpB,OAAO,WACDwC,IACJA,EAAWkkC,EAAgBP,EAAIW,OAC9BX,EAAIY,QAAUZ,EAAIa,QAAUb,EAAIc,UAC/Bd,EAAIe,mBAAqB,KAEb,UAATlnC,EACJmmC,EAAInC,QACgB,UAAThkC,EAKgB,iBAAfmmC,EAAIpC,OACfrK,EAAU,EAAG,SAEbA,EAGCyM,EAAIpC,OACJoC,EAAIlC,YAINvK,EACC2M,GAAkBF,EAAIpC,SAAYoC,EAAIpC,OACtCoC,EAAIlC,WAK+B,UAAjCkC,EAAIgB,cAAgB,SACM,iBAArBhB,EAAIiB,aACV,CAAEC,OAAQlB,EAAIrB,UACd,CAAElkC,KAAMulC,EAAIiB,cACbjB,EAAIxC,4BAQTwC,EAAIW,OAAStkC,IACbkkC,EAAgBP,EAAIY,QAAUZ,EAAIc,UAAYzkC,EAAU,cAKnC2B,IAAhBgiC,EAAIa,QACRb,EAAIa,QAAUN,EAEdP,EAAIe,mBAAqB,WAGA,IAAnBf,EAAIzmB,YAMRthB,EAAOkgB,WAAY,WACb9b,GACJkkC,OAQLlkC,EAAWA,EAAU,SAErB,IAGC2jC,EAAIzB,KAAMjhC,EAAQ4gC,YAAc5gC,EAAQwd,MAAQ,MAC/C,MAAQnW,GAGT,GAAKtI,EACJ,MAAMsI,IAKTk5B,MAAO,WACDxhC,GACJA,QAWLnB,EAAOmhC,cAAe,SAAUhD,GAC1BA,EAAE2E,cACN3E,EAAEhmB,SAAS9Y,QAAS,KAKtBW,EAAOihC,UAAW,CACjBR,QAAS,CACRphC,OAAQ,6FAGT8Y,SAAU,CACT9Y,OAAQ,2BAETuhC,WAAY,CACX2D,cAAe,SAAUhlC,GAExB,OADAS,EAAO0D,WAAYnE,GACZA,MAMVS,EAAOmhC,cAAe,SAAU,SAAUhD,QACxBr7B,IAAZq7B,EAAE9yB,QACN8yB,EAAE9yB,OAAQ,GAEN8yB,EAAE2E,cACN3E,EAAEx/B,KAAO,SAKXqB,EAAOohC,cAAe,SAAU,SAAUjD,GAIxC,IAAI9+B,EAAQ8B,EADb,GAAKg9B,EAAE2E,aAAe3E,EAAE8H,YAEvB,MAAO,CACN5C,KAAM,SAAUjpB,EAAGie,GAClBh5B,EAASW,EAAQ,YACfkP,KAAMivB,EAAE8H,aAAe,IACvBpmB,KAAM,CAAEqmB,QAAS/H,EAAEgI,cAAevnC,IAAKu/B,EAAEgC,MACzC5a,GAAI,aAAcpkB,EAAW,SAAUilC,GACvC/mC,EAAO0b,SACP5Z,EAAW,KACNilC,GACJ/N,EAAuB,UAAb+N,EAAIznC,KAAmB,IAAM,IAAKynC,EAAIznC,QAKnD/B,EAAS8C,KAAKC,YAAaN,EAAQ,KAEpCsjC,MAAO,WACDxhC,GACJA,QAUL,IAqGKyhB,GArGDyjB,GAAe,GAClBC,GAAS,oBAGVtmC,EAAOihC,UAAW,CACjBsF,MAAO,WACPC,cAAe,WACd,IAAIrlC,EAAWklC,GAAa//B,OAAWtG,EAAO+C,QAAU,IAAQlE,GAAMuF,OAEtE,OADApH,KAAMmE,IAAa,EACZA,KAKTnB,EAAOmhC,cAAe,aAAc,SAAUhD,EAAGsI,EAAkBlH,GAElE,IAAImH,EAAcC,EAAaC,EAC9BC,GAAuB,IAAZ1I,EAAEoI,QAAqBD,GAAO77B,KAAM0zB,EAAEgC,KAChD,MACkB,iBAAXhC,EAAEve,MAE6C,KADnDue,EAAEqC,aAAe,IACjB3iC,QAAS,sCACXyoC,GAAO77B,KAAM0zB,EAAEve,OAAU,QAI5B,GAAKinB,GAAiC,UAArB1I,EAAEkB,UAAW,GA8D7B,OA3DAqH,EAAevI,EAAEqI,cAAgBnoC,EAAY8/B,EAAEqI,eAC9CrI,EAAEqI,gBACFrI,EAAEqI,cAGEK,EACJ1I,EAAG0I,GAAa1I,EAAG0I,GAAW3jC,QAASojC,GAAQ,KAAOI,IAC/B,IAAZvI,EAAEoI,QACbpI,EAAEgC,MAAS5C,GAAO9yB,KAAM0zB,EAAEgC,KAAQ,IAAM,KAAQhC,EAAEoI,MAAQ,IAAMG,GAIjEvI,EAAEyC,WAAY,eAAkB,WAI/B,OAHMgG,GACL5mC,EAAOoD,MAAOsjC,EAAe,mBAEvBE,EAAmB,IAI3BzI,EAAEkB,UAAW,GAAM,OAGnBsH,EAAc5pC,EAAQ2pC,GACtB3pC,EAAQ2pC,GAAiB,WACxBE,EAAoBtlC,WAIrBi+B,EAAMhkB,OAAQ,gBAGQzY,IAAhB6jC,EACJ3mC,EAAQjD,GAAS2+B,WAAYgL,GAI7B3pC,EAAQ2pC,GAAiBC,EAIrBxI,EAAGuI,KAGPvI,EAAEqI,cAAgBC,EAAiBD,cAGnCH,GAAazoC,KAAM8oC,IAIfE,GAAqBvoC,EAAYsoC,IACrCA,EAAaC,EAAmB,IAGjCA,EAAoBD,OAAc7jC,IAI5B,WAYT1E,EAAQ0oC,qBACHlkB,GAAOhmB,EAASmqC,eAAeD,mBAAoB,IAAKlkB,MACvD5U,UAAY,6BACiB,IAA3B4U,GAAKpZ,WAAWlJ,QAQxBN,EAAO8X,UAAY,SAAU8H,EAAM1f,EAAS8mC,GAC3C,MAAqB,iBAATpnB,EACJ,IAEgB,kBAAZ1f,IACX8mC,EAAc9mC,EACdA,GAAU,GAKLA,IAIA9B,EAAQ0oC,qBAMZ9yB,GALA9T,EAAUtD,EAASmqC,eAAeD,mBAAoB,KAKvCxnC,cAAe,SACzBqT,KAAO/V,EAAS0V,SAASK,KAC9BzS,EAAQR,KAAKC,YAAaqU,IAE1B9T,EAAUtD,GAKZ4nB,GAAWwiB,GAAe,IAD1BC,EAASxvB,EAAWtN,KAAMyV,IAKlB,CAAE1f,EAAQZ,cAAe2nC,EAAQ,MAGzCA,EAAS1iB,GAAe,CAAE3E,GAAQ1f,EAASskB,GAEtCA,GAAWA,EAAQlkB,QACvBN,EAAQwkB,GAAUzJ,SAGZ/a,EAAOgB,MAAO,GAAIimC,EAAOz9B,cAlChC,IAAIwK,EAAMizB,EAAQziB,GAyCnBxkB,EAAOG,GAAGyoB,KAAO,SAAUuX,EAAK+G,EAAQ/lC,GACvC,IAAIlB,EAAUtB,EAAM8kC,EACnB7rB,EAAO5a,KACP4oB,EAAMua,EAAItiC,QAAS,KAsDpB,OApDY,EAAP+nB,IACJ3lB,EAAWs7B,GAAkB4E,EAAI7iC,MAAOsoB,IACxCua,EAAMA,EAAI7iC,MAAO,EAAGsoB,IAIhBvnB,EAAY6oC,IAGhB/lC,EAAW+lC,EACXA,OAASpkC,GAGEokC,GAA4B,iBAAXA,IAC5BvoC,EAAO,QAIW,EAAdiZ,EAAKtX,QACTN,EAAOqhC,KAAM,CACZlB,IAAKA,EAKLxhC,KAAMA,GAAQ,MACdygC,SAAU,OACVxf,KAAMsnB,IACHrhC,KAAM,SAAUkgC,GAGnBtC,EAAWniC,UAEXsW,EAAK8U,KAAMzsB,EAIVD,EAAQ,SAAUotB,OAAQptB,EAAO8X,UAAWiuB,IAAiBp4B,KAAM1N,GAGnE8lC,KAKExqB,OAAQpa,GAAY,SAAUo+B,EAAOmD,GACxC9qB,EAAK1W,KAAM,WACVC,EAASxD,MAAOX,KAAMymC,GAAY,CAAElE,EAAMwG,aAAcrD,EAAQnD,QAK5DviC,MAMRgD,EAAOgP,KAAKnI,QAAQsgC,SAAW,SAAU9lC,GACxC,OAAOrB,EAAO2B,KAAM3B,EAAO65B,OAAQ,SAAU15B,GAC5C,OAAOkB,IAASlB,EAAGkB,OAChBf,QAMLN,EAAOonC,OAAS,CACfC,UAAW,SAAUhmC,EAAMe,EAASjD,GACnC,IAAImoC,EAAaC,EAASC,EAAWC,EAAQC,EAAWC,EACvD3X,EAAWhwB,EAAO4hB,IAAKvgB,EAAM,YAC7BumC,EAAU5nC,EAAQqB,GAClB4nB,EAAQ,GAGS,WAAb+G,IACJ3uB,EAAKqgB,MAAMsO,SAAW,YAGvB0X,EAAYE,EAAQR,SACpBI,EAAYxnC,EAAO4hB,IAAKvgB,EAAM,OAC9BsmC,EAAa3nC,EAAO4hB,IAAKvgB,EAAM,SACI,aAAb2uB,GAAwC,UAAbA,KACA,GAA9CwX,EAAYG,GAAa9pC,QAAS,SAMpC4pC,GADAH,EAAcM,EAAQ5X,YACD9iB,IACrBq6B,EAAUD,EAAYvS,OAGtB0S,EAASpX,WAAYmX,IAAe,EACpCD,EAAUlX,WAAYsX,IAAgB,GAGlCtpC,EAAY+D,KAGhBA,EAAUA,EAAQ3E,KAAM4D,EAAMlC,EAAGa,EAAOmC,OAAQ,GAAIulC,KAGjC,MAAftlC,EAAQ8K,MACZ+b,EAAM/b,IAAQ9K,EAAQ8K,IAAMw6B,EAAUx6B,IAAQu6B,GAE1B,MAAhBrlC,EAAQ2yB,OACZ9L,EAAM8L,KAAS3yB,EAAQ2yB,KAAO2S,EAAU3S,KAASwS,GAG7C,UAAWnlC,EACfA,EAAQylC,MAAMpqC,KAAM4D,EAAM4nB,GAG1B2e,EAAQhmB,IAAKqH,KAKhBjpB,EAAOG,GAAGgC,OAAQ,CAGjBilC,OAAQ,SAAUhlC,GAGjB,GAAKd,UAAUhB,OACd,YAAmBwC,IAAZV,EACNpF,KACAA,KAAKkE,KAAM,SAAU/B,GACpBa,EAAOonC,OAAOC,UAAWrqC,KAAMoF,EAASjD,KAI3C,IAAI2oC,EAAMC,EACT1mC,EAAOrE,KAAM,GAEd,OAAMqE,EAQAA,EAAK8xB,iBAAiB7yB,QAK5BwnC,EAAOzmC,EAAKwzB,wBACZkT,EAAM1mC,EAAK6I,cAAc+C,YAClB,CACNC,IAAK46B,EAAK56B,IAAM66B,EAAIC,YACpBjT,KAAM+S,EAAK/S,KAAOgT,EAAIE,cARf,CAAE/6B,IAAK,EAAG6nB,KAAM,QATxB,GAuBD/E,SAAU,WACT,GAAMhzB,KAAM,GAAZ,CAIA,IAAIkrC,EAAcd,EAAQloC,EACzBmC,EAAOrE,KAAM,GACbmrC,EAAe,CAAEj7B,IAAK,EAAG6nB,KAAM,GAGhC,GAAwC,UAAnC/0B,EAAO4hB,IAAKvgB,EAAM,YAGtB+lC,EAAS/lC,EAAKwzB,4BAER,CACNuS,EAASpqC,KAAKoqC,SAIdloC,EAAMmC,EAAK6I,cACXg+B,EAAe7mC,EAAK6mC,cAAgBhpC,EAAI4N,gBACxC,MAAQo7B,IACLA,IAAiBhpC,EAAI0jB,MAAQslB,IAAiBhpC,EAAI4N,kBACT,WAA3C9M,EAAO4hB,IAAKsmB,EAAc,YAE1BA,EAAeA,EAAatoC,WAExBsoC,GAAgBA,IAAiB7mC,GAAkC,IAA1B6mC,EAAa3pC,YAG1D4pC,EAAenoC,EAAQkoC,GAAed,UACzBl6B,KAAOlN,EAAO4hB,IAAKsmB,EAAc,kBAAkB,GAChEC,EAAapT,MAAQ/0B,EAAO4hB,IAAKsmB,EAAc,mBAAmB,IAKpE,MAAO,CACNh7B,IAAKk6B,EAAOl6B,IAAMi7B,EAAaj7B,IAAMlN,EAAO4hB,IAAKvgB,EAAM,aAAa,GACpE0zB,KAAMqS,EAAOrS,KAAOoT,EAAapT,KAAO/0B,EAAO4hB,IAAKvgB,EAAM,cAAc,MAc1E6mC,aAAc,WACb,OAAOlrC,KAAKoE,IAAK,WAChB,IAAI8mC,EAAelrC,KAAKkrC,aAExB,MAAQA,GAA2D,WAA3CloC,EAAO4hB,IAAKsmB,EAAc,YACjDA,EAAeA,EAAaA,aAG7B,OAAOA,GAAgBp7B,QAM1B9M,EAAOkB,KAAM,CAAE+0B,WAAY,cAAeD,UAAW,eAAiB,SAAUlc,EAAQ+F,GACvF,IAAI3S,EAAM,gBAAkB2S,EAE5B7f,EAAOG,GAAI2Z,GAAW,SAAU1a,GAC/B,OAAOmf,EAAQvhB,KAAM,SAAUqE,EAAMyY,EAAQ1a,GAG5C,IAAI2oC,EAOJ,GANKtpC,EAAU4C,GACd0mC,EAAM1mC,EACuB,IAAlBA,EAAK9C,WAChBwpC,EAAM1mC,EAAK4L,kBAGCnK,IAAR1D,EACJ,OAAO2oC,EAAMA,EAAKloB,GAASxe,EAAMyY,GAG7BiuB,EACJA,EAAIK,SACFl7B,EAAY66B,EAAIE,YAAV7oC,EACP8N,EAAM9N,EAAM2oC,EAAIC,aAIjB3mC,EAAMyY,GAAW1a,GAEhB0a,EAAQ1a,EAAKkC,UAAUhB,WAU5BN,EAAOkB,KAAM,CAAE,MAAO,QAAU,SAAUsD,EAAIqb,GAC7C7f,EAAOszB,SAAUzT,GAASqP,GAAc9wB,EAAQsyB,cAC/C,SAAUrvB,EAAMstB,GACf,GAAKA,EAIJ,OAHAA,EAAWD,GAAQrtB,EAAMwe,GAGlBoO,GAAUxjB,KAAMkkB,GACtB3uB,EAAQqB,GAAO2uB,WAAYnQ,GAAS,KACpC8O,MAQL3uB,EAAOkB,KAAM,CAAEmnC,OAAQ,SAAUC,MAAO,SAAW,SAAUjmC,EAAM1D,GAClEqB,EAAOkB,KAAM,CACZ+zB,QAAS,QAAU5yB,EACnB8W,QAASxa,EACT4pC,GAAI,QAAUlmC,GACZ,SAAUmmC,EAAcC,GAG1BzoC,EAAOG,GAAIsoC,GAAa,SAAUzT,EAAQ7wB,GACzC,IAAIqa,EAAYld,UAAUhB,SAAYkoC,GAAkC,kBAAXxT,GAC5DnC,EAAQ2V,KAA6B,IAAXxT,IAA6B,IAAV7wB,EAAiB,SAAW,UAE1E,OAAOoa,EAAQvhB,KAAM,SAAUqE,EAAM1C,EAAMwF,GAC1C,IAAIjF,EAEJ,OAAKT,EAAU4C,GAGyB,IAAhConC,EAAS5qC,QAAS,SACxBwD,EAAM,QAAUgB,GAChBhB,EAAKzE,SAASkQ,gBAAiB,SAAWzK,GAIrB,IAAlBhB,EAAK9C,UACTW,EAAMmC,EAAKyL,gBAIJ9J,KAAKsvB,IACXjxB,EAAKuhB,KAAM,SAAWvgB,GAAQnD,EAAK,SAAWmD,GAC9ChB,EAAKuhB,KAAM,SAAWvgB,GAAQnD,EAAK,SAAWmD,GAC9CnD,EAAK,SAAWmD,UAIDS,IAAVqB,EAGNnE,EAAO4hB,IAAKvgB,EAAM1C,EAAMk0B,GAGxB7yB,EAAO0hB,MAAOrgB,EAAM1C,EAAMwF,EAAO0uB,IAChCl0B,EAAM6f,EAAYwW,OAASlyB,EAAW0b,QAM5Cxe,EAAOkB,KAAM,CACZ,YACA,WACA,eACA,YACA,cACA,YACE,SAAUsD,EAAI7F,GAChBqB,EAAOG,GAAIxB,GAAS,SAAUwB,GAC7B,OAAOnD,KAAKuoB,GAAI5mB,EAAMwB,MAOxBH,EAAOG,GAAGgC,OAAQ,CAEjBi2B,KAAM,SAAU5S,EAAO5F,EAAMzf,GAC5B,OAAOnD,KAAKuoB,GAAIC,EAAO,KAAM5F,EAAMzf,IAEpCuoC,OAAQ,SAAUljB,EAAOrlB,GACxB,OAAOnD,KAAK4oB,IAAKJ,EAAO,KAAMrlB,IAG/BwoC,SAAU,SAAU1oC,EAAUulB,EAAO5F,EAAMzf,GAC1C,OAAOnD,KAAKuoB,GAAIC,EAAOvlB,EAAU2f,EAAMzf,IAExCyoC,WAAY,SAAU3oC,EAAUulB,EAAOrlB,GAGtC,OAA4B,IAArBmB,UAAUhB,OAChBtD,KAAK4oB,IAAK3lB,EAAU,MACpBjD,KAAK4oB,IAAKJ,EAAOvlB,GAAY,KAAME,IAGrC0oC,MAAO,SAAUC,EAAQC,GACxB,OAAO/rC,KAAKquB,WAAYyd,GAASxd,WAAYyd,GAASD,MAIxD9oC,EAAOkB,KACN,wLAE4DqD,MAAO,KACnE,SAAUC,EAAInC,GAGbrC,EAAOG,GAAIkC,GAAS,SAAUud,EAAMzf,GACnC,OAA0B,EAAnBmB,UAAUhB,OAChBtD,KAAKuoB,GAAIljB,EAAM,KAAMud,EAAMzf,GAC3BnD,KAAKqpB,QAAShkB,MAYlB,IAAI2E,GAAQ,sDAMZhH,EAAOgpC,MAAQ,SAAU7oC,EAAID,GAC5B,IAAI4N,EAAK6D,EAAMq3B,EAUf,GARwB,iBAAZ9oC,IACX4N,EAAM3N,EAAID,GACVA,EAAUC,EACVA,EAAK2N,GAKAzP,EAAY8B,GAalB,OARAwR,EAAOrU,EAAMG,KAAM6D,UAAW,IAC9B0nC,EAAQ,WACP,OAAO7oC,EAAGxC,MAAOuC,GAAWlD,KAAM2U,EAAKjU,OAAQJ,EAAMG,KAAM6D,eAItD8C,KAAOjE,EAAGiE,KAAOjE,EAAGiE,MAAQpE,EAAOoE,OAElC4kC,GAGRhpC,EAAOipC,UAAY,SAAUC,GACvBA,EACJlpC,EAAOme,YAEPne,EAAO+X,OAAO,IAGhB/X,EAAO6C,QAAUD,MAAMC,QACvB7C,EAAOmpC,UAAY/oB,KAAKC,MACxBrgB,EAAOqJ,SAAWA,EAClBrJ,EAAO3B,WAAaA,EACpB2B,EAAOvB,SAAWA,EAClBuB,EAAOmf,UAAYA,EACnBnf,EAAOrB,KAAOmB,EAEdE,EAAOspB,IAAM5jB,KAAK4jB,IAElBtpB,EAAOopC,UAAY,SAAU9qC,GAK5B,IAAIK,EAAOqB,EAAOrB,KAAML,GACxB,OAAkB,WAATK,GAA8B,WAATA,KAK5B0qC,MAAO/qC,EAAM+xB,WAAY/xB,KAG5B0B,EAAOspC,KAAO,SAAU/pC,GACvB,OAAe,MAARA,EACN,IACEA,EAAO,IAAK2D,QAAS8D,GAAO,OAkBT,mBAAXuiC,QAAyBA,OAAOC,KAC3CD,OAAQ,SAAU,GAAI,WACrB,OAAOvpC,IAOT,IAGCypC,GAAU1sC,EAAOiD,OAGjB0pC,GAAK3sC,EAAO4sC,EAwBb,OAtBA3pC,EAAO4pC,WAAa,SAAUlnC,GAS7B,OARK3F,EAAO4sC,IAAM3pC,IACjBjD,EAAO4sC,EAAID,IAGPhnC,GAAQ3F,EAAOiD,SAAWA,IAC9BjD,EAAOiD,OAASypC,IAGVzpC,GAMiB,oBAAb/C,IACXF,EAAOiD,OAASjD,EAAO4sC,EAAI3pC,GAMrBA","file":"jquery-3.6.3.min.js"} \ No newline at end of file diff --git a/cps/static/js/libs/jszip.min.js b/cps/static/js/libs/jszip.min.js deleted file mode 100644 index 131b697d6..000000000 --- a/cps/static/js/libs/jszip.min.js +++ /dev/null @@ -1,13 +0,0 @@ -/*! - -JSZip v3.6.0 - A JavaScript class for generating and reading zip files - - -(c) 2009-2016 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library pako released under the MIT license : -https://github.com/nodeca/pako/blob/master/LICENSE -*/ - -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=e()}}(function(){return function s(a,o,u){function h(r,e){if(!o[r]){if(!a[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(f)return f(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var i=o[r]={exports:{}};a[r][0].call(i.exports,function(e){var t=a[r][1][e];return h(t||e)},i,i.exports,s,a,o,u)}return o[r].exports}for(var f="function"==typeof require&&require,e=0;e>2,s=(3&t)<<4|r>>4,a=1>6:64,o=2>4,r=(15&i)<<4|(s=p.indexOf(e.charAt(o++)))>>2,n=(3&s)<<6|(a=p.indexOf(e.charAt(o++))),h[u++]=t,64!==s&&(h[u++]=r),64!==a&&(h[u++]=n);return h}},{"./support":30,"./utils":32}],2:[function(e,t,r){"use strict";var n=e("./external"),i=e("./stream/DataWorker"),s=e("./stream/Crc32Probe"),a=e("./stream/DataLengthProbe");function o(e,t,r,n,i){this.compressedSize=e,this.uncompressedSize=t,this.crc32=r,this.compression=n,this.compressedContent=i}o.prototype={getContentWorker:function(){var e=new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),t=this;return e.on("end",function(){if(this.streamInfo.data_length!==t.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),e},getCompressedWorker:function(){return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(e,t,r){return e.pipe(new s).pipe(new a("uncompressedSize")).pipe(t.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",t)},t.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(e,t,r){"use strict";var n=e("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(e){return new n("STORE compression")},uncompressWorker:function(){return new n("STORE decompression")}},r.DEFLATE=e("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(e,t,r){"use strict";var n=e("./utils"),a=function(){for(var e,t=[],r=0;r<256;r++){e=r;for(var n=0;n<8;n++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t){return void 0!==e&&e.length?"string"!==n.getTypeOf(e)?function(e,t,r){var n=a,i=0+r;e^=-1;for(var s=0;s>>8^n[255&(e^t[s])];return-1^e}(0|t,e,e.length):function(e,t,r){var n=a,i=0+r;e^=-1;for(var s=0;s>>8^n[255&(e^t.charCodeAt(s))];return-1^e}(0|t,e,e.length):0}},{"./utils":32}],5:[function(e,t,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(e,t,r){"use strict";var n;n="undefined"!=typeof Promise?Promise:e("lie"),t.exports={Promise:n}},{lie:37}],7:[function(e,t,r){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,i=e("pako"),s=e("./utils"),a=e("./stream/GenericWorker"),o=n?"uint8array":"array";function u(e,t){a.call(this,"FlateWorker/"+e),this._pako=null,this._pakoAction=e,this._pakoOptions=t,this.meta={}}r.magic="\b\0",s.inherits(u,a),u.prototype.processChunk=function(e){this.meta=e.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,e.data),!1)},u.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},u.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},u.prototype._createPako=function(){this._pako=new i[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var t=this;this._pako.onData=function(e){t.push({data:e,meta:t.meta})}},r.compressWorker=function(e){return new u("Deflate",e)},r.uncompressWorker=function(){return new u("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(e,t,r){"use strict";function I(e,t){var r,n="";for(r=0;r>>=8;return n}function i(e,t,r,n,i,s){var a,o,u=e.file,h=e.compression,f=s!==B.utf8encode,l=O.transformTo("string",s(u.name)),d=O.transformTo("string",B.utf8encode(u.name)),c=u.comment,p=O.transformTo("string",s(c)),m=O.transformTo("string",B.utf8encode(c)),_=d.length!==u.name.length,g=m.length!==c.length,v="",b="",w="",y=u.dir,k=u.date,x={crc32:0,compressedSize:0,uncompressedSize:0};t&&!r||(x.crc32=e.crc32,x.compressedSize=e.compressedSize,x.uncompressedSize=e.uncompressedSize);var S=0;t&&(S|=8),f||!_&&!g||(S|=2048);var z,E=0,C=0;y&&(E|=16),"UNIX"===i?(C=798,E|=((z=u.unixPermissions)||(z=y?16893:33204),(65535&z)<<16)):(C=20,E|=63&(u.dosPermissions||0)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(v+="up"+I((b=I(1,1)+I(T(l),4)+d).length,2)+b),g&&(v+="uc"+I((w=I(1,1)+I(T(p),4)+m).length,2)+w);var A="";return A+="\n\0",A+=I(S,2),A+=h.magic,A+=I(a,2),A+=I(o,2),A+=I(x.crc32,4),A+=I(x.compressedSize,4),A+=I(x.uncompressedSize,4),A+=I(l.length,2),A+=I(v.length,2),{fileRecord:R.LOCAL_FILE_HEADER+A+l+v,dirRecord:R.CENTRAL_FILE_HEADER+I(C,2)+A+I(p.length,2)+"\0\0\0\0"+I(E,4)+I(n,4)+l+v+p}}var O=e("../utils"),s=e("../stream/GenericWorker"),B=e("../utf8"),T=e("../crc32"),R=e("../signature");function n(e,t,r,n){s.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=t,this.zipPlatform=r,this.encodeFileName=n,this.streamFiles=e,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}O.inherits(n,s),n.prototype.push=function(e){var t=e.meta.percent||0,r=this.entriesCount,n=this._sources.length;this.accumulate?this.contentBuffer.push(e):(this.bytesWritten+=e.data.length,s.prototype.push.call(this,{data:e.data,meta:{currentFile:this.currentFile,percent:r?(t+100*(r-n-1))/r:100}}))},n.prototype.openedSource=function(e){this.currentSourceOffset=this.bytesWritten,this.currentFile=e.file.name;var t=this.streamFiles&&!e.file.dir;if(t){var r=i(e,t,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}})}else this.accumulate=!0},n.prototype.closedSource=function(e){this.accumulate=!1;var t,r=this.streamFiles&&!e.file.dir,n=i(e,r,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(n.dirRecord),r)this.push({data:(t=e,R.DATA_DESCRIPTOR+I(t.crc32,4)+I(t.compressedSize,4)+I(t.uncompressedSize,4)),meta:{percent:100}});else for(this.push({data:n.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},n.prototype.flush=function(){for(var e=this.bytesWritten,t=0;t=this.index;t--)r=(r<<8)+this.byteAt(t);return this.index+=e,r},readString:function(e){return n.transformTo("string",this.readData(e))},readData:function(e){},lastIndexOfSignature:function(e){},readAndCheckSignature:function(e){},readDate:function(){var e=this.readInt(4);return new Date(Date.UTC(1980+(e>>25&127),(e>>21&15)-1,e>>16&31,e>>11&31,e>>5&63,(31&e)<<1))}},t.exports=i},{"../utils":32}],19:[function(e,t,r){"use strict";var n=e("./Uint8ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(e,t,r){"use strict";var n=e("./DataReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.byteAt=function(e){return this.data.charCodeAt(this.zero+e)},i.prototype.lastIndexOfSignature=function(e){return this.data.lastIndexOf(e)-this.zero},i.prototype.readAndCheckSignature=function(e){return e===this.readData(4)},i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./DataReader":18}],21:[function(e,t,r){"use strict";var n=e("./ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){if(this.checkOffset(e),0===e)return new Uint8Array(0);var t=this.data.subarray(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./ArrayReader":17}],22:[function(e,t,r){"use strict";var n=e("../utils"),i=e("../support"),s=e("./ArrayReader"),a=e("./StringReader"),o=e("./NodeBufferReader"),u=e("./Uint8ArrayReader");t.exports=function(e){var t=n.getTypeOf(e);return n.checkSupport(t),"string"!==t||i.uint8array?"nodebuffer"===t?new o(e):i.uint8array?new u(n.transformTo("uint8array",e)):new s(n.transformTo("array",e)):new a(e)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(e,t,r){"use strict";r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b"},{}],24:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../utils");function s(e){n.call(this,"ConvertWorker to "+e),this.destType=e}i.inherits(s,n),s.prototype.processChunk=function(e){this.push({data:i.transformTo(this.destType,e.data),meta:e.meta})},t.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../crc32");function s(){n.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}e("../utils").inherits(s,n),s.prototype.processChunk=function(e){this.streamInfo.crc32=i(e.data,this.streamInfo.crc32||0),this.push(e)},t.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataLengthProbe for "+e),this.propName=e,this.withStreamInfo(e,0)}n.inherits(s,i),s.prototype.processChunk=function(e){if(e){var t=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=t+e.data.length}i.prototype.processChunk.call(this,e)},t.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataWorker");var t=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,e.then(function(e){t.dataIsReady=!0,t.data=e,t.max=e&&e.length||0,t.type=n.getTypeOf(e),t.isPaused||t._tickAndRepeat()},function(e){t.error(e)})}n.inherits(s,i),s.prototype.cleanUp=function(){i.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!i.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,n.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(n.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var e=null,t=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":e=this.data.substring(this.index,t);break;case"uint8array":e=this.data.subarray(this.index,t);break;case"array":case"nodebuffer":e=this.data.slice(this.index,t)}return this.index=t,this.push({data:e,meta:{percent:this.max?this.index/this.max*100:0}})},t.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(e,t,r){"use strict";function n(e){this.name=e||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}n.prototype={push:function(e){this.emit("data",e)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(e){this.emit("error",e)}return!0},error:function(e){return!this.isFinished&&(this.isPaused?this.generatedError=e:(this.isFinished=!0,this.emit("error",e),this.previous&&this.previous.error(e),this.cleanUp()),!0)},on:function(e,t){return this._listeners[e].push(t),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(e,t){if(this._listeners[e])for(var r=0;r "+e:e}},t.exports=n},{}],29:[function(e,t,r){"use strict";var h=e("../utils"),i=e("./ConvertWorker"),s=e("./GenericWorker"),f=e("../base64"),n=e("../support"),a=e("../external"),o=null;if(n.nodestream)try{o=e("../nodejs/NodejsStreamOutputAdapter")}catch(e){}function u(e,t,r){var n=t;switch(t){case"blob":case"arraybuffer":n="uint8array";break;case"base64":n="string"}try{this._internalType=n,this._outputType=t,this._mimeType=r,h.checkSupport(n),this._worker=e.pipe(new i(n)),e.lock()}catch(e){this._worker=new s("error"),this._worker.error(e)}}u.prototype={accumulate:function(e){return o=this,u=e,new a.Promise(function(t,r){var n=[],i=o._internalType,s=o._outputType,a=o._mimeType;o.on("data",function(e,t){n.push(e),u&&u(t)}).on("error",function(e){n=[],r(e)}).on("end",function(){try{var e=function(e,t,r){switch(e){case"blob":return h.newBlob(h.transformTo("arraybuffer",t),r);case"base64":return f.encode(t);default:return h.transformTo(e,t)}}(s,function(e,t){var r,n=0,i=null,s=0;for(r=0;r>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t}(e)},s.utf8decode=function(e){return u.nodebuffer?o.transformTo("nodebuffer",e).toString("utf-8"):function(e){var t,r,n,i,s=e.length,a=new Array(2*s);for(t=r=0;t>10&1023,a[r++]=56320|1023&n)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(e=o.transformTo(u.uint8array?"uint8array":"array",e))},o.inherits(a,n),a.prototype.processChunk=function(e){var t=o.transformTo(u.uint8array?"uint8array":"array",e.data);if(this.leftOver&&this.leftOver.length){if(u.uint8array){var r=t;(t=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),t.set(r,this.leftOver.length)}else t=this.leftOver.concat(t);this.leftOver=null}var n=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+h[e[r]]>t?r:t}(t),i=t;n!==t.length&&(u.uint8array?(i=t.subarray(0,n),this.leftOver=t.subarray(n,t.length)):(i=t.slice(0,n),this.leftOver=t.slice(n,t.length))),this.push({data:s.utf8decode(i),meta:e.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(f,n),f.prototype.processChunk=function(e){this.push({data:s.utf8encode(e.data),meta:e.meta})},s.Utf8EncodeWorker=f},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(e,t,o){"use strict";var u=e("./support"),h=e("./base64"),r=e("./nodejsUtils"),n=e("set-immediate-shim"),f=e("./external");function i(e){return e}function l(e,t){for(var r=0;r>8;this.dir=!!(16&this.externalFileAttributes),0==e&&(this.dosPermissions=63&this.externalFileAttributes),3==e&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(e){if(this.extraFields[1]){var t=n(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=t.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=t.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=t.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=t.readInt(4))}},readExtraFields:function(e){var t,r,n,i=e.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});e.index+4>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t},r.buf2binstring=function(e){return f(e,e.length)},r.binstring2buf=function(e){for(var t=new u.Buf8(e.length),r=0,n=t.length;r>10&1023,o[n++]=56320|1023&i)}return f(o,n)},r.utf8border=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+h[e[r]]>t?r:t}},{"./common":41}],43:[function(e,t,r){"use strict";t.exports=function(e,t,r,n){for(var i=65535&e|0,s=e>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return-1^e}},{}],46:[function(e,t,r){"use strict";var u,d=e("../utils/common"),h=e("./trees"),c=e("./adler32"),p=e("./crc32"),n=e("./messages"),f=0,l=0,m=-2,i=2,_=8,s=286,a=30,o=19,g=2*s+1,v=15,b=3,w=258,y=w+b+1,k=42,x=113;function S(e,t){return e.msg=n[t],t}function z(e){return(e<<1)-(4e.avail_out&&(r=e.avail_out),0!==r&&(d.arraySet(e.output,t.pending_buf,t.pending_out,r,e.next_out),e.next_out+=r,t.pending_out+=r,e.total_out+=r,e.avail_out-=r,t.pending-=r,0===t.pending&&(t.pending_out=0))}function A(e,t){h._tr_flush_block(e,0<=e.block_start?e.block_start:-1,e.strstart-e.block_start,t),e.block_start=e.strstart,C(e.strm)}function I(e,t){e.pending_buf[e.pending++]=t}function O(e,t){e.pending_buf[e.pending++]=t>>>8&255,e.pending_buf[e.pending++]=255&t}function B(e,t){var r,n,i=e.max_chain_length,s=e.strstart,a=e.prev_length,o=e.nice_match,u=e.strstart>e.w_size-y?e.strstart-(e.w_size-y):0,h=e.window,f=e.w_mask,l=e.prev,d=e.strstart+w,c=h[s+a-1],p=h[s+a];e.prev_length>=e.good_match&&(i>>=2),o>e.lookahead&&(o=e.lookahead);do{if(h[(r=t)+a]===p&&h[r+a-1]===c&&h[r]===h[s]&&h[++r]===h[s+1]){s+=2,r++;do{}while(h[++s]===h[++r]&&h[++s]===h[++r]&&h[++s]===h[++r]&&h[++s]===h[++r]&&h[++s]===h[++r]&&h[++s]===h[++r]&&h[++s]===h[++r]&&h[++s]===h[++r]&&su&&0!=--i);return a<=e.lookahead?a:e.lookahead}function T(e){var t,r,n,i,s,a,o,u,h,f,l=e.w_size;do{if(i=e.window_size-e.lookahead-e.strstart,e.strstart>=l+(l-y)){for(d.arraySet(e.window,e.window,l,l,0),e.match_start-=l,e.strstart-=l,e.block_start-=l,t=r=e.hash_size;n=e.head[--t],e.head[t]=l<=n?n-l:0,--r;);for(t=r=l;n=e.prev[--t],e.prev[t]=l<=n?n-l:0,--r;);i+=l}if(0===e.strm.avail_in)break;if(a=e.strm,o=e.window,u=e.strstart+e.lookahead,f=void 0,(h=i)<(f=a.avail_in)&&(f=h),r=0===f?0:(a.avail_in-=f,d.arraySet(o,a.input,a.next_in,f,u),1===a.state.wrap?a.adler=c(a.adler,o,f,u):2===a.state.wrap&&(a.adler=p(a.adler,o,f,u)),a.next_in+=f,a.total_in+=f,f),e.lookahead+=r,e.lookahead+e.insert>=b)for(s=e.strstart-e.insert,e.ins_h=e.window[s],e.ins_h=(e.ins_h<=b&&(e.ins_h=(e.ins_h<=b)if(n=h._tr_tally(e,e.strstart-e.match_start,e.match_length-b),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=b){for(e.match_length--;e.strstart++,e.ins_h=(e.ins_h<=b&&(e.ins_h=(e.ins_h<=b&&e.match_length<=e.prev_length){for(i=e.strstart+e.lookahead-b,n=h._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-b),e.lookahead-=e.prev_length-1,e.prev_length-=2;++e.strstart<=i&&(e.ins_h=(e.ins_h<e.pending_buf_size-5&&(r=e.pending_buf_size-5);;){if(e.lookahead<=1){if(T(e),0===e.lookahead&&t===f)return 1;if(0===e.lookahead)break}e.strstart+=e.lookahead,e.lookahead=0;var n=e.block_start+r;if((0===e.strstart||e.strstart>=n)&&(e.lookahead=e.strstart-n,e.strstart=n,A(e,!1),0===e.strm.avail_out))return 1;if(e.strstart-e.block_start>=e.w_size-y&&(A(e,!1),0===e.strm.avail_out))return 1}return e.insert=0,4===t?(A(e,!0),0===e.strm.avail_out?3:4):(e.strstart>e.block_start&&(A(e,!1),e.strm.avail_out),1)}),new F(4,4,8,4,R),new F(4,5,16,8,R),new F(4,6,32,32,R),new F(4,4,16,16,D),new F(8,16,32,32,D),new F(8,16,128,128,D),new F(8,32,128,256,D),new F(32,128,258,1024,D),new F(32,258,258,4096,D)],r.deflateInit=function(e,t){return L(e,t,_,15,8,0)},r.deflateInit2=L,r.deflateReset=P,r.deflateResetKeep=U,r.deflateSetHeader=function(e,t){return e&&e.state?2!==e.state.wrap?m:(e.state.gzhead=t,l):m},r.deflate=function(e,t){var r,n,i,s;if(!e||!e.state||5>8&255),I(n,n.gzhead.time>>16&255),I(n,n.gzhead.time>>24&255),I(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),I(n,255&n.gzhead.os),n.gzhead.extra&&n.gzhead.extra.length&&(I(n,255&n.gzhead.extra.length),I(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=p(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=69):(I(n,0),I(n,0),I(n,0),I(n,0),I(n,0),I(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),I(n,3),n.status=x);else{var a=_+(n.w_bits-8<<4)<<8;a|=(2<=n.strategy||n.level<2?0:n.level<6?1:6===n.level?2:3)<<6,0!==n.strstart&&(a|=32),a+=31-a%31,n.status=x,O(n,a),0!==n.strstart&&(O(n,e.adler>>>16),O(n,65535&e.adler)),e.adler=1}if(69===n.status)if(n.gzhead.extra){for(i=n.pending;n.gzindex<(65535&n.gzhead.extra.length)&&(n.pending!==n.pending_buf_size||(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),C(e),i=n.pending,n.pending!==n.pending_buf_size));)I(n,255&n.gzhead.extra[n.gzindex]),n.gzindex++;n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=73)}else n.status=73;if(73===n.status)if(n.gzhead.name){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),C(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.gzindex=0,n.status=91)}else n.status=91;if(91===n.status)if(n.gzhead.comment){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),C(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.status=103)}else n.status=103;if(103===n.status&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&C(e),n.pending+2<=n.pending_buf_size&&(I(n,255&e.adler),I(n,e.adler>>8&255),e.adler=0,n.status=x)):n.status=x),0!==n.pending){if(C(e),0===e.avail_out)return n.last_flush=-1,l}else if(0===e.avail_in&&z(t)<=z(r)&&4!==t)return S(e,-5);if(666===n.status&&0!==e.avail_in)return S(e,-5);if(0!==e.avail_in||0!==n.lookahead||t!==f&&666!==n.status){var o=2===n.strategy?function(e,t){for(var r;;){if(0===e.lookahead&&(T(e),0===e.lookahead)){if(t===f)return 1;break}if(e.match_length=0,r=h._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,r&&(A(e,!1),0===e.strm.avail_out))return 1}return e.insert=0,4===t?(A(e,!0),0===e.strm.avail_out?3:4):e.last_lit&&(A(e,!1),0===e.strm.avail_out)?1:2}(n,t):3===n.strategy?function(e,t){for(var r,n,i,s,a=e.window;;){if(e.lookahead<=w){if(T(e),e.lookahead<=w&&t===f)return 1;if(0===e.lookahead)break}if(e.match_length=0,e.lookahead>=b&&0e.lookahead&&(e.match_length=e.lookahead)}if(e.match_length>=b?(r=h._tr_tally(e,1,e.match_length-b),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(r=h._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),r&&(A(e,!1),0===e.strm.avail_out))return 1}return e.insert=0,4===t?(A(e,!0),0===e.strm.avail_out?3:4):e.last_lit&&(A(e,!1),0===e.strm.avail_out)?1:2}(n,t):u[n.level].func(n,t);if(3!==o&&4!==o||(n.status=666),1===o||3===o)return 0===e.avail_out&&(n.last_flush=-1),l;if(2===o&&(1===t?h._tr_align(n):5!==t&&(h._tr_stored_block(n,0,0,!1),3===t&&(E(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),C(e),0===e.avail_out))return n.last_flush=-1,l}return 4!==t?l:n.wrap<=0?1:(2===n.wrap?(I(n,255&e.adler),I(n,e.adler>>8&255),I(n,e.adler>>16&255),I(n,e.adler>>24&255),I(n,255&e.total_in),I(n,e.total_in>>8&255),I(n,e.total_in>>16&255),I(n,e.total_in>>24&255)):(O(n,e.adler>>>16),O(n,65535&e.adler)),C(e),0=r.w_size&&(0===s&&(E(r.head),r.strstart=0,r.block_start=0,r.insert=0),h=new d.Buf8(r.w_size),d.arraySet(h,t,f-r.w_size,r.w_size,0),t=h,f=r.w_size),a=e.avail_in,o=e.next_in,u=e.input,e.avail_in=f,e.next_in=0,e.input=t,T(r);r.lookahead>=b;){for(n=r.strstart,i=r.lookahead-(b-1);r.ins_h=(r.ins_h<>>=w=b>>>24,p-=w,0==(w=b>>>16&255))E[s++]=65535&b;else{if(!(16&w)){if(0==(64&w)){b=m[(65535&b)+(c&(1<>>=w,p-=w),p<15&&(c+=z[n++]<>>=w=b>>>24,p-=w,!(16&(w=b>>>16&255))){if(0==(64&w)){b=_[(65535&b)+(c&(1<>>=w,p-=w,(w=s-a)>3,c&=(1<<(p-=y<<3))-1,e.next_in=n,e.next_out=s,e.avail_in=n>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=P,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new I.Buf32(n),t.distcode=t.distdyn=new I.Buf32(i),t.sane=1,t.back=-1,N):U}function o(e){var t;return e&&e.state?((t=e.state).wsize=0,t.whave=0,t.wnext=0,a(e)):U}function u(e,t){var r,n;return e&&e.state?(n=e.state,t<0?(r=0,t=-t):(r=1+(t>>4),t<48&&(t&=15)),t&&(t<8||15=s.wsize?(I.arraySet(s.window,t,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(n<(i=s.wsize-s.wnext)&&(i=n),I.arraySet(s.window,t,r-n,i,s.wnext),(n-=i)?(I.arraySet(s.window,t,r-n,n,0),s.wnext=n,s.whave=s.wsize):(s.wnext+=i,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,r.check=B(r.check,C,2,0),f=h=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&h)<<8)+(h>>8))%31){e.msg="incorrect header check",r.mode=30;break}if(8!=(15&h)){e.msg="unknown compression method",r.mode=30;break}if(f-=4,k=8+(15&(h>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){e.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(C[0]=255&h,C[1]=h>>>8&255,r.check=B(r.check,C,2,0)),f=h=0,r.mode=3;case 3:for(;f<32;){if(0===o)break e;o--,h+=n[s++]<>>8&255,C[2]=h>>>16&255,C[3]=h>>>24&255,r.check=B(r.check,C,4,0)),f=h=0,r.mode=4;case 4:for(;f<16;){if(0===o)break e;o--,h+=n[s++]<>8),512&r.flags&&(C[0]=255&h,C[1]=h>>>8&255,r.check=B(r.check,C,2,0)),f=h=0,r.mode=5;case 5:if(1024&r.flags){for(;f<16;){if(0===o)break e;o--,h+=n[s++]<>>8&255,r.check=B(r.check,C,2,0)),f=h=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(c=r.length)&&(c=o),c&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,n,s,c,k)),512&r.flags&&(r.check=B(r.check,n,c,s)),o-=c,s+=c,r.length-=c),r.length))break e;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break e;for(c=0;k=n[s+c++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&c>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=12;break;case 10:for(;f<32;){if(0===o)break e;o--,h+=n[s++]<>>=7&f,f-=7&f,r.mode=27;break}for(;f<3;){if(0===o)break e;o--,h+=n[s++]<>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==t)break;h>>>=2,f-=2;break e;case 2:r.mode=17;break;case 3:e.msg="invalid block type",r.mode=30}h>>>=2,f-=2;break;case 14:for(h>>>=7&f,f-=7&f;f<32;){if(0===o)break e;o--,h+=n[s++]<>>16^65535)){e.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&h,f=h=0,r.mode=15,6===t)break e;case 15:r.mode=16;case 16:if(c=r.length){if(o>>=5,f-=5,r.ndist=1+(31&h),h>>>=5,f-=5,r.ncode=4+(15&h),h>>>=4,f-=4,286>>=3,f-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=R(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,v=65535&E,!((_=E>>>24)<=f);){if(0===o)break e;o--,h+=n[s++]<>>=_,f-=_,r.lens[r.have++]=v;else{if(16===v){for(z=_+2;f>>=_,f-=_,0===r.have){e.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],c=3+(3&h),h>>>=2,f-=2}else if(17===v){for(z=_+3;f>>=_)),h>>>=3,f-=3}else{for(z=_+7;f>>=_)),h>>>=7,f-=7}if(r.have+c>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=30;break}for(;c--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=R(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=R(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){e.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===t)break e;case 20:r.mode=21;case 21:if(6<=o&&258<=u){e.next_out=a,e.avail_out=u,e.next_in=s,e.avail_in=o,r.hold=h,r.bits=f,T(e,d),a=e.next_out,i=e.output,u=e.avail_out,s=e.next_in,n=e.input,o=e.avail_in,h=r.hold,f=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(E=r.lencode[h&(1<>>16&255,v=65535&E,!((_=E>>>24)<=f);){if(0===o)break e;o--,h+=n[s++]<>b)])>>>16&255,v=65535&E,!(b+(_=E>>>24)<=f);){if(0===o)break e;o--,h+=n[s++]<>>=b,f-=b,r.back+=b}if(h>>>=_,f-=_,r.back+=_,r.length=v,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){e.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;f>>=r.extra,f-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(E=r.distcode[h&(1<>>16&255,v=65535&E,!((_=E>>>24)<=f);){if(0===o)break e;o--,h+=n[s++]<>b)])>>>16&255,v=65535&E,!(b+(_=E>>>24)<=f);){if(0===o)break e;o--,h+=n[s++]<>>=b,f-=b,r.back+=b}if(h>>>=_,f-=_,r.back+=_,64&g){e.msg="invalid distance code",r.mode=30;break}r.offset=v,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;f>>=r.extra,f-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===u)break e;if(c=d-u,r.offset>c){if((c=r.offset-c)>r.whave&&r.sane){e.msg="invalid distance too far back",r.mode=30;break}p=c>r.wnext?(c-=r.wnext,r.wsize-c):r.wnext-c,c>r.length&&(c=r.length),m=r.window}else m=i,p=a-r.offset,c=r.length;for(uc?(m=T[R+a[b]],A[I+a[b]]):(m=96,0),u=1<>S)+(h-=u)]=p<<24|m<<16|_|0,0!==h;);for(u=1<>=1;if(0!==u?(C&=u-1,C+=u):C=0,b++,0==--O[v]){if(v===y)break;v=t[r+a[b]]}if(k>>7)]}function x(e,t){e.pending_buf[e.pending++]=255&t,e.pending_buf[e.pending++]=t>>>8&255}function S(e,t,r){e.bi_valid>i-r?(e.bi_buf|=t<>i-e.bi_valid,e.bi_valid+=r-i):(e.bi_buf|=t<>>=1,r<<=1,0<--t;);return r>>>1}function C(e,t,r){var n,i,s=new Array(_+1),a=0;for(n=1;n<=_;n++)s[n]=a=a+r[n-1]<<1;for(i=0;i<=t;i++){var o=e[2*i+1];0!==o&&(e[2*i]=E(s[o]++,o))}}function A(e){var t;for(t=0;t<286;t++)e.dyn_ltree[2*t]=0;for(t=0;t<30;t++)e.dyn_dtree[2*t]=0;for(t=0;t<19;t++)e.bl_tree[2*t]=0;e.dyn_ltree[512]=1,e.opt_len=e.static_len=0,e.last_lit=e.matches=0}function I(e){8>1;1<=r;r--)B(e,s,r);for(i=u;r=e.heap[1],e.heap[1]=e.heap[e.heap_len--],B(e,s,1),n=e.heap[1],e.heap[--e.heap_max]=r,e.heap[--e.heap_max]=n,s[2*i]=s[2*r]+s[2*n],e.depth[i]=(e.depth[r]>=e.depth[n]?e.depth[r]:e.depth[n])+1,s[2*r+1]=s[2*n+1]=i,e.heap[1]=i++,B(e,s,1),2<=e.heap_len;);e.heap[--e.heap_max]=e.heap[1],function(e,t){var r,n,i,s,a,o,u=t.dyn_tree,h=t.max_code,f=t.stat_desc.static_tree,l=t.stat_desc.has_stree,d=t.stat_desc.extra_bits,c=t.stat_desc.extra_base,p=t.stat_desc.max_length,m=0;for(s=0;s<=_;s++)e.bl_count[s]=0;for(u[2*e.heap[e.heap_max]+1]=0,r=e.heap_max+1;r<573;r++)p<(s=u[2*u[2*(n=e.heap[r])+1]+1]+1)&&(s=p,m++),u[2*n+1]=s,h>=7;n<30;n++)for(w[n]=i<<7,e=0;e<1<>>=1)if(1&r&&0!==e.dyn_ltree[2*t])return 0;if(0!==e.dyn_ltree[18]||0!==e.dyn_ltree[20]||0!==e.dyn_ltree[26])return 1;for(t=32;t<256;t++)if(0!==e.dyn_ltree[2*t])return 1;return 0}(e)),R(e,e.l_desc),R(e,e.d_desc),a=function(e){var t;for(D(e,e.dyn_ltree,e.l_desc.max_code),D(e,e.dyn_dtree,e.d_desc.max_code),R(e,e.bl_desc),t=18;3<=t&&0===e.bl_tree[2*f[t]+1];t--);return e.opt_len+=3*(t+1)+5+5+4,t}(e),i=e.opt_len+3+7>>>3,(s=e.static_len+3+7>>>3)<=i&&(i=s)):i=s=r+5,r+4<=i&&-1!==t?U(e,t,r,n):4===e.strategy||s===i?(S(e,2+(n?1:0),3),T(e,l,d)):(S(e,4+(n?1:0),3),function(e,t,r,n){var i;for(S(e,t-257,5),S(e,r-1,5),S(e,n-4,4),i=0;i>>8&255,e.pending_buf[e.d_buf+2*e.last_lit+1]=255&t,e.pending_buf[e.l_buf+e.last_lit]=255&r,e.last_lit++,0===t?e.dyn_ltree[2*r]++:(e.matches++,t--,e.dyn_ltree[2*(p[r]+256+1)]++,e.dyn_dtree[2*k(t)]++),e.last_lit===e.lit_bufsize-1},r._tr_align=function(e){var t;S(e,2,3),z(e,256,l),16===(t=e).bi_valid?(x(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):8<=t.bi_valid&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}},{"../utils/common":41}],53:[function(e,t,r){"use strict";t.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],54:[function(e,t,r){"use strict";t.exports="function"==typeof setImmediate?setImmediate:function(){var e=[].slice.apply(arguments);e.splice(1,0,0),setTimeout.apply(null,e)}},{}]},{},[10])(10)})}).call(this,void 0!==r?r:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1])(1)})}).call(this,void 0!==r?r:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1])(1)})}).call(this,void 0!==r?r:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1])(1)})}).call(this,void 0!==r?r:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1])(1)})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/cps/static/js/libs/pdf.js b/cps/static/js/libs/pdf.js index 8d59e6dd9..63248c598 100644 --- a/cps/static/js/libs/pdf.js +++ b/cps/static/js/libs/pdf.js @@ -1,8 +1,8 @@ /** * @licstart The following is the entire license notice for the - * Javascript code in this page + * JavaScript code in this page * - * Copyright 2020 Mozilla Foundation + * Copyright 2022 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ * limitations under the License. * * @licend The above is the entire license notice for the - * Javascript code in this page + * JavaScript code in this page */ (function webpackUniversalModuleDefinition(root, factory) { @@ -29,925 +29,91 @@ exports["pdfjs-dist/build/pdf"] = factory(); else root["pdfjs-dist/build/pdf"] = root.pdfjsLib = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __w_pdfjs_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __w_pdfjs_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __w_pdfjs_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __w_pdfjs_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __w_pdfjs_require__.d = function(exports, name, getter) { -/******/ if(!__w_pdfjs_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __w_pdfjs_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __w_pdfjs_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __w_pdfjs_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __w_pdfjs_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __w_pdfjs_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __w_pdfjs_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __w_pdfjs_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __w_pdfjs_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __w_pdfjs_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __w_pdfjs_require__(__w_pdfjs_require__.s = 0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -Object.defineProperty(exports, "addLinkAttributes", { - enumerable: true, - get: function () { - return _display_utils.addLinkAttributes; - } -}); -Object.defineProperty(exports, "getFilenameFromUrl", { - enumerable: true, - get: function () { - return _display_utils.getFilenameFromUrl; - } -}); -Object.defineProperty(exports, "LinkTarget", { - enumerable: true, - get: function () { - return _display_utils.LinkTarget; - } -}); -Object.defineProperty(exports, "loadScript", { - enumerable: true, - get: function () { - return _display_utils.loadScript; - } -}); -Object.defineProperty(exports, "PDFDateString", { - enumerable: true, - get: function () { - return _display_utils.PDFDateString; - } -}); -Object.defineProperty(exports, "RenderingCancelledException", { - enumerable: true, - get: function () { - return _display_utils.RenderingCancelledException; - } -}); -Object.defineProperty(exports, "build", { - enumerable: true, - get: function () { - return _api.build; - } -}); -Object.defineProperty(exports, "getDocument", { - enumerable: true, - get: function () { - return _api.getDocument; - } -}); -Object.defineProperty(exports, "LoopbackPort", { - enumerable: true, - get: function () { - return _api.LoopbackPort; - } -}); -Object.defineProperty(exports, "PDFDataRangeTransport", { - enumerable: true, - get: function () { - return _api.PDFDataRangeTransport; - } -}); -Object.defineProperty(exports, "PDFWorker", { - enumerable: true, - get: function () { - return _api.PDFWorker; - } -}); -Object.defineProperty(exports, "version", { - enumerable: true, - get: function () { - return _api.version; - } -}); -Object.defineProperty(exports, "CMapCompressionType", { - enumerable: true, - get: function () { - return _util.CMapCompressionType; - } -}); -Object.defineProperty(exports, "createObjectURL", { - enumerable: true, - get: function () { - return _util.createObjectURL; - } -}); -Object.defineProperty(exports, "createPromiseCapability", { - enumerable: true, - get: function () { - return _util.createPromiseCapability; - } -}); -Object.defineProperty(exports, "createValidAbsoluteUrl", { - enumerable: true, - get: function () { - return _util.createValidAbsoluteUrl; - } -}); -Object.defineProperty(exports, "InvalidPDFException", { - enumerable: true, - get: function () { - return _util.InvalidPDFException; - } -}); -Object.defineProperty(exports, "MissingPDFException", { - enumerable: true, - get: function () { - return _util.MissingPDFException; - } -}); -Object.defineProperty(exports, "OPS", { - enumerable: true, - get: function () { - return _util.OPS; - } -}); -Object.defineProperty(exports, "PasswordResponses", { - enumerable: true, - get: function () { - return _util.PasswordResponses; - } -}); -Object.defineProperty(exports, "PermissionFlag", { - enumerable: true, - get: function () { - return _util.PermissionFlag; - } -}); -Object.defineProperty(exports, "removeNullCharacters", { - enumerable: true, - get: function () { - return _util.removeNullCharacters; - } -}); -Object.defineProperty(exports, "shadow", { - enumerable: true, - get: function () { - return _util.shadow; - } -}); -Object.defineProperty(exports, "UnexpectedResponseException", { - enumerable: true, - get: function () { - return _util.UnexpectedResponseException; - } -}); -Object.defineProperty(exports, "UNSUPPORTED_FEATURES", { - enumerable: true, - get: function () { - return _util.UNSUPPORTED_FEATURES; - } -}); -Object.defineProperty(exports, "Util", { - enumerable: true, - get: function () { - return _util.Util; - } -}); -Object.defineProperty(exports, "VerbosityLevel", { - enumerable: true, - get: function () { - return _util.VerbosityLevel; - } -}); -Object.defineProperty(exports, "AnnotationLayer", { - enumerable: true, - get: function () { - return _annotation_layer.AnnotationLayer; - } -}); -Object.defineProperty(exports, "apiCompatibilityParams", { - enumerable: true, - get: function () { - return _api_compatibility.apiCompatibilityParams; - } -}); -Object.defineProperty(exports, "GlobalWorkerOptions", { - enumerable: true, - get: function () { - return _worker_options.GlobalWorkerOptions; - } -}); -Object.defineProperty(exports, "renderTextLayer", { - enumerable: true, - get: function () { - return _text_layer.renderTextLayer; - } -}); -Object.defineProperty(exports, "SVGGraphics", { - enumerable: true, - get: function () { - return _svg.SVGGraphics; - } -}); - -var _display_utils = __w_pdfjs_require__(1); - -var _api = __w_pdfjs_require__(5); - -var _util = __w_pdfjs_require__(2); - -var _annotation_layer = __w_pdfjs_require__(19); - -var _api_compatibility = __w_pdfjs_require__(9); - -var _worker_options = __w_pdfjs_require__(12); - -var _text_layer = __w_pdfjs_require__(20); - -var _svg = __w_pdfjs_require__(21); - -const pdfjsVersion = '2.6.347'; -const pdfjsBuild = '3be9c65f'; -{ - const { - isNodeJS - } = __w_pdfjs_require__(4); - - if (isNodeJS) { - const PDFNodeStream = __w_pdfjs_require__(22).PDFNodeStream; - - (0, _api.setPDFNetworkStreamFactory)(params => { - return new PDFNodeStream(params); - }); - } else { - const PDFNetworkStream = __w_pdfjs_require__(25).PDFNetworkStream; - - let PDFFetchStream; - - if ((0, _display_utils.isFetchSupported)()) { - PDFFetchStream = __w_pdfjs_require__(26).PDFFetchStream; - } - - (0, _api.setPDFNetworkStreamFactory)(params => { - if (PDFFetchStream && (0, _display_utils.isValidFetchUrl)(params.url)) { - return new PDFFetchStream(params); - } - - return new PDFNetworkStream(params); - }); - } -} - -/***/ }), +})(globalThis, () => { +return /******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ([ +/* 0 */, /* 1 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.addLinkAttributes = addLinkAttributes; -exports.getFilenameFromUrl = getFilenameFromUrl; -exports.isFetchSupported = isFetchSupported; -exports.isValidFetchUrl = isValidFetchUrl; -exports.loadScript = loadScript; -exports.deprecated = deprecated; -exports.PDFDateString = exports.StatTimer = exports.DOMSVGFactory = exports.DOMCMapReaderFactory = exports.BaseCMapReaderFactory = exports.DOMCanvasFactory = exports.BaseCanvasFactory = exports.DEFAULT_LINK_REL = exports.LinkTarget = exports.RenderingCancelledException = exports.PageViewport = void 0; - -var _util = __w_pdfjs_require__(2); - -const DEFAULT_LINK_REL = "noopener noreferrer nofollow"; -exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL; -const SVG_NS = "http://www.w3.org/2000/svg"; - -class BaseCanvasFactory { - constructor() { - if (this.constructor === BaseCanvasFactory) { - (0, _util.unreachable)("Cannot initialize BaseCanvasFactory."); - } - } - - create(width, height) { - (0, _util.unreachable)("Abstract method `create` called."); - } - - reset(canvasAndContext, width, height) { - if (!canvasAndContext.canvas) { - throw new Error("Canvas is not specified"); - } - - if (width <= 0 || height <= 0) { - throw new Error("Invalid canvas size"); - } - - canvasAndContext.canvas.width = width; - canvasAndContext.canvas.height = height; - } - - destroy(canvasAndContext) { - if (!canvasAndContext.canvas) { - throw new Error("Canvas is not specified"); - } - - canvasAndContext.canvas.width = 0; - canvasAndContext.canvas.height = 0; - canvasAndContext.canvas = null; - canvasAndContext.context = null; - } - -} - -exports.BaseCanvasFactory = BaseCanvasFactory; - -class DOMCanvasFactory extends BaseCanvasFactory { - constructor({ - ownerDocument = globalThis.document - } = {}) { - super(); - this._document = ownerDocument; - } - - create(width, height) { - if (width <= 0 || height <= 0) { - throw new Error("Invalid canvas size"); - } - - const canvas = this._document.createElement("canvas"); - - const context = canvas.getContext("2d"); - canvas.width = width; - canvas.height = height; - return { - canvas, - context - }; - } - -} - -exports.DOMCanvasFactory = DOMCanvasFactory; - -class BaseCMapReaderFactory { - constructor({ - baseUrl = null, - isCompressed = false - }) { - if (this.constructor === BaseCMapReaderFactory) { - (0, _util.unreachable)("Cannot initialize BaseCMapReaderFactory."); - } - - this.baseUrl = baseUrl; - this.isCompressed = isCompressed; - } - - async fetch({ - name - }) { - if (!this.baseUrl) { - throw new Error('The CMap "baseUrl" parameter must be specified, ensure that ' + 'the "cMapUrl" and "cMapPacked" API parameters are provided.'); - } - - if (!name) { - throw new Error("CMap name must be specified."); - } - - const url = this.baseUrl + name + (this.isCompressed ? ".bcmap" : ""); - const compressionType = this.isCompressed ? _util.CMapCompressionType.BINARY : _util.CMapCompressionType.NONE; - return this._fetchData(url, compressionType).catch(reason => { - throw new Error(`Unable to load ${this.isCompressed ? "binary " : ""}CMap at: ${url}`); - }); - } - - _fetchData(url, compressionType) { - (0, _util.unreachable)("Abstract method `_fetchData` called."); - } - -} - -exports.BaseCMapReaderFactory = BaseCMapReaderFactory; - -class DOMCMapReaderFactory extends BaseCMapReaderFactory { - _fetchData(url, compressionType) { - if (isFetchSupported() && isValidFetchUrl(url, document.baseURI)) { - return fetch(url).then(async response => { - if (!response.ok) { - throw new Error(response.statusText); - } - - let cMapData; - - if (this.isCompressed) { - cMapData = new Uint8Array(await response.arrayBuffer()); - } else { - cMapData = (0, _util.stringToBytes)(await response.text()); - } - - return { - cMapData, - compressionType - }; - }); - } - - return new Promise((resolve, reject) => { - const request = new XMLHttpRequest(); - request.open("GET", url, true); - - if (this.isCompressed) { - request.responseType = "arraybuffer"; - } - - request.onreadystatechange = () => { - if (request.readyState !== XMLHttpRequest.DONE) { - return; - } - - if (request.status === 200 || request.status === 0) { - let cMapData; - - if (this.isCompressed && request.response) { - cMapData = new Uint8Array(request.response); - } else if (!this.isCompressed && request.responseText) { - cMapData = (0, _util.stringToBytes)(request.responseText); - } - - if (cMapData) { - resolve({ - cMapData, - compressionType - }); - return; - } - } - - reject(new Error(request.statusText)); - }; - - request.send(null); - }); - } - -} - -exports.DOMCMapReaderFactory = DOMCMapReaderFactory; - -class DOMSVGFactory { - create(width, height) { - (0, _util.assert)(width > 0 && height > 0, "Invalid SVG dimensions"); - const svg = document.createElementNS(SVG_NS, "svg:svg"); - svg.setAttribute("version", "1.1"); - svg.setAttribute("width", width + "px"); - svg.setAttribute("height", height + "px"); - svg.setAttribute("preserveAspectRatio", "none"); - svg.setAttribute("viewBox", "0 0 " + width + " " + height); - return svg; - } - - createElement(type) { - (0, _util.assert)(typeof type === "string", "Invalid SVG element type"); - return document.createElementNS(SVG_NS, type); - } - -} - -exports.DOMSVGFactory = DOMSVGFactory; - -class PageViewport { - constructor({ - viewBox, - scale, - rotation, - offsetX = 0, - offsetY = 0, - dontFlip = false - }) { - this.viewBox = viewBox; - this.scale = scale; - this.rotation = rotation; - this.offsetX = offsetX; - this.offsetY = offsetY; - const centerX = (viewBox[2] + viewBox[0]) / 2; - const centerY = (viewBox[3] + viewBox[1]) / 2; - let rotateA, rotateB, rotateC, rotateD; - rotation = rotation % 360; - rotation = rotation < 0 ? rotation + 360 : rotation; - - switch (rotation) { - case 180: - rotateA = -1; - rotateB = 0; - rotateC = 0; - rotateD = 1; - break; - - case 90: - rotateA = 0; - rotateB = 1; - rotateC = 1; - rotateD = 0; - break; - - case 270: - rotateA = 0; - rotateB = -1; - rotateC = -1; - rotateD = 0; - break; - - case 0: - rotateA = 1; - rotateB = 0; - rotateC = 0; - rotateD = -1; - break; - - default: - throw new Error("PageViewport: Invalid rotation, must be a multiple of 90 degrees."); - } - - if (dontFlip) { - rotateC = -rotateC; - rotateD = -rotateD; - } - - let offsetCanvasX, offsetCanvasY; - let width, height; - - if (rotateA === 0) { - offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX; - offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY; - width = Math.abs(viewBox[3] - viewBox[1]) * scale; - height = Math.abs(viewBox[2] - viewBox[0]) * scale; - } else { - offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX; - offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY; - width = Math.abs(viewBox[2] - viewBox[0]) * scale; - height = Math.abs(viewBox[3] - viewBox[1]) * scale; - } - - this.transform = [rotateA * scale, rotateB * scale, rotateC * scale, rotateD * scale, offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY]; - this.width = width; - this.height = height; - } - - clone({ - scale = this.scale, - rotation = this.rotation, - offsetX = this.offsetX, - offsetY = this.offsetY, - dontFlip = false - } = {}) { - return new PageViewport({ - viewBox: this.viewBox.slice(), - scale, - rotation, - offsetX, - offsetY, - dontFlip - }); - } - - convertToViewportPoint(x, y) { - return _util.Util.applyTransform([x, y], this.transform); - } - - convertToViewportRectangle(rect) { - const topLeft = _util.Util.applyTransform([rect[0], rect[1]], this.transform); - - const bottomRight = _util.Util.applyTransform([rect[2], rect[3]], this.transform); - - return [topLeft[0], topLeft[1], bottomRight[0], bottomRight[1]]; - } - - convertToPdfPoint(x, y) { - return _util.Util.applyInverseTransform([x, y], this.transform); - } - -} - -exports.PageViewport = PageViewport; - -class RenderingCancelledException extends _util.BaseException { - constructor(msg, type) { - super(msg); - this.type = type; - } - -} - -exports.RenderingCancelledException = RenderingCancelledException; -const LinkTarget = { - NONE: 0, - SELF: 1, - BLANK: 2, - PARENT: 3, - TOP: 4 -}; -exports.LinkTarget = LinkTarget; - -function addLinkAttributes(link, { - url, - target, - rel, - enabled = true -} = {}) { - (0, _util.assert)(url && typeof url === "string", 'addLinkAttributes: A valid "url" parameter must provided.'); - const urlNullRemoved = (0, _util.removeNullCharacters)(url); - - if (enabled) { - link.href = link.title = urlNullRemoved; - } else { - link.href = ""; - link.title = `Disabled: ${urlNullRemoved}`; - - link.onclick = () => { - return false; - }; - } - - let targetStr = ""; - - switch (target) { - case LinkTarget.NONE: - break; - - case LinkTarget.SELF: - targetStr = "_self"; - break; - - case LinkTarget.BLANK: - targetStr = "_blank"; - break; - - case LinkTarget.PARENT: - targetStr = "_parent"; - break; - - case LinkTarget.TOP: - targetStr = "_top"; - break; - } - - link.target = targetStr; - link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL; -} - -function getFilenameFromUrl(url) { - const anchor = url.indexOf("#"); - const query = url.indexOf("?"); - const end = Math.min(anchor > 0 ? anchor : url.length, query > 0 ? query : url.length); - return url.substring(url.lastIndexOf("/", end) + 1, end); -} - -class StatTimer { - constructor() { - this.started = Object.create(null); - this.times = []; - } - - time(name) { - if (name in this.started) { - (0, _util.warn)(`Timer is already running for ${name}`); - } - - this.started[name] = Date.now(); - } - - timeEnd(name) { - if (!(name in this.started)) { - (0, _util.warn)(`Timer has not been started for ${name}`); - } - - this.times.push({ - name, - start: this.started[name], - end: Date.now() - }); - delete this.started[name]; - } - - toString() { - const outBuf = []; - let longest = 0; - - for (const time of this.times) { - const name = time.name; - - if (name.length > longest) { - longest = name.length; - } - } - - for (const time of this.times) { - const duration = time.end - time.start; - outBuf.push(`${time.name.padEnd(longest)} ${duration}ms\n`); - } - - return outBuf.join(""); - } - -} - -exports.StatTimer = StatTimer; - -function isFetchSupported() { - return typeof fetch !== "undefined" && typeof Response !== "undefined" && "body" in Response.prototype && typeof ReadableStream !== "undefined"; -} - -function isValidFetchUrl(url, baseUrl) { - try { - const { - protocol - } = baseUrl ? new URL(url, baseUrl) : new URL(url); - return protocol === "http:" || protocol === "https:"; - } catch (ex) { - return false; - } -} - -function loadScript(src) { - return new Promise((resolve, reject) => { - const script = document.createElement("script"); - script.src = src; - script.onload = resolve; - - script.onerror = function () { - reject(new Error(`Cannot load script at: ${script.src}`)); - }; - - (document.head || document.documentElement).appendChild(script); - }); -} - -function deprecated(details) { - console.log("Deprecated API usage: " + details); -} - -let pdfDateStringRegex; - -class PDFDateString { - static toDateObject(input) { - if (!input || !(0, _util.isString)(input)) { - return null; - } - - if (!pdfDateStringRegex) { - pdfDateStringRegex = new RegExp("^D:" + "(\\d{4})" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "([Z|+|-])?" + "(\\d{2})?" + "'?" + "(\\d{2})?" + "'?"); - } - - const matches = pdfDateStringRegex.exec(input); - - if (!matches) { - return null; - } - - const year = parseInt(matches[1], 10); - let month = parseInt(matches[2], 10); - month = month >= 1 && month <= 12 ? month - 1 : 0; - let day = parseInt(matches[3], 10); - day = day >= 1 && day <= 31 ? day : 1; - let hour = parseInt(matches[4], 10); - hour = hour >= 0 && hour <= 23 ? hour : 0; - let minute = parseInt(matches[5], 10); - minute = minute >= 0 && minute <= 59 ? minute : 0; - let second = parseInt(matches[6], 10); - second = second >= 0 && second <= 59 ? second : 0; - const universalTimeRelation = matches[7] || "Z"; - let offsetHour = parseInt(matches[8], 10); - offsetHour = offsetHour >= 0 && offsetHour <= 23 ? offsetHour : 0; - let offsetMinute = parseInt(matches[9], 10) || 0; - offsetMinute = offsetMinute >= 0 && offsetMinute <= 59 ? offsetMinute : 0; - - if (universalTimeRelation === "-") { - hour += offsetHour; - minute += offsetMinute; - } else if (universalTimeRelation === "+") { - hour -= offsetHour; - minute -= offsetMinute; - } - - return new Date(Date.UTC(year, month, day, hour, minute, second)); - } - -} - -exports.PDFDateString = PDFDateString; - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); +})); +exports.VerbosityLevel = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.UNSUPPORTED_FEATURES = exports.TextRenderingMode = exports.StreamType = exports.RenderingIntentFlag = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.PageActionEventType = exports.OPS = exports.MissingPDFException = exports.LINE_FACTOR = exports.LINE_DESCENT_FACTOR = exports.InvalidPDFException = exports.ImageKind = exports.IDENTITY_MATRIX = exports.FormatError = exports.FontType = exports.FeatureTest = exports.FONT_IDENTITY_MATRIX = exports.DocumentActionEventType = exports.CMapCompressionType = exports.BaseException = exports.AnnotationType = exports.AnnotationStateModelType = exports.AnnotationReviewState = exports.AnnotationReplyType = exports.AnnotationMode = exports.AnnotationMarkedState = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationEditorType = exports.AnnotationEditorPrefix = exports.AnnotationEditorParamsType = exports.AnnotationBorderStyleType = exports.AnnotationActionEventType = exports.AbortException = void 0; exports.arrayByteLength = arrayByteLength; exports.arraysToBytes = arraysToBytes; exports.assert = assert; exports.bytesToString = bytesToString; exports.createPromiseCapability = createPromiseCapability; +exports.createValidAbsoluteUrl = createValidAbsoluteUrl; exports.escapeString = escapeString; exports.getModificationDate = getModificationDate; exports.getVerbosityLevel = getVerbosityLevel; exports.info = info; exports.isArrayBuffer = isArrayBuffer; exports.isArrayEqual = isArrayEqual; -exports.isBool = isBool; -exports.isNum = isNum; -exports.isString = isString; -exports.isSameOrigin = isSameOrigin; -exports.createValidAbsoluteUrl = createValidAbsoluteUrl; -exports.removeNullCharacters = removeNullCharacters; +exports.isAscii = isAscii; +exports.objectFromMap = objectFromMap; +exports.objectSize = objectSize; exports.setVerbosityLevel = setVerbosityLevel; exports.shadow = shadow; exports.string32 = string32; exports.stringToBytes = stringToBytes; exports.stringToPDFString = stringToPDFString; +exports.stringToUTF16BEString = stringToUTF16BEString; exports.stringToUTF8String = stringToUTF8String; +exports.unreachable = unreachable; exports.utf8StringToString = utf8StringToString; exports.warn = warn; -exports.unreachable = unreachable; -exports.IsEvalSupportedCached = exports.IsLittleEndianCached = exports.createObjectURL = exports.FormatError = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.MissingPDFException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationStateModelType = exports.AnnotationReviewState = exports.AnnotationReplyType = exports.AnnotationMarkedState = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = exports.BaseException = void 0; -__w_pdfjs_require__(3); +__w_pdfjs_require__(2); const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; exports.IDENTITY_MATRIX = IDENTITY_MATRIX; const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX; +const LINE_FACTOR = 1.35; +exports.LINE_FACTOR = LINE_FACTOR; +const LINE_DESCENT_FACTOR = 0.35; +exports.LINE_DESCENT_FACTOR = LINE_DESCENT_FACTOR; +const RenderingIntentFlag = { + ANY: 0x01, + DISPLAY: 0x02, + PRINT: 0x04, + ANNOTATIONS_FORMS: 0x10, + ANNOTATIONS_STORAGE: 0x20, + ANNOTATIONS_DISABLE: 0x40, + OPLIST: 0x100 +}; +exports.RenderingIntentFlag = RenderingIntentFlag; +const AnnotationMode = { + DISABLE: 0, + ENABLE: 1, + ENABLE_FORMS: 2, + ENABLE_STORAGE: 3 +}; +exports.AnnotationMode = AnnotationMode; +const AnnotationEditorPrefix = "pdfjs_internal_editor_"; +exports.AnnotationEditorPrefix = AnnotationEditorPrefix; +const AnnotationEditorType = { + DISABLE: -1, + NONE: 0, + FREETEXT: 3, + INK: 15 +}; +exports.AnnotationEditorType = AnnotationEditorType; +const AnnotationEditorParamsType = { + FREETEXT_SIZE: 1, + FREETEXT_COLOR: 2, + FREETEXT_OPACITY: 3, + INK_COLOR: 11, + INK_THICKNESS: 12, + INK_OPACITY: 13 +}; +exports.AnnotationEditorParamsType = AnnotationEditorParamsType; const PermissionFlag = { PRINT: 0x04, MODIFY_CONTENTS: 0x08, @@ -1073,6 +239,36 @@ const AnnotationBorderStyleType = { UNDERLINE: 5 }; exports.AnnotationBorderStyleType = AnnotationBorderStyleType; +const AnnotationActionEventType = { + E: "Mouse Enter", + X: "Mouse Exit", + D: "Mouse Down", + U: "Mouse Up", + Fo: "Focus", + Bl: "Blur", + PO: "PageOpen", + PC: "PageClose", + PV: "PageVisible", + PI: "PageInvisible", + K: "Keystroke", + F: "Format", + V: "Validate", + C: "Calculate" +}; +exports.AnnotationActionEventType = AnnotationActionEventType; +const DocumentActionEventType = { + WC: "WillClose", + WS: "WillSave", + DS: "DidSave", + WP: "WillPrint", + DP: "DidPrint" +}; +exports.DocumentActionEventType = DocumentActionEventType; +const PageActionEventType = { + O: "PageOpen", + C: "PageClose" +}; +exports.PageActionEventType = PageActionEventType; const StreamType = { UNKNOWN: "UNKNOWN", FLATE: "FLATE", @@ -1089,6 +285,7 @@ exports.StreamType = StreamType; const FontType = { UNKNOWN: "UNKNOWN", TYPE1: "TYPE1", + TYPE1STANDARD: "TYPE1STANDARD", TYPE1C: "TYPE1C", CIDFONTTYPE0: "CIDFONTTYPE0", CIDFONTTYPE0C: "CIDFONTTYPE0C", @@ -1210,6 +407,7 @@ const UNSUPPORTED_FEATURES = { unknown: "unknown", forms: "forms", javaScript: "javaScript", + signatures: "signatures", smask: "smask", shadingPattern: "shadingPattern", font: "font", @@ -1224,8 +422,10 @@ const UNSUPPORTED_FEATURES = { errorOperatorList: "errorOperatorList", errorFontToUnicode: "errorFontToUnicode", errorFontLoadNative: "errorFontLoadNative", + errorFontBuildPath: "errorFontBuildPath", errorFontGetPath: "errorFontGetPath", - errorMarkedContent: "errorMarkedContent" + errorMarkedContent: "errorMarkedContent", + errorContentSubStream: "errorContentSubStream" }; exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; const PasswordResponses = { @@ -1267,23 +467,6 @@ function assert(cond, msg) { } } -function isSameOrigin(baseUrl, otherUrl) { - let base; - - try { - base = new URL(baseUrl); - - if (!base.origin || base.origin === "null") { - return false; - } - } catch (e) { - return false; - } - - const other = new URL(otherUrl, base); - return base.origin === other.origin; -} - function _isValidProtocol(url) { if (!url) { return false; @@ -1302,12 +485,28 @@ function _isValidProtocol(url) { } } -function createValidAbsoluteUrl(url, baseUrl) { +function createValidAbsoluteUrl(url, baseUrl = null, options = null) { if (!url) { return null; } try { + if (options && typeof url === "string") { + if (options.addDefaultProtocol && url.startsWith("www.")) { + const dots = url.match(/\./g); + + if (dots && dots.length >= 2) { + url = `http://${url}`; + } + } + + if (options.tryConvertEncoding) { + try { + url = stringToUTF8String(url); + } catch (ex) {} + } + } + const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); if (_isValidProtocol(absoluteUrl)) { @@ -1329,13 +528,13 @@ function shadow(obj, prop, value) { } const BaseException = function BaseExceptionClosure() { - function BaseException(message) { + function BaseException(message, name) { if (this.constructor === BaseException) { unreachable("Cannot initialize BaseException."); } this.message = message; - this.name = this.constructor.name; + this.name = name; } BaseException.prototype = new Error(); @@ -1347,7 +546,7 @@ exports.BaseException = BaseException; class PasswordException extends BaseException { constructor(msg, code) { - super(msg); + super(msg, "PasswordException"); this.code = code; } @@ -1357,7 +556,7 @@ exports.PasswordException = PasswordException; class UnknownErrorException extends BaseException { constructor(msg, details) { - super(msg); + super(msg, "UnknownErrorException"); this.details = details; } @@ -1365,17 +564,27 @@ class UnknownErrorException extends BaseException { exports.UnknownErrorException = UnknownErrorException; -class InvalidPDFException extends BaseException {} +class InvalidPDFException extends BaseException { + constructor(msg) { + super(msg, "InvalidPDFException"); + } + +} exports.InvalidPDFException = InvalidPDFException; -class MissingPDFException extends BaseException {} +class MissingPDFException extends BaseException { + constructor(msg) { + super(msg, "MissingPDFException"); + } + +} exports.MissingPDFException = MissingPDFException; class UnexpectedResponseException extends BaseException { constructor(msg, status) { - super(msg); + super(msg, "UnexpectedResponseException"); this.status = status; } @@ -1383,26 +592,29 @@ class UnexpectedResponseException extends BaseException { exports.UnexpectedResponseException = UnexpectedResponseException; -class FormatError extends BaseException {} +class FormatError extends BaseException { + constructor(msg) { + super(msg, "FormatError"); + } + +} exports.FormatError = FormatError; -class AbortException extends BaseException {} - -exports.AbortException = AbortException; -const NullCharactersRegExp = /\x00/g; - -function removeNullCharacters(str) { - if (typeof str !== "string") { - warn("The argument for removeNullCharacters must be a string."); - return str; +class AbortException extends BaseException { + constructor(msg) { + super(msg, "AbortException"); } - return str.replace(NullCharactersRegExp, ""); } +exports.AbortException = AbortException; + function bytesToString(bytes) { - assert(bytes !== null && typeof bytes === "object" && bytes.length !== undefined, "Invalid argument for bytesToString"); + if (typeof bytes !== "object" || bytes === null || bytes.length === undefined) { + unreachable("Invalid argument for bytesToString"); + } + const length = bytes.length; const MAX_ARGUMENT_COUNT = 8192; @@ -1422,7 +634,10 @@ function bytesToString(bytes) { } function stringToBytes(str) { - assert(typeof str === "string", "Invalid argument for stringToBytes"); + if (typeof str !== "string") { + unreachable("Invalid argument for stringToBytes"); + } + const length = str.length; const bytes = new Uint8Array(length); @@ -1438,8 +653,11 @@ function arrayByteLength(arr) { return arr.length; } - assert(arr.byteLength !== undefined, "arrayByteLength - invalid argument."); - return arr.byteLength; + if (arr.byteLength !== undefined) { + return arr.byteLength; + } + + unreachable("Invalid argument for arrayByteLength"); } function arraysToBytes(arr) { @@ -1481,6 +699,20 @@ function string32(value) { return String.fromCharCode(value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff); } +function objectSize(obj) { + return Object.keys(obj).length; +} + +function objectFromMap(map) { + const obj = Object.create(null); + + for (const [key, value] of map) { + obj[key] = value; + } + + return obj; +} + function isLittleEndian() { const buffer8 = new Uint8Array(4); buffer8[0] = 1; @@ -1488,14 +720,6 @@ function isLittleEndian() { return view32[0] === 1; } -const IsLittleEndianCached = { - get value() { - return shadow(this, "value", isLittleEndian()); - } - -}; -exports.IsLittleEndianCached = IsLittleEndianCached; - function isEvalSupported() { try { new Function(""); @@ -1505,21 +729,81 @@ function isEvalSupported() { } } -const IsEvalSupportedCached = { - get value() { - return shadow(this, "value", isEvalSupported()); +class FeatureTest { + static get isLittleEndian() { + return shadow(this, "isLittleEndian", isLittleEndian()); } -}; -exports.IsEvalSupportedCached = IsEvalSupportedCached; -const rgbBuf = ["rgb(", 0, ",", 0, ",", 0, ")"]; + static get isEvalSupported() { + return shadow(this, "isEvalSupported", isEvalSupported()); + } + + static get isOffscreenCanvasSupported() { + return shadow(this, "isOffscreenCanvasSupported", typeof OffscreenCanvas !== "undefined"); + } + +} + +exports.FeatureTest = FeatureTest; +const hexNumbers = [...Array(256).keys()].map(n => n.toString(16).padStart(2, "0")); class Util { - static makeCssRgb(r, g, b) { - rgbBuf[1] = r; - rgbBuf[3] = g; - rgbBuf[5] = b; - return rgbBuf.join(""); + static makeHexColor(r, g, b) { + return `#${hexNumbers[r]}${hexNumbers[g]}${hexNumbers[b]}`; + } + + static scaleMinMax(transform, minMax) { + let temp; + + if (transform[0]) { + if (transform[0] < 0) { + temp = minMax[0]; + minMax[0] = minMax[1]; + minMax[1] = temp; + } + + minMax[0] *= transform[0]; + minMax[1] *= transform[0]; + + if (transform[3] < 0) { + temp = minMax[2]; + minMax[2] = minMax[3]; + minMax[3] = temp; + } + + minMax[2] *= transform[3]; + minMax[3] *= transform[3]; + } else { + temp = minMax[0]; + minMax[0] = minMax[2]; + minMax[2] = temp; + temp = minMax[1]; + minMax[1] = minMax[3]; + minMax[3] = temp; + + if (transform[1] < 0) { + temp = minMax[2]; + minMax[2] = minMax[3]; + minMax[3] = temp; + } + + minMax[2] *= transform[1]; + minMax[3] *= transform[1]; + + if (transform[2] < 0) { + temp = minMax[0]; + minMax[0] = minMax[1]; + minMax[1] = temp; + } + + minMax[0] *= transform[2]; + minMax[1] *= transform[2]; + } + + minMax[0] += transform[4]; + minMax[1] += transform[4]; + minMax[2] += transform[5]; + minMax[3] += transform[5]; } static transform(m1, m2) { @@ -1563,7 +847,7 @@ class Util { const c = m[2] * transpose[0] + m[3] * transpose[2]; const d = m[2] * transpose[1] + m[3] * transpose[3]; const first = (a + d) / 2; - const second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; + const second = Math.sqrt((a + d) ** 2 - 4 * (a * d - c * b)) / 2; const sx = first + second || 1; const sy = first - second || 1; return [Math.sqrt(sx), Math.sqrt(sy)]; @@ -1586,62 +870,157 @@ class Util { } static intersect(rect1, rect2) { - function compare(a, b) { - return a - b; - } + const xLow = Math.max(Math.min(rect1[0], rect1[2]), Math.min(rect2[0], rect2[2])); + const xHigh = Math.min(Math.max(rect1[0], rect1[2]), Math.max(rect2[0], rect2[2])); - const orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare); - const orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare); - const result = []; - rect1 = Util.normalizeRect(rect1); - rect2 = Util.normalizeRect(rect2); - - if (orderedX[0] === rect1[0] && orderedX[1] === rect2[0] || orderedX[0] === rect2[0] && orderedX[1] === rect1[0]) { - result[0] = orderedX[1]; - result[2] = orderedX[2]; - } else { + if (xLow > xHigh) { return null; } - if (orderedY[0] === rect1[1] && orderedY[1] === rect2[1] || orderedY[0] === rect2[1] && orderedY[1] === rect1[1]) { - result[1] = orderedY[1]; - result[3] = orderedY[2]; - } else { + const yLow = Math.max(Math.min(rect1[1], rect1[3]), Math.min(rect2[1], rect2[3])); + const yHigh = Math.min(Math.max(rect1[1], rect1[3]), Math.max(rect2[1], rect2[3])); + + if (yLow > yHigh) { return null; } - return result; + return [xLow, yLow, xHigh, yHigh]; + } + + static bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3) { + const tvalues = [], + bounds = [[], []]; + let a, b, c, t, t1, t2, b2ac, sqrtb2ac; + + for (let i = 0; i < 2; ++i) { + if (i === 0) { + b = 6 * x0 - 12 * x1 + 6 * x2; + a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; + c = 3 * x1 - 3 * x0; + } else { + b = 6 * y0 - 12 * y1 + 6 * y2; + a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; + c = 3 * y1 - 3 * y0; + } + + if (Math.abs(a) < 1e-12) { + if (Math.abs(b) < 1e-12) { + continue; + } + + t = -c / b; + + if (0 < t && t < 1) { + tvalues.push(t); + } + + continue; + } + + b2ac = b * b - 4 * c * a; + sqrtb2ac = Math.sqrt(b2ac); + + if (b2ac < 0) { + continue; + } + + t1 = (-b + sqrtb2ac) / (2 * a); + + if (0 < t1 && t1 < 1) { + tvalues.push(t1); + } + + t2 = (-b - sqrtb2ac) / (2 * a); + + if (0 < t2 && t2 < 1) { + tvalues.push(t2); + } + } + + let j = tvalues.length, + mt; + const jlen = j; + + while (j--) { + t = tvalues[j]; + mt = 1 - t; + bounds[0][j] = mt * mt * mt * x0 + 3 * mt * mt * t * x1 + 3 * mt * t * t * x2 + t * t * t * x3; + bounds[1][j] = mt * mt * mt * y0 + 3 * mt * mt * t * y1 + 3 * mt * t * t * y2 + t * t * t * y3; + } + + bounds[0][jlen] = x0; + bounds[1][jlen] = y0; + bounds[0][jlen + 1] = x3; + bounds[1][jlen + 1] = y3; + bounds[0].length = bounds[1].length = jlen + 2; + return [Math.min(...bounds[0]), Math.min(...bounds[1]), Math.max(...bounds[0]), Math.max(...bounds[1])]; } } exports.Util = Util; -const PDFStringTranslateTable = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160, 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC]; +const PDFStringTranslateTable = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2d8, 0x2c7, 0x2c6, 0x2d9, 0x2dd, 0x2db, 0x2da, 0x2dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x141, 0x152, 0x160, 0x178, 0x17d, 0x131, 0x142, 0x153, 0x161, 0x17e, 0, 0x20ac]; function stringToPDFString(str) { - const length = str.length, - strBuf = []; + if (str[0] >= "\xEF") { + let encoding; - if (str[0] === "\xFE" && str[1] === "\xFF") { - for (let i = 2; i < length; i += 2) { - strBuf.push(String.fromCharCode(str.charCodeAt(i) << 8 | str.charCodeAt(i + 1))); + if (str[0] === "\xFE" && str[1] === "\xFF") { + encoding = "utf-16be"; + } else if (str[0] === "\xFF" && str[1] === "\xFE") { + encoding = "utf-16le"; + } else if (str[0] === "\xEF" && str[1] === "\xBB" && str[2] === "\xBF") { + encoding = "utf-8"; } - } else if (str[0] === "\xFF" && str[1] === "\xFE") { - for (let i = 2; i < length; i += 2) { - strBuf.push(String.fromCharCode(str.charCodeAt(i + 1) << 8 | str.charCodeAt(i))); - } - } else { - for (let i = 0; i < length; ++i) { - const code = PDFStringTranslateTable[str.charCodeAt(i)]; - strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); + + if (encoding) { + try { + const decoder = new TextDecoder(encoding, { + fatal: true + }); + const buffer = stringToBytes(str); + return decoder.decode(buffer); + } catch (ex) { + warn(`stringToPDFString: "${ex}".`); + } } } + const strBuf = []; + + for (let i = 0, ii = str.length; i < ii; i++) { + const code = PDFStringTranslateTable[str.charCodeAt(i)]; + strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); + } + return strBuf.join(""); } function escapeString(str) { - return str.replace(/([\(\)\\])/g, "\\$1"); + return str.replace(/([()\\\n\r])/g, match => { + if (match === "\n") { + return "\\n"; + } else if (match === "\r") { + return "\\r"; + } + + return `\\${match}`; + }); +} + +function isAscii(str) { + return /^[\x00-\x7F]*$/.test(str); +} + +function stringToUTF16BEString(str) { + const buf = ["\xFE\xFF"]; + + for (let i = 0, ii = str.length; i < ii; i++) { + const char = str.charCodeAt(i); + buf.push(String.fromCharCode(char >> 8 & 0xff), String.fromCharCode(char & 0xff)); + } + + return buf.join(""); } function stringToUTF8String(str) { @@ -1652,18 +1031,6 @@ function utf8StringToString(str) { return unescape(encodeURIComponent(str)); } -function isBool(v) { - return typeof v === "boolean"; -} - -function isNum(v) { - return typeof v === "number"; -} - -function isString(v) { - return typeof v === "string"; -} - function isArrayBuffer(v) { return typeof v === "object" && v !== null && v.byteLength !== undefined; } @@ -1673,13 +1040,17 @@ function isArrayEqual(arr1, arr2) { return false; } - return arr1.every(function (element, index) { - return element === arr2[index]; - }); + for (let i = 0, ii = arr1.length; i < ii; i++) { + if (arr1[i] !== arr2[i]) { + return false; + } + } + + return true; } -function getModificationDate(date = new Date(Date.now())) { - const buffer = [date.getUTCFullYear().toString(), (date.getUTCMonth() + 1).toString().padStart(2, "0"), (date.getUTCDate() + 1).toString().padStart(2, "0"), date.getUTCHours().toString().padStart(2, "0"), date.getUTCMinutes().toString().padStart(2, "0"), date.getUTCSeconds().toString().padStart(2, "0")]; +function getModificationDate(date = new Date()) { + const buffer = [date.getUTCFullYear().toString(), (date.getUTCMonth() + 1).toString().padStart(2, "0"), date.getUTCDate().toString().padStart(2, "0"), date.getUTCHours().toString().padStart(2, "0"), date.getUTCMinutes().toString().padStart(2, "0"), date.getUTCSeconds().toString().padStart(2, "0")]; return buffer.join(""); } @@ -1706,106 +1077,88 @@ function createPromiseCapability() { return capability; } -const createObjectURL = function createObjectURLClosure() { - const digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - return function createObjectURL(data, contentType, forceDataSchema = false) { - if (!forceDataSchema && URL.createObjectURL) { - const blob = new Blob([data], { - type: contentType - }); - return URL.createObjectURL(blob); - } - - let buffer = `data:${contentType};base64,`; - - for (let i = 0, ii = data.length; i < ii; i += 3) { - const b1 = data[i] & 0xff; - const b2 = data[i + 1] & 0xff; - const b3 = data[i + 2] & 0xff; - const d1 = b1 >> 2, - d2 = (b1 & 3) << 4 | b2 >> 4; - const d3 = i + 1 < ii ? (b2 & 0xf) << 2 | b3 >> 6 : 64; - const d4 = i + 2 < ii ? b3 & 0x3f : 64; - buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; - } - - return buffer; - }; -}(); - -exports.createObjectURL = createObjectURL; - /***/ }), -/* 3 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 2 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { -var _is_node = __w_pdfjs_require__(4); + +var _is_node = __w_pdfjs_require__(3); ; /***/ }), -/* 4 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 3 */ +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.isNodeJS = void 0; const isNodeJS = typeof process === "object" && process + "" === "[object process]" && !process.versions.nw && !(process.versions.electron && process.type && process.type !== "browser"); exports.isNodeJS = isNodeJS; /***/ }), -/* 5 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 4 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.build = exports.RenderTask = exports.PDFWorkerUtil = exports.PDFWorker = exports.PDFPageProxy = exports.PDFDocumentProxy = exports.PDFDocumentLoadingTask = exports.PDFDataRangeTransport = exports.LoopbackPort = exports.DefaultStandardFontDataFactory = exports.DefaultCanvasFactory = exports.DefaultCMapReaderFactory = void 0; exports.getDocument = getDocument; exports.setPDFNetworkStreamFactory = setPDFNetworkStreamFactory; -exports.build = exports.version = exports.PDFPageProxy = exports.PDFDocumentProxy = exports.PDFWorker = exports.PDFDataRangeTransport = exports.LoopbackPort = void 0; +exports.version = void 0; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); -var _display_utils = __w_pdfjs_require__(1); +var _annotation_storage = __w_pdfjs_require__(5); -var _font_loader = __w_pdfjs_require__(6); +var _display_utils = __w_pdfjs_require__(8); -var _node_utils = __w_pdfjs_require__(7); +var _font_loader = __w_pdfjs_require__(11); -var _annotation_storage = __w_pdfjs_require__(8); +var _canvas = __w_pdfjs_require__(12); -var _api_compatibility = __w_pdfjs_require__(9); +var _worker_options = __w_pdfjs_require__(15); -var _canvas = __w_pdfjs_require__(10); +var _is_node = __w_pdfjs_require__(3); -var _worker_options = __w_pdfjs_require__(12); +var _message_handler = __w_pdfjs_require__(16); -var _is_node = __w_pdfjs_require__(4); +var _metadata = __w_pdfjs_require__(17); -var _message_handler = __w_pdfjs_require__(13); +var _optional_content_config = __w_pdfjs_require__(18); -var _metadata = __w_pdfjs_require__(14); +var _transport_stream = __w_pdfjs_require__(19); -var _optional_content_config = __w_pdfjs_require__(16); - -var _transport_stream = __w_pdfjs_require__(17); - -var _webgl = __w_pdfjs_require__(18); +var _xfa_text = __w_pdfjs_require__(20); const DEFAULT_RANGE_CHUNK_SIZE = 65536; const RENDERING_CANCELLED_TIMEOUT = 100; -const DefaultCanvasFactory = _is_node.isNodeJS ? _node_utils.NodeCanvasFactory : _display_utils.DOMCanvasFactory; -const DefaultCMapReaderFactory = _is_node.isNodeJS ? _node_utils.NodeCMapReaderFactory : _display_utils.DOMCMapReaderFactory; +let DefaultCanvasFactory = _display_utils.DOMCanvasFactory; +exports.DefaultCanvasFactory = DefaultCanvasFactory; +let DefaultCMapReaderFactory = _display_utils.DOMCMapReaderFactory; +exports.DefaultCMapReaderFactory = DefaultCMapReaderFactory; +let DefaultStandardFontDataFactory = _display_utils.DOMStandardFontDataFactory; +exports.DefaultStandardFontDataFactory = DefaultStandardFontDataFactory; + +if (_is_node.isNodeJS) { + const { + NodeCanvasFactory, + NodeCMapReaderFactory, + NodeStandardFontDataFactory + } = __w_pdfjs_require__(21); + + exports.DefaultCanvasFactory = DefaultCanvasFactory = NodeCanvasFactory; + exports.DefaultCMapReaderFactory = DefaultCMapReaderFactory = NodeCMapReaderFactory; + exports.DefaultStandardFontDataFactory = DefaultStandardFontDataFactory = NodeStandardFontDataFactory; +} + let createPDFNetworkStream; function setPDFNetworkStreamFactory(pdfNetworkStreamFactory) { @@ -1816,7 +1169,7 @@ function getDocument(src) { const task = new PDFDocumentLoadingTask(); let source; - if (typeof src === "string") { + if (typeof src === "string" || src instanceof URL) { source = { url: src }; @@ -1830,7 +1183,7 @@ function getDocument(src) { }; } else { if (typeof src !== "object") { - throw new Error("Invalid parameter in getDocument, " + "need either Uint8Array, string or a parameter object"); + throw new Error("Invalid parameter in getDocument, " + "need either string, URL, TypedArray, or parameter object."); } if (!src.url && !src.data && !src.range) { @@ -1845,53 +1198,97 @@ function getDocument(src) { worker = null; for (const key in source) { - if (key === "url" && typeof window !== "undefined") { - params[key] = new URL(source[key], window.location).href; - continue; - } else if (key === "range") { - rangeTransport = source[key]; - continue; - } else if (key === "worker") { - worker = source[key]; - continue; - } else if (key === "data" && !(source[key] instanceof Uint8Array)) { - const pdfBytes = source[key]; + const value = source[key]; - if (typeof pdfBytes === "string") { - params[key] = (0, _util.stringToBytes)(pdfBytes); - } else if (typeof pdfBytes === "object" && pdfBytes !== null && !isNaN(pdfBytes.length)) { - params[key] = new Uint8Array(pdfBytes); - } else if ((0, _util.isArrayBuffer)(pdfBytes)) { - params[key] = new Uint8Array(pdfBytes); - } else { - throw new Error("Invalid PDF binary data: either typed array, " + "string or array-like object is expected in the " + "data property."); - } + switch (key) { + case "url": + if (typeof window !== "undefined") { + try { + params[key] = new URL(value, window.location).href; + continue; + } catch (ex) { + (0, _util.warn)(`Cannot create valid URL: "${ex}".`); + } + } else if (typeof value === "string" || value instanceof URL) { + params[key] = value.toString(); + continue; + } - continue; + throw new Error("Invalid PDF url data: " + "either string or URL-object is expected in the url property."); + + case "range": + rangeTransport = value; + continue; + + case "worker": + worker = value; + continue; + + case "data": + if (_is_node.isNodeJS && typeof Buffer !== "undefined" && value instanceof Buffer) { + params[key] = new Uint8Array(value); + } else if (value instanceof Uint8Array) { + break; + } else if (typeof value === "string") { + params[key] = (0, _util.stringToBytes)(value); + } else if (typeof value === "object" && value !== null && !isNaN(value.length)) { + params[key] = new Uint8Array(value); + } else if ((0, _util.isArrayBuffer)(value)) { + params[key] = new Uint8Array(value); + } else { + throw new Error("Invalid PDF binary data: either TypedArray, " + "string, or array-like object is expected in the data property."); + } + + continue; } - params[key] = source[key]; + params[key] = value; } - params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE; params.CMapReaderFactory = params.CMapReaderFactory || DefaultCMapReaderFactory; + params.StandardFontDataFactory = params.StandardFontDataFactory || DefaultStandardFontDataFactory; params.ignoreErrors = params.stopAtErrors !== true; params.fontExtraProperties = params.fontExtraProperties === true; params.pdfBug = params.pdfBug === true; + params.enableXfa = params.enableXfa === true; - if (!Number.isInteger(params.maxImageSize)) { + if (!Number.isInteger(params.rangeChunkSize) || params.rangeChunkSize < 1) { + params.rangeChunkSize = DEFAULT_RANGE_CHUNK_SIZE; + } + + if (typeof params.docBaseUrl !== "string" || (0, _display_utils.isDataScheme)(params.docBaseUrl)) { + params.docBaseUrl = null; + } + + if (!Number.isInteger(params.maxImageSize) || params.maxImageSize < -1) { params.maxImageSize = -1; } + if (typeof params.cMapUrl !== "string") { + params.cMapUrl = null; + } + + if (typeof params.standardFontDataUrl !== "string") { + params.standardFontDataUrl = null; + } + + if (typeof params.useWorkerFetch !== "boolean") { + params.useWorkerFetch = params.CMapReaderFactory === _display_utils.DOMCMapReaderFactory && params.StandardFontDataFactory === _display_utils.DOMStandardFontDataFactory; + } + if (typeof params.isEvalSupported !== "boolean") { params.isEvalSupported = true; } if (typeof params.disableFontFace !== "boolean") { - params.disableFontFace = _api_compatibility.apiCompatibilityParams.disableFontFace || false; + params.disableFontFace = _is_node.isNodeJS; } - if (typeof params.ownerDocument === "undefined") { + if (typeof params.useSystemFonts !== "boolean") { + params.useSystemFonts = !_is_node.isNodeJS && !params.disableFontFace; + } + + if (typeof params.ownerDocument !== "object" || params.ownerDocument === null) { params.ownerDocument = globalThis.document; } @@ -1934,6 +1331,7 @@ function getDocument(src) { length: params.length, initialData: params.initialData, progressiveDone: params.progressiveDone, + contentDispositionFilename: params.contentDispositionFilename, disableRange: params.disableRange, disableStream: params.disableStream }, rangeTransport); @@ -1957,7 +1355,6 @@ function getDocument(src) { } const messageHandler = new _message_handler.MessageHandler(docId, workerId, worker.port); - messageHandler.postMessageTransfers = worker.postMessageTransfers; const transport = new WorkerTransport(messageHandler, task, networkStream, params); task._transport = transport; messageHandler.send("Ready", null); @@ -1966,20 +1363,21 @@ function getDocument(src) { return task; } -function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { +async function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { if (worker.destroyed) { - return Promise.reject(new Error("Worker was destroyed")); + throw new Error("Worker was destroyed"); } if (pdfDataRangeTransport) { source.length = pdfDataRangeTransport.length; source.initialData = pdfDataRangeTransport.initialData; source.progressiveDone = pdfDataRangeTransport.progressiveDone; + source.contentDispositionFilename = pdfDataRangeTransport.contentDispositionFilename; } - return worker.messageHandler.sendWithPromise("GetDocRequest", { + const workerId = await worker.messageHandler.sendWithPromise("GetDocRequest", { docId, - apiVersion: '2.6.347', + apiVersion: '2.16.105', source: { data: source.data, url: source.url, @@ -1990,63 +1388,67 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { }, maxImageSize: source.maxImageSize, disableFontFace: source.disableFontFace, - postMessageTransfers: worker.postMessageTransfers, docBaseUrl: source.docBaseUrl, ignoreErrors: source.ignoreErrors, isEvalSupported: source.isEvalSupported, - fontExtraProperties: source.fontExtraProperties - }).then(function (workerId) { - if (worker.destroyed) { - throw new Error("Worker was destroyed"); - } - - return workerId; + fontExtraProperties: source.fontExtraProperties, + enableXfa: source.enableXfa, + useSystemFonts: source.useSystemFonts, + cMapUrl: source.useWorkerFetch ? source.cMapUrl : null, + standardFontDataUrl: source.useWorkerFetch ? source.standardFontDataUrl : null }); -} - -const PDFDocumentLoadingTask = function PDFDocumentLoadingTaskClosure() { - let nextDocumentId = 0; - - class PDFDocumentLoadingTask { - constructor() { - this._capability = (0, _util.createPromiseCapability)(); - this._transport = null; - this._worker = null; - this.docId = "d" + nextDocumentId++; - this.destroyed = false; - this.onPassword = null; - this.onProgress = null; - this.onUnsupportedFeature = null; - } - - get promise() { - return this._capability.promise; - } - - destroy() { - this.destroyed = true; - const transportDestroyed = !this._transport ? Promise.resolve() : this._transport.destroy(); - return transportDestroyed.then(() => { - this._transport = null; - - if (this._worker) { - this._worker.destroy(); - - this._worker = null; - } - }); - } + if (source.data) { + source.data = null; } - return PDFDocumentLoadingTask; -}(); + if (worker.destroyed) { + throw new Error("Worker was destroyed"); + } + + return workerId; +} + +class PDFDocumentLoadingTask { + static #docId = 0; + + constructor() { + this._capability = (0, _util.createPromiseCapability)(); + this._transport = null; + this._worker = null; + this.docId = `d${PDFDocumentLoadingTask.#docId++}`; + this.destroyed = false; + this.onPassword = null; + this.onProgress = null; + this.onUnsupportedFeature = null; + } + + get promise() { + return this._capability.promise; + } + + async destroy() { + this.destroyed = true; + await this._transport?.destroy(); + this._transport = null; + + if (this._worker) { + this._worker.destroy(); + + this._worker = null; + } + } + +} + +exports.PDFDocumentLoadingTask = PDFDocumentLoadingTask; class PDFDataRangeTransport { - constructor(length, initialData, progressiveDone = false) { + constructor(length, initialData, progressiveDone = false, contentDispositionFilename = null) { this.length = length; this.initialData = initialData; this.progressiveDone = progressiveDone; + this.contentDispositionFilename = contentDispositionFilename; this._rangeListeners = []; this._progressListeners = []; this._progressiveReadListeners = []; @@ -2118,18 +1520,46 @@ class PDFDocumentProxy { constructor(pdfInfo, transport) { this._pdfInfo = pdfInfo; this._transport = transport; + Object.defineProperty(this, "fingerprint", { + get() { + (0, _display_utils.deprecated)("`PDFDocumentProxy.fingerprint`, " + "please use `PDFDocumentProxy.fingerprints` instead."); + return this.fingerprints[0]; + } + + }); + Object.defineProperty(this, "getStats", { + value: async () => { + (0, _display_utils.deprecated)("`PDFDocumentProxy.getStats`, " + "please use the `PDFDocumentProxy.stats`-getter instead."); + return this.stats || { + streamTypes: {}, + fontTypes: {} + }; + } + }); } get annotationStorage() { - return (0, _util.shadow)(this, "annotationStorage", new _annotation_storage.AnnotationStorage()); + return this._transport.annotationStorage; } get numPages() { return this._pdfInfo.numPages; } - get fingerprint() { - return this._pdfInfo.fingerprint; + get fingerprints() { + return this._pdfInfo.fingerprints; + } + + get stats() { + return this._transport.stats; + } + + get isPureXfa() { + return !!this._transport._htmlForXfa; + } + + get allXfaHtml() { + return this._transport._htmlForXfa; } getPage(pageNumber) { @@ -2176,6 +1606,10 @@ class PDFDocumentProxy { return this._transport.getJavaScript(); } + getJSActions() { + return this._transport.getDocJSActions(); + } + getOutline() { return this._transport.getOutline(); } @@ -2192,6 +1626,10 @@ class PDFDocumentProxy { return this._transport.getMetadata(); } + getMarkInfo() { + return this._transport.getMarkInfo(); + } + getData() { return this._transport.getData(); } @@ -2200,12 +1638,8 @@ class PDFDocumentProxy { return this._transport.downloadInfoCapability.promise; } - getStats() { - return this._transport.getStats(); - } - - cleanup() { - return this._transport.startCleanup(); + cleanup(keepLoadedFonts = false) { + return this._transport.startCleanup(keepLoadedFonts || this.isPureXfa); } destroy() { @@ -2220,8 +1654,24 @@ class PDFDocumentProxy { return this._transport.loadingTask; } - saveDocument(annotationStorage) { - return this._transport.saveDocument(annotationStorage); + saveDocument() { + if (this._transport.annotationStorage.size <= 0) { + (0, _display_utils.deprecated)("saveDocument called while `annotationStorage` is empty, " + "please use the getData-method instead."); + } + + return this._transport.saveDocument(); + } + + getFieldObjects() { + return this._transport.getFieldObjects(); + } + + hasJSActions() { + return this._transport.hasJSActions(); + } + + getCalculationOrderIds() { + return this._transport.getCalculationOrderIds(); } } @@ -2238,9 +1688,11 @@ class PDFPageProxy { this._pdfBug = pdfBug; this.commonObjs = transport.commonObjs; this.objs = new PDFObjects(); + this._bitmaps = new Set(); this.cleanupAfterRender = false; this.pendingCleanup = false; this._intentStates = new Map(); + this._annotationPromises = new Map(); this.destroyed = false; } @@ -2282,46 +1734,103 @@ class PDFPageProxy { } getAnnotations({ - intent = null + intent = "display" } = {}) { - if (!this.annotationsPromise || this.annotationsIntent !== intent) { - this.annotationsPromise = this._transport.getAnnotations(this._pageIndex, intent); - this.annotationsIntent = intent; + const intentArgs = this._transport.getRenderingIntent(intent); + + let promise = this._annotationPromises.get(intentArgs.cacheKey); + + if (!promise) { + promise = this._transport.getAnnotations(this._pageIndex, intentArgs.renderingIntent); + + this._annotationPromises.set(intentArgs.cacheKey, promise); + + promise = promise.then(annotations => { + for (const annotation of annotations) { + if (annotation.titleObj !== undefined) { + Object.defineProperty(annotation, "title", { + get() { + (0, _display_utils.deprecated)("`title`-property on annotation, please use `titleObj` instead."); + return annotation.titleObj.str; + } + + }); + } + + if (annotation.contentsObj !== undefined) { + Object.defineProperty(annotation, "contents", { + get() { + (0, _display_utils.deprecated)("`contents`-property on annotation, please use `contentsObj` instead."); + return annotation.contentsObj.str; + } + + }); + } + } + + return annotations; + }); } - return this.annotationsPromise; + return promise; + } + + getJSActions() { + return this._jsActionsPromise ||= this._transport.getPageJSActions(this._pageIndex); + } + + async getXfa() { + return this._transport._htmlForXfa?.children[this._pageIndex] || null; } render({ canvasContext, viewport, intent = "display", - enableWebGL = false, - renderInteractiveForms = false, + annotationMode = _util.AnnotationMode.ENABLE, transform = null, imageLayer = null, canvasFactory = null, background = null, - annotationStorage = null, - optionalContentConfigPromise = null + optionalContentConfigPromise = null, + annotationCanvasMap = null, + pageColors = null, + printAnnotationStorage = null }) { + if (arguments[0]?.renderInteractiveForms !== undefined) { + (0, _display_utils.deprecated)("render no longer accepts the `renderInteractiveForms`-option, " + "please use the `annotationMode`-option instead."); + + if (arguments[0].renderInteractiveForms === true && annotationMode === _util.AnnotationMode.ENABLE) { + annotationMode = _util.AnnotationMode.ENABLE_FORMS; + } + } + + if (arguments[0]?.includeAnnotationStorage !== undefined) { + (0, _display_utils.deprecated)("render no longer accepts the `includeAnnotationStorage`-option, " + "please use the `annotationMode`-option instead."); + + if (arguments[0].includeAnnotationStorage === true && annotationMode === _util.AnnotationMode.ENABLE) { + annotationMode = _util.AnnotationMode.ENABLE_STORAGE; + } + } + if (this._stats) { this._stats.time("Overall"); } - const renderingIntent = intent === "print" ? "print" : "display"; + const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage); + this.pendingCleanup = false; if (!optionalContentConfigPromise) { optionalContentConfigPromise = this._transport.getOptionalContentConfig(); } - let intentState = this._intentStates.get(renderingIntent); + let intentState = this._intentStates.get(intentArgs.cacheKey); if (!intentState) { intentState = Object.create(null); - this._intentStates.set(renderingIntent, intentState); + this._intentStates.set(intentArgs.cacheKey, intentState); } if (intentState.streamReaderCancelTimeout) { @@ -2332,38 +1841,28 @@ class PDFPageProxy { const canvasFactoryInstance = canvasFactory || new DefaultCanvasFactory({ ownerDocument: this._ownerDocument }); - const webGLContext = new _webgl.WebGLContext({ - enable: enableWebGL - }); + const intentPrint = !!(intentArgs.renderingIntent & _util.RenderingIntentFlag.PRINT); if (!intentState.displayReadyCapability) { intentState.displayReadyCapability = (0, _util.createPromiseCapability)(); intentState.operatorList = { fnArray: [], argsArray: [], - lastChunk: false + lastChunk: false, + separateAnnots: null }; if (this._stats) { this._stats.time("Page Request"); } - this._pumpOperatorList({ - pageIndex: this._pageIndex, - intent: renderingIntent, - renderInteractiveForms: renderInteractiveForms === true, - annotationStorage: annotationStorage && annotationStorage.getAll() || null - }); + this._pumpOperatorList(intentArgs); } const complete = error => { - const i = intentState.renderTasks.indexOf(internalRenderTask); + intentState.renderTasks.delete(internalRenderTask); - if (i >= 0) { - intentState.renderTasks.splice(i, 1); - } - - if (this.cleanupAfterRender || renderingIntent === "print") { + if (this.cleanupAfterRender || intentPrint) { this.pendingCleanup = true; } @@ -2374,7 +1873,7 @@ class PDFPageProxy { this._abortOperatorList({ intentState, - reason: error + reason: error instanceof Error ? error : new Error(error) }); } else { internalRenderTask.capability.resolve(); @@ -2398,19 +1897,15 @@ class PDFPageProxy { }, objs: this.objs, commonObjs: this.commonObjs, + annotationCanvasMap, operatorList: intentState.operatorList, pageIndex: this._pageIndex, canvasFactory: canvasFactoryInstance, - webGLContext, - useRequestAnimationFrame: renderingIntent !== "print", - pdfBug: this._pdfBug + useRequestAnimationFrame: !intentPrint, + pdfBug: this._pdfBug, + pageColors }); - - if (!intentState.renderTasks) { - intentState.renderTasks = []; - } - - intentState.renderTasks.push(internalRenderTask); + (intentState.renderTasks ||= new Set()).add(internalRenderTask); const renderTask = internalRenderTask.task; Promise.all([intentState.displayReadyCapability.promise, optionalContentConfigPromise]).then(([transparency, optionalContentConfig]) => { if (this.pendingCleanup) { @@ -2431,26 +1926,26 @@ class PDFPageProxy { return renderTask; } - getOperatorList() { + getOperatorList({ + intent = "display", + annotationMode = _util.AnnotationMode.ENABLE, + printAnnotationStorage = null + } = {}) { function operatorListChanged() { if (intentState.operatorList.lastChunk) { intentState.opListReadCapability.resolve(intentState.operatorList); - const i = intentState.renderTasks.indexOf(opListTask); - - if (i >= 0) { - intentState.renderTasks.splice(i, 1); - } + intentState.renderTasks.delete(opListTask); } } - const renderingIntent = "oplist"; + const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage, true); - let intentState = this._intentStates.get(renderingIntent); + let intentState = this._intentStates.get(intentArgs.cacheKey); if (!intentState) { intentState = Object.create(null); - this._intentStates.set(renderingIntent, intentState); + this._intentStates.set(intentArgs.cacheKey, intentState); } let opListTask; @@ -2459,36 +1954,33 @@ class PDFPageProxy { opListTask = Object.create(null); opListTask.operatorListChanged = operatorListChanged; intentState.opListReadCapability = (0, _util.createPromiseCapability)(); - intentState.renderTasks = []; - intentState.renderTasks.push(opListTask); + (intentState.renderTasks ||= new Set()).add(opListTask); intentState.operatorList = { fnArray: [], argsArray: [], - lastChunk: false + lastChunk: false, + separateAnnots: null }; if (this._stats) { this._stats.time("Page Request"); } - this._pumpOperatorList({ - pageIndex: this._pageIndex, - intent: renderingIntent - }); + this._pumpOperatorList(intentArgs); } return intentState.opListReadCapability.promise; } streamTextContent({ - normalizeWhitespace = false, - disableCombineTextItems = false + disableCombineTextItems = false, + includeMarkedContent = false } = {}) { const TEXT_CONTENT_CHUNK_SIZE = 100; return this._transport.messageHandler.sendWithStream("GetTextContent", { pageIndex: this._pageIndex, - normalizeWhitespace: normalizeWhitespace === true, - combineTextItems: disableCombineTextItems !== true + combineTextItems: disableCombineTextItems !== true, + includeMarkedContent: includeMarkedContent === true }, { highWaterMark: TEXT_CONTENT_CHUNK_SIZE, @@ -2500,6 +1992,12 @@ class PDFPageProxy { } getTextContent(params = {}) { + if (this._transport._htmlForXfa) { + return this.getXfa().then(xfa => { + return _xfa_text.XfaText.textContent(xfa); + }); + } + const readableStream = this.streamTextContent(params); return new Promise(function (resolve, reject) { function pump() { @@ -2527,19 +2025,22 @@ class PDFPageProxy { }); } + getStructTree() { + return this._structTreePromise ||= this._transport.getStructTree(this._pageIndex); + } + _destroy() { this.destroyed = true; - this._transport.pageCache[this._pageIndex] = null; const waitOn = []; - for (const [intent, intentState] of this._intentStates) { + for (const intentState of this._intentStates.values()) { this._abortOperatorList({ intentState, reason: new Error("Page was destroyed."), force: true }); - if (intent === "oplist") { + if (intentState.opListReadCapability) { continue; } @@ -2550,7 +2051,17 @@ class PDFPageProxy { } this.objs.clear(); - this.annotationsPromise = null; + + for (const bitmap of this._bitmaps) { + bitmap.close(); + } + + this._bitmaps.clear(); + + this._annotationPromises.clear(); + + this._jsActionsPromise = null; + this._structTreePromise = null; this.pendingCleanup = false; return Promise.all(waitOn); } @@ -2569,7 +2080,7 @@ class PDFPageProxy { renderTasks, operatorList } of this._intentStates.values()) { - if (renderTasks.length !== 0 || !operatorList.lastChunk) { + if (renderTasks.size > 0 || !operatorList.lastChunk) { return false; } } @@ -2577,18 +2088,28 @@ class PDFPageProxy { this._intentStates.clear(); this.objs.clear(); - this.annotationsPromise = null; + + this._annotationPromises.clear(); + + this._jsActionsPromise = null; + this._structTreePromise = null; if (resetStats && this._stats) { this._stats = new _display_utils.StatTimer(); } + for (const bitmap of this._bitmaps) { + bitmap.close(); + } + + this._bitmaps.clear(); + this.pendingCleanup = false; return true; } - _startRenderPage(transparency, intent) { - const intentState = this._intentStates.get(intent); + _startRenderPage(transparency, cacheKey) { + const intentState = this._intentStates.get(cacheKey); if (!intentState) { return; @@ -2610,9 +2131,10 @@ class PDFPageProxy { } intentState.operatorList.lastChunk = operatorListChunk.lastChunk; + intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots; - for (let i = 0; i < intentState.renderTasks.length; i++) { - intentState.renderTasks[i].operatorListChanged(); + for (const internalRenderTask of intentState.renderTasks) { + internalRenderTask.operatorListChanged(); } if (operatorListChunk.lastChunk) { @@ -2620,14 +2142,21 @@ class PDFPageProxy { } } - _pumpOperatorList(args) { - (0, _util.assert)(args.intent, 'PDFPageProxy._pumpOperatorList: Expected "intent" argument.'); - - const readableStream = this._transport.messageHandler.sendWithStream("GetOperatorList", args); + _pumpOperatorList({ + renderingIntent, + cacheKey, + annotationStorageMap + }) { + const readableStream = this._transport.messageHandler.sendWithStream("GetOperatorList", { + pageIndex: this._pageIndex, + intent: renderingIntent, + cacheKey, + annotationStorage: annotationStorageMap + }); const reader = readableStream.getReader(); - const intentState = this._intentStates.get(args.intent); + const intentState = this._intentStates.get(cacheKey); intentState.streamReader = reader; @@ -2658,8 +2187,8 @@ class PDFPageProxy { if (intentState.operatorList) { intentState.operatorList.lastChunk = true; - for (let i = 0; i < intentState.renderTasks.length; i++) { - intentState.renderTasks[i].operatorListChanged(); + for (const internalRenderTask of intentState.renderTasks) { + internalRenderTask.operatorListChanged(); } this._tryCleanup(); @@ -2683,14 +2212,12 @@ class PDFPageProxy { reason, force = false }) { - (0, _util.assert)(reason instanceof Error || typeof reason === "object" && reason !== null, 'PDFPageProxy._abortOperatorList: Expected "reason" argument.'); - if (!intentState.streamReader) { return; } if (!force) { - if (intentState.renderTasks.length !== 0) { + if (intentState.renderTasks.size > 0) { return; } @@ -2708,16 +2235,16 @@ class PDFPageProxy { } } - intentState.streamReader.cancel(new _util.AbortException(reason && reason.message)); + intentState.streamReader.cancel(new _util.AbortException(reason.message)).catch(() => {}); intentState.streamReader = null; if (this._transport.destroyed) { return; } - for (const [intent, curIntentState] of this._intentStates) { + for (const [curCacheKey, curIntentState] of this._intentStates) { if (curIntentState === intentState) { - this._intentStates.delete(intent); + this._intentStates.delete(curCacheKey); break; } @@ -2735,85 +2262,20 @@ class PDFPageProxy { exports.PDFPageProxy = PDFPageProxy; class LoopbackPort { - constructor(defer = true) { + constructor() { this._listeners = []; - this._defer = defer; - this._deferred = Promise.resolve(undefined); + this._deferred = Promise.resolve(); } postMessage(obj, transfers) { - function cloneValue(value) { - if (typeof value !== "object" || value === null) { - return value; - } - - if (cloned.has(value)) { - return cloned.get(value); - } - - let buffer, result; - - if ((buffer = value.buffer) && (0, _util.isArrayBuffer)(buffer)) { - const transferable = transfers && transfers.includes(buffer); - - if (transferable) { - result = new value.constructor(buffer, value.byteOffset, value.byteLength); - } else { - result = new value.constructor(value); - } - - cloned.set(value, result); - return result; - } - - result = Array.isArray(value) ? [] : {}; - cloned.set(value, result); - - for (const i in value) { - let desc, - p = value; - - while (!(desc = Object.getOwnPropertyDescriptor(p, i))) { - p = Object.getPrototypeOf(p); - } - - if (typeof desc.value === "undefined") { - continue; - } - - if (typeof desc.value === "function") { - if (value.hasOwnProperty && value.hasOwnProperty(i)) { - throw new Error(`LoopbackPort.postMessage - cannot clone: ${value[i]}`); - } - - continue; - } - - result[i] = cloneValue(desc.value); - } - - return result; - } - - if (!this._defer) { - this._listeners.forEach(listener => { - listener.call(this, { - data: obj - }); - }); - - return; - } - - const cloned = new WeakMap(); - const e = { - data: cloneValue(obj) + const event = { + data: structuredClone(obj, transfers) }; this._deferred.then(() => { - this._listeners.forEach(listener => { - listener.call(this, e); - }); + for (const listener of this._listeners) { + listener.call(this, event); + } }); } @@ -2834,305 +2296,309 @@ class LoopbackPort { } exports.LoopbackPort = LoopbackPort; - -const PDFWorker = function PDFWorkerClosure() { - const pdfWorkerPorts = new WeakMap(); - let isWorkerDisabled = false; - let fallbackWorkerSrc; - let nextFakeWorkerId = 0; - let fakeWorkerCapability; - +const PDFWorkerUtil = { + isWorkerDisabled: false, + fallbackWorkerSrc: null, + fakeWorkerId: 0 +}; +exports.PDFWorkerUtil = PDFWorkerUtil; +{ if (_is_node.isNodeJS && typeof require === "function") { - isWorkerDisabled = true; - fallbackWorkerSrc = "./pdf.worker.js"; - } else if (typeof document === "object" && "currentScript" in document) { - const pdfjsFilePath = document.currentScript && document.currentScript.src; + PDFWorkerUtil.isWorkerDisabled = true; + PDFWorkerUtil.fallbackWorkerSrc = "./pdf.worker.js"; + } else if (typeof document === "object") { + const pdfjsFilePath = document?.currentScript?.src; if (pdfjsFilePath) { - fallbackWorkerSrc = pdfjsFilePath.replace(/(\.(?:min\.)?js)(\?.*)?$/i, ".worker$1$2"); + PDFWorkerUtil.fallbackWorkerSrc = pdfjsFilePath.replace(/(\.(?:min\.)?js)(\?.*)?$/i, ".worker$1$2"); } } - function getWorkerSrc() { + PDFWorkerUtil.isSameOrigin = function (baseUrl, otherUrl) { + let base; + + try { + base = new URL(baseUrl); + + if (!base.origin || base.origin === "null") { + return false; + } + } catch (e) { + return false; + } + + const other = new URL(otherUrl, base); + return base.origin === other.origin; + }; + + PDFWorkerUtil.createCDNWrapper = function (url) { + const wrapper = `importScripts("${url}");`; + return URL.createObjectURL(new Blob([wrapper])); + }; +} + +class PDFWorker { + static #workerPorts = new WeakMap(); + + constructor({ + name = null, + port = null, + verbosity = (0, _util.getVerbosityLevel)() + } = {}) { + if (port && PDFWorker.#workerPorts.has(port)) { + throw new Error("Cannot use more than one PDFWorker per port."); + } + + this.name = name; + this.destroyed = false; + this.verbosity = verbosity; + this._readyCapability = (0, _util.createPromiseCapability)(); + this._port = null; + this._webWorker = null; + this._messageHandler = null; + + if (port) { + PDFWorker.#workerPorts.set(port, this); + + this._initializeFromPort(port); + + return; + } + + this._initialize(); + } + + get promise() { + return this._readyCapability.promise; + } + + get port() { + return this._port; + } + + get messageHandler() { + return this._messageHandler; + } + + _initializeFromPort(port) { + this._port = port; + this._messageHandler = new _message_handler.MessageHandler("main", "worker", port); + + this._messageHandler.on("ready", function () {}); + + this._readyCapability.resolve(); + } + + _initialize() { + if (!PDFWorkerUtil.isWorkerDisabled && !PDFWorker._mainThreadWorkerMessageHandler) { + let { + workerSrc + } = PDFWorker; + + try { + if (!PDFWorkerUtil.isSameOrigin(window.location.href, workerSrc)) { + workerSrc = PDFWorkerUtil.createCDNWrapper(new URL(workerSrc, window.location).href); + } + + const worker = new Worker(workerSrc); + const messageHandler = new _message_handler.MessageHandler("main", "worker", worker); + + const terminateEarly = () => { + worker.removeEventListener("error", onWorkerError); + messageHandler.destroy(); + worker.terminate(); + + if (this.destroyed) { + this._readyCapability.reject(new Error("Worker was destroyed")); + } else { + this._setupFakeWorker(); + } + }; + + const onWorkerError = () => { + if (!this._webWorker) { + terminateEarly(); + } + }; + + worker.addEventListener("error", onWorkerError); + messageHandler.on("test", data => { + worker.removeEventListener("error", onWorkerError); + + if (this.destroyed) { + terminateEarly(); + return; + } + + if (data) { + this._messageHandler = messageHandler; + this._port = worker; + this._webWorker = worker; + + this._readyCapability.resolve(); + + messageHandler.send("configure", { + verbosity: this.verbosity + }); + } else { + this._setupFakeWorker(); + + messageHandler.destroy(); + worker.terminate(); + } + }); + messageHandler.on("ready", data => { + worker.removeEventListener("error", onWorkerError); + + if (this.destroyed) { + terminateEarly(); + return; + } + + try { + sendTest(); + } catch (e) { + this._setupFakeWorker(); + } + }); + + const sendTest = () => { + const testObj = new Uint8Array(); + messageHandler.send("test", testObj, [testObj.buffer]); + }; + + sendTest(); + return; + } catch (e) { + (0, _util.info)("The worker has been disabled."); + } + } + + this._setupFakeWorker(); + } + + _setupFakeWorker() { + if (!PDFWorkerUtil.isWorkerDisabled) { + (0, _util.warn)("Setting up fake worker."); + PDFWorkerUtil.isWorkerDisabled = true; + } + + PDFWorker._setupFakeWorkerGlobal.then(WorkerMessageHandler => { + if (this.destroyed) { + this._readyCapability.reject(new Error("Worker was destroyed")); + + return; + } + + const port = new LoopbackPort(); + this._port = port; + const id = `fake${PDFWorkerUtil.fakeWorkerId++}`; + const workerHandler = new _message_handler.MessageHandler(id + "_worker", id, port); + WorkerMessageHandler.setup(workerHandler, port); + const messageHandler = new _message_handler.MessageHandler(id, id + "_worker", port); + this._messageHandler = messageHandler; + + this._readyCapability.resolve(); + + messageHandler.send("configure", { + verbosity: this.verbosity + }); + }).catch(reason => { + this._readyCapability.reject(new Error(`Setting up fake worker failed: "${reason.message}".`)); + }); + } + + destroy() { + this.destroyed = true; + + if (this._webWorker) { + this._webWorker.terminate(); + + this._webWorker = null; + } + + PDFWorker.#workerPorts.delete(this._port); + this._port = null; + + if (this._messageHandler) { + this._messageHandler.destroy(); + + this._messageHandler = null; + } + } + + static fromPort(params) { + if (!params?.port) { + throw new Error("PDFWorker.fromPort - invalid method signature."); + } + + if (this.#workerPorts.has(params.port)) { + return this.#workerPorts.get(params.port); + } + + return new PDFWorker(params); + } + + static get workerSrc() { if (_worker_options.GlobalWorkerOptions.workerSrc) { return _worker_options.GlobalWorkerOptions.workerSrc; } - if (typeof fallbackWorkerSrc !== "undefined") { + if (PDFWorkerUtil.fallbackWorkerSrc !== null) { if (!_is_node.isNodeJS) { (0, _display_utils.deprecated)('No "GlobalWorkerOptions.workerSrc" specified.'); } - return fallbackWorkerSrc; + return PDFWorkerUtil.fallbackWorkerSrc; } throw new Error('No "GlobalWorkerOptions.workerSrc" specified.'); } - function getMainThreadWorkerMessageHandler() { - let mainWorkerMessageHandler; - + static get _mainThreadWorkerMessageHandler() { try { - mainWorkerMessageHandler = globalThis.pdfjsWorker && globalThis.pdfjsWorker.WorkerMessageHandler; - } catch (ex) {} - - return mainWorkerMessageHandler || null; + return globalThis.pdfjsWorker?.WorkerMessageHandler || null; + } catch (ex) { + return null; + } } - function setupFakeWorkerGlobal() { - if (fakeWorkerCapability) { - return fakeWorkerCapability.promise; - } - - fakeWorkerCapability = (0, _util.createPromiseCapability)(); - - const loader = async function () { - const mainWorkerMessageHandler = getMainThreadWorkerMessageHandler(); + static get _setupFakeWorkerGlobal() { + const loader = async () => { + const mainWorkerMessageHandler = this._mainThreadWorkerMessageHandler; if (mainWorkerMessageHandler) { return mainWorkerMessageHandler; } if (_is_node.isNodeJS && typeof require === "function") { - const worker = eval("require")(getWorkerSrc()); + const worker = eval("require")(this.workerSrc); return worker.WorkerMessageHandler; } - await (0, _display_utils.loadScript)(getWorkerSrc()); + await (0, _display_utils.loadScript)(this.workerSrc); return window.pdfjsWorker.WorkerMessageHandler; }; - loader().then(fakeWorkerCapability.resolve, fakeWorkerCapability.reject); - return fakeWorkerCapability.promise; + return (0, _util.shadow)(this, "_setupFakeWorkerGlobal", loader()); } - function createCDNWrapper(url) { - const wrapper = "importScripts('" + url + "');"; - return URL.createObjectURL(new Blob([wrapper])); - } - - class PDFWorker { - constructor({ - name = null, - port = null, - verbosity = (0, _util.getVerbosityLevel)() - } = {}) { - if (port && pdfWorkerPorts.has(port)) { - throw new Error("Cannot use more than one PDFWorker per port"); - } - - this.name = name; - this.destroyed = false; - this.postMessageTransfers = true; - this.verbosity = verbosity; - this._readyCapability = (0, _util.createPromiseCapability)(); - this._port = null; - this._webWorker = null; - this._messageHandler = null; - - if (port) { - pdfWorkerPorts.set(port, this); - - this._initializeFromPort(port); - - return; - } - - this._initialize(); - } - - get promise() { - return this._readyCapability.promise; - } - - get port() { - return this._port; - } - - get messageHandler() { - return this._messageHandler; - } - - _initializeFromPort(port) { - this._port = port; - this._messageHandler = new _message_handler.MessageHandler("main", "worker", port); - - this._messageHandler.on("ready", function () {}); - - this._readyCapability.resolve(); - } - - _initialize() { - if (typeof Worker !== "undefined" && !isWorkerDisabled && !getMainThreadWorkerMessageHandler()) { - let workerSrc = getWorkerSrc(); - - try { - if (!(0, _util.isSameOrigin)(window.location.href, workerSrc)) { - workerSrc = createCDNWrapper(new URL(workerSrc, window.location).href); - } - - const worker = new Worker(workerSrc); - const messageHandler = new _message_handler.MessageHandler("main", "worker", worker); - - const terminateEarly = () => { - worker.removeEventListener("error", onWorkerError); - messageHandler.destroy(); - worker.terminate(); - - if (this.destroyed) { - this._readyCapability.reject(new Error("Worker was destroyed")); - } else { - this._setupFakeWorker(); - } - }; - - const onWorkerError = () => { - if (!this._webWorker) { - terminateEarly(); - } - }; - - worker.addEventListener("error", onWorkerError); - messageHandler.on("test", data => { - worker.removeEventListener("error", onWorkerError); - - if (this.destroyed) { - terminateEarly(); - return; - } - - if (data) { - this._messageHandler = messageHandler; - this._port = worker; - this._webWorker = worker; - - if (!data.supportTransfers) { - this.postMessageTransfers = false; - } - - this._readyCapability.resolve(); - - messageHandler.send("configure", { - verbosity: this.verbosity - }); - } else { - this._setupFakeWorker(); - - messageHandler.destroy(); - worker.terminate(); - } - }); - messageHandler.on("ready", data => { - worker.removeEventListener("error", onWorkerError); - - if (this.destroyed) { - terminateEarly(); - return; - } - - try { - sendTest(); - } catch (e) { - this._setupFakeWorker(); - } - }); - - const sendTest = () => { - const testObj = new Uint8Array([this.postMessageTransfers ? 255 : 0]); - - try { - messageHandler.send("test", testObj, [testObj.buffer]); - } catch (ex) { - (0, _util.warn)("Cannot use postMessage transfers."); - testObj[0] = 0; - messageHandler.send("test", testObj); - } - }; - - sendTest(); - return; - } catch (e) { - (0, _util.info)("The worker has been disabled."); - } - } - - this._setupFakeWorker(); - } - - _setupFakeWorker() { - if (!isWorkerDisabled) { - (0, _util.warn)("Setting up fake worker."); - isWorkerDisabled = true; - } - - setupFakeWorkerGlobal().then(WorkerMessageHandler => { - if (this.destroyed) { - this._readyCapability.reject(new Error("Worker was destroyed")); - - return; - } - - const port = new LoopbackPort(); - this._port = port; - const id = "fake" + nextFakeWorkerId++; - const workerHandler = new _message_handler.MessageHandler(id + "_worker", id, port); - WorkerMessageHandler.setup(workerHandler, port); - const messageHandler = new _message_handler.MessageHandler(id, id + "_worker", port); - this._messageHandler = messageHandler; - - this._readyCapability.resolve(); - - messageHandler.send("configure", { - verbosity: this.verbosity - }); - }).catch(reason => { - this._readyCapability.reject(new Error(`Setting up fake worker failed: "${reason.message}".`)); - }); - } - - destroy() { - this.destroyed = true; - - if (this._webWorker) { - this._webWorker.terminate(); - - this._webWorker = null; - } - - pdfWorkerPorts.delete(this._port); - this._port = null; - - if (this._messageHandler) { - this._messageHandler.destroy(); - - this._messageHandler = null; - } - } - - static fromPort(params) { - if (!params || !params.port) { - throw new Error("PDFWorker.fromPort - invalid method signature."); - } - - if (pdfWorkerPorts.has(params.port)) { - return pdfWorkerPorts.get(params.port); - } - - return new PDFWorker(params); - } - - static getWorkerSrc() { - return getWorkerSrc(); - } - - } - - return PDFWorker; -}(); +} exports.PDFWorker = PDFWorker; +{ + PDFWorker.getWorkerSrc = function () { + (0, _display_utils.deprecated)("`PDFWorker.getWorkerSrc()`, please use `PDFWorker.workerSrc` instead."); + return this.workerSrc; + }; +} class WorkerTransport { + #docStats = null; + #pageCache = new Map(); + #pagePromises = new Map(); + #metadataPromise = null; + constructor(messageHandler, loadingTask, networkStream, params) { this.messageHandler = messageHandler; this.loadingTask = loadingTask; @@ -3140,25 +2606,92 @@ class WorkerTransport { this.fontLoader = new _font_loader.FontLoader({ docId: loadingTask.docId, onUnsupportedFeature: this._onUnsupportedFeature.bind(this), - ownerDocument: params.ownerDocument + ownerDocument: params.ownerDocument, + styleElement: params.styleElement }); this._params = params; - this.CMapReaderFactory = new params.CMapReaderFactory({ - baseUrl: params.cMapUrl, - isCompressed: params.cMapPacked - }); + + if (!params.useWorkerFetch) { + this.CMapReaderFactory = new params.CMapReaderFactory({ + baseUrl: params.cMapUrl, + isCompressed: params.cMapPacked + }); + this.StandardFontDataFactory = new params.StandardFontDataFactory({ + baseUrl: params.standardFontDataUrl + }); + } + this.destroyed = false; this.destroyCapability = null; this._passwordCapability = null; this._networkStream = networkStream; this._fullReader = null; this._lastProgress = null; - this.pageCache = []; - this.pagePromises = []; this.downloadInfoCapability = (0, _util.createPromiseCapability)(); this.setupMessageHandler(); } + get annotationStorage() { + return (0, _util.shadow)(this, "annotationStorage", new _annotation_storage.AnnotationStorage()); + } + + get stats() { + return this.#docStats; + } + + getRenderingIntent(intent, annotationMode = _util.AnnotationMode.ENABLE, printAnnotationStorage = null, isOpList = false) { + let renderingIntent = _util.RenderingIntentFlag.DISPLAY; + let annotationMap = null; + + switch (intent) { + case "any": + renderingIntent = _util.RenderingIntentFlag.ANY; + break; + + case "display": + break; + + case "print": + renderingIntent = _util.RenderingIntentFlag.PRINT; + break; + + default: + (0, _util.warn)(`getRenderingIntent - invalid intent: ${intent}`); + } + + switch (annotationMode) { + case _util.AnnotationMode.DISABLE: + renderingIntent += _util.RenderingIntentFlag.ANNOTATIONS_DISABLE; + break; + + case _util.AnnotationMode.ENABLE: + break; + + case _util.AnnotationMode.ENABLE_FORMS: + renderingIntent += _util.RenderingIntentFlag.ANNOTATIONS_FORMS; + break; + + case _util.AnnotationMode.ENABLE_STORAGE: + renderingIntent += _util.RenderingIntentFlag.ANNOTATIONS_STORAGE; + const annotationStorage = renderingIntent & _util.RenderingIntentFlag.PRINT && printAnnotationStorage instanceof _annotation_storage.PrintAnnotationStorage ? printAnnotationStorage : this.annotationStorage; + annotationMap = annotationStorage.serializable; + break; + + default: + (0, _util.warn)(`getRenderingIntent - invalid annotationMode: ${annotationMode}`); + } + + if (isOpList) { + renderingIntent += _util.RenderingIntentFlag.OPLIST; + } + + return { + renderingIntent, + cacheKey: `${renderingIntent}_${_annotation_storage.AnnotationStorage.getHash(annotationMap)}`, + annotationStorageMap: annotationMap + }; + } + destroy() { if (this.destroyCapability) { return this.destroyCapability.promise; @@ -3172,17 +2705,26 @@ class WorkerTransport { } const waitOn = []; - this.pageCache.forEach(function (page) { - if (page) { - waitOn.push(page._destroy()); - } - }); - this.pageCache.length = 0; - this.pagePromises.length = 0; + + for (const page of this.#pageCache.values()) { + waitOn.push(page._destroy()); + } + + this.#pageCache.clear(); + this.#pagePromises.clear(); + + if (this.hasOwnProperty("annotationStorage")) { + this.annotationStorage.resetModified(); + } + const terminated = this.messageHandler.sendWithPromise("Terminate", null); waitOn.push(terminated); Promise.all(waitOn).then(() => { + this.commonObjs.clear(); this.fontLoader.clear(); + this.#metadataPromise = null; + this._getFieldObjectsPromise = null; + this._hasJSActionsPromise = null; if (this._networkStream) { this._networkStream.cancelAllRequests(new _util.AbortException("Worker was terminated.")); @@ -3248,17 +2790,15 @@ class WorkerTransport { const fullReader = this._fullReader; fullReader.headersReady.then(() => { if (!fullReader.isStreamingSupported || !fullReader.isRangeSupported) { - if (this._lastProgress && loadingTask.onProgress) { - loadingTask.onProgress(this._lastProgress); + if (this._lastProgress) { + loadingTask.onProgress?.(this._lastProgress); } fullReader.onProgress = evt => { - if (loadingTask.onProgress) { - loadingTask.onProgress({ - loaded: evt.loaded, - total: evt.total - }); - } + loadingTask.onProgress?.({ + loaded: evt.loaded, + total: evt.total + }); }; } @@ -3312,6 +2852,8 @@ class WorkerTransport { pdfInfo }) => { this._numPages = pdfInfo.numPages; + this._htmlForXfa = pdfInfo.htmlForXfa; + delete pdfInfo.htmlForXfa; loadingTask._capability.resolve(new PDFDocumentProxy(pdfInfo, this)); }); @@ -3338,11 +2880,9 @@ class WorkerTransport { case "UnknownErrorException": reason = new _util.UnknownErrorException(ex.message, ex.details); break; - } - if (!(reason instanceof Error)) { - const msg = "DocException - expected a valid Error."; - (0, _util.warn)(msg); + default: + (0, _util.unreachable)("DocException - expected a valid Error."); } loadingTask._capability.reject(reason); @@ -3352,9 +2892,13 @@ class WorkerTransport { if (loadingTask.onPassword) { const updatePassword = password => { - this._passwordCapability.resolve({ - password - }); + if (password instanceof Error) { + this._passwordCapability.reject(password); + } else { + this._passwordCapability.resolve({ + password + }); + } }; try { @@ -3369,13 +2913,10 @@ class WorkerTransport { return this._passwordCapability.promise; }); messageHandler.on("DataLoaded", data => { - if (loadingTask.onProgress) { - loadingTask.onProgress({ - loaded: data.length, - total: data.length - }); - } - + loadingTask.onProgress?.({ + loaded: data.length, + total: data.length + }); this.downloadInfoCapability.resolve(data); }); messageHandler.on("StartRenderPage", data => { @@ -3383,17 +2924,15 @@ class WorkerTransport { return; } - const page = this.pageCache[data.pageIndex]; + const page = this.#pageCache.get(data.pageIndex); - page._startRenderPage(data.transparency, data.intent); + page._startRenderPage(data.transparency, data.cacheKey); }); - messageHandler.on("commonobj", data => { + messageHandler.on("commonobj", ([id, type, exportedData]) => { if (this.destroyed) { return; } - const [id, type, exportedData] = data; - if (this.commonObjs.has(id)) { return; } @@ -3411,7 +2950,7 @@ class WorkerTransport { let fontRegistry = null; - if (params.pdfBug && globalThis.FontInspector && globalThis.FontInspector.enabled) { + if (params.pdfBug && globalThis.FontInspector?.enabled) { fontRegistry = { registerFont(font, url) { globalThis.FontInspector.fontAdded(font, url); @@ -3449,16 +2988,15 @@ class WorkerTransport { throw new Error(`Got unknown common object type ${type}`); } }); - messageHandler.on("obj", data => { + messageHandler.on("obj", ([id, pageIndex, type, imageData]) => { if (this.destroyed) { - return undefined; + return; } - const [id, pageIndex, type, imageData] = data; - const pageProxy = this.pageCache[pageIndex]; + const pageProxy = this.#pageCache.get(pageIndex); if (pageProxy.objs.has(id)) { - return undefined; + return; } switch (type) { @@ -3466,52 +3004,79 @@ class WorkerTransport { pageProxy.objs.resolve(id, imageData); const MAX_IMAGE_SIZE_TO_STORE = 8000000; - if (imageData && "data" in imageData && imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) { - pageProxy.cleanupAfterRender = true; + if (imageData) { + let length; + + if (imageData.bitmap) { + const { + bitmap, + width, + height + } = imageData; + length = width * height * 4; + + pageProxy._bitmaps.add(bitmap); + } else { + length = imageData.data?.length || 0; + } + + if (length > MAX_IMAGE_SIZE_TO_STORE) { + pageProxy.cleanupAfterRender = true; + } } break; + case "Pattern": + pageProxy.objs.resolve(id, imageData); + break; + default: throw new Error(`Got unknown object type ${type}`); } - - return undefined; }); messageHandler.on("DocProgress", data => { if (this.destroyed) { return; } - if (loadingTask.onProgress) { - loadingTask.onProgress({ - loaded: data.loaded, - total: data.total - }); - } + loadingTask.onProgress?.({ + loaded: data.loaded, + total: data.total + }); }); - messageHandler.on("UnsupportedFeature", this._onUnsupportedFeature.bind(this)); - messageHandler.on("FetchBuiltInCMap", (data, sink) => { + messageHandler.on("DocStats", data => { if (this.destroyed) { - sink.error(new Error("Worker was destroyed")); return; } - let fetched = false; + this.#docStats = Object.freeze({ + streamTypes: Object.freeze(data.streamTypes), + fontTypes: Object.freeze(data.fontTypes) + }); + }); + messageHandler.on("UnsupportedFeature", this._onUnsupportedFeature.bind(this)); + messageHandler.on("FetchBuiltInCMap", data => { + if (this.destroyed) { + return Promise.reject(new Error("Worker was destroyed.")); + } - sink.onPull = () => { - if (fetched) { - sink.close(); - return; - } + if (!this.CMapReaderFactory) { + return Promise.reject(new Error("CMapReaderFactory not initialized, see the `useWorkerFetch` parameter.")); + } - fetched = true; - this.CMapReaderFactory.fetch(data).then(function (builtInCMap) { - sink.enqueue(builtInCMap, 1, [builtInCMap.cMapData.buffer]); - }).catch(function (reason) { - sink.error(reason); - }); - }; + return this.CMapReaderFactory.fetch(data); + }); + messageHandler.on("FetchStandardFontData", data => { + if (this.destroyed) { + return Promise.reject(new Error("Worker was destroyed.")); + } + + if (!this.StandardFontDataFactory) { + return Promise.reject(new Error("StandardFontDataFactory not initialized, see the `useWorkerFetch` parameter.")); + } + + return this.StandardFontDataFactory.fetch(data); }); } @@ -3522,9 +3087,7 @@ class WorkerTransport { return; } - if (this.loadingTask.onUnsupportedFeature) { - this.loadingTask.onUnsupportedFeature(featureId); - } + this.loadingTask.onUnsupportedFeature?.(featureId); } getData() { @@ -3533,13 +3096,14 @@ class WorkerTransport { getPage(pageNumber) { if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this._numPages) { - return Promise.reject(new Error("Invalid page request")); + return Promise.reject(new Error("Invalid page request.")); } - const pageIndex = pageNumber - 1; + const pageIndex = pageNumber - 1, + cachedPromise = this.#pagePromises.get(pageIndex); - if (pageIndex in this.pagePromises) { - return this.pagePromises[pageIndex]; + if (cachedPromise) { + return cachedPromise; } const promise = this.messageHandler.sendWithPromise("GetPage", { @@ -3550,18 +3114,21 @@ class WorkerTransport { } const page = new PDFPageProxy(pageIndex, pageInfo, this, this._params.ownerDocument, this._params.pdfBug); - this.pageCache[pageIndex] = page; + this.#pageCache.set(pageIndex, page); return page; }); - this.pagePromises[pageIndex] = promise; + this.#pagePromises.set(pageIndex, promise); return promise; } getPageIndex(ref) { + if (typeof ref !== "object" || ref === null || !Number.isInteger(ref.num) || ref.num < 0 || !Number.isInteger(ref.gen) || ref.gen < 0) { + return Promise.reject(new Error("Invalid pageIndex request.")); + } + return this.messageHandler.sendWithPromise("GetPageIndex", { - ref - }).catch(function (reason) { - return Promise.reject(new Error(reason)); + num: ref.num, + gen: ref.gen }); } @@ -3572,18 +3139,29 @@ class WorkerTransport { }); } - saveDocument(annotationStorage) { + saveDocument() { return this.messageHandler.sendWithPromise("SaveDocument", { + isPureXfa: !!this._htmlForXfa, numPages: this._numPages, - annotationStorage: annotationStorage && annotationStorage.getAll() || null, - filename: this._fullReader ? this._fullReader.filename : null + annotationStorage: this.annotationStorage.serializable, + filename: this._fullReader?.filename ?? null }).finally(() => { - if (annotationStorage) { - annotationStorage.resetModified(); - } + this.annotationStorage.resetModified(); }); } + getFieldObjects() { + return this._getFieldObjectsPromise ||= this.messageHandler.sendWithPromise("GetFieldObjects", null); + } + + hasJSActions() { + return this._hasJSActionsPromise ||= this.messageHandler.sendWithPromise("HasJSActions", null); + } + + getCalculationOrderIds() { + return this.messageHandler.sendWithPromise("GetCalculationOrderIds", null); + } + getDestinations() { return this.messageHandler.sendWithPromise("GetDestinations", null); } @@ -3626,6 +3204,22 @@ class WorkerTransport { return this.messageHandler.sendWithPromise("GetJavaScript", null); } + getDocJSActions() { + return this.messageHandler.sendWithPromise("GetDocJSActions", null); + } + + getPageJSActions(pageIndex) { + return this.messageHandler.sendWithPromise("GetPageJSActions", { + pageIndex + }); + } + + getStructTree(pageIndex) { + return this.messageHandler.sendWithPromise("GetStructTree", { + pageIndex + }); + } + getOutline() { return this.messageHandler.sendWithPromise("GetOutline", null); } @@ -3641,75 +3235,82 @@ class WorkerTransport { } getMetadata() { - return this.messageHandler.sendWithPromise("GetMetadata", null).then(results => { + return this.#metadataPromise ||= this.messageHandler.sendWithPromise("GetMetadata", null).then(results => { return { info: results[0], metadata: results[1] ? new _metadata.Metadata(results[1]) : null, - contentDispositionFilename: this._fullReader ? this._fullReader.filename : null + contentDispositionFilename: this._fullReader?.filename ?? null, + contentLength: this._fullReader?.contentLength ?? null }; }); } - getStats() { - return this.messageHandler.sendWithPromise("GetStats", null); + getMarkInfo() { + return this.messageHandler.sendWithPromise("GetMarkInfo", null); } - startCleanup() { - return this.messageHandler.sendWithPromise("Cleanup", null).then(() => { - for (let i = 0, ii = this.pageCache.length; i < ii; i++) { - const page = this.pageCache[i]; + async startCleanup(keepLoadedFonts = false) { + await this.messageHandler.sendWithPromise("Cleanup", null); - if (page) { - const cleanupSuccessful = page.cleanup(); + if (this.destroyed) { + return; + } - if (!cleanupSuccessful) { - throw new Error(`startCleanup: Page ${i + 1} is currently rendering.`); - } - } + for (const page of this.#pageCache.values()) { + const cleanupSuccessful = page.cleanup(); + + if (!cleanupSuccessful) { + throw new Error(`startCleanup: Page ${page.pageNumber} is currently rendering.`); } + } - this.commonObjs.clear(); + this.commonObjs.clear(); + + if (!keepLoadedFonts) { this.fontLoader.clear(); - }); + } + + this.#metadataPromise = null; + this._getFieldObjectsPromise = null; + this._hasJSActionsPromise = null; } get loadingParams() { const params = this._params; return (0, _util.shadow)(this, "loadingParams", { disableAutoFetch: params.disableAutoFetch, - disableFontFace: params.disableFontFace + enableXfa: params.enableXfa }); } } class PDFObjects { - constructor() { - this._objs = Object.create(null); - } + #objs = Object.create(null); - _ensureObj(objId) { - if (this._objs[objId]) { - return this._objs[objId]; + #ensureObj(objId) { + const obj = this.#objs[objId]; + + if (obj) { + return obj; } - return this._objs[objId] = { + return this.#objs[objId] = { capability: (0, _util.createPromiseCapability)(), - data: null, - resolved: false + data: null }; } get(objId, callback = null) { if (callback) { - this._ensureObj(objId).capability.promise.then(callback); - + const obj = this.#ensureObj(objId); + obj.capability.promise.then(() => callback(obj.data)); return null; } - const obj = this._objs[objId]; + const obj = this.#objs[objId]; - if (!obj || !obj.resolved) { + if (!obj?.capability.settled) { throw new Error(`Requesting object that isn't resolved yet ${objId}.`); } @@ -3717,237 +3318,2375 @@ class PDFObjects { } has(objId) { - const obj = this._objs[objId]; - return obj ? obj.resolved : false; + const obj = this.#objs[objId]; + return obj?.capability.settled || false; } - resolve(objId, data) { - const obj = this._ensureObj(objId); - - obj.resolved = true; + resolve(objId, data = null) { + const obj = this.#ensureObj(objId); obj.data = data; - obj.capability.resolve(data); + obj.capability.resolve(); } clear() { - this._objs = Object.create(null); + this.#objs = Object.create(null); } } class RenderTask { + #internalRenderTask = null; + constructor(internalRenderTask) { - this._internalRenderTask = internalRenderTask; + this.#internalRenderTask = internalRenderTask; this.onContinue = null; } get promise() { - return this._internalRenderTask.capability.promise; + return this.#internalRenderTask.capability.promise; } cancel() { - this._internalRenderTask.cancel(); + this.#internalRenderTask.cancel(); + } + + get separateAnnots() { + const { + separateAnnots + } = this.#internalRenderTask.operatorList; + + if (!separateAnnots) { + return false; + } + + const { + annotationCanvasMap + } = this.#internalRenderTask; + return separateAnnots.form || separateAnnots.canvas && annotationCanvasMap?.size > 0; } } -const InternalRenderTask = function InternalRenderTaskClosure() { - const canvasInRendering = new WeakSet(); +exports.RenderTask = RenderTask; - class InternalRenderTask { - constructor({ - callback, - params, - objs, - commonObjs, - operatorList, - pageIndex, - canvasFactory, - webGLContext, - useRequestAnimationFrame = false, - pdfBug = false - }) { - this.callback = callback; - this.params = params; - this.objs = objs; - this.commonObjs = commonObjs; - this.operatorListIdx = null; - this.operatorList = operatorList; - this._pageIndex = pageIndex; - this.canvasFactory = canvasFactory; - this.webGLContext = webGLContext; - this._pdfBug = pdfBug; - this.running = false; - this.graphicsReadyCallback = null; - this.graphicsReady = false; - this._useRequestAnimationFrame = useRequestAnimationFrame === true && typeof window !== "undefined"; - this.cancelled = false; - this.capability = (0, _util.createPromiseCapability)(); - this.task = new RenderTask(this); - this._continueBound = this._continue.bind(this); - this._scheduleNextBound = this._scheduleNext.bind(this); - this._nextBound = this._next.bind(this); - this._canvas = params.canvasContext.canvas; - } - - get completed() { - return this.capability.promise.catch(function () {}); - } - - initializeGraphics({ - transparency = false, - optionalContentConfig - }) { - if (this.cancelled) { - return; - } - - if (this._canvas) { - if (canvasInRendering.has(this._canvas)) { - throw new Error("Cannot use the same canvas during multiple render() operations. " + "Use different canvas or ensure previous operations were " + "cancelled or completed."); - } - - canvasInRendering.add(this._canvas); - } - - if (this._pdfBug && globalThis.StepperManager && globalThis.StepperManager.enabled) { - this.stepper = globalThis.StepperManager.create(this._pageIndex); - this.stepper.init(this.operatorList); - this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint(); - } - - const { - canvasContext, - viewport, - transform, - imageLayer, - background - } = this.params; - this.gfx = new _canvas.CanvasGraphics(canvasContext, this.commonObjs, this.objs, this.canvasFactory, this.webGLContext, imageLayer, optionalContentConfig); - this.gfx.beginDrawing({ - transform, - viewport, - transparency, - background - }); - this.operatorListIdx = 0; - this.graphicsReady = true; - - if (this.graphicsReadyCallback) { - this.graphicsReadyCallback(); - } - } - - cancel(error = null) { - this.running = false; - this.cancelled = true; - - if (this.gfx) { - this.gfx.endDrawing(); - } - - if (this._canvas) { - canvasInRendering.delete(this._canvas); - } - - this.callback(error || new _display_utils.RenderingCancelledException(`Rendering cancelled, page ${this._pageIndex + 1}`, "canvas")); - } - - operatorListChanged() { - if (!this.graphicsReady) { - if (!this.graphicsReadyCallback) { - this.graphicsReadyCallback = this._continueBound; - } - - return; - } - - if (this.stepper) { - this.stepper.updateOperatorList(this.operatorList); - } - - if (this.running) { - return; - } - - this._continue(); - } - - _continue() { - this.running = true; - - if (this.cancelled) { - return; - } - - if (this.task.onContinue) { - this.task.onContinue(this._scheduleNextBound); - } else { - this._scheduleNext(); - } - } - - _scheduleNext() { - if (this._useRequestAnimationFrame) { - window.requestAnimationFrame(() => { - this._nextBound().catch(this.cancel.bind(this)); - }); - } else { - Promise.resolve().then(this._nextBound).catch(this.cancel.bind(this)); - } - } - - async _next() { - if (this.cancelled) { - return; - } - - this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList, this.operatorListIdx, this._continueBound, this.stepper); - - if (this.operatorListIdx === this.operatorList.argsArray.length) { - this.running = false; - - if (this.operatorList.lastChunk) { - this.gfx.endDrawing(); - - if (this._canvas) { - canvasInRendering.delete(this._canvas); - } - - this.callback(); - } - } - } +class InternalRenderTask { + static #canvasInUse = new WeakSet(); + constructor({ + callback, + params, + objs, + commonObjs, + annotationCanvasMap, + operatorList, + pageIndex, + canvasFactory, + useRequestAnimationFrame = false, + pdfBug = false, + pageColors = null + }) { + this.callback = callback; + this.params = params; + this.objs = objs; + this.commonObjs = commonObjs; + this.annotationCanvasMap = annotationCanvasMap; + this.operatorListIdx = null; + this.operatorList = operatorList; + this._pageIndex = pageIndex; + this.canvasFactory = canvasFactory; + this._pdfBug = pdfBug; + this.pageColors = pageColors; + this.running = false; + this.graphicsReadyCallback = null; + this.graphicsReady = false; + this._useRequestAnimationFrame = useRequestAnimationFrame === true && typeof window !== "undefined"; + this.cancelled = false; + this.capability = (0, _util.createPromiseCapability)(); + this.task = new RenderTask(this); + this._cancelBound = this.cancel.bind(this); + this._continueBound = this._continue.bind(this); + this._scheduleNextBound = this._scheduleNext.bind(this); + this._nextBound = this._next.bind(this); + this._canvas = params.canvasContext.canvas; } - return InternalRenderTask; -}(); + get completed() { + return this.capability.promise.catch(function () {}); + } -const version = '2.6.347'; + initializeGraphics({ + transparency = false, + optionalContentConfig + }) { + if (this.cancelled) { + return; + } + + if (this._canvas) { + if (InternalRenderTask.#canvasInUse.has(this._canvas)) { + throw new Error("Cannot use the same canvas during multiple render() operations. " + "Use different canvas or ensure previous operations were " + "cancelled or completed."); + } + + InternalRenderTask.#canvasInUse.add(this._canvas); + } + + if (this._pdfBug && globalThis.StepperManager?.enabled) { + this.stepper = globalThis.StepperManager.create(this._pageIndex); + this.stepper.init(this.operatorList); + this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint(); + } + + const { + canvasContext, + viewport, + transform, + imageLayer, + background + } = this.params; + this.gfx = new _canvas.CanvasGraphics(canvasContext, this.commonObjs, this.objs, this.canvasFactory, imageLayer, optionalContentConfig, this.annotationCanvasMap, this.pageColors); + this.gfx.beginDrawing({ + transform, + viewport, + transparency, + background + }); + this.operatorListIdx = 0; + this.graphicsReady = true; + + if (this.graphicsReadyCallback) { + this.graphicsReadyCallback(); + } + } + + cancel(error = null) { + this.running = false; + this.cancelled = true; + + if (this.gfx) { + this.gfx.endDrawing(); + } + + if (this._canvas) { + InternalRenderTask.#canvasInUse.delete(this._canvas); + } + + this.callback(error || new _display_utils.RenderingCancelledException(`Rendering cancelled, page ${this._pageIndex + 1}`, "canvas")); + } + + operatorListChanged() { + if (!this.graphicsReady) { + if (!this.graphicsReadyCallback) { + this.graphicsReadyCallback = this._continueBound; + } + + return; + } + + if (this.stepper) { + this.stepper.updateOperatorList(this.operatorList); + } + + if (this.running) { + return; + } + + this._continue(); + } + + _continue() { + this.running = true; + + if (this.cancelled) { + return; + } + + if (this.task.onContinue) { + this.task.onContinue(this._scheduleNextBound); + } else { + this._scheduleNext(); + } + } + + _scheduleNext() { + if (this._useRequestAnimationFrame) { + window.requestAnimationFrame(() => { + this._nextBound().catch(this._cancelBound); + }); + } else { + Promise.resolve().then(this._nextBound).catch(this._cancelBound); + } + } + + async _next() { + if (this.cancelled) { + return; + } + + this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList, this.operatorListIdx, this._continueBound, this.stepper); + + if (this.operatorListIdx === this.operatorList.argsArray.length) { + this.running = false; + + if (this.operatorList.lastChunk) { + this.gfx.endDrawing(); + + if (this._canvas) { + InternalRenderTask.#canvasInUse.delete(this._canvas); + } + + this.callback(); + } + } + } + +} + +const version = '2.16.105'; exports.version = version; -const build = '3be9c65f'; +const build = '172ccdbe5'; exports.build = build; /***/ }), -/* 6 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 5 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.PrintAnnotationStorage = exports.AnnotationStorage = void 0; + +var _util = __w_pdfjs_require__(1); + +var _editor = __w_pdfjs_require__(6); + +var _murmurhash = __w_pdfjs_require__(10); + +class AnnotationStorage { + constructor() { + this._storage = new Map(); + this._modified = false; + this.onSetModified = null; + this.onResetModified = null; + this.onAnnotationEditor = null; + } + + getValue(key, defaultValue) { + const value = this._storage.get(key); + + if (value === undefined) { + return defaultValue; + } + + return Object.assign(defaultValue, value); + } + + getRawValue(key) { + return this._storage.get(key); + } + + remove(key) { + this._storage.delete(key); + + if (this._storage.size === 0) { + this.resetModified(); + } + + if (typeof this.onAnnotationEditor === "function") { + for (const value of this._storage.values()) { + if (value instanceof _editor.AnnotationEditor) { + return; + } + } + + this.onAnnotationEditor(null); + } + } + + setValue(key, value) { + const obj = this._storage.get(key); + + let modified = false; + + if (obj !== undefined) { + for (const [entry, val] of Object.entries(value)) { + if (obj[entry] !== val) { + modified = true; + obj[entry] = val; + } + } + } else { + modified = true; + + this._storage.set(key, value); + } + + if (modified) { + this.#setModified(); + } + + if (value instanceof _editor.AnnotationEditor && typeof this.onAnnotationEditor === "function") { + this.onAnnotationEditor(value.constructor._type); + } + } + + has(key) { + return this._storage.has(key); + } + + getAll() { + return this._storage.size > 0 ? (0, _util.objectFromMap)(this._storage) : null; + } + + get size() { + return this._storage.size; + } + + #setModified() { + if (!this._modified) { + this._modified = true; + + if (typeof this.onSetModified === "function") { + this.onSetModified(); + } + } + } + + resetModified() { + if (this._modified) { + this._modified = false; + + if (typeof this.onResetModified === "function") { + this.onResetModified(); + } + } + } + + get print() { + return new PrintAnnotationStorage(this); + } + + get serializable() { + if (this._storage.size === 0) { + return null; + } + + const clone = new Map(); + + for (const [key, val] of this._storage) { + const serialized = val instanceof _editor.AnnotationEditor ? val.serialize() : val; + + if (serialized) { + clone.set(key, serialized); + } + } + + return clone; + } + + static getHash(map) { + if (!map) { + return ""; + } + + const hash = new _murmurhash.MurmurHash3_64(); + + for (const [key, val] of map) { + hash.update(`${key}:${JSON.stringify(val)}`); + } + + return hash.hexdigest(); + } + +} + +exports.AnnotationStorage = AnnotationStorage; + +class PrintAnnotationStorage extends AnnotationStorage { + #serializable = null; + + constructor(parent) { + super(); + this.#serializable = structuredClone(parent.serializable); + } + + get print() { + (0, _util.unreachable)("Should not call PrintAnnotationStorage.print"); + } + + get serializable() { + return this.#serializable; + } + +} + +exports.PrintAnnotationStorage = PrintAnnotationStorage; + +/***/ }), +/* 6 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.AnnotationEditor = void 0; + +var _tools = __w_pdfjs_require__(7); + +var _util = __w_pdfjs_require__(1); + +class AnnotationEditor { + #boundFocusin = this.focusin.bind(this); + #boundFocusout = this.focusout.bind(this); + #hasBeenSelected = false; + #isEditing = false; + #isInEditMode = false; + #zIndex = AnnotationEditor._zIndex++; + static _colorManager = new _tools.ColorManager(); + static _zIndex = 1; + + constructor(parameters) { + if (this.constructor === AnnotationEditor) { + (0, _util.unreachable)("Cannot initialize AnnotationEditor."); + } + + this.parent = parameters.parent; + this.id = parameters.id; + this.width = this.height = null; + this.pageIndex = parameters.parent.pageIndex; + this.name = parameters.name; + this.div = null; + const [width, height] = this.parent.viewportBaseDimensions; + this.x = parameters.x / width; + this.y = parameters.y / height; + this.rotation = this.parent.viewport.rotation; + this.isAttachedToDOM = false; + } + + static get _defaultLineColor() { + return (0, _util.shadow)(this, "_defaultLineColor", this._colorManager.getHexCode("CanvasText")); + } + + setInBackground() { + this.div.style.zIndex = 0; + } + + setInForeground() { + this.div.style.zIndex = this.#zIndex; + } + + focusin(event) { + if (!this.#hasBeenSelected) { + this.parent.setSelected(this); + } else { + this.#hasBeenSelected = false; + } + } + + focusout(event) { + if (!this.isAttachedToDOM) { + return; + } + + const target = event.relatedTarget; + + if (target?.closest(`#${this.id}`)) { + return; + } + + event.preventDefault(); + + if (!this.parent.isMultipleSelection) { + this.commitOrRemove(); + } + } + + commitOrRemove() { + if (this.isEmpty()) { + this.remove(); + } else { + this.commit(); + } + } + + commit() { + this.parent.addToAnnotationStorage(this); + } + + dragstart(event) { + const rect = this.parent.div.getBoundingClientRect(); + this.startX = event.clientX - rect.x; + this.startY = event.clientY - rect.y; + event.dataTransfer.setData("text/plain", this.id); + event.dataTransfer.effectAllowed = "move"; + } + + setAt(x, y, tx, ty) { + const [width, height] = this.parent.viewportBaseDimensions; + [tx, ty] = this.screenToPageTranslation(tx, ty); + this.x = (x + tx) / width; + this.y = (y + ty) / height; + this.div.style.left = `${100 * this.x}%`; + this.div.style.top = `${100 * this.y}%`; + } + + translate(x, y) { + const [width, height] = this.parent.viewportBaseDimensions; + [x, y] = this.screenToPageTranslation(x, y); + this.x += x / width; + this.y += y / height; + this.div.style.left = `${100 * this.x}%`; + this.div.style.top = `${100 * this.y}%`; + } + + screenToPageTranslation(x, y) { + const { + rotation + } = this.parent.viewport; + + switch (rotation) { + case 90: + return [y, -x]; + + case 180: + return [-x, -y]; + + case 270: + return [-y, x]; + + default: + return [x, y]; + } + } + + setDims(width, height) { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.div.style.width = `${100 * width / parentWidth}%`; + this.div.style.height = `${100 * height / parentHeight}%`; + } + + getInitialTranslation() { + return [0, 0]; + } + + render() { + this.div = document.createElement("div"); + this.div.setAttribute("data-editor-rotation", (360 - this.rotation) % 360); + this.div.className = this.name; + this.div.setAttribute("id", this.id); + this.div.setAttribute("tabIndex", 0); + this.setInForeground(); + this.div.addEventListener("focusin", this.#boundFocusin); + this.div.addEventListener("focusout", this.#boundFocusout); + const [tx, ty] = this.getInitialTranslation(); + this.translate(tx, ty); + (0, _tools.bindEvents)(this, this.div, ["dragstart", "pointerdown"]); + return this.div; + } + + pointerdown(event) { + const isMac = _tools.KeyboardManager.platform.isMac; + + if (event.button !== 0 || event.ctrlKey && isMac) { + event.preventDefault(); + return; + } + + if (event.ctrlKey && !isMac || event.shiftKey || event.metaKey && isMac) { + this.parent.toggleSelected(this); + } else { + this.parent.setSelected(this); + } + + this.#hasBeenSelected = true; + } + + getRect(tx, ty) { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + const [pageWidth, pageHeight] = this.parent.pageDimensions; + const shiftX = pageWidth * tx / parentWidth; + const shiftY = pageHeight * ty / parentHeight; + const x = this.x * pageWidth; + const y = this.y * pageHeight; + const width = this.width * pageWidth; + const height = this.height * pageHeight; + + switch (this.rotation) { + case 0: + return [x + shiftX, pageHeight - y - shiftY - height, x + shiftX + width, pageHeight - y - shiftY]; + + case 90: + return [x + shiftY, pageHeight - y + shiftX, x + shiftY + height, pageHeight - y + shiftX + width]; + + case 180: + return [x - shiftX - width, pageHeight - y + shiftY, x - shiftX, pageHeight - y + shiftY + height]; + + case 270: + return [x - shiftY - height, pageHeight - y - shiftX - width, x - shiftY, pageHeight - y - shiftX]; + + default: + throw new Error("Invalid rotation"); + } + } + + getRectInCurrentCoords(rect, pageHeight) { + const [x1, y1, x2, y2] = rect; + const width = x2 - x1; + const height = y2 - y1; + + switch (this.rotation) { + case 0: + return [x1, pageHeight - y2, width, height]; + + case 90: + return [x1, pageHeight - y1, height, width]; + + case 180: + return [x2, pageHeight - y1, width, height]; + + case 270: + return [x2, pageHeight - y2, height, width]; + + default: + throw new Error("Invalid rotation"); + } + } + + onceAdded() {} + + isEmpty() { + return false; + } + + enableEditMode() { + this.#isInEditMode = true; + } + + disableEditMode() { + this.#isInEditMode = false; + } + + isInEditMode() { + return this.#isInEditMode; + } + + shouldGetKeyboardEvents() { + return false; + } + + needsToBeRebuilt() { + return this.div && !this.isAttachedToDOM; + } + + rebuild() { + this.div?.addEventListener("focusin", this.#boundFocusin); + } + + serialize() { + (0, _util.unreachable)("An editor must be serializable"); + } + + static deserialize(data, parent) { + const editor = new this.prototype.constructor({ + parent, + id: parent.getNextId() + }); + editor.rotation = data.rotation; + const [pageWidth, pageHeight] = parent.pageDimensions; + const [x, y, width, height] = editor.getRectInCurrentCoords(data.rect, pageHeight); + editor.x = x / pageWidth; + editor.y = y / pageHeight; + editor.width = width / pageWidth; + editor.height = height / pageHeight; + return editor; + } + + remove() { + this.div.removeEventListener("focusin", this.#boundFocusin); + this.div.removeEventListener("focusout", this.#boundFocusout); + + if (!this.isEmpty()) { + this.commit(); + } + + this.parent.remove(this); + } + + select() { + this.div?.classList.add("selectedEditor"); + } + + unselect() { + this.div?.classList.remove("selectedEditor"); + } + + updateParams(type, value) {} + + disableEditing() {} + + enableEditing() {} + + get propertiesToUpdate() { + return {}; + } + + get contentDiv() { + return this.div; + } + + get isEditing() { + return this.#isEditing; + } + + set isEditing(value) { + this.#isEditing = value; + + if (value) { + this.parent.setSelected(this); + this.parent.setActiveEditor(this); + } else { + this.parent.setActiveEditor(null); + } + } + +} + +exports.AnnotationEditor = AnnotationEditor; + +/***/ }), +/* 7 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.KeyboardManager = exports.CommandManager = exports.ColorManager = exports.AnnotationEditorUIManager = void 0; +exports.bindEvents = bindEvents; +exports.opacityToHex = opacityToHex; + +var _util = __w_pdfjs_require__(1); + +var _display_utils = __w_pdfjs_require__(8); + +function bindEvents(obj, element, names) { + for (const name of names) { + element.addEventListener(name, obj[name].bind(obj)); + } +} + +function opacityToHex(opacity) { + return Math.round(Math.min(255, Math.max(1, 255 * opacity))).toString(16).padStart(2, "0"); +} + +class IdManager { + #id = 0; + + getId() { + return `${_util.AnnotationEditorPrefix}${this.#id++}`; + } + +} + +class CommandManager { + #commands = []; + #locked = false; + #maxSize; + #position = -1; + + constructor(maxSize = 128) { + this.#maxSize = maxSize; + } + + add({ + cmd, + undo, + mustExec, + type = NaN, + overwriteIfSameType = false, + keepUndo = false + }) { + if (mustExec) { + cmd(); + } + + if (this.#locked) { + return; + } + + const save = { + cmd, + undo, + type + }; + + if (this.#position === -1) { + if (this.#commands.length > 0) { + this.#commands.length = 0; + } + + this.#position = 0; + this.#commands.push(save); + return; + } + + if (overwriteIfSameType && this.#commands[this.#position].type === type) { + if (keepUndo) { + save.undo = this.#commands[this.#position].undo; + } + + this.#commands[this.#position] = save; + return; + } + + const next = this.#position + 1; + + if (next === this.#maxSize) { + this.#commands.splice(0, 1); + } else { + this.#position = next; + + if (next < this.#commands.length) { + this.#commands.splice(next); + } + } + + this.#commands.push(save); + } + + undo() { + if (this.#position === -1) { + return; + } + + this.#locked = true; + this.#commands[this.#position].undo(); + this.#locked = false; + this.#position -= 1; + } + + redo() { + if (this.#position < this.#commands.length - 1) { + this.#position += 1; + this.#locked = true; + this.#commands[this.#position].cmd(); + this.#locked = false; + } + } + + hasSomethingToUndo() { + return this.#position !== -1; + } + + hasSomethingToRedo() { + return this.#position < this.#commands.length - 1; + } + + destroy() { + this.#commands = null; + } + +} + +exports.CommandManager = CommandManager; + +class KeyboardManager { + constructor(callbacks) { + this.buffer = []; + this.callbacks = new Map(); + this.allKeys = new Set(); + const isMac = KeyboardManager.platform.isMac; + + for (const [keys, callback] of callbacks) { + for (const key of keys) { + const isMacKey = key.startsWith("mac+"); + + if (isMac && isMacKey) { + this.callbacks.set(key.slice(4), callback); + this.allKeys.add(key.split("+").at(-1)); + } else if (!isMac && !isMacKey) { + this.callbacks.set(key, callback); + this.allKeys.add(key.split("+").at(-1)); + } + } + } + } + + static get platform() { + const platform = typeof navigator !== "undefined" ? navigator.platform : ""; + return (0, _util.shadow)(this, "platform", { + isWin: platform.includes("Win"), + isMac: platform.includes("Mac") + }); + } + + #serialize(event) { + if (event.altKey) { + this.buffer.push("alt"); + } + + if (event.ctrlKey) { + this.buffer.push("ctrl"); + } + + if (event.metaKey) { + this.buffer.push("meta"); + } + + if (event.shiftKey) { + this.buffer.push("shift"); + } + + this.buffer.push(event.key); + const str = this.buffer.join("+"); + this.buffer.length = 0; + return str; + } + + exec(self, event) { + if (!this.allKeys.has(event.key)) { + return; + } + + const callback = this.callbacks.get(this.#serialize(event)); + + if (!callback) { + return; + } + + callback.bind(self)(); + event.stopPropagation(); + event.preventDefault(); + } + +} + +exports.KeyboardManager = KeyboardManager; + +class ClipboardManager { + #elements = null; + + copy(element) { + if (!element) { + return; + } + + if (Array.isArray(element)) { + this.#elements = element.map(el => el.serialize()); + } else { + this.#elements = [element.serialize()]; + } + + this.#elements = this.#elements.filter(el => !!el); + + if (this.#elements.length === 0) { + this.#elements = null; + } + } + + paste() { + return this.#elements; + } + + isEmpty() { + return this.#elements === null; + } + + destroy() { + this.#elements = null; + } + +} + +class ColorManager { + static _colorsMapping = new Map([["CanvasText", [0, 0, 0]], ["Canvas", [255, 255, 255]]]); + + get _colors() { + const colors = new Map([["CanvasText", null], ["Canvas", null]]); + (0, _display_utils.getColorValues)(colors); + return (0, _util.shadow)(this, "_colors", colors); + } + + convert(color) { + const rgb = (0, _display_utils.getRGB)(color); + + if (!window.matchMedia("(forced-colors: active)").matches) { + return rgb; + } + + for (const [name, RGB] of this._colors) { + if (RGB.every((x, i) => x === rgb[i])) { + return ColorManager._colorsMapping.get(name); + } + } + + return rgb; + } + + getHexCode(name) { + const rgb = this._colors.get(name); + + if (!rgb) { + return name; + } + + return _util.Util.makeHexColor(...rgb); + } + +} + +exports.ColorManager = ColorManager; + +class AnnotationEditorUIManager { + #activeEditor = null; + #allEditors = new Map(); + #allLayers = new Map(); + #clipboardManager = new ClipboardManager(); + #commandManager = new CommandManager(); + #currentPageIndex = 0; + #editorTypes = null; + #eventBus = null; + #idManager = new IdManager(); + #isEnabled = false; + #mode = _util.AnnotationEditorType.NONE; + #selectedEditors = new Set(); + #boundKeydown = this.keydown.bind(this); + #boundOnEditingAction = this.onEditingAction.bind(this); + #boundOnPageChanging = this.onPageChanging.bind(this); + #previousStates = { + isEditing: false, + isEmpty: true, + hasEmptyClipboard: true, + hasSomethingToUndo: false, + hasSomethingToRedo: false, + hasSelectedEditor: false + }; + #container = null; + static _keyboardManager = new KeyboardManager([[["ctrl+a", "mac+meta+a"], AnnotationEditorUIManager.prototype.selectAll], [["ctrl+c", "mac+meta+c"], AnnotationEditorUIManager.prototype.copy], [["ctrl+v", "mac+meta+v"], AnnotationEditorUIManager.prototype.paste], [["ctrl+x", "mac+meta+x"], AnnotationEditorUIManager.prototype.cut], [["ctrl+z", "mac+meta+z"], AnnotationEditorUIManager.prototype.undo], [["ctrl+y", "ctrl+shift+Z", "mac+meta+shift+Z"], AnnotationEditorUIManager.prototype.redo], [["Backspace", "alt+Backspace", "ctrl+Backspace", "shift+Backspace", "mac+Backspace", "mac+alt+Backspace", "mac+ctrl+Backspace", "Delete", "ctrl+Delete", "shift+Delete"], AnnotationEditorUIManager.prototype.delete], [["Escape", "mac+Escape"], AnnotationEditorUIManager.prototype.unselectAll]]); + + constructor(container, eventBus) { + this.#container = container; + this.#eventBus = eventBus; + + this.#eventBus._on("editingaction", this.#boundOnEditingAction); + + this.#eventBus._on("pagechanging", this.#boundOnPageChanging); + } + + destroy() { + this.#removeKeyboardManager(); + + this.#eventBus._off("editingaction", this.#boundOnEditingAction); + + this.#eventBus._off("pagechanging", this.#boundOnPageChanging); + + for (const layer of this.#allLayers.values()) { + layer.destroy(); + } + + this.#allLayers.clear(); + this.#allEditors.clear(); + this.#activeEditor = null; + this.#selectedEditors.clear(); + this.#clipboardManager.destroy(); + this.#commandManager.destroy(); + } + + onPageChanging({ + pageNumber + }) { + this.#currentPageIndex = pageNumber - 1; + } + + focusMainContainer() { + this.#container.focus(); + } + + #addKeyboardManager() { + this.#container.addEventListener("keydown", this.#boundKeydown); + } + + #removeKeyboardManager() { + this.#container.removeEventListener("keydown", this.#boundKeydown); + } + + keydown(event) { + if (!this.getActive()?.shouldGetKeyboardEvents()) { + AnnotationEditorUIManager._keyboardManager.exec(this, event); + } + } + + onEditingAction(details) { + if (["undo", "redo", "cut", "copy", "paste", "delete", "selectAll"].includes(details.name)) { + this[details.name](); + } + } + + #dispatchUpdateStates(details) { + const hasChanged = Object.entries(details).some(([key, value]) => this.#previousStates[key] !== value); + + if (hasChanged) { + this.#eventBus.dispatch("annotationeditorstateschanged", { + source: this, + details: Object.assign(this.#previousStates, details) + }); + } + } + + #dispatchUpdateUI(details) { + this.#eventBus.dispatch("annotationeditorparamschanged", { + source: this, + details + }); + } + + setEditingState(isEditing) { + if (isEditing) { + this.#addKeyboardManager(); + this.#dispatchUpdateStates({ + isEditing: this.#mode !== _util.AnnotationEditorType.NONE, + isEmpty: this.#isEmpty(), + hasSomethingToUndo: this.#commandManager.hasSomethingToUndo(), + hasSomethingToRedo: this.#commandManager.hasSomethingToRedo(), + hasSelectedEditor: false, + hasEmptyClipboard: this.#clipboardManager.isEmpty() + }); + } else { + this.#removeKeyboardManager(); + this.#dispatchUpdateStates({ + isEditing: false + }); + } + } + + registerEditorTypes(types) { + this.#editorTypes = types; + + for (const editorType of this.#editorTypes) { + this.#dispatchUpdateUI(editorType.defaultPropertiesToUpdate); + } + } + + getId() { + return this.#idManager.getId(); + } + + addLayer(layer) { + this.#allLayers.set(layer.pageIndex, layer); + + if (this.#isEnabled) { + layer.enable(); + } else { + layer.disable(); + } + } + + removeLayer(layer) { + this.#allLayers.delete(layer.pageIndex); + } + + updateMode(mode) { + this.#mode = mode; + + if (mode === _util.AnnotationEditorType.NONE) { + this.setEditingState(false); + this.#disableAll(); + } else { + this.setEditingState(true); + this.#enableAll(); + + for (const layer of this.#allLayers.values()) { + layer.updateMode(mode); + } + } + } + + updateToolbar(mode) { + if (mode === this.#mode) { + return; + } + + this.#eventBus.dispatch("switchannotationeditormode", { + source: this, + mode + }); + } + + updateParams(type, value) { + for (const editor of this.#selectedEditors) { + editor.updateParams(type, value); + } + + for (const editorType of this.#editorTypes) { + editorType.updateDefaultParams(type, value); + } + } + + #enableAll() { + if (!this.#isEnabled) { + this.#isEnabled = true; + + for (const layer of this.#allLayers.values()) { + layer.enable(); + } + } + } + + #disableAll() { + this.unselectAll(); + + if (this.#isEnabled) { + this.#isEnabled = false; + + for (const layer of this.#allLayers.values()) { + layer.disable(); + } + } + } + + getEditors(pageIndex) { + const editors = []; + + for (const editor of this.#allEditors.values()) { + if (editor.pageIndex === pageIndex) { + editors.push(editor); + } + } + + return editors; + } + + getEditor(id) { + return this.#allEditors.get(id); + } + + addEditor(editor) { + this.#allEditors.set(editor.id, editor); + } + + removeEditor(editor) { + this.#allEditors.delete(editor.id); + this.unselect(editor); + } + + #addEditorToLayer(editor) { + const layer = this.#allLayers.get(editor.pageIndex); + + if (layer) { + layer.addOrRebuild(editor); + } else { + this.addEditor(editor); + } + } + + setActiveEditor(editor) { + if (this.#activeEditor === editor) { + return; + } + + this.#activeEditor = editor; + + if (editor) { + this.#dispatchUpdateUI(editor.propertiesToUpdate); + } + } + + toggleSelected(editor) { + if (this.#selectedEditors.has(editor)) { + this.#selectedEditors.delete(editor); + editor.unselect(); + this.#dispatchUpdateStates({ + hasSelectedEditor: this.hasSelection + }); + return; + } + + this.#selectedEditors.add(editor); + editor.select(); + this.#dispatchUpdateUI(editor.propertiesToUpdate); + this.#dispatchUpdateStates({ + hasSelectedEditor: true + }); + } + + setSelected(editor) { + for (const ed of this.#selectedEditors) { + if (ed !== editor) { + ed.unselect(); + } + } + + this.#selectedEditors.clear(); + this.#selectedEditors.add(editor); + editor.select(); + this.#dispatchUpdateUI(editor.propertiesToUpdate); + this.#dispatchUpdateStates({ + hasSelectedEditor: true + }); + } + + isSelected(editor) { + return this.#selectedEditors.has(editor); + } + + unselect(editor) { + editor.unselect(); + this.#selectedEditors.delete(editor); + this.#dispatchUpdateStates({ + hasSelectedEditor: this.hasSelection + }); + } + + get hasSelection() { + return this.#selectedEditors.size !== 0; + } + + undo() { + this.#commandManager.undo(); + this.#dispatchUpdateStates({ + hasSomethingToUndo: this.#commandManager.hasSomethingToUndo(), + hasSomethingToRedo: true, + isEmpty: this.#isEmpty() + }); + } + + redo() { + this.#commandManager.redo(); + this.#dispatchUpdateStates({ + hasSomethingToUndo: true, + hasSomethingToRedo: this.#commandManager.hasSomethingToRedo(), + isEmpty: this.#isEmpty() + }); + } + + addCommands(params) { + this.#commandManager.add(params); + this.#dispatchUpdateStates({ + hasSomethingToUndo: true, + hasSomethingToRedo: false, + isEmpty: this.#isEmpty() + }); + } + + #isEmpty() { + if (this.#allEditors.size === 0) { + return true; + } + + if (this.#allEditors.size === 1) { + for (const editor of this.#allEditors.values()) { + return editor.isEmpty(); + } + } + + return false; + } + + delete() { + if (this.#activeEditor) { + this.#activeEditor.commitOrRemove(); + } + + if (!this.hasSelection) { + return; + } + + const editors = [...this.#selectedEditors]; + + const cmd = () => { + for (const editor of editors) { + editor.remove(); + } + }; + + const undo = () => { + for (const editor of editors) { + this.#addEditorToLayer(editor); + } + }; + + this.addCommands({ + cmd, + undo, + mustExec: true + }); + } + + copy() { + if (this.#activeEditor) { + this.#activeEditor.commitOrRemove(); + } + + if (this.hasSelection) { + const editors = []; + + for (const editor of this.#selectedEditors) { + if (!editor.isEmpty()) { + editors.push(editor); + } + } + + if (editors.length === 0) { + return; + } + + this.#clipboardManager.copy(editors); + this.#dispatchUpdateStates({ + hasEmptyClipboard: false + }); + } + } + + cut() { + this.copy(); + this.delete(); + } + + paste() { + if (this.#clipboardManager.isEmpty()) { + return; + } + + this.unselectAll(); + const layer = this.#allLayers.get(this.#currentPageIndex); + const newEditors = this.#clipboardManager.paste().map(data => layer.deserialize(data)); + + const cmd = () => { + for (const editor of newEditors) { + this.#addEditorToLayer(editor); + } + + this.#selectEditors(newEditors); + }; + + const undo = () => { + for (const editor of newEditors) { + editor.remove(); + } + }; + + this.addCommands({ + cmd, + undo, + mustExec: true + }); + } + + #selectEditors(editors) { + this.#selectedEditors.clear(); + + for (const editor of editors) { + if (editor.isEmpty()) { + continue; + } + + this.#selectedEditors.add(editor); + editor.select(); + } + + this.#dispatchUpdateStates({ + hasSelectedEditor: true + }); + } + + selectAll() { + for (const editor of this.#selectedEditors) { + editor.commit(); + } + + this.#selectEditors(this.#allEditors.values()); + } + + unselectAll() { + if (this.#activeEditor) { + this.#activeEditor.commitOrRemove(); + return; + } + + if (this.#selectEditors.size === 0) { + return; + } + + for (const editor of this.#selectedEditors) { + editor.unselect(); + } + + this.#selectedEditors.clear(); + this.#dispatchUpdateStates({ + hasSelectedEditor: false + }); + } + + isActive(editor) { + return this.#activeEditor === editor; + } + + getActive() { + return this.#activeEditor; + } + + getMode() { + return this.#mode; + } + +} + +exports.AnnotationEditorUIManager = AnnotationEditorUIManager; + +/***/ }), +/* 8 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.StatTimer = exports.RenderingCancelledException = exports.PixelsPerInch = exports.PageViewport = exports.PDFDateString = exports.DOMStandardFontDataFactory = exports.DOMSVGFactory = exports.DOMCanvasFactory = exports.DOMCMapReaderFactory = exports.AnnotationPrefix = void 0; +exports.deprecated = deprecated; +exports.getColorValues = getColorValues; +exports.getCurrentTransform = getCurrentTransform; +exports.getCurrentTransformInverse = getCurrentTransformInverse; +exports.getFilenameFromUrl = getFilenameFromUrl; +exports.getPdfFilenameFromUrl = getPdfFilenameFromUrl; +exports.getRGB = getRGB; +exports.getXfaPageViewport = getXfaPageViewport; +exports.isDataScheme = isDataScheme; +exports.isPdfFile = isPdfFile; +exports.isValidFetchUrl = isValidFetchUrl; +exports.loadScript = loadScript; + +var _base_factory = __w_pdfjs_require__(9); + +var _util = __w_pdfjs_require__(1); + +const SVG_NS = "http://www.w3.org/2000/svg"; +const AnnotationPrefix = "pdfjs_internal_id_"; +exports.AnnotationPrefix = AnnotationPrefix; + +class PixelsPerInch { + static CSS = 96.0; + static PDF = 72.0; + static PDF_TO_CSS_UNITS = this.CSS / this.PDF; +} + +exports.PixelsPerInch = PixelsPerInch; + +class DOMCanvasFactory extends _base_factory.BaseCanvasFactory { + constructor({ + ownerDocument = globalThis.document + } = {}) { + super(); + this._document = ownerDocument; + } + + _createCanvas(width, height) { + const canvas = this._document.createElement("canvas"); + + canvas.width = width; + canvas.height = height; + return canvas; + } + +} + +exports.DOMCanvasFactory = DOMCanvasFactory; + +async function fetchData(url, asTypedArray = false) { + if (isValidFetchUrl(url, document.baseURI)) { + const response = await fetch(url); + + if (!response.ok) { + throw new Error(response.statusText); + } + + return asTypedArray ? new Uint8Array(await response.arrayBuffer()) : (0, _util.stringToBytes)(await response.text()); + } + + return new Promise((resolve, reject) => { + const request = new XMLHttpRequest(); + request.open("GET", url, true); + + if (asTypedArray) { + request.responseType = "arraybuffer"; + } + + request.onreadystatechange = () => { + if (request.readyState !== XMLHttpRequest.DONE) { + return; + } + + if (request.status === 200 || request.status === 0) { + let data; + + if (asTypedArray && request.response) { + data = new Uint8Array(request.response); + } else if (!asTypedArray && request.responseText) { + data = (0, _util.stringToBytes)(request.responseText); + } + + if (data) { + resolve(data); + return; + } + } + + reject(new Error(request.statusText)); + }; + + request.send(null); + }); +} + +class DOMCMapReaderFactory extends _base_factory.BaseCMapReaderFactory { + _fetchData(url, compressionType) { + return fetchData(url, this.isCompressed).then(data => { + return { + cMapData: data, + compressionType + }; + }); + } + +} + +exports.DOMCMapReaderFactory = DOMCMapReaderFactory; + +class DOMStandardFontDataFactory extends _base_factory.BaseStandardFontDataFactory { + _fetchData(url) { + return fetchData(url, true); + } + +} + +exports.DOMStandardFontDataFactory = DOMStandardFontDataFactory; + +class DOMSVGFactory extends _base_factory.BaseSVGFactory { + _createSVG(type) { + return document.createElementNS(SVG_NS, type); + } + +} + +exports.DOMSVGFactory = DOMSVGFactory; + +class PageViewport { + constructor({ + viewBox, + scale, + rotation, + offsetX = 0, + offsetY = 0, + dontFlip = false + }) { + this.viewBox = viewBox; + this.scale = scale; + this.rotation = rotation; + this.offsetX = offsetX; + this.offsetY = offsetY; + const centerX = (viewBox[2] + viewBox[0]) / 2; + const centerY = (viewBox[3] + viewBox[1]) / 2; + let rotateA, rotateB, rotateC, rotateD; + rotation %= 360; + + if (rotation < 0) { + rotation += 360; + } + + switch (rotation) { + case 180: + rotateA = -1; + rotateB = 0; + rotateC = 0; + rotateD = 1; + break; + + case 90: + rotateA = 0; + rotateB = 1; + rotateC = 1; + rotateD = 0; + break; + + case 270: + rotateA = 0; + rotateB = -1; + rotateC = -1; + rotateD = 0; + break; + + case 0: + rotateA = 1; + rotateB = 0; + rotateC = 0; + rotateD = -1; + break; + + default: + throw new Error("PageViewport: Invalid rotation, must be a multiple of 90 degrees."); + } + + if (dontFlip) { + rotateC = -rotateC; + rotateD = -rotateD; + } + + let offsetCanvasX, offsetCanvasY; + let width, height; + + if (rotateA === 0) { + offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX; + offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY; + width = Math.abs(viewBox[3] - viewBox[1]) * scale; + height = Math.abs(viewBox[2] - viewBox[0]) * scale; + } else { + offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX; + offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY; + width = Math.abs(viewBox[2] - viewBox[0]) * scale; + height = Math.abs(viewBox[3] - viewBox[1]) * scale; + } + + this.transform = [rotateA * scale, rotateB * scale, rotateC * scale, rotateD * scale, offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY]; + this.width = width; + this.height = height; + } + + clone({ + scale = this.scale, + rotation = this.rotation, + offsetX = this.offsetX, + offsetY = this.offsetY, + dontFlip = false + } = {}) { + return new PageViewport({ + viewBox: this.viewBox.slice(), + scale, + rotation, + offsetX, + offsetY, + dontFlip + }); + } + + convertToViewportPoint(x, y) { + return _util.Util.applyTransform([x, y], this.transform); + } + + convertToViewportRectangle(rect) { + const topLeft = _util.Util.applyTransform([rect[0], rect[1]], this.transform); + + const bottomRight = _util.Util.applyTransform([rect[2], rect[3]], this.transform); + + return [topLeft[0], topLeft[1], bottomRight[0], bottomRight[1]]; + } + + convertToPdfPoint(x, y) { + return _util.Util.applyInverseTransform([x, y], this.transform); + } + +} + +exports.PageViewport = PageViewport; + +class RenderingCancelledException extends _util.BaseException { + constructor(msg, type) { + super(msg, "RenderingCancelledException"); + this.type = type; + } + +} + +exports.RenderingCancelledException = RenderingCancelledException; + +function isDataScheme(url) { + const ii = url.length; + let i = 0; + + while (i < ii && url[i].trim() === "") { + i++; + } + + return url.substring(i, i + 5).toLowerCase() === "data:"; +} + +function isPdfFile(filename) { + return typeof filename === "string" && /\.pdf$/i.test(filename); +} + +function getFilenameFromUrl(url) { + const anchor = url.indexOf("#"); + const query = url.indexOf("?"); + const end = Math.min(anchor > 0 ? anchor : url.length, query > 0 ? query : url.length); + return url.substring(url.lastIndexOf("/", end) + 1, end); +} + +function getPdfFilenameFromUrl(url, defaultFilename = "document.pdf") { + if (typeof url !== "string") { + return defaultFilename; + } + + if (isDataScheme(url)) { + (0, _util.warn)('getPdfFilenameFromUrl: ignore "data:"-URL for performance reasons.'); + return defaultFilename; + } + + const reURI = /^(?:(?:[^:]+:)?\/\/[^/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/; + const reFilename = /[^/?#=]+\.pdf\b(?!.*\.pdf\b)/i; + const splitURI = reURI.exec(url); + let suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]); + + if (suggestedFilename) { + suggestedFilename = suggestedFilename[0]; + + if (suggestedFilename.includes("%")) { + try { + suggestedFilename = reFilename.exec(decodeURIComponent(suggestedFilename))[0]; + } catch (ex) {} + } + } + + return suggestedFilename || defaultFilename; +} + +class StatTimer { + constructor() { + this.started = Object.create(null); + this.times = []; + } + + time(name) { + if (name in this.started) { + (0, _util.warn)(`Timer is already running for ${name}`); + } + + this.started[name] = Date.now(); + } + + timeEnd(name) { + if (!(name in this.started)) { + (0, _util.warn)(`Timer has not been started for ${name}`); + } + + this.times.push({ + name, + start: this.started[name], + end: Date.now() + }); + delete this.started[name]; + } + + toString() { + const outBuf = []; + let longest = 0; + + for (const time of this.times) { + const name = time.name; + + if (name.length > longest) { + longest = name.length; + } + } + + for (const time of this.times) { + const duration = time.end - time.start; + outBuf.push(`${time.name.padEnd(longest)} ${duration}ms\n`); + } + + return outBuf.join(""); + } + +} + +exports.StatTimer = StatTimer; + +function isValidFetchUrl(url, baseUrl) { + try { + const { + protocol + } = baseUrl ? new URL(url, baseUrl) : new URL(url); + return protocol === "http:" || protocol === "https:"; + } catch (ex) { + return false; + } +} + +function loadScript(src, removeScriptElement = false) { + return new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.src = src; + + script.onload = function (evt) { + if (removeScriptElement) { + script.remove(); + } + + resolve(evt); + }; + + script.onerror = function () { + reject(new Error(`Cannot load script at: ${script.src}`)); + }; + + (document.head || document.documentElement).append(script); + }); +} + +function deprecated(details) { + console.log("Deprecated API usage: " + details); +} + +let pdfDateStringRegex; + +class PDFDateString { + static toDateObject(input) { + if (!input || typeof input !== "string") { + return null; + } + + if (!pdfDateStringRegex) { + pdfDateStringRegex = new RegExp("^D:" + "(\\d{4})" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "([Z|+|-])?" + "(\\d{2})?" + "'?" + "(\\d{2})?" + "'?"); + } + + const matches = pdfDateStringRegex.exec(input); + + if (!matches) { + return null; + } + + const year = parseInt(matches[1], 10); + let month = parseInt(matches[2], 10); + month = month >= 1 && month <= 12 ? month - 1 : 0; + let day = parseInt(matches[3], 10); + day = day >= 1 && day <= 31 ? day : 1; + let hour = parseInt(matches[4], 10); + hour = hour >= 0 && hour <= 23 ? hour : 0; + let minute = parseInt(matches[5], 10); + minute = minute >= 0 && minute <= 59 ? minute : 0; + let second = parseInt(matches[6], 10); + second = second >= 0 && second <= 59 ? second : 0; + const universalTimeRelation = matches[7] || "Z"; + let offsetHour = parseInt(matches[8], 10); + offsetHour = offsetHour >= 0 && offsetHour <= 23 ? offsetHour : 0; + let offsetMinute = parseInt(matches[9], 10) || 0; + offsetMinute = offsetMinute >= 0 && offsetMinute <= 59 ? offsetMinute : 0; + + if (universalTimeRelation === "-") { + hour += offsetHour; + minute += offsetMinute; + } else if (universalTimeRelation === "+") { + hour -= offsetHour; + minute -= offsetMinute; + } + + return new Date(Date.UTC(year, month, day, hour, minute, second)); + } + +} + +exports.PDFDateString = PDFDateString; + +function getXfaPageViewport(xfaPage, { + scale = 1, + rotation = 0 +}) { + const { + width, + height + } = xfaPage.attributes.style; + const viewBox = [0, 0, parseInt(width), parseInt(height)]; + return new PageViewport({ + viewBox, + scale, + rotation + }); +} + +function getRGB(color) { + if (color.startsWith("#")) { + const colorRGB = parseInt(color.slice(1), 16); + return [(colorRGB & 0xff0000) >> 16, (colorRGB & 0x00ff00) >> 8, colorRGB & 0x0000ff]; + } + + if (color.startsWith("rgb(")) { + return color.slice(4, -1).split(",").map(x => parseInt(x)); + } + + if (color.startsWith("rgba(")) { + return color.slice(5, -1).split(",").map(x => parseInt(x)).slice(0, 3); + } + + (0, _util.warn)(`Not a valid color format: "${color}"`); + return [0, 0, 0]; +} + +function getColorValues(colors) { + const span = document.createElement("span"); + span.style.visibility = "hidden"; + document.body.append(span); + + for (const name of colors.keys()) { + span.style.color = name; + const computedColor = window.getComputedStyle(span).color; + colors.set(name, getRGB(computedColor)); + } + + span.remove(); +} + +function getCurrentTransform(ctx) { + const { + a, + b, + c, + d, + e, + f + } = ctx.getTransform(); + return [a, b, c, d, e, f]; +} + +function getCurrentTransformInverse(ctx) { + const { + a, + b, + c, + d, + e, + f + } = ctx.getTransform().invertSelf(); + return [a, b, c, d, e, f]; +} + +/***/ }), +/* 9 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.BaseStandardFontDataFactory = exports.BaseSVGFactory = exports.BaseCanvasFactory = exports.BaseCMapReaderFactory = void 0; + +var _util = __w_pdfjs_require__(1); + +class BaseCanvasFactory { + constructor() { + if (this.constructor === BaseCanvasFactory) { + (0, _util.unreachable)("Cannot initialize BaseCanvasFactory."); + } + } + + create(width, height) { + if (width <= 0 || height <= 0) { + throw new Error("Invalid canvas size"); + } + + const canvas = this._createCanvas(width, height); + + return { + canvas, + context: canvas.getContext("2d") + }; + } + + reset(canvasAndContext, width, height) { + if (!canvasAndContext.canvas) { + throw new Error("Canvas is not specified"); + } + + if (width <= 0 || height <= 0) { + throw new Error("Invalid canvas size"); + } + + canvasAndContext.canvas.width = width; + canvasAndContext.canvas.height = height; + } + + destroy(canvasAndContext) { + if (!canvasAndContext.canvas) { + throw new Error("Canvas is not specified"); + } + + canvasAndContext.canvas.width = 0; + canvasAndContext.canvas.height = 0; + canvasAndContext.canvas = null; + canvasAndContext.context = null; + } + + _createCanvas(width, height) { + (0, _util.unreachable)("Abstract method `_createCanvas` called."); + } + +} + +exports.BaseCanvasFactory = BaseCanvasFactory; + +class BaseCMapReaderFactory { + constructor({ + baseUrl = null, + isCompressed = false + }) { + if (this.constructor === BaseCMapReaderFactory) { + (0, _util.unreachable)("Cannot initialize BaseCMapReaderFactory."); + } + + this.baseUrl = baseUrl; + this.isCompressed = isCompressed; + } + + async fetch({ + name + }) { + if (!this.baseUrl) { + throw new Error('The CMap "baseUrl" parameter must be specified, ensure that ' + 'the "cMapUrl" and "cMapPacked" API parameters are provided.'); + } + + if (!name) { + throw new Error("CMap name must be specified."); + } + + const url = this.baseUrl + name + (this.isCompressed ? ".bcmap" : ""); + const compressionType = this.isCompressed ? _util.CMapCompressionType.BINARY : _util.CMapCompressionType.NONE; + return this._fetchData(url, compressionType).catch(reason => { + throw new Error(`Unable to load ${this.isCompressed ? "binary " : ""}CMap at: ${url}`); + }); + } + + _fetchData(url, compressionType) { + (0, _util.unreachable)("Abstract method `_fetchData` called."); + } + +} + +exports.BaseCMapReaderFactory = BaseCMapReaderFactory; + +class BaseStandardFontDataFactory { + constructor({ + baseUrl = null + }) { + if (this.constructor === BaseStandardFontDataFactory) { + (0, _util.unreachable)("Cannot initialize BaseStandardFontDataFactory."); + } + + this.baseUrl = baseUrl; + } + + async fetch({ + filename + }) { + if (!this.baseUrl) { + throw new Error('The standard font "baseUrl" parameter must be specified, ensure that ' + 'the "standardFontDataUrl" API parameter is provided.'); + } + + if (!filename) { + throw new Error("Font filename must be specified."); + } + + const url = `${this.baseUrl}${filename}`; + return this._fetchData(url).catch(reason => { + throw new Error(`Unable to load font data at: ${url}`); + }); + } + + _fetchData(url) { + (0, _util.unreachable)("Abstract method `_fetchData` called."); + } + +} + +exports.BaseStandardFontDataFactory = BaseStandardFontDataFactory; + +class BaseSVGFactory { + constructor() { + if (this.constructor === BaseSVGFactory) { + (0, _util.unreachable)("Cannot initialize BaseSVGFactory."); + } + } + + create(width, height, skipDimensions = false) { + if (width <= 0 || height <= 0) { + throw new Error("Invalid SVG dimensions"); + } + + const svg = this._createSVG("svg:svg"); + + svg.setAttribute("version", "1.1"); + + if (!skipDimensions) { + svg.setAttribute("width", `${width}px`); + svg.setAttribute("height", `${height}px`); + } + + svg.setAttribute("preserveAspectRatio", "none"); + svg.setAttribute("viewBox", `0 0 ${width} ${height}`); + return svg; + } + + createElement(type) { + if (typeof type !== "string") { + throw new Error("Invalid SVG element type"); + } + + return this._createSVG(type); + } + + _createSVG(type) { + (0, _util.unreachable)("Abstract method `_createSVG` called."); + } + +} + +exports.BaseSVGFactory = BaseSVGFactory; + +/***/ }), +/* 10 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.MurmurHash3_64 = void 0; + +var _util = __w_pdfjs_require__(1); + +const SEED = 0xc3d2e1f0; +const MASK_HIGH = 0xffff0000; +const MASK_LOW = 0xffff; + +class MurmurHash3_64 { + constructor(seed) { + this.h1 = seed ? seed & 0xffffffff : SEED; + this.h2 = seed ? seed & 0xffffffff : SEED; + } + + update(input) { + let data, length; + + if (typeof input === "string") { + data = new Uint8Array(input.length * 2); + length = 0; + + for (let i = 0, ii = input.length; i < ii; i++) { + const code = input.charCodeAt(i); + + if (code <= 0xff) { + data[length++] = code; + } else { + data[length++] = code >>> 8; + data[length++] = code & 0xff; + } + } + } else if ((0, _util.isArrayBuffer)(input)) { + data = input.slice(); + length = data.byteLength; + } else { + throw new Error("Wrong data format in MurmurHash3_64_update. " + "Input must be a string or array."); + } + + const blockCounts = length >> 2; + const tailLength = length - blockCounts * 4; + const dataUint32 = new Uint32Array(data.buffer, 0, blockCounts); + let k1 = 0, + k2 = 0; + let h1 = this.h1, + h2 = this.h2; + const C1 = 0xcc9e2d51, + C2 = 0x1b873593; + const C1_LOW = C1 & MASK_LOW, + C2_LOW = C2 & MASK_LOW; + + for (let i = 0; i < blockCounts; i++) { + if (i & 1) { + k1 = dataUint32[i]; + k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW; + k1 = k1 << 15 | k1 >>> 17; + k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW; + h1 ^= k1; + h1 = h1 << 13 | h1 >>> 19; + h1 = h1 * 5 + 0xe6546b64; + } else { + k2 = dataUint32[i]; + k2 = k2 * C1 & MASK_HIGH | k2 * C1_LOW & MASK_LOW; + k2 = k2 << 15 | k2 >>> 17; + k2 = k2 * C2 & MASK_HIGH | k2 * C2_LOW & MASK_LOW; + h2 ^= k2; + h2 = h2 << 13 | h2 >>> 19; + h2 = h2 * 5 + 0xe6546b64; + } + } + + k1 = 0; + + switch (tailLength) { + case 3: + k1 ^= data[blockCounts * 4 + 2] << 16; + + case 2: + k1 ^= data[blockCounts * 4 + 1] << 8; + + case 1: + k1 ^= data[blockCounts * 4]; + k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW; + k1 = k1 << 15 | k1 >>> 17; + k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW; + + if (blockCounts & 1) { + h1 ^= k1; + } else { + h2 ^= k1; + } + + } + + this.h1 = h1; + this.h2 = h2; + } + + hexdigest() { + let h1 = this.h1, + h2 = this.h2; + h1 ^= h2 >>> 1; + h1 = h1 * 0xed558ccd & MASK_HIGH | h1 * 0x8ccd & MASK_LOW; + h2 = h2 * 0xff51afd7 & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16; + h1 ^= h2 >>> 1; + h1 = h1 * 0x1a85ec53 & MASK_HIGH | h1 * 0xec53 & MASK_LOW; + h2 = h2 * 0xc4ceb9fe & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16; + h1 ^= h2 >>> 1; + const hex1 = (h1 >>> 0).toString(16), + hex2 = (h2 >>> 0).toString(16); + return hex1.padStart(8, "0") + hex2.padStart(8, "0"); + } + +} + +exports.MurmurHash3_64 = MurmurHash3_64; + +/***/ }), +/* 11 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.FontLoader = exports.FontFaceObject = void 0; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); class BaseFontLoader { constructor({ docId, onUnsupportedFeature, - ownerDocument = globalThis.document + ownerDocument = globalThis.document, + styleElement = null }) { if (this.constructor === BaseFontLoader) { (0, _util.unreachable)("Cannot initialize BaseFontLoader."); @@ -3973,7 +5712,7 @@ class BaseFontLoader { styleElement = this.styleElement = this._document.createElement("style"); styleElement.id = `PDFJS_FONT_STYLE_TAG_${this.docId}`; - this._document.documentElement.getElementsByTagName("head")[0].appendChild(styleElement); + this._document.documentElement.getElementsByTagName("head")[0].append(styleElement); } const styleSheet = styleElement.sheet; @@ -3981,9 +5720,10 @@ class BaseFontLoader { } clear() { - this.nativeFontFaces.forEach(nativeFontFace => { + for (const nativeFontFace of this.nativeFontFaces) { this._document.fonts.delete(nativeFontFace); - }); + } + this.nativeFontFaces.length = 0; if (this.styleElement) { @@ -4043,8 +5783,8 @@ class BaseFontLoader { } get isFontLoadingAPISupported() { - const supported = typeof this._document !== "undefined" && !!this._document.fonts; - return (0, _util.shadow)(this, "isFontLoadingAPISupported", supported); + const hasFonts = !!this._document?.fonts; + return (0, _util.shadow)(this, "isFontLoadingAPISupported", hasFonts); } get isSyncFontLoadingSupported() { @@ -4082,7 +5822,7 @@ exports.FontLoader = FontLoader; } else { const m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent); - if (m && m[1] >= 14) { + if (m?.[1] >= 14) { supported = true; } } @@ -4183,8 +5923,8 @@ exports.FontLoader = FontLoader; this.insertRule(rule); const names = []; - for (i = 0, ii = fonts.length; i < ii; i++) { - names.push(fonts[i].loadedName); + for (const font of fonts) { + names.push(font.loadedName); } names.push(loadTestFontId); @@ -4196,19 +5936,18 @@ exports.FontLoader = FontLoader; div.style.position = "absolute"; div.style.top = div.style.left = "0px"; - for (i = 0, ii = names.length; i < ii; ++i) { + for (const name of names) { const span = this._document.createElement("span"); span.textContent = "Hi"; - span.style.fontFamily = names[i]; - div.appendChild(span); + span.style.fontFamily = name; + div.append(span); } - this._document.body.appendChild(div); + this._document.body.append(div); isFontReady(loadTestFontId, () => { - this._document.body.removeChild(div); - + div.remove(); request.complete(); }); } @@ -4221,7 +5960,7 @@ class FontFaceObject { isEvalSupported = true, disableFontFace = false, ignoreErrors = false, - onUnsupportedFeature = null, + onUnsupportedFeature, fontRegistry = null }) { this.compiledGlyphs = Object.create(null); @@ -4242,7 +5981,21 @@ class FontFaceObject { return null; } - const nativeFontFace = new FontFace(this.loadedName, this.data, {}); + let nativeFontFace; + + if (!this.cssFontInfo) { + nativeFontFace = new FontFace(this.loadedName, this.data, {}); + } else { + const css = { + weight: this.cssFontInfo.fontWeight + }; + + if (this.cssFontInfo.italicAngle) { + css.style = `oblique ${this.cssFontInfo.italicAngle}deg`; + } + + nativeFontFace = new FontFace(this.cssFontInfo.fontFamily, this.data, css); + } if (this.fontRegistry) { this.fontRegistry.registerFont(this); @@ -4256,9 +6009,21 @@ class FontFaceObject { return null; } - const data = (0, _util.bytesToString)(new Uint8Array(this.data)); + const data = (0, _util.bytesToString)(this.data); const url = `url(data:${this.mimetype};base64,${btoa(data)});`; - const rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`; + let rule; + + if (!this.cssFontInfo) { + rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`; + } else { + let css = `font-weight: ${this.cssFontInfo.fontWeight};`; + + if (this.cssFontInfo.italicAngle) { + css += `font-style: oblique ${this.cssFontInfo.italicAngle}deg;`; + } + + rule = `@font-face {font-family:"${this.cssFontInfo.fontFamily}";${css}src:${url}}`; + } if (this.fontRegistry) { this.fontRegistry.registerFont(this, url); @@ -4272,7 +6037,7 @@ class FontFaceObject { return this.compiledGlyphs[character]; } - let cmds, current; + let cmds; try { cmds = objs.get(this.loadedName + "_path_" + character); @@ -4281,39 +6046,27 @@ class FontFaceObject { throw ex; } - if (this._onUnsupportedFeature) { - this._onUnsupportedFeature({ - featureId: _util.UNSUPPORTED_FEATURES.errorFontGetPath - }); - } + this._onUnsupportedFeature({ + featureId: _util.UNSUPPORTED_FEATURES.errorFontGetPath + }); (0, _util.warn)(`getPathGenerator - ignoring character: "${ex}".`); return this.compiledGlyphs[character] = function (c, size) {}; } - if (this.isEvalSupported && _util.IsEvalSupportedCached.value) { - let args, - js = ""; + if (this.isEvalSupported && _util.FeatureTest.isEvalSupported) { + const jsBuf = []; - for (let i = 0, ii = cmds.length; i < ii; i++) { - current = cmds[i]; - - if (current.args !== undefined) { - args = current.args.join(","); - } else { - args = ""; - } - - js += "c." + current.cmd + "(" + args + ");\n"; + for (const current of cmds) { + const args = current.args !== undefined ? current.args.join(",") : ""; + jsBuf.push("c.", current.cmd, "(", args, ");\n"); } - return this.compiledGlyphs[character] = new Function("c", "size", js); + return this.compiledGlyphs[character] = new Function("c", "size", jsBuf.join("")); } return this.compiledGlyphs[character] = function (c, size) { - for (let i = 0, ii = cmds.length; i < ii; i++) { - current = cmds[i]; - + for (const current of cmds) { if (current.cmd === "scale") { current.args = [size, -size]; } @@ -4328,350 +6081,259 @@ class FontFaceObject { exports.FontFaceObject = FontFaceObject; /***/ }), -/* 7 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 12 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.NodeCMapReaderFactory = exports.NodeCanvasFactory = void 0; - -var _display_utils = __w_pdfjs_require__(1); - -var _is_node = __w_pdfjs_require__(4); - -var _util = __w_pdfjs_require__(2); - -let NodeCanvasFactory = class { - constructor() { - (0, _util.unreachable)("Not implemented: NodeCanvasFactory"); - } - -}; -exports.NodeCanvasFactory = NodeCanvasFactory; -let NodeCMapReaderFactory = class { - constructor() { - (0, _util.unreachable)("Not implemented: NodeCMapReaderFactory"); - } - -}; -exports.NodeCMapReaderFactory = NodeCMapReaderFactory; - -if (_is_node.isNodeJS) { - exports.NodeCanvasFactory = NodeCanvasFactory = class extends _display_utils.BaseCanvasFactory { - create(width, height) { - if (width <= 0 || height <= 0) { - throw new Error("Invalid canvas size"); - } - - const Canvas = require("canvas"); - - const canvas = Canvas.createCanvas(width, height); - return { - canvas, - context: canvas.getContext("2d") - }; - } - - }; - exports.NodeCMapReaderFactory = NodeCMapReaderFactory = class extends _display_utils.BaseCMapReaderFactory { - _fetchData(url, compressionType) { - return new Promise((resolve, reject) => { - const fs = require("fs"); - - fs.readFile(url, (error, data) => { - if (error || !data) { - reject(new Error(error)); - return; - } - - resolve({ - cMapData: new Uint8Array(data), - compressionType - }); - }); - }); - } - - }; -} - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.AnnotationStorage = void 0; - -class AnnotationStorage { - constructor() { - this._storage = new Map(); - this._modified = false; - this.onSetModified = null; - this.onResetModified = null; - } - - getOrCreateValue(key, defaultValue) { - if (this._storage.has(key)) { - return this._storage.get(key); - } - - this._storage.set(key, defaultValue); - - return defaultValue; - } - - setValue(key, value) { - if (this._storage.get(key) !== value) { - this._setModified(); - } - - this._storage.set(key, value); - } - - getAll() { - if (this._storage.size === 0) { - return null; - } - - return Object.fromEntries(this._storage); - } - - get size() { - return this._storage.size; - } - - _setModified() { - if (!this._modified) { - this._modified = true; - - if (typeof this.onSetModified === "function") { - this.onSetModified(); - } - } - } - - resetModified() { - if (this._modified) { - this._modified = false; - - if (typeof this.onResetModified === "function") { - this.onResetModified(); - } - } - } - -} - -exports.AnnotationStorage = AnnotationStorage; - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.apiCompatibilityParams = void 0; - -var _is_node = __w_pdfjs_require__(4); - -const compatibilityParams = Object.create(null); -{ - (function checkFontFace() { - if (_is_node.isNodeJS) { - compatibilityParams.disableFontFace = true; - } - })(); -} -const apiCompatibilityParams = Object.freeze(compatibilityParams); -exports.apiCompatibilityParams = apiCompatibilityParams; - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); +})); exports.CanvasGraphics = void 0; -var _util = __w_pdfjs_require__(2); +var _display_utils = __w_pdfjs_require__(8); -var _pattern_helper = __w_pdfjs_require__(11); +var _util = __w_pdfjs_require__(1); -var MIN_FONT_SIZE = 16; -var MAX_FONT_SIZE = 100; -var MAX_GROUP_SIZE = 4096; -var MIN_WIDTH_FACTOR = 0.65; -var COMPILE_TYPE3_GLYPHS = true; -var MAX_SIZE_TO_COMPILE = 1000; -var FULL_CHUNK_HEIGHT = 16; +var _pattern_helper = __w_pdfjs_require__(13); -function addContextCurrentTransform(ctx) { - if (!ctx.mozCurrentTransform) { - ctx._originalSave = ctx.save; - ctx._originalRestore = ctx.restore; - ctx._originalRotate = ctx.rotate; - ctx._originalScale = ctx.scale; - ctx._originalTranslate = ctx.translate; - ctx._originalTransform = ctx.transform; - ctx._originalSetTransform = ctx.setTransform; - ctx._transformMatrix = ctx._transformMatrix || [1, 0, 0, 1, 0, 0]; - ctx._transformStack = []; - Object.defineProperty(ctx, "mozCurrentTransform", { - get: function getCurrentTransform() { - return this._transformMatrix; - } - }); - Object.defineProperty(ctx, "mozCurrentTransformInverse", { - get: function getCurrentTransformInverse() { - var m = this._transformMatrix; - var a = m[0], - b = m[1], - c = m[2], - d = m[3], - e = m[4], - f = m[5]; - var ad_bc = a * d - b * c; - var bc_ad = b * c - a * d; - return [d / ad_bc, b / bc_ad, c / bc_ad, a / ad_bc, (d * e - c * f) / bc_ad, (b * e - a * f) / ad_bc]; - } - }); +var _image_utils = __w_pdfjs_require__(14); - ctx.save = function ctxSave() { - var old = this._transformMatrix; +var _is_node = __w_pdfjs_require__(3); - this._transformStack.push(old); +const MIN_FONT_SIZE = 16; +const MAX_FONT_SIZE = 100; +const MAX_GROUP_SIZE = 4096; +const EXECUTION_TIME = 15; +const EXECUTION_STEPS = 10; +const MAX_SIZE_TO_COMPILE = _is_node.isNodeJS && typeof Path2D === "undefined" ? -1 : 1000; +const FULL_CHUNK_HEIGHT = 16; - this._transformMatrix = old.slice(0, 6); - - this._originalSave(); - }; - - ctx.restore = function ctxRestore() { - var prev = this._transformStack.pop(); - - if (prev) { - this._transformMatrix = prev; - - this._originalRestore(); - } - }; - - ctx.translate = function ctxTranslate(x, y) { - var m = this._transformMatrix; - m[4] = m[0] * x + m[2] * y + m[4]; - m[5] = m[1] * x + m[3] * y + m[5]; - - this._originalTranslate(x, y); - }; - - ctx.scale = function ctxScale(x, y) { - var m = this._transformMatrix; - m[0] = m[0] * x; - m[1] = m[1] * x; - m[2] = m[2] * y; - m[3] = m[3] * y; - - this._originalScale(x, y); - }; - - ctx.transform = function ctxTransform(a, b, c, d, e, f) { - var m = this._transformMatrix; - this._transformMatrix = [m[0] * a + m[2] * b, m[1] * a + m[3] * b, m[0] * c + m[2] * d, m[1] * c + m[3] * d, m[0] * e + m[2] * f + m[4], m[1] * e + m[3] * f + m[5]]; - - ctx._originalTransform(a, b, c, d, e, f); - }; - - ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) { - this._transformMatrix = [a, b, c, d, e, f]; - - ctx._originalSetTransform(a, b, c, d, e, f); - }; - - ctx.rotate = function ctxRotate(angle) { - var cosValue = Math.cos(angle); - var sinValue = Math.sin(angle); - var m = this._transformMatrix; - this._transformMatrix = [m[0] * cosValue + m[2] * sinValue, m[1] * cosValue + m[3] * sinValue, m[0] * -sinValue + m[2] * cosValue, m[1] * -sinValue + m[3] * cosValue, m[4], m[5]]; - - this._originalRotate(angle); - }; +function mirrorContextOperations(ctx, destCtx) { + if (ctx._removeMirroring) { + throw new Error("Context is already forwarding operations."); } + + ctx.__originalSave = ctx.save; + ctx.__originalRestore = ctx.restore; + ctx.__originalRotate = ctx.rotate; + ctx.__originalScale = ctx.scale; + ctx.__originalTranslate = ctx.translate; + ctx.__originalTransform = ctx.transform; + ctx.__originalSetTransform = ctx.setTransform; + ctx.__originalResetTransform = ctx.resetTransform; + ctx.__originalClip = ctx.clip; + ctx.__originalMoveTo = ctx.moveTo; + ctx.__originalLineTo = ctx.lineTo; + ctx.__originalBezierCurveTo = ctx.bezierCurveTo; + ctx.__originalRect = ctx.rect; + ctx.__originalClosePath = ctx.closePath; + ctx.__originalBeginPath = ctx.beginPath; + + ctx._removeMirroring = () => { + ctx.save = ctx.__originalSave; + ctx.restore = ctx.__originalRestore; + ctx.rotate = ctx.__originalRotate; + ctx.scale = ctx.__originalScale; + ctx.translate = ctx.__originalTranslate; + ctx.transform = ctx.__originalTransform; + ctx.setTransform = ctx.__originalSetTransform; + ctx.resetTransform = ctx.__originalResetTransform; + ctx.clip = ctx.__originalClip; + ctx.moveTo = ctx.__originalMoveTo; + ctx.lineTo = ctx.__originalLineTo; + ctx.bezierCurveTo = ctx.__originalBezierCurveTo; + ctx.rect = ctx.__originalRect; + ctx.closePath = ctx.__originalClosePath; + ctx.beginPath = ctx.__originalBeginPath; + delete ctx._removeMirroring; + }; + + ctx.save = function ctxSave() { + destCtx.save(); + + this.__originalSave(); + }; + + ctx.restore = function ctxRestore() { + destCtx.restore(); + + this.__originalRestore(); + }; + + ctx.translate = function ctxTranslate(x, y) { + destCtx.translate(x, y); + + this.__originalTranslate(x, y); + }; + + ctx.scale = function ctxScale(x, y) { + destCtx.scale(x, y); + + this.__originalScale(x, y); + }; + + ctx.transform = function ctxTransform(a, b, c, d, e, f) { + destCtx.transform(a, b, c, d, e, f); + + this.__originalTransform(a, b, c, d, e, f); + }; + + ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) { + destCtx.setTransform(a, b, c, d, e, f); + + this.__originalSetTransform(a, b, c, d, e, f); + }; + + ctx.resetTransform = function ctxResetTransform() { + destCtx.resetTransform(); + + this.__originalResetTransform(); + }; + + ctx.rotate = function ctxRotate(angle) { + destCtx.rotate(angle); + + this.__originalRotate(angle); + }; + + ctx.clip = function ctxRotate(rule) { + destCtx.clip(rule); + + this.__originalClip(rule); + }; + + ctx.moveTo = function (x, y) { + destCtx.moveTo(x, y); + + this.__originalMoveTo(x, y); + }; + + ctx.lineTo = function (x, y) { + destCtx.lineTo(x, y); + + this.__originalLineTo(x, y); + }; + + ctx.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) { + destCtx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); + + this.__originalBezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); + }; + + ctx.rect = function (x, y, width, height) { + destCtx.rect(x, y, width, height); + + this.__originalRect(x, y, width, height); + }; + + ctx.closePath = function () { + destCtx.closePath(); + + this.__originalClosePath(); + }; + + ctx.beginPath = function () { + destCtx.beginPath(); + + this.__originalBeginPath(); + }; } -var CachedCanvases = function CachedCanvasesClosure() { - function CachedCanvases(canvasFactory) { +class CachedCanvases { + constructor(canvasFactory) { this.canvasFactory = canvasFactory; this.cache = Object.create(null); } - CachedCanvases.prototype = { - getCanvas: function CachedCanvases_getCanvas(id, width, height, trackTransform) { - var canvasEntry; + getCanvas(id, width, height) { + let canvasEntry; - if (this.cache[id] !== undefined) { - canvasEntry = this.cache[id]; - this.canvasFactory.reset(canvasEntry, width, height); - canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0); - } else { - canvasEntry = this.canvasFactory.create(width, height); - this.cache[id] = canvasEntry; - } - - if (trackTransform) { - addContextCurrentTransform(canvasEntry.context); - } - - return canvasEntry; - }, - - clear() { - for (var id in this.cache) { - var canvasEntry = this.cache[id]; - this.canvasFactory.destroy(canvasEntry); - delete this.cache[id]; - } + if (this.cache[id] !== undefined) { + canvasEntry = this.cache[id]; + this.canvasFactory.reset(canvasEntry, width, height); + } else { + canvasEntry = this.canvasFactory.create(width, height); + this.cache[id] = canvasEntry; } - }; - return CachedCanvases; -}(); + return canvasEntry; + } + + delete(id) { + delete this.cache[id]; + } + + clear() { + for (const id in this.cache) { + const canvasEntry = this.cache[id]; + this.canvasFactory.destroy(canvasEntry); + delete this.cache[id]; + } + } + +} + +function drawImageAtIntegerCoords(ctx, srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH) { + const [a, b, c, d, tx, ty] = (0, _display_utils.getCurrentTransform)(ctx); + + if (b === 0 && c === 0) { + const tlX = destX * a + tx; + const rTlX = Math.round(tlX); + const tlY = destY * d + ty; + const rTlY = Math.round(tlY); + const brX = (destX + destW) * a + tx; + const rWidth = Math.abs(Math.round(brX) - rTlX) || 1; + const brY = (destY + destH) * d + ty; + const rHeight = Math.abs(Math.round(brY) - rTlY) || 1; + ctx.setTransform(Math.sign(a), 0, 0, Math.sign(d), rTlX, rTlY); + ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rWidth, rHeight); + ctx.setTransform(a, b, c, d, tx, ty); + return [rWidth, rHeight]; + } + + if (a === 0 && d === 0) { + const tlX = destY * c + tx; + const rTlX = Math.round(tlX); + const tlY = destX * b + ty; + const rTlY = Math.round(tlY); + const brX = (destY + destH) * c + tx; + const rWidth = Math.abs(Math.round(brX) - rTlX) || 1; + const brY = (destX + destW) * b + ty; + const rHeight = Math.abs(Math.round(brY) - rTlY) || 1; + ctx.setTransform(0, Math.sign(b), Math.sign(c), 0, rTlX, rTlY); + ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rHeight, rWidth); + ctx.setTransform(a, b, c, d, tx, ty); + return [rHeight, rWidth]; + } + + ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH); + const scaleX = Math.hypot(a, b); + const scaleY = Math.hypot(c, d); + return [scaleX * destW, scaleY * destH]; +} function compileType3Glyph(imgData) { - var POINT_TO_PROCESS_LIMIT = 1000; - var width = imgData.width, - height = imgData.height; - var i, - j, - j0, - width1 = width + 1; - var points = new Uint8Array(width1 * (height + 1)); - var POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]); - var lineSize = width + 7 & ~7, - data0 = imgData.data; - var data = new Uint8Array(lineSize * height), - pos = 0, - ii; + const { + width, + height + } = imgData; - for (i = 0, ii = data0.length; i < ii; i++) { - var mask = 128, - elem = data0[i]; + if (width > MAX_SIZE_TO_COMPILE || height > MAX_SIZE_TO_COMPILE) { + return null; + } + + const POINT_TO_PROCESS_LIMIT = 1000; + const POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]); + const width1 = width + 1; + let points = new Uint8Array(width1 * (height + 1)); + let i, j, j0; + const lineSize = width + 7 & ~7; + let data = new Uint8Array(lineSize * height), + pos = 0; + + for (const elem of imgData.data) { + let mask = 128; while (mask > 0) { data[pos++] = elem & mask ? 0 : 255; @@ -4679,7 +6341,7 @@ function compileType3Glyph(imgData) { } } - var count = 0; + let count = 0; pos = 0; if (data[pos] !== 0) { @@ -4710,7 +6372,7 @@ function compileType3Glyph(imgData) { ++count; } - var sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0); + let sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0); for (j = 1; j < width; j++) { sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) + (data[pos - lineSize + 1] ? 8 : 0); @@ -4759,12 +6421,12 @@ function compileType3Glyph(imgData) { return null; } - var steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]); - var outlines = []; + const steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]); + const path = new Path2D(); for (i = 0; count && i <= height; i++) { - var p = i * width1; - var end = p + width; + let p = i * width1; + const end = p + width; while (p < end && !points[p]) { p++; @@ -4774,19 +6436,18 @@ function compileType3Glyph(imgData) { continue; } - var coords = [p % width1, i]; - var type = points[p], - p0 = p, - pp; + path.moveTo(p % width1, i); + const p0 = p; + let type = points[p]; do { - var step = steps[type]; + const step = steps[type]; do { p += step; } while (!points[p]); - pp = points[p]; + const pp = points[p]; if (pp !== 5 && pp !== 10) { type = pp; @@ -4796,34 +6457,24 @@ function compileType3Glyph(imgData) { points[p] &= type >> 2 | type << 2; } - coords.push(p % width1); - coords.push(p / width1 | 0); + path.lineTo(p % width1, p / width1 | 0); if (!points[p]) { --count; } } while (p0 !== p); - outlines.push(coords); --i; } - var drawOutline = function (c) { + data = null; + points = null; + + const drawOutline = function (c) { c.save(); c.scale(1 / width, -1 / height); c.translate(0, -height); - c.beginPath(); - - for (let k = 0, kk = outlines.length; k < kk; k++) { - var o = outlines[k]; - c.moveTo(o[0], o[1]); - - for (let l = 2, ll = o.length; l < ll; l += 2) { - c.lineTo(o[l], o[l + 1]); - } - } - - c.fill(); + c.fill(path); c.beginPath(); c.restore(); }; @@ -4831,8 +6482,8 @@ function compileType3Glyph(imgData) { return drawOutline; } -var CanvasExtraState = function CanvasExtraStateClosure() { - function CanvasExtraState() { +class CanvasExtraState { + constructor(width, height) { this.alphaIsShape = false; this.fontSize = 0; this.fontSizeScale = 1; @@ -4856,29 +6507,471 @@ var CanvasExtraState = function CanvasExtraStateClosure() { this.strokeAlpha = 1; this.lineWidth = 1; this.activeSMask = null; - this.resumeSMaskCtx = null; this.transferMaps = null; + this.startNewPathAndClipBox([0, 0, width, height]); } - CanvasExtraState.prototype = { - clone: function CanvasExtraState_clone() { - return Object.create(this); - }, - setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) { - this.x = x; - this.y = y; + clone() { + const clone = Object.create(this); + clone.clipBox = this.clipBox.slice(); + return clone; + } + + setCurrentPoint(x, y) { + this.x = x; + this.y = y; + } + + updatePathMinMax(transform, x, y) { + [x, y] = _util.Util.applyTransform([x, y], transform); + this.minX = Math.min(this.minX, x); + this.minY = Math.min(this.minY, y); + this.maxX = Math.max(this.maxX, x); + this.maxY = Math.max(this.maxY, y); + } + + updateRectMinMax(transform, rect) { + const p1 = _util.Util.applyTransform(rect, transform); + + const p2 = _util.Util.applyTransform(rect.slice(2), transform); + + this.minX = Math.min(this.minX, p1[0], p2[0]); + this.minY = Math.min(this.minY, p1[1], p2[1]); + this.maxX = Math.max(this.maxX, p1[0], p2[0]); + this.maxY = Math.max(this.maxY, p1[1], p2[1]); + } + + updateScalingPathMinMax(transform, minMax) { + _util.Util.scaleMinMax(transform, minMax); + + this.minX = Math.min(this.minX, minMax[0]); + this.maxX = Math.max(this.maxX, minMax[1]); + this.minY = Math.min(this.minY, minMax[2]); + this.maxY = Math.max(this.maxY, minMax[3]); + } + + updateCurvePathMinMax(transform, x0, y0, x1, y1, x2, y2, x3, y3, minMax) { + const box = _util.Util.bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3); + + if (minMax) { + minMax[0] = Math.min(minMax[0], box[0], box[2]); + minMax[1] = Math.max(minMax[1], box[0], box[2]); + minMax[2] = Math.min(minMax[2], box[1], box[3]); + minMax[3] = Math.max(minMax[3], box[1], box[3]); + return; } - }; - return CanvasExtraState; -}(); -var CanvasGraphics = function CanvasGraphicsClosure() { - var EXECUTION_TIME = 15; - var EXECUTION_STEPS = 10; + this.updateRectMinMax(transform, box); + } - function CanvasGraphics(canvasCtx, commonObjs, objs, canvasFactory, webGLContext, imageLayer, optionalContentConfig) { + getPathBoundingBox(pathType = _pattern_helper.PathType.FILL, transform = null) { + const box = [this.minX, this.minY, this.maxX, this.maxY]; + + if (pathType === _pattern_helper.PathType.STROKE) { + if (!transform) { + (0, _util.unreachable)("Stroke bounding box must include transform."); + } + + const scale = _util.Util.singularValueDecompose2dScale(transform); + + const xStrokePad = scale[0] * this.lineWidth / 2; + const yStrokePad = scale[1] * this.lineWidth / 2; + box[0] -= xStrokePad; + box[1] -= yStrokePad; + box[2] += xStrokePad; + box[3] += yStrokePad; + } + + return box; + } + + updateClipFromPath() { + const intersect = _util.Util.intersect(this.clipBox, this.getPathBoundingBox()); + + this.startNewPathAndClipBox(intersect || [0, 0, 0, 0]); + } + + isEmptyClip() { + return this.minX === Infinity; + } + + startNewPathAndClipBox(box) { + this.clipBox = box; + this.minX = Infinity; + this.minY = Infinity; + this.maxX = 0; + this.maxY = 0; + } + + getClippedPathBoundingBox(pathType = _pattern_helper.PathType.FILL, transform = null) { + return _util.Util.intersect(this.clipBox, this.getPathBoundingBox(pathType, transform)); + } + +} + +function putBinaryImageData(ctx, imgData, transferMaps = null) { + if (typeof ImageData !== "undefined" && imgData instanceof ImageData) { + ctx.putImageData(imgData, 0, 0); + return; + } + + const height = imgData.height, + width = imgData.width; + const partialChunkHeight = height % FULL_CHUNK_HEIGHT; + const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; + const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; + const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); + let srcPos = 0, + destPos; + const src = imgData.data; + const dest = chunkImgData.data; + let i, j, thisChunkHeight, elemsInThisChunk; + let transferMapRed, transferMapGreen, transferMapBlue, transferMapGray; + + if (transferMaps) { + switch (transferMaps.length) { + case 1: + transferMapRed = transferMaps[0]; + transferMapGreen = transferMaps[0]; + transferMapBlue = transferMaps[0]; + transferMapGray = transferMaps[0]; + break; + + case 4: + transferMapRed = transferMaps[0]; + transferMapGreen = transferMaps[1]; + transferMapBlue = transferMaps[2]; + transferMapGray = transferMaps[3]; + break; + } + } + + if (imgData.kind === _util.ImageKind.GRAYSCALE_1BPP) { + const srcLength = src.byteLength; + const dest32 = new Uint32Array(dest.buffer, 0, dest.byteLength >> 2); + const dest32DataLength = dest32.length; + const fullSrcDiff = width + 7 >> 3; + let white = 0xffffffff; + let black = _util.FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff; + + if (transferMapGray) { + if (transferMapGray[0] === 0xff && transferMapGray[0xff] === 0) { + [white, black] = [black, white]; + } + } + + for (i = 0; i < totalChunks; i++) { + thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight; + destPos = 0; + + for (j = 0; j < thisChunkHeight; j++) { + const srcDiff = srcLength - srcPos; + let k = 0; + const kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7; + const kEndUnrolled = kEnd & ~7; + let mask = 0; + let srcByte = 0; + + for (; k < kEndUnrolled; k += 8) { + srcByte = src[srcPos++]; + dest32[destPos++] = srcByte & 128 ? white : black; + dest32[destPos++] = srcByte & 64 ? white : black; + dest32[destPos++] = srcByte & 32 ? white : black; + dest32[destPos++] = srcByte & 16 ? white : black; + dest32[destPos++] = srcByte & 8 ? white : black; + dest32[destPos++] = srcByte & 4 ? white : black; + dest32[destPos++] = srcByte & 2 ? white : black; + dest32[destPos++] = srcByte & 1 ? white : black; + } + + for (; k < kEnd; k++) { + if (mask === 0) { + srcByte = src[srcPos++]; + mask = 128; + } + + dest32[destPos++] = srcByte & mask ? white : black; + mask >>= 1; + } + } + + while (destPos < dest32DataLength) { + dest32[destPos++] = 0; + } + + ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); + } + } else if (imgData.kind === _util.ImageKind.RGBA_32BPP) { + const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue); + j = 0; + elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4; + + for (i = 0; i < fullChunks; i++) { + dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); + srcPos += elemsInThisChunk; + + if (hasTransferMaps) { + for (let k = 0; k < elemsInThisChunk; k += 4) { + if (transferMapRed) { + dest[k + 0] = transferMapRed[dest[k + 0]]; + } + + if (transferMapGreen) { + dest[k + 1] = transferMapGreen[dest[k + 1]]; + } + + if (transferMapBlue) { + dest[k + 2] = transferMapBlue[dest[k + 2]]; + } + } + } + + ctx.putImageData(chunkImgData, 0, j); + j += FULL_CHUNK_HEIGHT; + } + + if (i < totalChunks) { + elemsInThisChunk = width * partialChunkHeight * 4; + dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); + + if (hasTransferMaps) { + for (let k = 0; k < elemsInThisChunk; k += 4) { + if (transferMapRed) { + dest[k + 0] = transferMapRed[dest[k + 0]]; + } + + if (transferMapGreen) { + dest[k + 1] = transferMapGreen[dest[k + 1]]; + } + + if (transferMapBlue) { + dest[k + 2] = transferMapBlue[dest[k + 2]]; + } + } + } + + ctx.putImageData(chunkImgData, 0, j); + } + } else if (imgData.kind === _util.ImageKind.RGB_24BPP) { + const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue); + thisChunkHeight = FULL_CHUNK_HEIGHT; + elemsInThisChunk = width * thisChunkHeight; + + for (i = 0; i < totalChunks; i++) { + if (i >= fullChunks) { + thisChunkHeight = partialChunkHeight; + elemsInThisChunk = width * thisChunkHeight; + } + + destPos = 0; + + for (j = elemsInThisChunk; j--;) { + dest[destPos++] = src[srcPos++]; + dest[destPos++] = src[srcPos++]; + dest[destPos++] = src[srcPos++]; + dest[destPos++] = 255; + } + + if (hasTransferMaps) { + for (let k = 0; k < destPos; k += 4) { + if (transferMapRed) { + dest[k + 0] = transferMapRed[dest[k + 0]]; + } + + if (transferMapGreen) { + dest[k + 1] = transferMapGreen[dest[k + 1]]; + } + + if (transferMapBlue) { + dest[k + 2] = transferMapBlue[dest[k + 2]]; + } + } + } + + ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); + } + } else { + throw new Error(`bad image kind: ${imgData.kind}`); + } +} + +function putBinaryImageMask(ctx, imgData) { + if (imgData.bitmap) { + ctx.drawImage(imgData.bitmap, 0, 0); + return; + } + + const height = imgData.height, + width = imgData.width; + const partialChunkHeight = height % FULL_CHUNK_HEIGHT; + const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; + const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; + const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); + let srcPos = 0; + const src = imgData.data; + const dest = chunkImgData.data; + + for (let i = 0; i < totalChunks; i++) { + const thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight; + ({ + srcPos + } = (0, _image_utils.applyMaskImageData)({ + src, + srcPos, + dest, + width, + height: thisChunkHeight + })); + ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); + } +} + +function copyCtxState(sourceCtx, destCtx) { + const properties = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font"]; + + for (let i = 0, ii = properties.length; i < ii; i++) { + const property = properties[i]; + + if (sourceCtx[property] !== undefined) { + destCtx[property] = sourceCtx[property]; + } + } + + if (sourceCtx.setLineDash !== undefined) { + destCtx.setLineDash(sourceCtx.getLineDash()); + destCtx.lineDashOffset = sourceCtx.lineDashOffset; + } +} + +function resetCtxToDefault(ctx, foregroundColor) { + ctx.strokeStyle = ctx.fillStyle = foregroundColor || "#000000"; + ctx.fillRule = "nonzero"; + ctx.globalAlpha = 1; + ctx.lineWidth = 1; + ctx.lineCap = "butt"; + ctx.lineJoin = "miter"; + ctx.miterLimit = 10; + ctx.globalCompositeOperation = "source-over"; + ctx.font = "10px sans-serif"; + + if (ctx.setLineDash !== undefined) { + ctx.setLineDash([]); + ctx.lineDashOffset = 0; + } +} + +function composeSMaskBackdrop(bytes, r0, g0, b0) { + const length = bytes.length; + + for (let i = 3; i < length; i += 4) { + const alpha = bytes[i]; + + if (alpha === 0) { + bytes[i - 3] = r0; + bytes[i - 2] = g0; + bytes[i - 1] = b0; + } else if (alpha < 255) { + const alpha_ = 255 - alpha; + bytes[i - 3] = bytes[i - 3] * alpha + r0 * alpha_ >> 8; + bytes[i - 2] = bytes[i - 2] * alpha + g0 * alpha_ >> 8; + bytes[i - 1] = bytes[i - 1] * alpha + b0 * alpha_ >> 8; + } + } +} + +function composeSMaskAlpha(maskData, layerData, transferMap) { + const length = maskData.length; + const scale = 1 / 255; + + for (let i = 3; i < length; i += 4) { + const alpha = transferMap ? transferMap[maskData[i]] : maskData[i]; + layerData[i] = layerData[i] * alpha * scale | 0; + } +} + +function composeSMaskLuminosity(maskData, layerData, transferMap) { + const length = maskData.length; + + for (let i = 3; i < length; i += 4) { + const y = maskData[i - 3] * 77 + maskData[i - 2] * 152 + maskData[i - 1] * 28; + layerData[i] = transferMap ? layerData[i] * transferMap[y >> 8] >> 8 : layerData[i] * y >> 16; + } +} + +function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap, layerOffsetX, layerOffsetY, maskOffsetX, maskOffsetY) { + const hasBackdrop = !!backdrop; + const r0 = hasBackdrop ? backdrop[0] : 0; + const g0 = hasBackdrop ? backdrop[1] : 0; + const b0 = hasBackdrop ? backdrop[2] : 0; + let composeFn; + + if (subtype === "Luminosity") { + composeFn = composeSMaskLuminosity; + } else { + composeFn = composeSMaskAlpha; + } + + const PIXELS_TO_PROCESS = 1048576; + const chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width)); + + for (let row = 0; row < height; row += chunkSize) { + const chunkHeight = Math.min(chunkSize, height - row); + const maskData = maskCtx.getImageData(layerOffsetX - maskOffsetX, row + (layerOffsetY - maskOffsetY), width, chunkHeight); + const layerData = layerCtx.getImageData(layerOffsetX, row + layerOffsetY, width, chunkHeight); + + if (hasBackdrop) { + composeSMaskBackdrop(maskData.data, r0, g0, b0); + } + + composeFn(maskData.data, layerData.data, transferMap); + layerCtx.putImageData(layerData, layerOffsetX, row + layerOffsetY); + } +} + +function composeSMask(ctx, smask, layerCtx, layerBox) { + const layerOffsetX = layerBox[0]; + const layerOffsetY = layerBox[1]; + const layerWidth = layerBox[2] - layerOffsetX; + const layerHeight = layerBox[3] - layerOffsetY; + + if (layerWidth === 0 || layerHeight === 0) { + return; + } + + genericComposeSMask(smask.context, layerCtx, layerWidth, layerHeight, smask.subtype, smask.backdrop, smask.transferMap, layerOffsetX, layerOffsetY, smask.offsetX, smask.offsetY); + ctx.save(); + ctx.globalAlpha = 1; + ctx.globalCompositeOperation = "source-over"; + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.drawImage(layerCtx.canvas, 0, 0); + ctx.restore(); +} + +function getImageSmoothingEnabled(transform, interpolate) { + const scale = _util.Util.singularValueDecompose2dScale(transform); + + scale[0] = Math.fround(scale[0]); + scale[1] = Math.fround(scale[1]); + const actualScale = Math.fround((globalThis.devicePixelRatio || 1) * _display_utils.PixelsPerInch.PDF_TO_CSS_UNITS); + + if (interpolate !== undefined) { + return interpolate; + } else if (scale[0] <= actualScale || scale[1] <= actualScale) { + return true; + } + + return false; +} + +const LINE_CAP_STYLES = ["butt", "round", "square"]; +const LINE_JOIN_STYLES = ["miter", "round", "bevel"]; +const NORMAL_CLIP = {}; +const EO_CLIP = {}; + +class CanvasGraphics { + constructor(canvasCtx, commonObjs, objs, canvasFactory, imageLayer, optionalContentConfig, annotationCanvasMap, pageColors) { this.ctx = canvasCtx; - this.current = new CanvasExtraState(); + this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height); this.stateStack = []; this.pendingClip = null; this.pendingEOFill = false; @@ -4887,7 +6980,6 @@ var CanvasGraphics = function CanvasGraphicsClosure() { this.commonObjs = commonObjs; this.objs = objs; this.canvasFactory = canvasFactory; - this.webGLContext = webGLContext; this.imageLayer = imageLayer; this.groupStack = []; this.processingType3 = null; @@ -4897,1841 +6989,1918 @@ var CanvasGraphics = function CanvasGraphicsClosure() { this.smaskStack = []; this.smaskCounter = 0; this.tempSMask = null; + this.suspendedCtx = null; this.contentVisible = true; this.markedContentStack = []; this.optionalContentConfig = optionalContentConfig; this.cachedCanvases = new CachedCanvases(this.canvasFactory); - - if (canvasCtx) { - addContextCurrentTransform(canvasCtx); - } - + this.cachedPatterns = new Map(); + this.annotationCanvasMap = annotationCanvasMap; + this.viewportScale = 1; + this.outputScaleX = 1; + this.outputScaleY = 1; + this.backgroundColor = pageColors?.background || null; + this.foregroundColor = pageColors?.foreground || null; + this._cachedScaleForStroking = null; this._cachedGetSinglePixelWidth = null; + this._cachedBitmapsMap = new Map(); } - function putBinaryImageData(ctx, imgData, transferMaps = null) { - if (typeof ImageData !== "undefined" && imgData instanceof ImageData) { - ctx.putImageData(imgData, 0, 0); - return; + getObject(data, fallback = null) { + if (typeof data === "string") { + return data.startsWith("g_") ? this.commonObjs.get(data) : this.objs.get(data); } - var height = imgData.height, - width = imgData.width; - var partialChunkHeight = height % FULL_CHUNK_HEIGHT; - var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; - var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; - var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); - var srcPos = 0, - destPos; - var src = imgData.data; - var dest = chunkImgData.data; - var i, j, thisChunkHeight, elemsInThisChunk; - let transferMapRed, transferMapGreen, transferMapBlue, transferMapGray; + return fallback; + } - if (transferMaps) { - switch (transferMaps.length) { - case 1: - transferMapRed = transferMaps[0]; - transferMapGreen = transferMaps[0]; - transferMapBlue = transferMaps[0]; - transferMapGray = transferMaps[0]; - break; + beginDrawing({ + transform, + viewport, + transparency = false, + background = null + }) { + const width = this.ctx.canvas.width; + const height = this.ctx.canvas.height; + const defaultBackgroundColor = background || "#ffffff"; + this.ctx.save(); - case 4: - transferMapRed = transferMaps[0]; - transferMapGreen = transferMaps[1]; - transferMapBlue = transferMaps[2]; - transferMapGray = transferMaps[3]; - break; + if (this.foregroundColor && this.backgroundColor) { + this.ctx.fillStyle = this.foregroundColor; + const fg = this.foregroundColor = this.ctx.fillStyle; + this.ctx.fillStyle = this.backgroundColor; + const bg = this.backgroundColor = this.ctx.fillStyle; + let isValidDefaultBg = true; + let defaultBg = defaultBackgroundColor; + this.ctx.fillStyle = defaultBackgroundColor; + defaultBg = this.ctx.fillStyle; + isValidDefaultBg = typeof defaultBg === "string" && /^#[0-9A-Fa-f]{6}$/.test(defaultBg); + + if (fg === "#000000" && bg === "#ffffff" || fg === bg || !isValidDefaultBg) { + this.foregroundColor = this.backgroundColor = null; + } else { + const [rB, gB, bB] = (0, _display_utils.getRGB)(defaultBg); + + const newComp = x => { + x /= 255; + return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4; + }; + + const lumB = Math.round(0.2126 * newComp(rB) + 0.7152 * newComp(gB) + 0.0722 * newComp(bB)); + + this.selectColor = (r, g, b) => { + const lumC = 0.2126 * newComp(r) + 0.7152 * newComp(g) + 0.0722 * newComp(b); + return Math.round(lumC) === lumB ? bg : fg; + }; } } - if (imgData.kind === _util.ImageKind.GRAYSCALE_1BPP) { - var srcLength = src.byteLength; - var dest32 = new Uint32Array(dest.buffer, 0, dest.byteLength >> 2); - var dest32DataLength = dest32.length; - var fullSrcDiff = width + 7 >> 3; - var white = 0xffffffff; - var black = _util.IsLittleEndianCached.value ? 0xff000000 : 0x000000ff; + this.ctx.fillStyle = this.backgroundColor || defaultBackgroundColor; + this.ctx.fillRect(0, 0, width, height); + this.ctx.restore(); - if (transferMapGray) { - if (transferMapGray[0] === 0xff && transferMapGray[0xff] === 0) { - [white, black] = [black, white]; - } - } - - for (i = 0; i < totalChunks; i++) { - thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight; - destPos = 0; - - for (j = 0; j < thisChunkHeight; j++) { - var srcDiff = srcLength - srcPos; - let k = 0; - var kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7; - var kEndUnrolled = kEnd & ~7; - var mask = 0; - var srcByte = 0; - - for (; k < kEndUnrolled; k += 8) { - srcByte = src[srcPos++]; - dest32[destPos++] = srcByte & 128 ? white : black; - dest32[destPos++] = srcByte & 64 ? white : black; - dest32[destPos++] = srcByte & 32 ? white : black; - dest32[destPos++] = srcByte & 16 ? white : black; - dest32[destPos++] = srcByte & 8 ? white : black; - dest32[destPos++] = srcByte & 4 ? white : black; - dest32[destPos++] = srcByte & 2 ? white : black; - dest32[destPos++] = srcByte & 1 ? white : black; - } - - for (; k < kEnd; k++) { - if (mask === 0) { - srcByte = src[srcPos++]; - mask = 128; - } - - dest32[destPos++] = srcByte & mask ? white : black; - mask >>= 1; - } - } - - while (destPos < dest32DataLength) { - dest32[destPos++] = 0; - } - - ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); - } - } else if (imgData.kind === _util.ImageKind.RGBA_32BPP) { - const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue); - j = 0; - elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4; - - for (i = 0; i < fullChunks; i++) { - dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); - srcPos += elemsInThisChunk; - - if (hasTransferMaps) { - for (let k = 0; k < elemsInThisChunk; k += 4) { - if (transferMapRed) { - dest[k + 0] = transferMapRed[dest[k + 0]]; - } - - if (transferMapGreen) { - dest[k + 1] = transferMapGreen[dest[k + 1]]; - } - - if (transferMapBlue) { - dest[k + 2] = transferMapBlue[dest[k + 2]]; - } - } - } - - ctx.putImageData(chunkImgData, 0, j); - j += FULL_CHUNK_HEIGHT; - } - - if (i < totalChunks) { - elemsInThisChunk = width * partialChunkHeight * 4; - dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); - - if (hasTransferMaps) { - for (let k = 0; k < elemsInThisChunk; k += 4) { - if (transferMapRed) { - dest[k + 0] = transferMapRed[dest[k + 0]]; - } - - if (transferMapGreen) { - dest[k + 1] = transferMapGreen[dest[k + 1]]; - } - - if (transferMapBlue) { - dest[k + 2] = transferMapBlue[dest[k + 2]]; - } - } - } - - ctx.putImageData(chunkImgData, 0, j); - } - } else if (imgData.kind === _util.ImageKind.RGB_24BPP) { - const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue); - thisChunkHeight = FULL_CHUNK_HEIGHT; - elemsInThisChunk = width * thisChunkHeight; - - for (i = 0; i < totalChunks; i++) { - if (i >= fullChunks) { - thisChunkHeight = partialChunkHeight; - elemsInThisChunk = width * thisChunkHeight; - } - - destPos = 0; - - for (j = elemsInThisChunk; j--;) { - dest[destPos++] = src[srcPos++]; - dest[destPos++] = src[srcPos++]; - dest[destPos++] = src[srcPos++]; - dest[destPos++] = 255; - } - - if (hasTransferMaps) { - for (let k = 0; k < destPos; k += 4) { - if (transferMapRed) { - dest[k + 0] = transferMapRed[dest[k + 0]]; - } - - if (transferMapGreen) { - dest[k + 1] = transferMapGreen[dest[k + 1]]; - } - - if (transferMapBlue) { - dest[k + 2] = transferMapBlue[dest[k + 2]]; - } - } - } - - ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); - } - } else { - throw new Error(`bad image kind: ${imgData.kind}`); - } - } - - function putBinaryImageMask(ctx, imgData) { - var height = imgData.height, - width = imgData.width; - var partialChunkHeight = height % FULL_CHUNK_HEIGHT; - var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; - var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; - var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); - var srcPos = 0; - var src = imgData.data; - var dest = chunkImgData.data; - - for (var i = 0; i < totalChunks; i++) { - var thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight; - var destPos = 3; - - for (var j = 0; j < thisChunkHeight; j++) { - var mask = 0; - - for (var k = 0; k < width; k++) { - if (!mask) { - var elem = src[srcPos++]; - mask = 128; - } - - dest[destPos] = elem & mask ? 0 : 255; - destPos += 4; - mask >>= 1; - } - } - - ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); - } - } - - function copyCtxState(sourceCtx, destCtx) { - var properties = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font"]; - - for (var i = 0, ii = properties.length; i < ii; i++) { - var property = properties[i]; - - if (sourceCtx[property] !== undefined) { - destCtx[property] = sourceCtx[property]; - } - } - - if (sourceCtx.setLineDash !== undefined) { - destCtx.setLineDash(sourceCtx.getLineDash()); - destCtx.lineDashOffset = sourceCtx.lineDashOffset; - } - } - - function resetCtxToDefault(ctx) { - ctx.strokeStyle = "#000000"; - ctx.fillStyle = "#000000"; - ctx.fillRule = "nonzero"; - ctx.globalAlpha = 1; - ctx.lineWidth = 1; - ctx.lineCap = "butt"; - ctx.lineJoin = "miter"; - ctx.miterLimit = 10; - ctx.globalCompositeOperation = "source-over"; - ctx.font = "10px sans-serif"; - - if (ctx.setLineDash !== undefined) { - ctx.setLineDash([]); - ctx.lineDashOffset = 0; - } - } - - function composeSMaskBackdrop(bytes, r0, g0, b0) { - var length = bytes.length; - - for (var i = 3; i < length; i += 4) { - var alpha = bytes[i]; - - if (alpha === 0) { - bytes[i - 3] = r0; - bytes[i - 2] = g0; - bytes[i - 1] = b0; - } else if (alpha < 255) { - var alpha_ = 255 - alpha; - bytes[i - 3] = bytes[i - 3] * alpha + r0 * alpha_ >> 8; - bytes[i - 2] = bytes[i - 2] * alpha + g0 * alpha_ >> 8; - bytes[i - 1] = bytes[i - 1] * alpha + b0 * alpha_ >> 8; - } - } - } - - function composeSMaskAlpha(maskData, layerData, transferMap) { - var length = maskData.length; - var scale = 1 / 255; - - for (var i = 3; i < length; i += 4) { - var alpha = transferMap ? transferMap[maskData[i]] : maskData[i]; - layerData[i] = layerData[i] * alpha * scale | 0; - } - } - - function composeSMaskLuminosity(maskData, layerData, transferMap) { - var length = maskData.length; - - for (var i = 3; i < length; i += 4) { - var y = maskData[i - 3] * 77 + maskData[i - 2] * 152 + maskData[i - 1] * 28; - layerData[i] = transferMap ? layerData[i] * transferMap[y >> 8] >> 8 : layerData[i] * y >> 16; - } - } - - function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap) { - var hasBackdrop = !!backdrop; - var r0 = hasBackdrop ? backdrop[0] : 0; - var g0 = hasBackdrop ? backdrop[1] : 0; - var b0 = hasBackdrop ? backdrop[2] : 0; - var composeFn; - - if (subtype === "Luminosity") { - composeFn = composeSMaskLuminosity; - } else { - composeFn = composeSMaskAlpha; - } - - var PIXELS_TO_PROCESS = 1048576; - var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width)); - - for (var row = 0; row < height; row += chunkSize) { - var chunkHeight = Math.min(chunkSize, height - row); - var maskData = maskCtx.getImageData(0, row, width, chunkHeight); - var layerData = layerCtx.getImageData(0, row, width, chunkHeight); - - if (hasBackdrop) { - composeSMaskBackdrop(maskData.data, r0, g0, b0); - } - - composeFn(maskData.data, layerData.data, transferMap); - maskCtx.putImageData(layerData, 0, row); - } - } - - function composeSMask(ctx, smask, layerCtx, webGLContext) { - var mask = smask.canvas; - var maskCtx = smask.context; - ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY, smask.offsetX, smask.offsetY); - var backdrop = smask.backdrop || null; - - if (!smask.transferMap && webGLContext.isEnabled) { - const composed = webGLContext.composeSMask({ - layer: layerCtx.canvas, - mask, - properties: { - subtype: smask.subtype, - backdrop - } - }); - ctx.setTransform(1, 0, 0, 1, 0, 0); - ctx.drawImage(composed, smask.offsetX, smask.offsetY); - return; - } - - genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height, smask.subtype, backdrop, smask.transferMap); - ctx.drawImage(mask, 0, 0); - } - - var LINE_CAP_STYLES = ["butt", "round", "square"]; - var LINE_JOIN_STYLES = ["miter", "round", "bevel"]; - var NORMAL_CLIP = {}; - var EO_CLIP = {}; - CanvasGraphics.prototype = { - beginDrawing({ - transform, - viewport, - transparency = false, - background = null - }) { - var width = this.ctx.canvas.width; - var height = this.ctx.canvas.height; + if (transparency) { + const transparentCanvas = this.cachedCanvases.getCanvas("transparent", width, height); + this.compositeCtx = this.ctx; + this.transparentCanvas = transparentCanvas.canvas; + this.ctx = transparentCanvas.context; this.ctx.save(); - this.ctx.fillStyle = background || "rgb(255, 255, 255)"; - this.ctx.fillRect(0, 0, width, height); - this.ctx.restore(); + this.ctx.transform(...(0, _display_utils.getCurrentTransform)(this.compositeCtx)); + } - if (transparency) { - var transparentCanvas = this.cachedCanvases.getCanvas("transparent", width, height, true); - this.compositeCtx = this.ctx; - this.transparentCanvas = transparentCanvas.canvas; - this.ctx = transparentCanvas.context; - this.ctx.save(); - this.ctx.transform.apply(this.ctx, this.compositeCtx.mozCurrentTransform); - } + this.ctx.save(); + resetCtxToDefault(this.ctx, this.foregroundColor); - this.ctx.save(); - resetCtxToDefault(this.ctx); + if (transform) { + this.ctx.transform(...transform); + this.outputScaleX = transform[0]; + this.outputScaleY = transform[0]; + } - if (transform) { - this.ctx.transform.apply(this.ctx, transform); - } + this.ctx.transform(...viewport.transform); + this.viewportScale = viewport.scale; + this.baseTransform = (0, _display_utils.getCurrentTransform)(this.ctx); - this.ctx.transform.apply(this.ctx, viewport.transform); - this.baseTransform = this.ctx.mozCurrentTransform.slice(); + if (this.imageLayer) { + (0, _display_utils.deprecated)("The `imageLayer` functionality will be removed in the future."); + this.imageLayer.beginLayout(); + } + } - if (this.imageLayer) { - this.imageLayer.beginLayout(); - } - }, + executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper) { + const argsArray = operatorList.argsArray; + const fnArray = operatorList.fnArray; + let i = executionStartIdx || 0; + const argsArrayLen = argsArray.length; - executeOperatorList: function CanvasGraphics_executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper) { - var argsArray = operatorList.argsArray; - var fnArray = operatorList.fnArray; - var i = executionStartIdx || 0; - var argsArrayLen = argsArray.length; + if (argsArrayLen === i) { + return i; + } - if (argsArrayLen === i) { + const chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function"; + const endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0; + let steps = 0; + const commonObjs = this.commonObjs; + const objs = this.objs; + let fnId; + + while (true) { + if (stepper !== undefined && i === stepper.nextBreakPoint) { + stepper.breakIt(i, continueCallback); return i; } - var chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function"; - var endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0; - var steps = 0; - var commonObjs = this.commonObjs; - var objs = this.objs; - var fnId; + fnId = fnArray[i]; - while (true) { - if (stepper !== undefined && i === stepper.nextBreakPoint) { - stepper.breakIt(i, continueCallback); - return i; - } + if (fnId !== _util.OPS.dependency) { + this[fnId].apply(this, argsArray[i]); + } else { + for (const depObjId of argsArray[i]) { + const objsPool = depObjId.startsWith("g_") ? commonObjs : objs; - fnId = fnArray[i]; - - if (fnId !== _util.OPS.dependency) { - this[fnId].apply(this, argsArray[i]); - } else { - for (const depObjId of argsArray[i]) { - const objsPool = depObjId.startsWith("g_") ? commonObjs : objs; - - if (!objsPool.has(depObjId)) { - objsPool.get(depObjId, continueCallback); - return i; - } - } - } - - i++; - - if (i === argsArrayLen) { - return i; - } - - if (chunkOperations && ++steps > EXECUTION_STEPS) { - if (Date.now() > endTime) { - continueCallback(); + if (!objsPool.has(depObjId)) { + objsPool.get(depObjId, continueCallback); return i; } - - steps = 0; } } - }, - endDrawing: function CanvasGraphics_endDrawing() { - if (this.current.activeSMask !== null) { - this.endSMaskGroup(); + + i++; + + if (i === argsArrayLen) { + return i; } + if (chunkOperations && ++steps > EXECUTION_STEPS) { + if (Date.now() > endTime) { + continueCallback(); + return i; + } + + steps = 0; + } + } + } + + #restoreInitialState() { + while (this.stateStack.length || this.inSMaskMode) { + this.restore(); + } + + this.ctx.restore(); + + if (this.transparentCanvas) { + this.ctx = this.compositeCtx; + this.ctx.save(); + this.ctx.setTransform(1, 0, 0, 1, 0, 0); + this.ctx.drawImage(this.transparentCanvas, 0, 0); this.ctx.restore(); + this.transparentCanvas = null; + } + } - if (this.transparentCanvas) { - this.ctx = this.compositeCtx; - this.ctx.save(); - this.ctx.setTransform(1, 0, 0, 1, 0, 0); - this.ctx.drawImage(this.transparentCanvas, 0, 0); - this.ctx.restore(); - this.transparentCanvas = null; - } + endDrawing() { + this.#restoreInitialState(); + this.cachedCanvases.clear(); + this.cachedPatterns.clear(); - this.cachedCanvases.clear(); - this.webGLContext.clear(); - - if (this.imageLayer) { - this.imageLayer.endLayout(); - } - }, - setLineWidth: function CanvasGraphics_setLineWidth(width) { - this.current.lineWidth = width; - this.ctx.lineWidth = width; - }, - setLineCap: function CanvasGraphics_setLineCap(style) { - this.ctx.lineCap = LINE_CAP_STYLES[style]; - }, - setLineJoin: function CanvasGraphics_setLineJoin(style) { - this.ctx.lineJoin = LINE_JOIN_STYLES[style]; - }, - setMiterLimit: function CanvasGraphics_setMiterLimit(limit) { - this.ctx.miterLimit = limit; - }, - setDash: function CanvasGraphics_setDash(dashArray, dashPhase) { - var ctx = this.ctx; - - if (ctx.setLineDash !== undefined) { - ctx.setLineDash(dashArray); - ctx.lineDashOffset = dashPhase; - } - }, - - setRenderingIntent(intent) {}, - - setFlatness(flatness) {}, - - setGState: function CanvasGraphics_setGState(states) { - for (var i = 0, ii = states.length; i < ii; i++) { - var state = states[i]; - var key = state[0]; - var value = state[1]; - - switch (key) { - case "LW": - this.setLineWidth(value); - break; - - case "LC": - this.setLineCap(value); - break; - - case "LJ": - this.setLineJoin(value); - break; - - case "ML": - this.setMiterLimit(value); - break; - - case "D": - this.setDash(value[0], value[1]); - break; - - case "RI": - this.setRenderingIntent(value); - break; - - case "FL": - this.setFlatness(value); - break; - - case "Font": - this.setFont(value[0], value[1]); - break; - - case "CA": - this.current.strokeAlpha = state[1]; - break; - - case "ca": - this.current.fillAlpha = state[1]; - this.ctx.globalAlpha = state[1]; - break; - - case "BM": - this.ctx.globalCompositeOperation = value; - break; - - case "SMask": - if (this.current.activeSMask) { - if (this.stateStack.length > 0 && this.stateStack[this.stateStack.length - 1].activeSMask === this.current.activeSMask) { - this.suspendSMaskGroup(); - } else { - this.endSMaskGroup(); - } - } - - this.current.activeSMask = value ? this.tempSMask : null; - - if (this.current.activeSMask) { - this.beginSMaskGroup(); - } - - this.tempSMask = null; - break; - - case "TR": - this.current.transferMaps = value; + for (const cache of this._cachedBitmapsMap.values()) { + for (const canvas of cache.values()) { + if (typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement) { + canvas.width = canvas.height = 0; } } - }, - beginSMaskGroup: function CanvasGraphics_beginSMaskGroup() { - var activeSMask = this.current.activeSMask; - var drawnWidth = activeSMask.canvas.width; - var drawnHeight = activeSMask.canvas.height; - var cacheId = "smaskGroupAt" + this.groupLevel; - var scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true); - var currentCtx = this.ctx; - var currentTransform = currentCtx.mozCurrentTransform; - this.ctx.save(); - var groupCtx = scratchCanvas.context; - groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY); - groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY); - groupCtx.transform.apply(groupCtx, currentTransform); - activeSMask.startTransformInverse = groupCtx.mozCurrentTransformInverse; - copyCtxState(currentCtx, groupCtx); - this.ctx = groupCtx; - this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]); - this.groupStack.push(currentCtx); - this.groupLevel++; - }, - suspendSMaskGroup: function CanvasGraphics_endSMaskGroup() { - var groupCtx = this.ctx; - this.groupLevel--; - this.ctx = this.groupStack.pop(); - composeSMask(this.ctx, this.current.activeSMask, groupCtx, this.webGLContext); - this.ctx.restore(); - this.ctx.save(); - copyCtxState(groupCtx, this.ctx); - this.current.resumeSMaskCtx = groupCtx; - var deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform); + cache.clear(); + } - this.ctx.transform.apply(this.ctx, deltaTransform); - groupCtx.save(); - groupCtx.setTransform(1, 0, 0, 1, 0, 0); - groupCtx.clearRect(0, 0, groupCtx.canvas.width, groupCtx.canvas.height); - groupCtx.restore(); - }, - resumeSMaskGroup: function CanvasGraphics_endSMaskGroup() { - var groupCtx = this.current.resumeSMaskCtx; - var currentCtx = this.ctx; - this.ctx = groupCtx; - this.groupStack.push(currentCtx); - this.groupLevel++; - }, - endSMaskGroup: function CanvasGraphics_endSMaskGroup() { - var groupCtx = this.ctx; - this.groupLevel--; - this.ctx = this.groupStack.pop(); - composeSMask(this.ctx, this.current.activeSMask, groupCtx, this.webGLContext); - this.ctx.restore(); - copyCtxState(groupCtx, this.ctx); + this._cachedBitmapsMap.clear(); - var deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform); + if (this.imageLayer) { + this.imageLayer.endLayout(); + } + } - this.ctx.transform.apply(this.ctx, deltaTransform); - }, - save: function CanvasGraphics_save() { - this.ctx.save(); - var old = this.current; - this.stateStack.push(old); - this.current = old.clone(); - this.current.resumeSMaskCtx = null; - }, - restore: function CanvasGraphics_restore() { - if (this.current.resumeSMaskCtx) { - this.resumeSMaskGroup(); + _scaleImage(img, inverseTransform) { + const width = img.width; + const height = img.height; + let widthScale = Math.max(Math.hypot(inverseTransform[0], inverseTransform[1]), 1); + let heightScale = Math.max(Math.hypot(inverseTransform[2], inverseTransform[3]), 1); + let paintWidth = width, + paintHeight = height; + let tmpCanvasId = "prescale1"; + let tmpCanvas, tmpCtx; + + while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) { + let newWidth = paintWidth, + newHeight = paintHeight; + + if (widthScale > 2 && paintWidth > 1) { + newWidth = Math.ceil(paintWidth / 2); + widthScale /= paintWidth / newWidth; } - if (this.current.activeSMask !== null && (this.stateStack.length === 0 || this.stateStack[this.stateStack.length - 1].activeSMask !== this.current.activeSMask)) { - this.endSMaskGroup(); + if (heightScale > 2 && paintHeight > 1) { + newHeight = Math.ceil(paintHeight / 2); + heightScale /= paintHeight / newHeight; } - if (this.stateStack.length !== 0) { - this.current = this.stateStack.pop(); + tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight); + tmpCtx = tmpCanvas.context; + tmpCtx.clearRect(0, 0, newWidth, newHeight); + tmpCtx.drawImage(img, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight); + img = tmpCanvas.canvas; + paintWidth = newWidth; + paintHeight = newHeight; + tmpCanvasId = tmpCanvasId === "prescale1" ? "prescale2" : "prescale1"; + } + + return { + img, + paintWidth, + paintHeight + }; + } + + _createMaskCanvas(img) { + const ctx = this.ctx; + const { + width, + height + } = img; + const fillColor = this.current.fillColor; + const isPatternFill = this.current.patternFill; + const currentTransform = (0, _display_utils.getCurrentTransform)(ctx); + let cache, cacheKey, scaled, maskCanvas; + + if ((img.bitmap || img.data) && img.count > 1) { + const mainKey = img.bitmap || img.data.buffer; + const withoutTranslation = currentTransform.slice(0, 4); + cacheKey = JSON.stringify(isPatternFill ? withoutTranslation : [withoutTranslation, fillColor]); + cache = this._cachedBitmapsMap.get(mainKey); + + if (!cache) { + cache = new Map(); + + this._cachedBitmapsMap.set(mainKey, cache); + } + + const cachedImage = cache.get(cacheKey); + + if (cachedImage && !isPatternFill) { + const offsetX = Math.round(Math.min(currentTransform[0], currentTransform[2]) + currentTransform[4]); + const offsetY = Math.round(Math.min(currentTransform[1], currentTransform[3]) + currentTransform[5]); + return { + canvas: cachedImage, + offsetX, + offsetY + }; + } + + scaled = cachedImage; + } + + if (!scaled) { + maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height); + putBinaryImageMask(maskCanvas.context, img); + } + + let maskToCanvas = _util.Util.transform(currentTransform, [1 / width, 0, 0, -1 / height, 0, 0]); + + maskToCanvas = _util.Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]); + + const cord1 = _util.Util.applyTransform([0, 0], maskToCanvas); + + const cord2 = _util.Util.applyTransform([width, height], maskToCanvas); + + const rect = _util.Util.normalizeRect([cord1[0], cord1[1], cord2[0], cord2[1]]); + + const drawnWidth = Math.round(rect[2] - rect[0]) || 1; + const drawnHeight = Math.round(rect[3] - rect[1]) || 1; + const fillCanvas = this.cachedCanvases.getCanvas("fillCanvas", drawnWidth, drawnHeight); + const fillCtx = fillCanvas.context; + const offsetX = Math.min(cord1[0], cord2[0]); + const offsetY = Math.min(cord1[1], cord2[1]); + fillCtx.translate(-offsetX, -offsetY); + fillCtx.transform(...maskToCanvas); + + if (!scaled) { + scaled = this._scaleImage(maskCanvas.canvas, (0, _display_utils.getCurrentTransformInverse)(fillCtx)); + scaled = scaled.img; + + if (cache && isPatternFill) { + cache.set(cacheKey, scaled); + } + } + + fillCtx.imageSmoothingEnabled = getImageSmoothingEnabled((0, _display_utils.getCurrentTransform)(fillCtx), img.interpolate); + drawImageAtIntegerCoords(fillCtx, scaled, 0, 0, scaled.width, scaled.height, 0, 0, width, height); + fillCtx.globalCompositeOperation = "source-in"; + + const inverse = _util.Util.transform((0, _display_utils.getCurrentTransformInverse)(fillCtx), [1, 0, 0, 1, -offsetX, -offsetY]); + + fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, _pattern_helper.PathType.FILL) : fillColor; + fillCtx.fillRect(0, 0, width, height); + + if (cache && !isPatternFill) { + this.cachedCanvases.delete("fillCanvas"); + cache.set(cacheKey, fillCanvas.canvas); + } + + return { + canvas: fillCanvas.canvas, + offsetX: Math.round(offsetX), + offsetY: Math.round(offsetY) + }; + } + + setLineWidth(width) { + if (width !== this.current.lineWidth) { + this._cachedScaleForStroking = null; + } + + this.current.lineWidth = width; + this.ctx.lineWidth = width; + } + + setLineCap(style) { + this.ctx.lineCap = LINE_CAP_STYLES[style]; + } + + setLineJoin(style) { + this.ctx.lineJoin = LINE_JOIN_STYLES[style]; + } + + setMiterLimit(limit) { + this.ctx.miterLimit = limit; + } + + setDash(dashArray, dashPhase) { + const ctx = this.ctx; + + if (ctx.setLineDash !== undefined) { + ctx.setLineDash(dashArray); + ctx.lineDashOffset = dashPhase; + } + } + + setRenderingIntent(intent) {} + + setFlatness(flatness) {} + + setGState(states) { + for (let i = 0, ii = states.length; i < ii; i++) { + const state = states[i]; + const key = state[0]; + const value = state[1]; + + switch (key) { + case "LW": + this.setLineWidth(value); + break; + + case "LC": + this.setLineCap(value); + break; + + case "LJ": + this.setLineJoin(value); + break; + + case "ML": + this.setMiterLimit(value); + break; + + case "D": + this.setDash(value[0], value[1]); + break; + + case "RI": + this.setRenderingIntent(value); + break; + + case "FL": + this.setFlatness(value); + break; + + case "Font": + this.setFont(value[0], value[1]); + break; + + case "CA": + this.current.strokeAlpha = state[1]; + break; + + case "ca": + this.current.fillAlpha = state[1]; + this.ctx.globalAlpha = state[1]; + break; + + case "BM": + this.ctx.globalCompositeOperation = value; + break; + + case "SMask": + this.current.activeSMask = value ? this.tempSMask : null; + this.tempSMask = null; + this.checkSMaskState(); + break; + + case "TR": + this.current.transferMaps = value; + } + } + } + + get inSMaskMode() { + return !!this.suspendedCtx; + } + + checkSMaskState() { + const inSMaskMode = this.inSMaskMode; + + if (this.current.activeSMask && !inSMaskMode) { + this.beginSMaskMode(); + } else if (!this.current.activeSMask && inSMaskMode) { + this.endSMaskMode(); + } + } + + beginSMaskMode() { + if (this.inSMaskMode) { + throw new Error("beginSMaskMode called while already in smask mode"); + } + + const drawnWidth = this.ctx.canvas.width; + const drawnHeight = this.ctx.canvas.height; + const cacheId = "smaskGroupAt" + this.groupLevel; + const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight); + this.suspendedCtx = this.ctx; + this.ctx = scratchCanvas.context; + const ctx = this.ctx; + ctx.setTransform(...(0, _display_utils.getCurrentTransform)(this.suspendedCtx)); + copyCtxState(this.suspendedCtx, ctx); + mirrorContextOperations(ctx, this.suspendedCtx); + this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]); + } + + endSMaskMode() { + if (!this.inSMaskMode) { + throw new Error("endSMaskMode called while not in smask mode"); + } + + this.ctx._removeMirroring(); + + copyCtxState(this.ctx, this.suspendedCtx); + this.ctx = this.suspendedCtx; + this.suspendedCtx = null; + } + + compose(dirtyBox) { + if (!this.current.activeSMask) { + return; + } + + if (!dirtyBox) { + dirtyBox = [0, 0, this.ctx.canvas.width, this.ctx.canvas.height]; + } else { + dirtyBox[0] = Math.floor(dirtyBox[0]); + dirtyBox[1] = Math.floor(dirtyBox[1]); + dirtyBox[2] = Math.ceil(dirtyBox[2]); + dirtyBox[3] = Math.ceil(dirtyBox[3]); + } + + const smask = this.current.activeSMask; + const suspendedCtx = this.suspendedCtx; + composeSMask(suspendedCtx, smask, this.ctx, dirtyBox); + this.ctx.save(); + this.ctx.setTransform(1, 0, 0, 1, 0, 0); + this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); + this.ctx.restore(); + } + + save() { + if (this.inSMaskMode) { + copyCtxState(this.ctx, this.suspendedCtx); + this.suspendedCtx.save(); + } else { + this.ctx.save(); + } + + const old = this.current; + this.stateStack.push(old); + this.current = old.clone(); + } + + restore() { + if (this.stateStack.length === 0 && this.inSMaskMode) { + this.endSMaskMode(); + } + + if (this.stateStack.length !== 0) { + this.current = this.stateStack.pop(); + + if (this.inSMaskMode) { + this.suspendedCtx.restore(); + copyCtxState(this.suspendedCtx, this.ctx); + } else { this.ctx.restore(); - this.pendingClip = null; - this._cachedGetSinglePixelWidth = null; } - }, - transform: function CanvasGraphics_transform(a, b, c, d, e, f) { - this.ctx.transform(a, b, c, d, e, f); + + this.checkSMaskState(); + this.pendingClip = null; + this._cachedScaleForStroking = null; this._cachedGetSinglePixelWidth = null; - }, - constructPath: function CanvasGraphics_constructPath(ops, args) { - var ctx = this.ctx; - var current = this.current; - var x = current.x, - y = current.y; + } + } - for (var i = 0, j = 0, ii = ops.length; i < ii; i++) { - switch (ops[i] | 0) { - case _util.OPS.rectangle: - x = args[j++]; - y = args[j++]; - var width = args[j++]; - var height = args[j++]; + transform(a, b, c, d, e, f) { + this.ctx.transform(a, b, c, d, e, f); + this._cachedScaleForStroking = null; + this._cachedGetSinglePixelWidth = null; + } - if (width === 0 && ctx.lineWidth < this.getSinglePixelWidth()) { - width = this.getSinglePixelWidth(); - } + constructPath(ops, args, minMax) { + const ctx = this.ctx; + const current = this.current; + let x = current.x, + y = current.y; + let startX, startY; + const currentTransform = (0, _display_utils.getCurrentTransform)(ctx); + const isScalingMatrix = currentTransform[0] === 0 && currentTransform[3] === 0 || currentTransform[1] === 0 && currentTransform[2] === 0; + const minMaxForBezier = isScalingMatrix ? minMax.slice(0) : null; - if (height === 0 && ctx.lineWidth < this.getSinglePixelWidth()) { - height = this.getSinglePixelWidth(); - } + for (let i = 0, j = 0, ii = ops.length; i < ii; i++) { + switch (ops[i] | 0) { + case _util.OPS.rectangle: + x = args[j++]; + y = args[j++]; + const width = args[j++]; + const height = args[j++]; + const xw = x + width; + const yh = y + height; + ctx.moveTo(x, y); - var xw = x + width; - var yh = y + height; - ctx.moveTo(x, y); + if (width === 0 || height === 0) { + ctx.lineTo(xw, yh); + } else { ctx.lineTo(xw, y); ctx.lineTo(xw, yh); ctx.lineTo(x, yh); - ctx.lineTo(x, y); - ctx.closePath(); - break; + } - case _util.OPS.moveTo: - x = args[j++]; - y = args[j++]; - ctx.moveTo(x, y); - break; + if (!isScalingMatrix) { + current.updateRectMinMax(currentTransform, [x, y, xw, yh]); + } - case _util.OPS.lineTo: - x = args[j++]; - y = args[j++]; - ctx.lineTo(x, y); - break; + ctx.closePath(); + break; - case _util.OPS.curveTo: - x = args[j + 4]; - y = args[j + 5]; - ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y); - j += 6; - break; + case _util.OPS.moveTo: + x = args[j++]; + y = args[j++]; + ctx.moveTo(x, y); - case _util.OPS.curveTo2: - ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]); - x = args[j + 2]; - y = args[j + 3]; - j += 4; - break; + if (!isScalingMatrix) { + current.updatePathMinMax(currentTransform, x, y); + } - case _util.OPS.curveTo3: - x = args[j + 2]; - y = args[j + 3]; - ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y); - j += 4; - break; + break; - case _util.OPS.closePath: - ctx.closePath(); - break; - } + case _util.OPS.lineTo: + x = args[j++]; + y = args[j++]; + ctx.lineTo(x, y); + + if (!isScalingMatrix) { + current.updatePathMinMax(currentTransform, x, y); + } + + break; + + case _util.OPS.curveTo: + startX = x; + startY = y; + x = args[j + 4]; + y = args[j + 5]; + ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y); + current.updateCurvePathMinMax(currentTransform, startX, startY, args[j], args[j + 1], args[j + 2], args[j + 3], x, y, minMaxForBezier); + j += 6; + break; + + case _util.OPS.curveTo2: + startX = x; + startY = y; + ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]); + current.updateCurvePathMinMax(currentTransform, startX, startY, x, y, args[j], args[j + 1], args[j + 2], args[j + 3], minMaxForBezier); + x = args[j + 2]; + y = args[j + 3]; + j += 4; + break; + + case _util.OPS.curveTo3: + startX = x; + startY = y; + x = args[j + 2]; + y = args[j + 3]; + ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y); + current.updateCurvePathMinMax(currentTransform, startX, startY, args[j], args[j + 1], x, y, x, y, minMaxForBezier); + j += 4; + break; + + case _util.OPS.closePath: + ctx.closePath(); + break; } + } - current.setCurrentPoint(x, y); - }, - closePath: function CanvasGraphics_closePath() { - this.ctx.closePath(); - }, - stroke: function CanvasGraphics_stroke(consumePath) { - consumePath = typeof consumePath !== "undefined" ? consumePath : true; - var ctx = this.ctx; - var strokeColor = this.current.strokeColor; - ctx.globalAlpha = this.current.strokeAlpha; + if (isScalingMatrix) { + current.updateScalingPathMinMax(currentTransform, minMaxForBezier); + } - if (this.contentVisible) { - if (strokeColor && strokeColor.hasOwnProperty("type") && strokeColor.type === "Pattern") { - ctx.save(); - const transform = ctx.mozCurrentTransform; + current.setCurrentPoint(x, y); + } - const scale = _util.Util.singularValueDecompose2dScale(transform)[0]; + closePath() { + this.ctx.closePath(); + } - ctx.strokeStyle = strokeColor.getPattern(ctx, this); - ctx.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, this.current.lineWidth * scale); - ctx.stroke(); - ctx.restore(); - } else { - ctx.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, this.current.lineWidth); - ctx.stroke(); - } - } + stroke(consumePath) { + consumePath = typeof consumePath !== "undefined" ? consumePath : true; + const ctx = this.ctx; + const strokeColor = this.current.strokeColor; + ctx.globalAlpha = this.current.strokeAlpha; - if (consumePath) { - this.consumePath(); - } - - ctx.globalAlpha = this.current.fillAlpha; - }, - closeStroke: function CanvasGraphics_closeStroke() { - this.closePath(); - this.stroke(); - }, - fill: function CanvasGraphics_fill(consumePath) { - consumePath = typeof consumePath !== "undefined" ? consumePath : true; - var ctx = this.ctx; - var fillColor = this.current.fillColor; - var isPatternFill = this.current.patternFill; - var needRestore = false; - - if (isPatternFill) { + if (this.contentVisible) { + if (typeof strokeColor === "object" && strokeColor?.getPattern) { ctx.save(); - - if (this.baseTransform) { - ctx.setTransform.apply(ctx, this.baseTransform); - } - - ctx.fillStyle = fillColor.getPattern(ctx, this); - needRestore = true; - } - - if (this.contentVisible) { - if (this.pendingEOFill) { - ctx.fill("evenodd"); - this.pendingEOFill = false; - } else { - ctx.fill(); - } - } - - if (needRestore) { + ctx.strokeStyle = strokeColor.getPattern(ctx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.STROKE); + this.rescaleAndStroke(false); ctx.restore(); + } else { + this.rescaleAndStroke(true); } + } - if (consumePath) { - this.consumePath(); - } - }, - eoFill: function CanvasGraphics_eoFill() { - this.pendingEOFill = true; - this.fill(); - }, - fillStroke: function CanvasGraphics_fillStroke() { - this.fill(false); - this.stroke(false); - this.consumePath(); - }, - eoFillStroke: function CanvasGraphics_eoFillStroke() { - this.pendingEOFill = true; - this.fillStroke(); - }, - closeFillStroke: function CanvasGraphics_closeFillStroke() { - this.closePath(); - this.fillStroke(); - }, - closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() { - this.pendingEOFill = true; - this.closePath(); - this.fillStroke(); - }, - endPath: function CanvasGraphics_endPath() { - this.consumePath(); - }, - clip: function CanvasGraphics_clip() { - this.pendingClip = NORMAL_CLIP; - }, - eoClip: function CanvasGraphics_eoClip() { - this.pendingClip = EO_CLIP; - }, - beginText: function CanvasGraphics_beginText() { - this.current.textMatrix = _util.IDENTITY_MATRIX; - this.current.textMatrixScale = 1; - this.current.x = this.current.lineX = 0; - this.current.y = this.current.lineY = 0; - }, - endText: function CanvasGraphics_endText() { - var paths = this.pendingTextPaths; - var ctx = this.ctx; + if (consumePath) { + this.consumePath(this.current.getClippedPathBoundingBox()); + } - if (paths === undefined) { - ctx.beginPath(); - return; - } + ctx.globalAlpha = this.current.fillAlpha; + } + closeStroke() { + this.closePath(); + this.stroke(); + } + + fill(consumePath) { + consumePath = typeof consumePath !== "undefined" ? consumePath : true; + const ctx = this.ctx; + const fillColor = this.current.fillColor; + const isPatternFill = this.current.patternFill; + let needRestore = false; + + if (isPatternFill) { ctx.save(); - ctx.beginPath(); + ctx.fillStyle = fillColor.getPattern(ctx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.FILL); + needRestore = true; + } - for (var i = 0; i < paths.length; i++) { - var path = paths[i]; - ctx.setTransform.apply(ctx, path.transform); - ctx.translate(path.x, path.y); - path.addToPath(ctx, path.fontSize); + const intersect = this.current.getClippedPathBoundingBox(); + + if (this.contentVisible && intersect !== null) { + if (this.pendingEOFill) { + ctx.fill("evenodd"); + this.pendingEOFill = false; + } else { + ctx.fill(); + } + } + + if (needRestore) { + ctx.restore(); + } + + if (consumePath) { + this.consumePath(intersect); + } + } + + eoFill() { + this.pendingEOFill = true; + this.fill(); + } + + fillStroke() { + this.fill(false); + this.stroke(false); + this.consumePath(); + } + + eoFillStroke() { + this.pendingEOFill = true; + this.fillStroke(); + } + + closeFillStroke() { + this.closePath(); + this.fillStroke(); + } + + closeEOFillStroke() { + this.pendingEOFill = true; + this.closePath(); + this.fillStroke(); + } + + endPath() { + this.consumePath(); + } + + clip() { + this.pendingClip = NORMAL_CLIP; + } + + eoClip() { + this.pendingClip = EO_CLIP; + } + + beginText() { + this.current.textMatrix = _util.IDENTITY_MATRIX; + this.current.textMatrixScale = 1; + this.current.x = this.current.lineX = 0; + this.current.y = this.current.lineY = 0; + } + + endText() { + const paths = this.pendingTextPaths; + const ctx = this.ctx; + + if (paths === undefined) { + ctx.beginPath(); + return; + } + + ctx.save(); + ctx.beginPath(); + + for (const path of paths) { + ctx.setTransform(...path.transform); + ctx.translate(path.x, path.y); + path.addToPath(ctx, path.fontSize); + } + + ctx.restore(); + ctx.clip(); + ctx.beginPath(); + delete this.pendingTextPaths; + } + + setCharSpacing(spacing) { + this.current.charSpacing = spacing; + } + + setWordSpacing(spacing) { + this.current.wordSpacing = spacing; + } + + setHScale(scale) { + this.current.textHScale = scale / 100; + } + + setLeading(leading) { + this.current.leading = -leading; + } + + setFont(fontRefName, size) { + const fontObj = this.commonObjs.get(fontRefName); + const current = this.current; + + if (!fontObj) { + throw new Error(`Can't find font for ${fontRefName}`); + } + + current.fontMatrix = fontObj.fontMatrix || _util.FONT_IDENTITY_MATRIX; + + if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) { + (0, _util.warn)("Invalid font matrix for font " + fontRefName); + } + + if (size < 0) { + size = -size; + current.fontDirection = -1; + } else { + current.fontDirection = 1; + } + + this.current.font = fontObj; + this.current.fontSize = size; + + if (fontObj.isType3Font) { + return; + } + + const name = fontObj.loadedName || "sans-serif"; + let bold = "normal"; + + if (fontObj.black) { + bold = "900"; + } else if (fontObj.bold) { + bold = "bold"; + } + + const italic = fontObj.italic ? "italic" : "normal"; + const typeface = `"${name}", ${fontObj.fallbackName}`; + let browserFontSize = size; + + if (size < MIN_FONT_SIZE) { + browserFontSize = MIN_FONT_SIZE; + } else if (size > MAX_FONT_SIZE) { + browserFontSize = MAX_FONT_SIZE; + } + + this.current.fontSizeScale = size / browserFontSize; + this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`; + } + + setTextRenderingMode(mode) { + this.current.textRenderingMode = mode; + } + + setTextRise(rise) { + this.current.textRise = rise; + } + + moveText(x, y) { + this.current.x = this.current.lineX += x; + this.current.y = this.current.lineY += y; + } + + setLeadingMoveText(x, y) { + this.setLeading(-y); + this.moveText(x, y); + } + + setTextMatrix(a, b, c, d, e, f) { + this.current.textMatrix = [a, b, c, d, e, f]; + this.current.textMatrixScale = Math.hypot(a, b); + this.current.x = this.current.lineX = 0; + this.current.y = this.current.lineY = 0; + } + + nextLine() { + this.moveText(0, this.current.leading); + } + + paintChar(character, x, y, patternTransform) { + const ctx = this.ctx; + const current = this.current; + const font = current.font; + const textRenderingMode = current.textRenderingMode; + const fontSize = current.fontSize / current.fontSizeScale; + const fillStrokeMode = textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK; + const isAddToPathSet = !!(textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG); + const patternFill = current.patternFill && !font.missingFile; + let addToPath; + + if (font.disableFontFace || isAddToPathSet || patternFill) { + addToPath = font.getPathGenerator(this.commonObjs, character); + } + + if (font.disableFontFace || patternFill) { + ctx.save(); + ctx.translate(x, y); + ctx.beginPath(); + addToPath(ctx, fontSize); + + if (patternTransform) { + ctx.setTransform(...patternTransform); + } + + if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + ctx.fill(); + } + + if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + ctx.stroke(); } ctx.restore(); - ctx.clip(); - ctx.beginPath(); - delete this.pendingTextPaths; - }, - setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) { - this.current.charSpacing = spacing; - }, - setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) { - this.current.wordSpacing = spacing; - }, - setHScale: function CanvasGraphics_setHScale(scale) { - this.current.textHScale = scale / 100; - }, - setLeading: function CanvasGraphics_setLeading(leading) { - this.current.leading = -leading; - }, - setFont: function CanvasGraphics_setFont(fontRefName, size) { - var fontObj = this.commonObjs.get(fontRefName); - var current = this.current; - - if (!fontObj) { - throw new Error(`Can't find font for ${fontRefName}`); + } else { + if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + ctx.fillText(character, x, y); } - current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix : _util.FONT_IDENTITY_MATRIX; - - if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) { - (0, _util.warn)("Invalid font matrix for font " + fontRefName); + if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + ctx.strokeText(character, x, y); } + } - if (size < 0) { - size = -size; - current.fontDirection = -1; - } else { - current.fontDirection = 1; + if (isAddToPathSet) { + const paths = this.pendingTextPaths || (this.pendingTextPaths = []); + paths.push({ + transform: (0, _display_utils.getCurrentTransform)(ctx), + x, + y, + fontSize, + addToPath + }); + } + } + + get isFontSubpixelAAEnabled() { + const { + context: ctx + } = this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled", 10, 10); + ctx.scale(1.5, 1); + ctx.fillText("I", 0, 10); + const data = ctx.getImageData(0, 0, 10, 10).data; + let enabled = false; + + for (let i = 3; i < data.length; i += 4) { + if (data[i] > 0 && data[i] < 255) { + enabled = true; + break; } + } - this.current.font = fontObj; - this.current.fontSize = size; + return (0, _util.shadow)(this, "isFontSubpixelAAEnabled", enabled); + } - if (fontObj.isType3Font) { - return; - } + showText(glyphs) { + const current = this.current; + const font = current.font; - var name = fontObj.loadedName || "sans-serif"; - let bold = "normal"; + if (font.isType3Font) { + return this.showType3Text(glyphs); + } - if (fontObj.black) { - bold = "900"; - } else if (fontObj.bold) { - bold = "bold"; - } + const fontSize = current.fontSize; - var italic = fontObj.italic ? "italic" : "normal"; - var typeface = `"${name}", ${fontObj.fallbackName}`; - let browserFontSize = size; + if (fontSize === 0) { + return undefined; + } - if (size < MIN_FONT_SIZE) { - browserFontSize = MIN_FONT_SIZE; - } else if (size > MAX_FONT_SIZE) { - browserFontSize = MAX_FONT_SIZE; - } + const ctx = this.ctx; + const fontSizeScale = current.fontSizeScale; + const charSpacing = current.charSpacing; + const wordSpacing = current.wordSpacing; + const fontDirection = current.fontDirection; + const textHScale = current.textHScale * fontDirection; + const glyphsLength = glyphs.length; + const vertical = font.vertical; + const spacingDir = vertical ? 1 : -1; + const defaultVMetrics = font.defaultVMetrics; + const widthAdvanceScale = fontSize * current.fontMatrix[0]; + const simpleFillText = current.textRenderingMode === _util.TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill; + ctx.save(); + ctx.transform(...current.textMatrix); + ctx.translate(current.x, current.y + current.textRise); - this.current.fontSizeScale = size / browserFontSize; - this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`; - }, - setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) { - this.current.textRenderingMode = mode; - }, - setTextRise: function CanvasGraphics_setTextRise(rise) { - this.current.textRise = rise; - }, - moveText: function CanvasGraphics_moveText(x, y) { - this.current.x = this.current.lineX += x; - this.current.y = this.current.lineY += y; - }, - setLeadingMoveText: function CanvasGraphics_setLeadingMoveText(x, y) { - this.setLeading(-y); - this.moveText(x, y); - }, - setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) { - this.current.textMatrix = [a, b, c, d, e, f]; - this.current.textMatrixScale = Math.sqrt(a * a + b * b); - this.current.x = this.current.lineX = 0; - this.current.y = this.current.lineY = 0; - }, - nextLine: function CanvasGraphics_nextLine() { - this.moveText(0, this.current.leading); - }, + if (fontDirection > 0) { + ctx.scale(textHScale, -1); + } else { + ctx.scale(textHScale, 1); + } - paintChar(character, x, y, patternTransform) { - var ctx = this.ctx; - var current = this.current; - var font = current.font; - var textRenderingMode = current.textRenderingMode; - var fontSize = current.fontSize / current.fontSizeScale; - var fillStrokeMode = textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK; - var isAddToPathSet = !!(textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG); - const patternFill = current.patternFill && !font.missingFile; - var addToPath; + let patternTransform; - if (font.disableFontFace || isAddToPathSet || patternFill) { - addToPath = font.getPathGenerator(this.commonObjs, character); - } - - if (font.disableFontFace || patternFill) { - ctx.save(); - ctx.translate(x, y); - ctx.beginPath(); - addToPath(ctx, fontSize); - - if (patternTransform) { - ctx.setTransform.apply(ctx, patternTransform); - } - - if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { - ctx.fill(); - } - - if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { - ctx.stroke(); - } - - ctx.restore(); - } else { - if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { - ctx.fillText(character, x, y); - } - - if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { - ctx.strokeText(character, x, y); - } - } - - if (isAddToPathSet) { - var paths = this.pendingTextPaths || (this.pendingTextPaths = []); - paths.push({ - transform: ctx.mozCurrentTransform, - x, - y, - fontSize, - addToPath - }); - } - }, - - get isFontSubpixelAAEnabled() { - const { - context: ctx - } = this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled", 10, 10); - ctx.scale(1.5, 1); - ctx.fillText("I", 0, 10); - var data = ctx.getImageData(0, 0, 10, 10).data; - var enabled = false; - - for (var i = 3; i < data.length; i += 4) { - if (data[i] > 0 && data[i] < 255) { - enabled = true; - break; - } - } - - return (0, _util.shadow)(this, "isFontSubpixelAAEnabled", enabled); - }, - - showText: function CanvasGraphics_showText(glyphs) { - var current = this.current; - var font = current.font; - - if (font.isType3Font) { - return this.showType3Text(glyphs); - } - - var fontSize = current.fontSize; - - if (fontSize === 0) { - return undefined; - } - - var ctx = this.ctx; - var fontSizeScale = current.fontSizeScale; - var charSpacing = current.charSpacing; - var wordSpacing = current.wordSpacing; - var fontDirection = current.fontDirection; - var textHScale = current.textHScale * fontDirection; - var glyphsLength = glyphs.length; - var vertical = font.vertical; - var spacingDir = vertical ? 1 : -1; - var defaultVMetrics = font.defaultVMetrics; - var widthAdvanceScale = fontSize * current.fontMatrix[0]; - var simpleFillText = current.textRenderingMode === _util.TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill; + if (current.patternFill) { ctx.save(); - let patternTransform; + const pattern = current.fillColor.getPattern(ctx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.FILL); + patternTransform = (0, _display_utils.getCurrentTransform)(ctx); + ctx.restore(); + ctx.fillStyle = pattern; + } - if (current.patternFill) { - ctx.save(); - const pattern = current.fillColor.getPattern(ctx, this); - patternTransform = ctx.mozCurrentTransform; - ctx.restore(); - ctx.fillStyle = pattern; + let lineWidth = current.lineWidth; + const scale = current.textMatrixScale; + + if (scale === 0 || lineWidth === 0) { + const fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK; + + if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + lineWidth = this.getSinglePixelWidth(); + } + } else { + lineWidth /= scale; + } + + if (fontSizeScale !== 1.0) { + ctx.scale(fontSizeScale, fontSizeScale); + lineWidth /= fontSizeScale; + } + + ctx.lineWidth = lineWidth; + let x = 0, + i; + + for (i = 0; i < glyphsLength; ++i) { + const glyph = glyphs[i]; + + if (typeof glyph === "number") { + x += spacingDir * glyph * fontSize / 1000; + continue; } - ctx.transform.apply(ctx, current.textMatrix); - ctx.translate(current.x, current.y + current.textRise); - - if (fontDirection > 0) { - ctx.scale(textHScale, -1); - } else { - ctx.scale(textHScale, 1); - } - - var lineWidth = current.lineWidth; - var scale = current.textMatrixScale; - - if (scale === 0 || lineWidth === 0) { - var fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK; - - if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { - this._cachedGetSinglePixelWidth = null; - lineWidth = this.getSinglePixelWidth() * MIN_WIDTH_FACTOR; - } - } else { - lineWidth /= scale; - } - - if (fontSizeScale !== 1.0) { - ctx.scale(fontSizeScale, fontSizeScale); - lineWidth /= fontSizeScale; - } - - ctx.lineWidth = lineWidth; - var x = 0, - i; - - for (i = 0; i < glyphsLength; ++i) { - var glyph = glyphs[i]; - - if ((0, _util.isNum)(glyph)) { - x += spacingDir * glyph * fontSize / 1000; - continue; - } - - var restoreNeeded = false; - var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; - var character = glyph.fontChar; - var accent = glyph.accent; - var scaledX, scaledY, scaledAccentX, scaledAccentY; - var width = glyph.width; - - if (vertical) { - var vmetric, vx, vy; - vmetric = glyph.vmetric || defaultVMetrics; - vx = glyph.vmetric ? vmetric[1] : width * 0.5; - vx = -vx * widthAdvanceScale; - vy = vmetric[2] * widthAdvanceScale; - width = vmetric ? -vmetric[0] : width; - scaledX = vx / fontSizeScale; - scaledY = (x + vy) / fontSizeScale; - } else { - scaledX = x / fontSizeScale; - scaledY = 0; - } - - if (font.remeasure && width > 0) { - var measuredWidth = ctx.measureText(character).width * 1000 / fontSize * fontSizeScale; - - if (width < measuredWidth && this.isFontSubpixelAAEnabled) { - var characterScaleX = width / measuredWidth; - restoreNeeded = true; - ctx.save(); - ctx.scale(characterScaleX, 1); - scaledX /= characterScaleX; - } else if (width !== measuredWidth) { - scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale; - } - } - - if (this.contentVisible && (glyph.isInFont || font.missingFile)) { - if (simpleFillText && !accent) { - ctx.fillText(character, scaledX, scaledY); - } else { - this.paintChar(character, scaledX, scaledY, patternTransform); - - if (accent) { - scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale; - scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale; - this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY, patternTransform); - } - } - } - - var charWidth; - - if (vertical) { - charWidth = width * widthAdvanceScale - spacing * fontDirection; - } else { - charWidth = width * widthAdvanceScale + spacing * fontDirection; - } - - x += charWidth; - - if (restoreNeeded) { - ctx.restore(); - } - } + let restoreNeeded = false; + const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; + const character = glyph.fontChar; + const accent = glyph.accent; + let scaledX, scaledY; + let width = glyph.width; if (vertical) { - current.y -= x; + const vmetric = glyph.vmetric || defaultVMetrics; + const vx = -(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale; + const vy = vmetric[2] * widthAdvanceScale; + width = vmetric ? -vmetric[0] : width; + scaledX = vx / fontSizeScale; + scaledY = (x + vy) / fontSizeScale; } else { - current.x += x * textHScale; + scaledX = x / fontSizeScale; + scaledY = 0; } - ctx.restore(); - }, - showType3Text: function CanvasGraphics_showType3Text(glyphs) { - var ctx = this.ctx; - var current = this.current; - var font = current.font; - var fontSize = current.fontSize; - var fontDirection = current.fontDirection; - var spacingDir = font.vertical ? 1 : -1; - var charSpacing = current.charSpacing; - var wordSpacing = current.wordSpacing; - var textHScale = current.textHScale * fontDirection; - var fontMatrix = current.fontMatrix || _util.FONT_IDENTITY_MATRIX; - var glyphsLength = glyphs.length; - var isTextInvisible = current.textRenderingMode === _util.TextRenderingMode.INVISIBLE; - var i, glyph, width, spacingLength; + if (font.remeasure && width > 0) { + const measuredWidth = ctx.measureText(character).width * 1000 / fontSize * fontSizeScale; - if (isTextInvisible || fontSize === 0) { - return; + if (width < measuredWidth && this.isFontSubpixelAAEnabled) { + const characterScaleX = width / measuredWidth; + restoreNeeded = true; + ctx.save(); + ctx.scale(characterScaleX, 1); + scaledX /= characterScaleX; + } else if (width !== measuredWidth) { + scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale; + } } - this._cachedGetSinglePixelWidth = null; - ctx.save(); - ctx.transform.apply(ctx, current.textMatrix); - ctx.translate(current.x, current.y); - ctx.scale(textHScale, fontDirection); + if (this.contentVisible && (glyph.isInFont || font.missingFile)) { + if (simpleFillText && !accent) { + ctx.fillText(character, scaledX, scaledY); + } else { + this.paintChar(character, scaledX, scaledY, patternTransform); - for (i = 0; i < glyphsLength; ++i) { - glyph = glyphs[i]; - - if ((0, _util.isNum)(glyph)) { - spacingLength = spacingDir * glyph * fontSize / 1000; - this.ctx.translate(spacingLength, 0); - current.x += spacingLength * textHScale; - continue; + if (accent) { + const scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale; + const scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale; + this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY, patternTransform); + } } - - var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; - var operatorList = font.charProcOperatorList[glyph.operatorListId]; - - if (!operatorList) { - (0, _util.warn)(`Type3 character "${glyph.operatorListId}" is not available.`); - continue; - } - - if (this.contentVisible) { - this.processingType3 = glyph; - this.save(); - ctx.scale(fontSize, fontSize); - ctx.transform.apply(ctx, fontMatrix); - this.executeOperatorList(operatorList); - this.restore(); - } - - var transformed = _util.Util.applyTransform([glyph.width, 0], fontMatrix); - - width = transformed[0] * fontSize + spacing; - ctx.translate(width, 0); - current.x += width * textHScale; } - ctx.restore(); - this.processingType3 = null; - }, - setCharWidth: function CanvasGraphics_setCharWidth(xWidth, yWidth) {}, - setCharWidthAndBounds: function CanvasGraphics_setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) { - this.ctx.rect(llx, lly, urx - llx, ury - lly); + let charWidth; + + if (vertical) { + charWidth = width * widthAdvanceScale - spacing * fontDirection; + } else { + charWidth = width * widthAdvanceScale + spacing * fontDirection; + } + + x += charWidth; + + if (restoreNeeded) { + ctx.restore(); + } + } + + if (vertical) { + current.y -= x; + } else { + current.x += x * textHScale; + } + + ctx.restore(); + this.compose(); + return undefined; + } + + showType3Text(glyphs) { + const ctx = this.ctx; + const current = this.current; + const font = current.font; + const fontSize = current.fontSize; + const fontDirection = current.fontDirection; + const spacingDir = font.vertical ? 1 : -1; + const charSpacing = current.charSpacing; + const wordSpacing = current.wordSpacing; + const textHScale = current.textHScale * fontDirection; + const fontMatrix = current.fontMatrix || _util.FONT_IDENTITY_MATRIX; + const glyphsLength = glyphs.length; + const isTextInvisible = current.textRenderingMode === _util.TextRenderingMode.INVISIBLE; + let i, glyph, width, spacingLength; + + if (isTextInvisible || fontSize === 0) { + return; + } + + this._cachedScaleForStroking = null; + this._cachedGetSinglePixelWidth = null; + ctx.save(); + ctx.transform(...current.textMatrix); + ctx.translate(current.x, current.y); + ctx.scale(textHScale, fontDirection); + + for (i = 0; i < glyphsLength; ++i) { + glyph = glyphs[i]; + + if (typeof glyph === "number") { + spacingLength = spacingDir * glyph * fontSize / 1000; + this.ctx.translate(spacingLength, 0); + current.x += spacingLength * textHScale; + continue; + } + + const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; + const operatorList = font.charProcOperatorList[glyph.operatorListId]; + + if (!operatorList) { + (0, _util.warn)(`Type3 character "${glyph.operatorListId}" is not available.`); + continue; + } + + if (this.contentVisible) { + this.processingType3 = glyph; + this.save(); + ctx.scale(fontSize, fontSize); + ctx.transform(...fontMatrix); + this.executeOperatorList(operatorList); + this.restore(); + } + + const transformed = _util.Util.applyTransform([glyph.width, 0], fontMatrix); + + width = transformed[0] * fontSize + spacing; + ctx.translate(width, 0); + current.x += width * textHScale; + } + + ctx.restore(); + this.processingType3 = null; + } + + setCharWidth(xWidth, yWidth) {} + + setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) { + this.ctx.rect(llx, lly, urx - llx, ury - lly); + this.ctx.clip(); + this.endPath(); + } + + getColorN_Pattern(IR) { + let pattern; + + if (IR[0] === "TilingPattern") { + const color = IR[1]; + const baseTransform = this.baseTransform || (0, _display_utils.getCurrentTransform)(this.ctx); + const canvasGraphicsFactory = { + createCanvasGraphics: ctx => { + return new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory); + } + }; + pattern = new _pattern_helper.TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform); + } else { + pattern = this._getPattern(IR[1], IR[2]); + } + + return pattern; + } + + setStrokeColorN() { + this.current.strokeColor = this.getColorN_Pattern(arguments); + } + + setFillColorN() { + this.current.fillColor = this.getColorN_Pattern(arguments); + this.current.patternFill = true; + } + + setStrokeRGBColor(r, g, b) { + const color = this.selectColor?.(r, g, b) || _util.Util.makeHexColor(r, g, b); + + this.ctx.strokeStyle = color; + this.current.strokeColor = color; + } + + setFillRGBColor(r, g, b) { + const color = this.selectColor?.(r, g, b) || _util.Util.makeHexColor(r, g, b); + + this.ctx.fillStyle = color; + this.current.fillColor = color; + this.current.patternFill = false; + } + + _getPattern(objId, matrix = null) { + let pattern; + + if (this.cachedPatterns.has(objId)) { + pattern = this.cachedPatterns.get(objId); + } else { + pattern = (0, _pattern_helper.getShadingPattern)(this.objs.get(objId)); + this.cachedPatterns.set(objId, pattern); + } + + if (matrix) { + pattern.matrix = matrix; + } + + return pattern; + } + + shadingFill(objId) { + if (!this.contentVisible) { + return; + } + + const ctx = this.ctx; + this.save(); + + const pattern = this._getPattern(objId); + + ctx.fillStyle = pattern.getPattern(ctx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.SHADING); + const inv = (0, _display_utils.getCurrentTransformInverse)(ctx); + + if (inv) { + const canvas = ctx.canvas; + const width = canvas.width; + const height = canvas.height; + + const bl = _util.Util.applyTransform([0, 0], inv); + + const br = _util.Util.applyTransform([0, height], inv); + + const ul = _util.Util.applyTransform([width, 0], inv); + + const ur = _util.Util.applyTransform([width, height], inv); + + const x0 = Math.min(bl[0], br[0], ul[0], ur[0]); + const y0 = Math.min(bl[1], br[1], ul[1], ur[1]); + const x1 = Math.max(bl[0], br[0], ul[0], ur[0]); + const y1 = Math.max(bl[1], br[1], ul[1], ur[1]); + this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0); + } else { + this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); + } + + this.compose(this.current.getClippedPathBoundingBox()); + this.restore(); + } + + beginInlineImage() { + (0, _util.unreachable)("Should not call beginInlineImage"); + } + + beginImageData() { + (0, _util.unreachable)("Should not call beginImageData"); + } + + paintFormXObjectBegin(matrix, bbox) { + if (!this.contentVisible) { + return; + } + + this.save(); + this.baseTransformStack.push(this.baseTransform); + + if (Array.isArray(matrix) && matrix.length === 6) { + this.transform(...matrix); + } + + this.baseTransform = (0, _display_utils.getCurrentTransform)(this.ctx); + + if (bbox) { + const width = bbox[2] - bbox[0]; + const height = bbox[3] - bbox[1]; + this.ctx.rect(bbox[0], bbox[1], width, height); + this.current.updateRectMinMax((0, _display_utils.getCurrentTransform)(this.ctx), bbox); this.clip(); this.endPath(); - }, - getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) { - var pattern; + } + } - if (IR[0] === "TilingPattern") { - var color = IR[1]; - var baseTransform = this.baseTransform || this.ctx.mozCurrentTransform.slice(); - var canvasGraphicsFactory = { - createCanvasGraphics: ctx => { - return new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory, this.webGLContext); - } - }; - pattern = new _pattern_helper.TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform); - } else { - pattern = (0, _pattern_helper.getShadingPatternFromIR)(IR); - } + paintFormXObjectEnd() { + if (!this.contentVisible) { + return; + } - return pattern; - }, - setStrokeColorN: function CanvasGraphics_setStrokeColorN() { - this.current.strokeColor = this.getColorN_Pattern(arguments); - }, - setFillColorN: function CanvasGraphics_setFillColorN() { - this.current.fillColor = this.getColorN_Pattern(arguments); - this.current.patternFill = true; - }, - setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) { - var color = _util.Util.makeCssRgb(r, g, b); + this.restore(); + this.baseTransform = this.baseTransformStack.pop(); + } - this.ctx.strokeStyle = color; - this.current.strokeColor = color; - }, - setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) { - var color = _util.Util.makeCssRgb(r, g, b); + beginGroup(group) { + if (!this.contentVisible) { + return; + } - this.ctx.fillStyle = color; - this.current.fillColor = color; - this.current.patternFill = false; - }, - shadingFill: function CanvasGraphics_shadingFill(patternIR) { - if (!this.contentVisible) { - return; - } + this.save(); - var ctx = this.ctx; - this.save(); - var pattern = (0, _pattern_helper.getShadingPatternFromIR)(patternIR); - ctx.fillStyle = pattern.getPattern(ctx, this, true); - var inv = ctx.mozCurrentTransformInverse; - - if (inv) { - var canvas = ctx.canvas; - var width = canvas.width; - var height = canvas.height; - - var bl = _util.Util.applyTransform([0, 0], inv); - - var br = _util.Util.applyTransform([0, height], inv); - - var ul = _util.Util.applyTransform([width, 0], inv); - - var ur = _util.Util.applyTransform([width, height], inv); - - var x0 = Math.min(bl[0], br[0], ul[0], ur[0]); - var y0 = Math.min(bl[1], br[1], ul[1], ur[1]); - var x1 = Math.max(bl[0], br[0], ul[0], ur[0]); - var y1 = Math.max(bl[1], br[1], ul[1], ur[1]); - this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0); - } else { - this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); - } - - this.restore(); - }, - beginInlineImage: function CanvasGraphics_beginInlineImage() { - (0, _util.unreachable)("Should not call beginInlineImage"); - }, - beginImageData: function CanvasGraphics_beginImageData() { - (0, _util.unreachable)("Should not call beginImageData"); - }, - paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix, bbox) { - if (!this.contentVisible) { - return; - } - - this.save(); - this.baseTransformStack.push(this.baseTransform); - - if (Array.isArray(matrix) && matrix.length === 6) { - this.transform.apply(this, matrix); - } - - this.baseTransform = this.ctx.mozCurrentTransform; - - if (bbox) { - var width = bbox[2] - bbox[0]; - var height = bbox[3] - bbox[1]; - this.ctx.rect(bbox[0], bbox[1], width, height); - this.clip(); - this.endPath(); - } - }, - paintFormXObjectEnd: function CanvasGraphics_paintFormXObjectEnd() { - if (!this.contentVisible) { - return; - } - - this.restore(); - this.baseTransform = this.baseTransformStack.pop(); - }, - beginGroup: function CanvasGraphics_beginGroup(group) { - if (!this.contentVisible) { - return; - } - - this.save(); - var currentCtx = this.ctx; - - if (!group.isolated) { - (0, _util.info)("TODO: Support non-isolated groups."); - } - - if (group.knockout) { - (0, _util.warn)("Knockout groups not supported."); - } - - var currentTransform = currentCtx.mozCurrentTransform; - - if (group.matrix) { - currentCtx.transform.apply(currentCtx, group.matrix); - } - - if (!group.bbox) { - throw new Error("Bounding box is required."); - } - - var bounds = _util.Util.getAxialAlignedBoundingBox(group.bbox, currentCtx.mozCurrentTransform); - - var canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height]; - bounds = _util.Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0]; - var offsetX = Math.floor(bounds[0]); - var offsetY = Math.floor(bounds[1]); - var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1); - var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1); - var scaleX = 1, - scaleY = 1; - - if (drawnWidth > MAX_GROUP_SIZE) { - scaleX = drawnWidth / MAX_GROUP_SIZE; - drawnWidth = MAX_GROUP_SIZE; - } - - if (drawnHeight > MAX_GROUP_SIZE) { - scaleY = drawnHeight / MAX_GROUP_SIZE; - drawnHeight = MAX_GROUP_SIZE; - } - - var cacheId = "groupAt" + this.groupLevel; - - if (group.smask) { - cacheId += "_smask_" + this.smaskCounter++ % 2; - } - - var scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true); - var groupCtx = scratchCanvas.context; - groupCtx.scale(1 / scaleX, 1 / scaleY); - groupCtx.translate(-offsetX, -offsetY); - groupCtx.transform.apply(groupCtx, currentTransform); - - if (group.smask) { - this.smaskStack.push({ - canvas: scratchCanvas.canvas, - context: groupCtx, - offsetX, - offsetY, - scaleX, - scaleY, - subtype: group.smask.subtype, - backdrop: group.smask.backdrop, - transferMap: group.smask.transferMap || null, - startTransformInverse: null - }); - } else { - currentCtx.setTransform(1, 0, 0, 1, 0, 0); - currentCtx.translate(offsetX, offsetY); - currentCtx.scale(scaleX, scaleY); - } - - copyCtxState(currentCtx, groupCtx); - this.ctx = groupCtx; - this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]); - this.groupStack.push(currentCtx); - this.groupLevel++; + if (this.inSMaskMode) { + this.endSMaskMode(); this.current.activeSMask = null; - }, - endGroup: function CanvasGraphics_endGroup(group) { - if (!this.contentVisible) { - return; - } + } - this.groupLevel--; - var groupCtx = this.ctx; - this.ctx = this.groupStack.pop(); + const currentCtx = this.ctx; - if (this.ctx.imageSmoothingEnabled !== undefined) { - this.ctx.imageSmoothingEnabled = false; - } else { - this.ctx.mozImageSmoothingEnabled = false; - } + if (!group.isolated) { + (0, _util.info)("TODO: Support non-isolated groups."); + } - if (group.smask) { - this.tempSMask = this.smaskStack.pop(); - } else { - this.ctx.drawImage(groupCtx.canvas, 0, 0); - } + if (group.knockout) { + (0, _util.warn)("Knockout groups not supported."); + } + const currentTransform = (0, _display_utils.getCurrentTransform)(currentCtx); + + if (group.matrix) { + currentCtx.transform(...group.matrix); + } + + if (!group.bbox) { + throw new Error("Bounding box is required."); + } + + let bounds = _util.Util.getAxialAlignedBoundingBox(group.bbox, (0, _display_utils.getCurrentTransform)(currentCtx)); + + const canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height]; + bounds = _util.Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0]; + const offsetX = Math.floor(bounds[0]); + const offsetY = Math.floor(bounds[1]); + let drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1); + let drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1); + let scaleX = 1, + scaleY = 1; + + if (drawnWidth > MAX_GROUP_SIZE) { + scaleX = drawnWidth / MAX_GROUP_SIZE; + drawnWidth = MAX_GROUP_SIZE; + } + + if (drawnHeight > MAX_GROUP_SIZE) { + scaleY = drawnHeight / MAX_GROUP_SIZE; + drawnHeight = MAX_GROUP_SIZE; + } + + this.current.startNewPathAndClipBox([0, 0, drawnWidth, drawnHeight]); + let cacheId = "groupAt" + this.groupLevel; + + if (group.smask) { + cacheId += "_smask_" + this.smaskCounter++ % 2; + } + + const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight); + const groupCtx = scratchCanvas.context; + groupCtx.scale(1 / scaleX, 1 / scaleY); + groupCtx.translate(-offsetX, -offsetY); + groupCtx.transform(...currentTransform); + + if (group.smask) { + this.smaskStack.push({ + canvas: scratchCanvas.canvas, + context: groupCtx, + offsetX, + offsetY, + scaleX, + scaleY, + subtype: group.smask.subtype, + backdrop: group.smask.backdrop, + transferMap: group.smask.transferMap || null, + startTransformInverse: null + }); + } else { + currentCtx.setTransform(1, 0, 0, 1, 0, 0); + currentCtx.translate(offsetX, offsetY); + currentCtx.scale(scaleX, scaleY); + currentCtx.save(); + } + + copyCtxState(currentCtx, groupCtx); + this.ctx = groupCtx; + this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]); + this.groupStack.push(currentCtx); + this.groupLevel++; + } + + endGroup(group) { + if (!this.contentVisible) { + return; + } + + this.groupLevel--; + const groupCtx = this.ctx; + const ctx = this.groupStack.pop(); + this.ctx = ctx; + this.ctx.imageSmoothingEnabled = false; + + if (group.smask) { + this.tempSMask = this.smaskStack.pop(); this.restore(); - }, - beginAnnotations: function CanvasGraphics_beginAnnotations() { - this.save(); - - if (this.baseTransform) { - this.ctx.setTransform.apply(this.ctx, this.baseTransform); - } - }, - endAnnotations: function CanvasGraphics_endAnnotations() { + } else { + this.ctx.restore(); + const currentMtx = (0, _display_utils.getCurrentTransform)(this.ctx); this.restore(); - }, - beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform, matrix) { - this.save(); - resetCtxToDefault(this.ctx); - this.current = new CanvasExtraState(); + this.ctx.save(); + this.ctx.setTransform(...currentMtx); - if (Array.isArray(rect) && rect.length === 4) { - var width = rect[2] - rect[0]; - var height = rect[3] - rect[1]; + const dirtyBox = _util.Util.getAxialAlignedBoundingBox([0, 0, groupCtx.canvas.width, groupCtx.canvas.height], currentMtx); + + this.ctx.drawImage(groupCtx.canvas, 0, 0); + this.ctx.restore(); + this.compose(dirtyBox); + } + } + + beginAnnotation(id, rect, transform, matrix, hasOwnCanvas) { + this.#restoreInitialState(); + resetCtxToDefault(this.ctx, this.foregroundColor); + this.ctx.save(); + this.save(); + + if (this.baseTransform) { + this.ctx.setTransform(...this.baseTransform); + } + + if (Array.isArray(rect) && rect.length === 4) { + const width = rect[2] - rect[0]; + const height = rect[3] - rect[1]; + + if (hasOwnCanvas && this.annotationCanvasMap) { + transform = transform.slice(); + transform[4] -= rect[0]; + transform[5] -= rect[1]; + rect = rect.slice(); + rect[0] = rect[1] = 0; + rect[2] = width; + rect[3] = height; + + const [scaleX, scaleY] = _util.Util.singularValueDecompose2dScale((0, _display_utils.getCurrentTransform)(this.ctx)); + + const { + viewportScale + } = this; + const canvasWidth = Math.ceil(width * this.outputScaleX * viewportScale); + const canvasHeight = Math.ceil(height * this.outputScaleY * viewportScale); + this.annotationCanvas = this.canvasFactory.create(canvasWidth, canvasHeight); + const { + canvas, + context + } = this.annotationCanvas; + this.annotationCanvasMap.set(id, canvas); + this.annotationCanvas.savedCtx = this.ctx; + this.ctx = context; + this.ctx.setTransform(scaleX, 0, 0, -scaleY, 0, height * scaleY); + resetCtxToDefault(this.ctx, this.foregroundColor); + } else { + resetCtxToDefault(this.ctx, this.foregroundColor); this.ctx.rect(rect[0], rect[1], width, height); - this.clip(); + this.ctx.clip(); this.endPath(); } + } - this.transform.apply(this, transform); - this.transform.apply(this, matrix); - }, - endAnnotation: function CanvasGraphics_endAnnotation() { - this.restore(); - }, - paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) { - if (!this.contentVisible) { - return; + this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height); + this.transform(...transform); + this.transform(...matrix); + } + + endAnnotation() { + if (this.annotationCanvas) { + this.ctx = this.annotationCanvas.savedCtx; + delete this.annotationCanvas.savedCtx; + delete this.annotationCanvas; + } + } + + paintImageMaskXObject(img) { + if (!this.contentVisible) { + return; + } + + const count = img.count; + img = this.getObject(img.data, img); + img.count = count; + const ctx = this.ctx; + const glyph = this.processingType3; + + if (glyph) { + if (glyph.compiled === undefined) { + glyph.compiled = compileType3Glyph(img); } - var ctx = this.ctx; - var width = img.width, - height = img.height; - var fillColor = this.current.fillColor; - var isPatternFill = this.current.patternFill; - var glyph = this.processingType3; - - if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) { - if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) { - glyph.compiled = compileType3Glyph({ - data: img.data, - width, - height - }); - } else { - glyph.compiled = null; - } - } - - if (glyph && glyph.compiled) { + if (glyph.compiled) { glyph.compiled(ctx); return; } + } - var maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height); - var maskCtx = maskCanvas.context; + const mask = this._createMaskCanvas(img); + + const maskCanvas = mask.canvas; + ctx.save(); + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY); + ctx.restore(); + this.compose(); + } + + paintImageMaskXObjectRepeat(img, scaleX, skewX = 0, skewY = 0, scaleY, positions) { + if (!this.contentVisible) { + return; + } + + img = this.getObject(img.data, img); + const ctx = this.ctx; + ctx.save(); + const currentTransform = (0, _display_utils.getCurrentTransform)(ctx); + ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0); + + const mask = this._createMaskCanvas(img); + + ctx.setTransform(1, 0, 0, 1, 0, 0); + + for (let i = 0, ii = positions.length; i < ii; i += 2) { + const trans = _util.Util.transform(currentTransform, [scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]]); + + const [x, y] = _util.Util.applyTransform([0, 0], trans); + + ctx.drawImage(mask.canvas, x, y); + } + + ctx.restore(); + this.compose(); + } + + paintImageMaskXObjectGroup(images) { + if (!this.contentVisible) { + return; + } + + const ctx = this.ctx; + const fillColor = this.current.fillColor; + const isPatternFill = this.current.patternFill; + + for (const image of images) { + const { + data, + width, + height, + transform + } = image; + const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height); + const maskCtx = maskCanvas.context; maskCtx.save(); + const img = this.getObject(data, image); putBinaryImageMask(maskCtx, img); maskCtx.globalCompositeOperation = "source-in"; - maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor; + maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.FILL) : fillColor; maskCtx.fillRect(0, 0, width, height); maskCtx.restore(); - this.paintInlineImageXObject(maskCanvas.canvas); - }, + ctx.save(); + ctx.transform(...transform); + ctx.scale(1, -1); + drawImageAtIntegerCoords(ctx, maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1); + ctx.restore(); + } - paintImageMaskXObjectRepeat(imgData, scaleX, skewX = 0, skewY = 0, scaleY, positions) { - if (!this.contentVisible) { - return; - } + this.compose(); + } - var width = imgData.width; - var height = imgData.height; - var fillColor = this.current.fillColor; - var isPatternFill = this.current.patternFill; - var maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height); - var maskCtx = maskCanvas.context; - maskCtx.save(); - putBinaryImageMask(maskCtx, imgData); - maskCtx.globalCompositeOperation = "source-in"; - maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor; - maskCtx.fillRect(0, 0, width, height); - maskCtx.restore(); - var ctx = this.ctx; + paintImageXObject(objId) { + if (!this.contentVisible) { + return; + } - for (var i = 0, ii = positions.length; i < ii; i += 2) { - ctx.save(); - ctx.transform(scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]); - ctx.scale(1, -1); - ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1); - ctx.restore(); - } - }, + const imgData = this.getObject(objId); - paintImageMaskXObjectGroup: function CanvasGraphics_paintImageMaskXObjectGroup(images) { - if (!this.contentVisible) { - return; - } + if (!imgData) { + (0, _util.warn)("Dependent image isn't ready yet"); + return; + } - var ctx = this.ctx; - var fillColor = this.current.fillColor; - var isPatternFill = this.current.patternFill; + this.paintInlineImageXObject(imgData); + } - for (var i = 0, ii = images.length; i < ii; i++) { - var image = images[i]; - var width = image.width, - height = image.height; - var maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height); - var maskCtx = maskCanvas.context; - maskCtx.save(); - putBinaryImageMask(maskCtx, image); - maskCtx.globalCompositeOperation = "source-in"; - maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor; - maskCtx.fillRect(0, 0, width, height); - maskCtx.restore(); - ctx.save(); - ctx.transform.apply(ctx, image.transform); - ctx.scale(1, -1); - ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1); - ctx.restore(); - } - }, - paintImageXObject: function CanvasGraphics_paintImageXObject(objId) { - if (!this.contentVisible) { - return; - } + paintImageXObjectRepeat(objId, scaleX, scaleY, positions) { + if (!this.contentVisible) { + return; + } - const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId); + const imgData = this.getObject(objId); - if (!imgData) { - (0, _util.warn)("Dependent image isn't ready yet"); - return; - } + if (!imgData) { + (0, _util.warn)("Dependent image isn't ready yet"); + return; + } - this.paintInlineImageXObject(imgData); - }, - paintImageXObjectRepeat: function CanvasGraphics_paintImageXObjectRepeat(objId, scaleX, scaleY, positions) { - if (!this.contentVisible) { - return; - } + const width = imgData.width; + const height = imgData.height; + const map = []; - const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId); + for (let i = 0, ii = positions.length; i < ii; i += 2) { + map.push({ + transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]], + x: 0, + y: 0, + w: width, + h: height + }); + } - if (!imgData) { - (0, _util.warn)("Dependent image isn't ready yet"); - return; - } + this.paintInlineImageXObjectGroup(imgData, map); + } - var width = imgData.width; - var height = imgData.height; - var map = []; + paintInlineImageXObject(imgData) { + if (!this.contentVisible) { + return; + } - for (var i = 0, ii = positions.length; i < ii; i += 2) { - map.push({ - transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]], - x: 0, - y: 0, - w: width, - h: height - }); - } + const width = imgData.width; + const height = imgData.height; + const ctx = this.ctx; + this.save(); + ctx.scale(1 / width, -1 / height); + let imgToPaint; - this.paintInlineImageXObjectGroup(imgData, map); - }, - paintInlineImageXObject: function CanvasGraphics_paintInlineImageXObject(imgData) { - if (!this.contentVisible) { - return; - } + if (typeof HTMLElement === "function" && imgData instanceof HTMLElement || !imgData.data) { + imgToPaint = imgData; + } else { + const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height); + const tmpCtx = tmpCanvas.context; + putBinaryImageData(tmpCtx, imgData, this.current.transferMaps); + imgToPaint = tmpCanvas.canvas; + } - var width = imgData.width; - var height = imgData.height; - var ctx = this.ctx; - this.save(); - ctx.scale(1 / width, -1 / height); - var currentTransform = ctx.mozCurrentTransformInverse; - var a = currentTransform[0], - b = currentTransform[1]; - var widthScale = Math.max(Math.sqrt(a * a + b * b), 1); - var c = currentTransform[2], - d = currentTransform[3]; - var heightScale = Math.max(Math.sqrt(c * c + d * d), 1); - var imgToPaint, tmpCanvas; + const scaled = this._scaleImage(imgToPaint, (0, _display_utils.getCurrentTransformInverse)(ctx)); - if (typeof HTMLElement === "function" && imgData instanceof HTMLElement || !imgData.data) { - imgToPaint = imgData; - } else { - tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height); - var tmpCtx = tmpCanvas.context; - putBinaryImageData(tmpCtx, imgData, this.current.transferMaps); - imgToPaint = tmpCanvas.canvas; - } + ctx.imageSmoothingEnabled = getImageSmoothingEnabled((0, _display_utils.getCurrentTransform)(ctx), imgData.interpolate); + const [rWidth, rHeight] = drawImageAtIntegerCoords(ctx, scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height); - var paintWidth = width, - paintHeight = height; - var tmpCanvasId = "prescale1"; + if (this.imageLayer) { + const [left, top] = _util.Util.applyTransform([0, -height], (0, _display_utils.getCurrentTransform)(this.ctx)); - while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) { - var newWidth = paintWidth, - newHeight = paintHeight; + this.imageLayer.appendImage({ + imgData, + left, + top, + width: rWidth, + height: rHeight + }); + } - if (widthScale > 2 && paintWidth > 1) { - newWidth = Math.ceil(paintWidth / 2); - widthScale /= paintWidth / newWidth; - } + this.compose(); + this.restore(); + } - if (heightScale > 2 && paintHeight > 1) { - newHeight = Math.ceil(paintHeight / 2); - heightScale /= paintHeight / newHeight; - } + paintInlineImageXObjectGroup(imgData, map) { + if (!this.contentVisible) { + return; + } - tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight); - tmpCtx = tmpCanvas.context; - tmpCtx.clearRect(0, 0, newWidth, newHeight); - tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight); - imgToPaint = tmpCanvas.canvas; - paintWidth = newWidth; - paintHeight = newHeight; - tmpCanvasId = tmpCanvasId === "prescale1" ? "prescale2" : "prescale1"; - } + const ctx = this.ctx; + const w = imgData.width; + const h = imgData.height; + const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h); + const tmpCtx = tmpCanvas.context; + putBinaryImageData(tmpCtx, imgData, this.current.transferMaps); - ctx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight, 0, -height, width, height); + for (const entry of map) { + ctx.save(); + ctx.transform(...entry.transform); + ctx.scale(1, -1); + drawImageAtIntegerCoords(ctx, tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1); if (this.imageLayer) { - var position = this.getCanvasPosition(0, -height); + const [left, top] = _util.Util.applyTransform([entry.x, entry.y], (0, _display_utils.getCurrentTransform)(this.ctx)); + this.imageLayer.appendImage({ imgData, - left: position[0], - top: position[1], - width: width / currentTransform[0], - height: height / currentTransform[3] + left, + top, + width: w, + height: h }); } - this.restore(); - }, - paintInlineImageXObjectGroup: function CanvasGraphics_paintInlineImageXObjectGroup(imgData, map) { - if (!this.contentVisible) { - return; - } + ctx.restore(); + } - var ctx = this.ctx; - var w = imgData.width; - var h = imgData.height; - var tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h); - var tmpCtx = tmpCanvas.context; - putBinaryImageData(tmpCtx, imgData, this.current.transferMaps); + this.compose(); + } - for (var i = 0, ii = map.length; i < ii; i++) { - var entry = map[i]; - ctx.save(); - ctx.transform.apply(ctx, entry.transform); - ctx.scale(1, -1); - ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1); + paintSolidColorImageMask() { + if (!this.contentVisible) { + return; + } - if (this.imageLayer) { - var position = this.getCanvasPosition(entry.x, entry.y); - this.imageLayer.appendImage({ - imgData, - left: position[0], - top: position[1], - width: w, - height: h - }); - } + this.ctx.fillRect(0, 0, 1, 1); + this.compose(); + } - ctx.restore(); - } - }, - paintSolidColorImageMask: function CanvasGraphics_paintSolidColorImageMask() { - if (!this.contentVisible) { - return; - } + markPoint(tag) {} - this.ctx.fillRect(0, 0, 1, 1); - }, - markPoint: function CanvasGraphics_markPoint(tag) {}, - markPointProps: function CanvasGraphics_markPointProps(tag, properties) {}, - beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) { + markPointProps(tag, properties) {} + + beginMarkedContent(tag) { + this.markedContentStack.push({ + visible: true + }); + } + + beginMarkedContentProps(tag, properties) { + if (tag === "OC") { + this.markedContentStack.push({ + visible: this.optionalContentConfig.isVisible(properties) + }); + } else { this.markedContentStack.push({ visible: true }); - }, - beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps(tag, properties) { - if (tag === "OC") { - this.markedContentStack.push({ - visible: this.optionalContentConfig.isVisible(properties) - }); - } else { - this.markedContentStack.push({ - visible: true - }); - } + } - this.contentVisible = this.isContentVisible(); - }, - endMarkedContent: function CanvasGraphics_endMarkedContent() { - this.markedContentStack.pop(); - this.contentVisible = this.isContentVisible(); - }, - beginCompat: function CanvasGraphics_beginCompat() {}, - endCompat: function CanvasGraphics_endCompat() {}, - consumePath: function CanvasGraphics_consumePath() { - var ctx = this.ctx; + this.contentVisible = this.isContentVisible(); + } - if (this.pendingClip) { + endMarkedContent() { + this.markedContentStack.pop(); + this.contentVisible = this.isContentVisible(); + } + + beginCompat() {} + + endCompat() {} + + consumePath(clipBox) { + const isEmpty = this.current.isEmptyClip(); + + if (this.pendingClip) { + this.current.updateClipFromPath(); + } + + if (!this.pendingClip) { + this.compose(clipBox); + } + + const ctx = this.ctx; + + if (this.pendingClip) { + if (!isEmpty) { if (this.pendingClip === EO_CLIP) { ctx.clip("evenodd"); } else { ctx.clip(); } - - this.pendingClip = null; } - ctx.beginPath(); - }, + this.pendingClip = null; + } - getSinglePixelWidth(scale) { - if (this._cachedGetSinglePixelWidth === null) { - const inverse = this.ctx.mozCurrentTransformInverse; - this._cachedGetSinglePixelWidth = Math.sqrt(Math.max(inverse[0] * inverse[0] + inverse[1] * inverse[1], inverse[2] * inverse[2] + inverse[3] * inverse[3])); + this.current.startNewPathAndClipBox(this.current.clipBox); + ctx.beginPath(); + } + + getSinglePixelWidth() { + if (!this._cachedGetSinglePixelWidth) { + const m = (0, _display_utils.getCurrentTransform)(this.ctx); + + if (m[1] === 0 && m[2] === 0) { + this._cachedGetSinglePixelWidth = 1 / Math.min(Math.abs(m[0]), Math.abs(m[3])); + } else { + const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]); + const normX = Math.hypot(m[0], m[2]); + const normY = Math.hypot(m[1], m[3]); + this._cachedGetSinglePixelWidth = Math.max(normX, normY) / absDet; } + } - return this._cachedGetSinglePixelWidth; - }, + return this._cachedGetSinglePixelWidth; + } - getCanvasPosition: function CanvasGraphics_getCanvasPosition(x, y) { - var transform = this.ctx.mozCurrentTransform; - return [transform[0] * x + transform[2] * y + transform[4], transform[1] * x + transform[3] * y + transform[5]]; - }, - isContentVisible: function CanvasGraphics_isContentVisible() { - for (let i = this.markedContentStack.length - 1; i >= 0; i--) { - if (!this.markedContentStack[i].visible) { - return false; + getScaleForStroking() { + if (!this._cachedScaleForStroking) { + const { + lineWidth + } = this.current; + const m = (0, _display_utils.getCurrentTransform)(this.ctx); + let scaleX, scaleY; + + if (m[1] === 0 && m[2] === 0) { + const normX = Math.abs(m[0]); + const normY = Math.abs(m[3]); + + if (lineWidth === 0) { + scaleX = 1 / normX; + scaleY = 1 / normY; + } else { + const scaledXLineWidth = normX * lineWidth; + const scaledYLineWidth = normY * lineWidth; + scaleX = scaledXLineWidth < 1 ? 1 / scaledXLineWidth : 1; + scaleY = scaledYLineWidth < 1 ? 1 / scaledYLineWidth : 1; + } + } else { + const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]); + const normX = Math.hypot(m[0], m[1]); + const normY = Math.hypot(m[2], m[3]); + + if (lineWidth === 0) { + scaleX = normY / absDet; + scaleY = normX / absDet; + } else { + const baseArea = lineWidth * absDet; + scaleX = normY > baseArea ? normY / baseArea : 1; + scaleY = normX > baseArea ? normX / baseArea : 1; } } - return true; + this._cachedScaleForStroking = [scaleX, scaleY]; } - }; - for (var op in _util.OPS) { - CanvasGraphics.prototype[_util.OPS[op]] = CanvasGraphics.prototype[op]; + return this._cachedScaleForStroking; } - return CanvasGraphics; -}(); + rescaleAndStroke(saveRestore) { + const { + ctx + } = this; + const { + lineWidth + } = this.current; + const [scaleX, scaleY] = this.getScaleForStroking(); + ctx.lineWidth = lineWidth || 1; + + if (scaleX === 1 && scaleY === 1) { + ctx.stroke(); + return; + } + + let savedMatrix, savedDashes, savedDashOffset; + + if (saveRestore) { + savedMatrix = (0, _display_utils.getCurrentTransform)(ctx); + savedDashes = ctx.getLineDash().slice(); + savedDashOffset = ctx.lineDashOffset; + } + + ctx.scale(scaleX, scaleY); + const scale = Math.max(scaleX, scaleY); + ctx.setLineDash(ctx.getLineDash().map(x => x / scale)); + ctx.lineDashOffset /= scale; + ctx.stroke(); + + if (saveRestore) { + ctx.setTransform(...savedMatrix); + ctx.setLineDash(savedDashes); + ctx.lineDashOffset = savedDashOffset; + } + } + + isContentVisible() { + for (let i = this.markedContentStack.length - 1; i >= 0; i--) { + if (!this.markedContentStack[i].visible) { + return false; + } + } + + return true; + } + +} exports.CanvasGraphics = CanvasGraphics; +for (const op in _util.OPS) { + if (CanvasGraphics.prototype[op] !== undefined) { + CanvasGraphics.prototype[_util.OPS[op]] = CanvasGraphics.prototype[op]; + } +} + /***/ }), -/* 11 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 13 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.getShadingPatternFromIR = getShadingPatternFromIR; -exports.TilingPattern = void 0; +})); +exports.TilingPattern = exports.PathType = void 0; +exports.getShadingPattern = getShadingPattern; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); -var ShadingIRs = {}; +var _display_utils = __w_pdfjs_require__(8); + +var _is_node = __w_pdfjs_require__(3); + +const PathType = { + FILL: "Fill", + STROKE: "Stroke", + SHADING: "Shading" +}; +exports.PathType = PathType; function applyBoundingBox(ctx, bbox) { - if (!bbox || typeof Path2D === "undefined") { + if (!bbox || _is_node.isNodeJS) { return; } @@ -6742,259 +8911,303 @@ function applyBoundingBox(ctx, bbox) { ctx.clip(region); } -ShadingIRs.RadialAxial = { - fromIR: function RadialAxial_fromIR(raw) { - var type = raw[1]; - var bbox = raw[2]; - var colorStops = raw[3]; - var p0 = raw[4]; - var p1 = raw[5]; - var r0 = raw[6]; - var r1 = raw[7]; - return { - type: "Pattern", - getPattern: function RadialAxial_getPattern(ctx) { - applyBoundingBox(ctx, bbox); - var grad; - - if (type === "axial") { - grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]); - } else if (type === "radial") { - grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1); - } - - for (var i = 0, ii = colorStops.length; i < ii; ++i) { - var c = colorStops[i]; - grad.addColorStop(c[0], c[1]); - } - - return grad; - } - }; +class BaseShadingPattern { + constructor() { + if (this.constructor === BaseShadingPattern) { + (0, _util.unreachable)("Cannot initialize BaseShadingPattern."); + } } -}; -var createMeshCanvas = function createMeshCanvasClosure() { - function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) { - var coords = context.coords, + getPattern() { + (0, _util.unreachable)("Abstract method `getPattern` called."); + } + +} + +class RadialAxialShadingPattern extends BaseShadingPattern { + constructor(IR) { + super(); + this._type = IR[1]; + this._bbox = IR[2]; + this._colorStops = IR[3]; + this._p0 = IR[4]; + this._p1 = IR[5]; + this._r0 = IR[6]; + this._r1 = IR[7]; + this.matrix = null; + } + + _createGradient(ctx) { + let grad; + + if (this._type === "axial") { + grad = ctx.createLinearGradient(this._p0[0], this._p0[1], this._p1[0], this._p1[1]); + } else if (this._type === "radial") { + grad = ctx.createRadialGradient(this._p0[0], this._p0[1], this._r0, this._p1[0], this._p1[1], this._r1); + } + + for (const colorStop of this._colorStops) { + grad.addColorStop(colorStop[0], colorStop[1]); + } + + return grad; + } + + getPattern(ctx, owner, inverse, pathType) { + let pattern; + + if (pathType === PathType.STROKE || pathType === PathType.FILL) { + const ownerBBox = owner.current.getClippedPathBoundingBox(pathType, (0, _display_utils.getCurrentTransform)(ctx)) || [0, 0, 0, 0]; + const width = Math.ceil(ownerBBox[2] - ownerBBox[0]) || 1; + const height = Math.ceil(ownerBBox[3] - ownerBBox[1]) || 1; + const tmpCanvas = owner.cachedCanvases.getCanvas("pattern", width, height, true); + const tmpCtx = tmpCanvas.context; + tmpCtx.clearRect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height); + tmpCtx.beginPath(); + tmpCtx.rect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height); + tmpCtx.translate(-ownerBBox[0], -ownerBBox[1]); + inverse = _util.Util.transform(inverse, [1, 0, 0, 1, ownerBBox[0], ownerBBox[1]]); + tmpCtx.transform(...owner.baseTransform); + + if (this.matrix) { + tmpCtx.transform(...this.matrix); + } + + applyBoundingBox(tmpCtx, this._bbox); + tmpCtx.fillStyle = this._createGradient(tmpCtx); + tmpCtx.fill(); + pattern = ctx.createPattern(tmpCanvas.canvas, "no-repeat"); + const domMatrix = new DOMMatrix(inverse); + + try { + pattern.setTransform(domMatrix); + } catch (ex) { + (0, _util.warn)(`RadialAxialShadingPattern.getPattern: "${ex?.message}".`); + } + } else { + applyBoundingBox(ctx, this._bbox); + pattern = this._createGradient(ctx); + } + + return pattern; + } + +} + +function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) { + const coords = context.coords, colors = context.colors; - var bytes = data.data, + const bytes = data.data, rowSize = data.width * 4; - var tmp; + let tmp; - if (coords[p1 + 1] > coords[p2 + 1]) { - tmp = p1; - p1 = p2; - p2 = tmp; - tmp = c1; - c1 = c2; - c2 = tmp; - } + if (coords[p1 + 1] > coords[p2 + 1]) { + tmp = p1; + p1 = p2; + p2 = tmp; + tmp = c1; + c1 = c2; + c2 = tmp; + } - if (coords[p2 + 1] > coords[p3 + 1]) { - tmp = p2; - p2 = p3; - p3 = tmp; - tmp = c2; - c2 = c3; - c3 = tmp; - } + if (coords[p2 + 1] > coords[p3 + 1]) { + tmp = p2; + p2 = p3; + p3 = tmp; + tmp = c2; + c2 = c3; + c3 = tmp; + } - if (coords[p1 + 1] > coords[p2 + 1]) { - tmp = p1; - p1 = p2; - p2 = tmp; - tmp = c1; - c1 = c2; - c2 = tmp; - } + if (coords[p1 + 1] > coords[p2 + 1]) { + tmp = p1; + p1 = p2; + p2 = tmp; + tmp = c1; + c1 = c2; + c2 = tmp; + } - var x1 = (coords[p1] + context.offsetX) * context.scaleX; - var y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY; - var x2 = (coords[p2] + context.offsetX) * context.scaleX; - var y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY; - var x3 = (coords[p3] + context.offsetX) * context.scaleX; - var y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY; + const x1 = (coords[p1] + context.offsetX) * context.scaleX; + const y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY; + const x2 = (coords[p2] + context.offsetX) * context.scaleX; + const y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY; + const x3 = (coords[p3] + context.offsetX) * context.scaleX; + const y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY; - if (y1 >= y3) { - return; - } + if (y1 >= y3) { + return; + } - var c1r = colors[c1], + const c1r = colors[c1], c1g = colors[c1 + 1], c1b = colors[c1 + 2]; - var c2r = colors[c2], + const c2r = colors[c2], c2g = colors[c2 + 1], c2b = colors[c2 + 2]; - var c3r = colors[c3], + const c3r = colors[c3], c3g = colors[c3 + 1], c3b = colors[c3 + 2]; - var minY = Math.round(y1), + const minY = Math.round(y1), maxY = Math.round(y3); - var xa, car, cag, cab; - var xb, cbr, cbg, cbb; - - for (var y = minY; y <= maxY; y++) { - if (y < y2) { - let k; - - if (y < y1) { - k = 0; - } else if (y1 === y2) { - k = 1; - } else { - k = (y1 - y) / (y1 - y2); - } - - xa = x1 - (x1 - x2) * k; - car = c1r - (c1r - c2r) * k; - cag = c1g - (c1g - c2g) * k; - cab = c1b - (c1b - c2b) * k; - } else { - let k; - - if (y > y3) { - k = 1; - } else if (y2 === y3) { - k = 0; - } else { - k = (y2 - y) / (y2 - y3); - } - - xa = x2 - (x2 - x3) * k; - car = c2r - (c2r - c3r) * k; - cag = c2g - (c2g - c3g) * k; - cab = c2b - (c2b - c3b) * k; - } + let xa, car, cag, cab; + let xb, cbr, cbg, cbb; + for (let y = minY; y <= maxY; y++) { + if (y < y2) { let k; if (y < y1) { k = 0; - } else if (y > y3) { - k = 1; } else { - k = (y1 - y) / (y1 - y3); + k = (y1 - y) / (y1 - y2); } - xb = x1 - (x1 - x3) * k; - cbr = c1r - (c1r - c3r) * k; - cbg = c1g - (c1g - c3g) * k; - cbb = c1b - (c1b - c3b) * k; - var x1_ = Math.round(Math.min(xa, xb)); - var x2_ = Math.round(Math.max(xa, xb)); - var j = rowSize * y + x1_ * 4; + xa = x1 - (x1 - x2) * k; + car = c1r - (c1r - c2r) * k; + cag = c1g - (c1g - c2g) * k; + cab = c1b - (c1b - c2b) * k; + } else { + let k; - for (var x = x1_; x <= x2_; x++) { - k = (xa - x) / (xa - xb); - - if (k < 0) { - k = 0; - } else if (k > 1) { - k = 1; - } - - bytes[j++] = car - (car - cbr) * k | 0; - bytes[j++] = cag - (cag - cbg) * k | 0; - bytes[j++] = cab - (cab - cbb) * k | 0; - bytes[j++] = 255; + if (y > y3) { + k = 1; + } else if (y2 === y3) { + k = 0; + } else { + k = (y2 - y) / (y2 - y3); } + + xa = x2 - (x2 - x3) * k; + car = c2r - (c2r - c3r) * k; + cag = c2g - (c2g - c3g) * k; + cab = c2b - (c2b - c3b) * k; + } + + let k; + + if (y < y1) { + k = 0; + } else if (y > y3) { + k = 1; + } else { + k = (y1 - y) / (y1 - y3); + } + + xb = x1 - (x1 - x3) * k; + cbr = c1r - (c1r - c3r) * k; + cbg = c1g - (c1g - c3g) * k; + cbb = c1b - (c1b - c3b) * k; + const x1_ = Math.round(Math.min(xa, xb)); + const x2_ = Math.round(Math.max(xa, xb)); + let j = rowSize * y + x1_ * 4; + + for (let x = x1_; x <= x2_; x++) { + k = (xa - x) / (xa - xb); + + if (k < 0) { + k = 0; + } else if (k > 1) { + k = 1; + } + + bytes[j++] = car - (car - cbr) * k | 0; + bytes[j++] = cag - (cag - cbg) * k | 0; + bytes[j++] = cab - (cab - cbb) * k | 0; + bytes[j++] = 255; } } +} - function drawFigure(data, figure, context) { - var ps = figure.coords; - var cs = figure.colors; - var i, ii; +function drawFigure(data, figure, context) { + const ps = figure.coords; + const cs = figure.colors; + let i, ii; - switch (figure.type) { - case "lattice": - var verticesPerRow = figure.verticesPerRow; - var rows = Math.floor(ps.length / verticesPerRow) - 1; - var cols = verticesPerRow - 1; + switch (figure.type) { + case "lattice": + const verticesPerRow = figure.verticesPerRow; + const rows = Math.floor(ps.length / verticesPerRow) - 1; + const cols = verticesPerRow - 1; - for (i = 0; i < rows; i++) { - var q = i * verticesPerRow; + for (i = 0; i < rows; i++) { + let q = i * verticesPerRow; - for (var j = 0; j < cols; j++, q++) { - drawTriangle(data, context, ps[q], ps[q + 1], ps[q + verticesPerRow], cs[q], cs[q + 1], cs[q + verticesPerRow]); - drawTriangle(data, context, ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow], cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]); - } + for (let j = 0; j < cols; j++, q++) { + drawTriangle(data, context, ps[q], ps[q + 1], ps[q + verticesPerRow], cs[q], cs[q + 1], cs[q + verticesPerRow]); + drawTriangle(data, context, ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow], cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]); } + } - break; + break; - case "triangles": - for (i = 0, ii = ps.length; i < ii; i += 3) { - drawTriangle(data, context, ps[i], ps[i + 1], ps[i + 2], cs[i], cs[i + 1], cs[i + 2]); - } + case "triangles": + for (i = 0, ii = ps.length; i < ii; i += 3) { + drawTriangle(data, context, ps[i], ps[i + 1], ps[i + 2], cs[i], cs[i + 1], cs[i + 2]); + } - break; + break; - default: - throw new Error("illegal figure"); - } + default: + throw new Error("illegal figure"); + } +} + +class MeshShadingPattern extends BaseShadingPattern { + constructor(IR) { + super(); + this._coords = IR[2]; + this._colors = IR[3]; + this._figures = IR[4]; + this._bounds = IR[5]; + this._bbox = IR[7]; + this._background = IR[8]; + this.matrix = null; } - function createMeshCanvas(bounds, combinesScale, coords, colors, figures, backgroundColor, cachedCanvases, webGLContext) { - var EXPECTED_SCALE = 1.1; - var MAX_PATTERN_SIZE = 3000; - var BORDER_SIZE = 2; - var offsetX = Math.floor(bounds[0]); - var offsetY = Math.floor(bounds[1]); - var boundsWidth = Math.ceil(bounds[2]) - offsetX; - var boundsHeight = Math.ceil(bounds[3]) - offsetY; - var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] * EXPECTED_SCALE)), MAX_PATTERN_SIZE); - var height = Math.min(Math.ceil(Math.abs(boundsHeight * combinesScale[1] * EXPECTED_SCALE)), MAX_PATTERN_SIZE); - var scaleX = boundsWidth / width; - var scaleY = boundsHeight / height; - var context = { - coords, - colors, + _createMeshCanvas(combinedScale, backgroundColor, cachedCanvases) { + const EXPECTED_SCALE = 1.1; + const MAX_PATTERN_SIZE = 3000; + const BORDER_SIZE = 2; + const offsetX = Math.floor(this._bounds[0]); + const offsetY = Math.floor(this._bounds[1]); + const boundsWidth = Math.ceil(this._bounds[2]) - offsetX; + const boundsHeight = Math.ceil(this._bounds[3]) - offsetY; + const width = Math.min(Math.ceil(Math.abs(boundsWidth * combinedScale[0] * EXPECTED_SCALE)), MAX_PATTERN_SIZE); + const height = Math.min(Math.ceil(Math.abs(boundsHeight * combinedScale[1] * EXPECTED_SCALE)), MAX_PATTERN_SIZE); + const scaleX = boundsWidth / width; + const scaleY = boundsHeight / height; + const context = { + coords: this._coords, + colors: this._colors, offsetX: -offsetX, offsetY: -offsetY, scaleX: 1 / scaleX, scaleY: 1 / scaleY }; - var paddedWidth = width + BORDER_SIZE * 2; - var paddedHeight = height + BORDER_SIZE * 2; - var canvas, tmpCanvas, i, ii; + const paddedWidth = width + BORDER_SIZE * 2; + const paddedHeight = height + BORDER_SIZE * 2; + const tmpCanvas = cachedCanvases.getCanvas("mesh", paddedWidth, paddedHeight, false); + const tmpCtx = tmpCanvas.context; + const data = tmpCtx.createImageData(width, height); - if (webGLContext.isEnabled) { - canvas = webGLContext.drawFigures({ - width, - height, - backgroundColor, - figures, - context - }); - tmpCanvas = cachedCanvases.getCanvas("mesh", paddedWidth, paddedHeight, false); - tmpCanvas.context.drawImage(canvas, BORDER_SIZE, BORDER_SIZE); - canvas = tmpCanvas.canvas; - } else { - tmpCanvas = cachedCanvases.getCanvas("mesh", paddedWidth, paddedHeight, false); - var tmpCtx = tmpCanvas.context; - var data = tmpCtx.createImageData(width, height); + if (backgroundColor) { + const bytes = data.data; - if (backgroundColor) { - var bytes = data.data; - - for (i = 0, ii = bytes.length; i < ii; i += 4) { - bytes[i] = backgroundColor[0]; - bytes[i + 1] = backgroundColor[1]; - bytes[i + 2] = backgroundColor[2]; - bytes[i + 3] = 255; - } + for (let i = 0, ii = bytes.length; i < ii; i += 4) { + bytes[i] = backgroundColor[0]; + bytes[i + 1] = backgroundColor[1]; + bytes[i + 2] = backgroundColor[2]; + bytes[i + 3] = 255; } - - for (i = 0; i < figures.length; i++) { - drawFigure(data, figures[i], context); - } - - tmpCtx.putImageData(data, BORDER_SIZE, BORDER_SIZE); - canvas = tmpCanvas.canvas; } + for (const figure of this._figures) { + drawFigure(data, figure, context); + } + + tmpCtx.putImageData(data, BORDER_SIZE, BORDER_SIZE); + const canvas = tmpCanvas.canvas; return { canvas, offsetX: offsetX - BORDER_SIZE * scaleX, @@ -7004,82 +9217,72 @@ var createMeshCanvas = function createMeshCanvasClosure() { }; } - return createMeshCanvas; -}(); + getPattern(ctx, owner, inverse, pathType) { + applyBoundingBox(ctx, this._bbox); + let scale; -ShadingIRs.Mesh = { - fromIR: function Mesh_fromIR(raw) { - var coords = raw[2]; - var colors = raw[3]; - var figures = raw[4]; - var bounds = raw[5]; - var matrix = raw[6]; - var bbox = raw[7]; - var background = raw[8]; - return { - type: "Pattern", - getPattern: function Mesh_getPattern(ctx, owner, shadingFill) { - applyBoundingBox(ctx, bbox); - var scale; + if (pathType === PathType.SHADING) { + scale = _util.Util.singularValueDecompose2dScale((0, _display_utils.getCurrentTransform)(ctx)); + } else { + scale = _util.Util.singularValueDecompose2dScale(owner.baseTransform); - if (shadingFill) { - scale = _util.Util.singularValueDecompose2dScale(ctx.mozCurrentTransform); - } else { - scale = _util.Util.singularValueDecompose2dScale(owner.baseTransform); + if (this.matrix) { + const matrixScale = _util.Util.singularValueDecompose2dScale(this.matrix); - if (matrix) { - var matrixScale = _util.Util.singularValueDecompose2dScale(matrix); - - scale = [scale[0] * matrixScale[0], scale[1] * matrixScale[1]]; - } - } - - var temporaryPatternCanvas = createMeshCanvas(bounds, scale, coords, colors, figures, shadingFill ? null : background, owner.cachedCanvases, owner.webGLContext); - - if (!shadingFill) { - ctx.setTransform.apply(ctx, owner.baseTransform); - - if (matrix) { - ctx.transform.apply(ctx, matrix); - } - } - - ctx.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY); - ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY); - return ctx.createPattern(temporaryPatternCanvas.canvas, "no-repeat"); + scale = [scale[0] * matrixScale[0], scale[1] * matrixScale[1]]; } - }; - } -}; -ShadingIRs.Dummy = { - fromIR: function Dummy_fromIR() { - return { - type: "Pattern", - getPattern: function Dummy_fromIR_getPattern() { - return "hotpink"; + } + + const temporaryPatternCanvas = this._createMeshCanvas(scale, pathType === PathType.SHADING ? null : this._background, owner.cachedCanvases); + + if (pathType !== PathType.SHADING) { + ctx.setTransform(...owner.baseTransform); + + if (this.matrix) { + ctx.transform(...this.matrix); } - }; - } -}; + } -function getShadingPatternFromIR(raw) { - var shadingIR = ShadingIRs[raw[0]]; - - if (!shadingIR) { - throw new Error(`Unknown IR type: ${raw[0]}`); + ctx.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY); + ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY); + return ctx.createPattern(temporaryPatternCanvas.canvas, "no-repeat"); } - return shadingIR.fromIR(raw); } -var TilingPattern = function TilingPatternClosure() { - var PaintType = { - COLORED: 1, - UNCOLORED: 2 - }; - var MAX_PATTERN_SIZE = 3000; +class DummyShadingPattern extends BaseShadingPattern { + getPattern() { + return "hotpink"; + } - function TilingPattern(IR, color, ctx, canvasGraphicsFactory, baseTransform) { +} + +function getShadingPattern(IR) { + switch (IR[0]) { + case "RadialAxial": + return new RadialAxialShadingPattern(IR); + + case "Mesh": + return new MeshShadingPattern(IR); + + case "Dummy": + return new DummyShadingPattern(); + } + + throw new Error(`Unknown IR type: ${IR[0]}`); +} + +const PaintType = { + COLORED: 1, + UNCOLORED: 2 +}; + +class TilingPattern { + static get MAX_PATTERN_SIZE() { + return (0, _util.shadow)(this, "MAX_PATTERN_SIZE", 3000); + } + + constructor(IR, color, ctx, canvasGraphicsFactory, baseTransform) { this.operatorList = IR[2]; this.matrix = IR[3] || [1, 0, 0, 1, 0, 0]; this.bbox = IR[4]; @@ -7088,122 +9291,220 @@ var TilingPattern = function TilingPatternClosure() { this.paintType = IR[7]; this.tilingType = IR[8]; this.color = color; + this.ctx = ctx; this.canvasGraphicsFactory = canvasGraphicsFactory; this.baseTransform = baseTransform; - this.type = "Pattern"; - this.ctx = ctx; } - TilingPattern.prototype = { - createPatternCanvas: function TilinPattern_createPatternCanvas(owner) { - var operatorList = this.operatorList; - var bbox = this.bbox; - var xstep = this.xstep; - var ystep = this.ystep; - var paintType = this.paintType; - var tilingType = this.tilingType; - var color = this.color; - var canvasGraphicsFactory = this.canvasGraphicsFactory; - (0, _util.info)("TilingType: " + tilingType); - var x0 = bbox[0], + createPatternCanvas(owner) { + const operatorList = this.operatorList; + const bbox = this.bbox; + const xstep = this.xstep; + const ystep = this.ystep; + const paintType = this.paintType; + const tilingType = this.tilingType; + const color = this.color; + const canvasGraphicsFactory = this.canvasGraphicsFactory; + (0, _util.info)("TilingType: " + tilingType); + const x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3]; - var matrixScale = _util.Util.singularValueDecompose2dScale(this.matrix); + const matrixScale = _util.Util.singularValueDecompose2dScale(this.matrix); - var curMatrixScale = _util.Util.singularValueDecompose2dScale(this.baseTransform); + const curMatrixScale = _util.Util.singularValueDecompose2dScale(this.baseTransform); - var combinedScale = [matrixScale[0] * curMatrixScale[0], matrixScale[1] * curMatrixScale[1]]; - var dimx = this.getSizeAndScale(xstep, this.ctx.canvas.width, combinedScale[0]); - var dimy = this.getSizeAndScale(ystep, this.ctx.canvas.height, combinedScale[1]); - var tmpCanvas = owner.cachedCanvases.getCanvas("pattern", dimx.size, dimy.size, true); - var tmpCtx = tmpCanvas.context; - var graphics = canvasGraphicsFactory.createCanvasGraphics(tmpCtx); - graphics.groupLevel = owner.groupLevel; - this.setFillAndStrokeStyleToContext(graphics, paintType, color); - graphics.transform(dimx.scale, 0, 0, dimy.scale, 0, 0); - graphics.transform(1, 0, 0, 1, -x0, -y0); - this.clipBbox(graphics, bbox, x0, y0, x1, y1); - graphics.executeOperatorList(operatorList); - this.ctx.transform(1, 0, 0, 1, x0, y0); - this.ctx.scale(1 / dimx.scale, 1 / dimy.scale); - return tmpCanvas.canvas; - }, - getSizeAndScale: function TilingPattern_getSizeAndScale(step, realOutputSize, scale) { - step = Math.abs(step); - var maxSize = Math.max(MAX_PATTERN_SIZE, realOutputSize); - var size = Math.ceil(step * scale); + const combinedScale = [matrixScale[0] * curMatrixScale[0], matrixScale[1] * curMatrixScale[1]]; + const dimx = this.getSizeAndScale(xstep, this.ctx.canvas.width, combinedScale[0]); + const dimy = this.getSizeAndScale(ystep, this.ctx.canvas.height, combinedScale[1]); + const tmpCanvas = owner.cachedCanvases.getCanvas("pattern", dimx.size, dimy.size, true); + const tmpCtx = tmpCanvas.context; + const graphics = canvasGraphicsFactory.createCanvasGraphics(tmpCtx); + graphics.groupLevel = owner.groupLevel; + this.setFillAndStrokeStyleToContext(graphics, paintType, color); + let adjustedX0 = x0; + let adjustedY0 = y0; + let adjustedX1 = x1; + let adjustedY1 = y1; - if (size >= maxSize) { - size = maxSize; - } else { - scale = size / step; - } - - return { - scale, - size - }; - }, - clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) { - if (Array.isArray(bbox) && bbox.length === 4) { - var bboxWidth = x1 - x0; - var bboxHeight = y1 - y0; - graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight); - graphics.clip(); - graphics.endPath(); - } - }, - setFillAndStrokeStyleToContext: function setFillAndStrokeStyleToContext(graphics, paintType, color) { - const context = graphics.ctx, - current = graphics.current; - - switch (paintType) { - case PaintType.COLORED: - var ctx = this.ctx; - context.fillStyle = ctx.fillStyle; - context.strokeStyle = ctx.strokeStyle; - current.fillColor = ctx.fillStyle; - current.strokeColor = ctx.strokeStyle; - break; - - case PaintType.UNCOLORED: - var cssColor = _util.Util.makeCssRgb(color[0], color[1], color[2]); - - context.fillStyle = cssColor; - context.strokeStyle = cssColor; - current.fillColor = cssColor; - current.strokeColor = cssColor; - break; - - default: - throw new _util.FormatError(`Unsupported paint type: ${paintType}`); - } - }, - getPattern: function TilingPattern_getPattern(ctx, owner) { - ctx = this.ctx; - ctx.setTransform.apply(ctx, this.baseTransform); - ctx.transform.apply(ctx, this.matrix); - var temporaryPatternCanvas = this.createPatternCanvas(owner); - return ctx.createPattern(temporaryPatternCanvas, "repeat"); + if (x0 < 0) { + adjustedX0 = 0; + adjustedX1 += Math.abs(x0); } - }; - return TilingPattern; -}(); + + if (y0 < 0) { + adjustedY0 = 0; + adjustedY1 += Math.abs(y0); + } + + tmpCtx.translate(-(dimx.scale * adjustedX0), -(dimy.scale * adjustedY0)); + graphics.transform(dimx.scale, 0, 0, dimy.scale, 0, 0); + tmpCtx.save(); + this.clipBbox(graphics, adjustedX0, adjustedY0, adjustedX1, adjustedY1); + graphics.baseTransform = (0, _display_utils.getCurrentTransform)(graphics.ctx); + graphics.executeOperatorList(operatorList); + graphics.endDrawing(); + return { + canvas: tmpCanvas.canvas, + scaleX: dimx.scale, + scaleY: dimy.scale, + offsetX: adjustedX0, + offsetY: adjustedY0 + }; + } + + getSizeAndScale(step, realOutputSize, scale) { + step = Math.abs(step); + const maxSize = Math.max(TilingPattern.MAX_PATTERN_SIZE, realOutputSize); + let size = Math.ceil(step * scale); + + if (size >= maxSize) { + size = maxSize; + } else { + scale = size / step; + } + + return { + scale, + size + }; + } + + clipBbox(graphics, x0, y0, x1, y1) { + const bboxWidth = x1 - x0; + const bboxHeight = y1 - y0; + graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight); + graphics.current.updateRectMinMax((0, _display_utils.getCurrentTransform)(graphics.ctx), [x0, y0, x1, y1]); + graphics.clip(); + graphics.endPath(); + } + + setFillAndStrokeStyleToContext(graphics, paintType, color) { + const context = graphics.ctx, + current = graphics.current; + + switch (paintType) { + case PaintType.COLORED: + const ctx = this.ctx; + context.fillStyle = ctx.fillStyle; + context.strokeStyle = ctx.strokeStyle; + current.fillColor = ctx.fillStyle; + current.strokeColor = ctx.strokeStyle; + break; + + case PaintType.UNCOLORED: + const cssColor = _util.Util.makeHexColor(color[0], color[1], color[2]); + + context.fillStyle = cssColor; + context.strokeStyle = cssColor; + current.fillColor = cssColor; + current.strokeColor = cssColor; + break; + + default: + throw new _util.FormatError(`Unsupported paint type: ${paintType}`); + } + } + + getPattern(ctx, owner, inverse, pathType) { + let matrix = inverse; + + if (pathType !== PathType.SHADING) { + matrix = _util.Util.transform(matrix, owner.baseTransform); + + if (this.matrix) { + matrix = _util.Util.transform(matrix, this.matrix); + } + } + + const temporaryPatternCanvas = this.createPatternCanvas(owner); + let domMatrix = new DOMMatrix(matrix); + domMatrix = domMatrix.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY); + domMatrix = domMatrix.scale(1 / temporaryPatternCanvas.scaleX, 1 / temporaryPatternCanvas.scaleY); + const pattern = ctx.createPattern(temporaryPatternCanvas.canvas, "repeat"); + + try { + pattern.setTransform(domMatrix); + } catch (ex) { + (0, _util.warn)(`TilingPattern.getPattern: "${ex?.message}".`); + } + + return pattern; + } + +} exports.TilingPattern = TilingPattern; /***/ }), -/* 12 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 14 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.applyMaskImageData = applyMaskImageData; + +var _util = __w_pdfjs_require__(1); + +function applyMaskImageData({ + src, + srcPos = 0, + dest, + destPos = 0, + width, + height, + inverseDecode = false +}) { + const opaque = _util.FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff; + const [zeroMapping, oneMapping] = !inverseDecode ? [opaque, 0] : [0, opaque]; + const widthInSource = width >> 3; + const widthRemainder = width & 7; + const srcLength = src.length; + dest = new Uint32Array(dest.buffer); + + for (let i = 0; i < height; i++) { + for (const max = srcPos + widthInSource; srcPos < max; srcPos++) { + const elem = srcPos < srcLength ? src[srcPos] : 255; + dest[destPos++] = elem & 0b10000000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b1000000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b100000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b10000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b1000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b100 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b10 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b1 ? oneMapping : zeroMapping; + } + + if (widthRemainder === 0) { + continue; + } + + const elem = srcPos < srcLength ? src[srcPos++] : 255; + + for (let j = 0; j < widthRemainder; j++) { + dest[destPos++] = elem & 1 << 7 - j ? oneMapping : zeroMapping; + } + } + + return { + srcPos, + destPos + }; +} + +/***/ }), +/* 15 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.GlobalWorkerOptions = void 0; const GlobalWorkerOptions = Object.create(null); exports.GlobalWorkerOptions = GlobalWorkerOptions; @@ -7211,18 +9512,17 @@ GlobalWorkerOptions.workerPort = GlobalWorkerOptions.workerPort === undefined ? GlobalWorkerOptions.workerSrc = GlobalWorkerOptions.workerSrc === undefined ? "" : GlobalWorkerOptions.workerSrc; /***/ }), -/* 13 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 16 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.MessageHandler = void 0; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); const CallbackKind = { UNKNOWN: 0, @@ -7242,8 +9542,8 @@ const StreamKind = { }; function wrapReason(reason) { - if (typeof reason !== "object" || reason === null) { - return reason; + if (!(reason instanceof Error || typeof reason === "object" && reason !== null)) { + (0, _util.unreachable)('wrapReason: Expected "reason" to be a (possibly cloned) Error.'); } switch (reason.name) { @@ -7253,6 +9553,9 @@ function wrapReason(reason) { case "MissingPDFException": return new _util.MissingPDFException(reason.message); + case "PasswordException": + return new _util.PasswordException(reason.message, reason.code); + case "UnexpectedResponseException": return new _util.UnexpectedResponseException(reason.message, reason.status); @@ -7271,7 +9574,6 @@ class MessageHandler { this.comObj = comObj; this.callbackId = 1; this.streamId = 1; - this.postMessageTransfers = true; this.streamSinks = Object.create(null); this.streamControllers = Object.create(null); this.callbackCapabilities = Object.create(null); @@ -7365,7 +9667,7 @@ class MessageHandler { } send(actionName, data, transfers) { - this._postMessage({ + this.comObj.postMessage({ sourceName: this.sourceName, targetName: this.targetName, action: actionName, @@ -7379,7 +9681,7 @@ class MessageHandler { this.callbackCapabilities[callbackId] = capability; try { - this._postMessage({ + this.comObj.postMessage({ sourceName: this.sourceName, targetName: this.targetName, action: actionName, @@ -7394,10 +9696,10 @@ class MessageHandler { } sendWithStream(actionName, data, queueingStrategy, transfers) { - const streamId = this.streamId++; - const sourceName = this.sourceName; - const targetName = this.targetName; - const comObj = this.comObj; + const streamId = this.streamId++, + sourceName = this.sourceName, + targetName = this.targetName, + comObj = this.comObj; return new ReadableStream({ start: controller => { const startCapability = (0, _util.createPromiseCapability)(); @@ -7408,8 +9710,7 @@ class MessageHandler { cancelCall: null, isClosed: false }; - - this._postMessage({ + comObj.postMessage({ sourceName, targetName, action: actionName, @@ -7417,7 +9718,6 @@ class MessageHandler { data, desiredSize: controller.desiredSize }, transfers); - return startCapability.promise; }, pull: controller => { @@ -7450,12 +9750,12 @@ class MessageHandler { } _createStreamSink(data) { - const self = this; - const action = this.actionHandler[data.action]; - const streamId = data.streamId; - const sourceName = this.sourceName; - const targetName = data.sourceName; - const comObj = this.comObj; + const streamId = data.streamId, + sourceName = this.sourceName, + targetName = data.sourceName, + comObj = this.comObj; + const self = this, + action = this.actionHandler[data.action]; const streamSink = { enqueue(chunk, size = 1, transfers) { if (this.isCancelled) { @@ -7470,7 +9770,7 @@ class MessageHandler { this.ready = this.sinkCapability.promise; } - self._postMessage({ + comObj.postMessage({ sourceName, targetName, stream: StreamKind.ENQUEUE, @@ -7543,32 +9843,34 @@ class MessageHandler { } _processStreamMessage(data) { - const streamId = data.streamId; - const sourceName = this.sourceName; - const targetName = data.sourceName; - const comObj = this.comObj; + const streamId = data.streamId, + sourceName = this.sourceName, + targetName = data.sourceName, + comObj = this.comObj; + const streamController = this.streamControllers[streamId], + streamSink = this.streamSinks[streamId]; switch (data.stream) { case StreamKind.START_COMPLETE: if (data.success) { - this.streamControllers[streamId].startCall.resolve(); + streamController.startCall.resolve(); } else { - this.streamControllers[streamId].startCall.reject(wrapReason(data.reason)); + streamController.startCall.reject(wrapReason(data.reason)); } break; case StreamKind.PULL_COMPLETE: if (data.success) { - this.streamControllers[streamId].pullCall.resolve(); + streamController.pullCall.resolve(); } else { - this.streamControllers[streamId].pullCall.reject(wrapReason(data.reason)); + streamController.pullCall.reject(wrapReason(data.reason)); } break; case StreamKind.PULL: - if (!this.streamSinks[streamId]) { + if (!streamSink) { comObj.postMessage({ sourceName, targetName, @@ -7579,16 +9881,13 @@ class MessageHandler { break; } - if (this.streamSinks[streamId].desiredSize <= 0 && data.desiredSize > 0) { - this.streamSinks[streamId].sinkCapability.resolve(); + if (streamSink.desiredSize <= 0 && data.desiredSize > 0) { + streamSink.sinkCapability.resolve(); } - this.streamSinks[streamId].desiredSize = data.desiredSize; - const { - onPull - } = this.streamSinks[data.streamId]; + streamSink.desiredSize = data.desiredSize; new Promise(function (resolve) { - resolve(onPull && onPull()); + resolve(streamSink.onPull && streamSink.onPull()); }).then(function () { comObj.postMessage({ sourceName, @@ -7609,58 +9908,55 @@ class MessageHandler { break; case StreamKind.ENQUEUE: - (0, _util.assert)(this.streamControllers[streamId], "enqueue should have stream controller"); + (0, _util.assert)(streamController, "enqueue should have stream controller"); - if (this.streamControllers[streamId].isClosed) { + if (streamController.isClosed) { break; } - this.streamControllers[streamId].controller.enqueue(data.chunk); + streamController.controller.enqueue(data.chunk); break; case StreamKind.CLOSE: - (0, _util.assert)(this.streamControllers[streamId], "close should have stream controller"); + (0, _util.assert)(streamController, "close should have stream controller"); - if (this.streamControllers[streamId].isClosed) { + if (streamController.isClosed) { break; } - this.streamControllers[streamId].isClosed = true; - this.streamControllers[streamId].controller.close(); + streamController.isClosed = true; + streamController.controller.close(); - this._deleteStreamController(streamId); + this._deleteStreamController(streamController, streamId); break; case StreamKind.ERROR: - (0, _util.assert)(this.streamControllers[streamId], "error should have stream controller"); - this.streamControllers[streamId].controller.error(wrapReason(data.reason)); + (0, _util.assert)(streamController, "error should have stream controller"); + streamController.controller.error(wrapReason(data.reason)); - this._deleteStreamController(streamId); + this._deleteStreamController(streamController, streamId); break; case StreamKind.CANCEL_COMPLETE: if (data.success) { - this.streamControllers[streamId].cancelCall.resolve(); + streamController.cancelCall.resolve(); } else { - this.streamControllers[streamId].cancelCall.reject(wrapReason(data.reason)); + streamController.cancelCall.reject(wrapReason(data.reason)); } - this._deleteStreamController(streamId); + this._deleteStreamController(streamController, streamId); break; case StreamKind.CANCEL: - if (!this.streamSinks[streamId]) { + if (!streamSink) { break; } - const { - onCancel - } = this.streamSinks[data.streamId]; new Promise(function (resolve) { - resolve(onCancel && onCancel(wrapReason(data.reason))); + resolve(streamSink.onCancel && streamSink.onCancel(wrapReason(data.reason))); }).then(function () { comObj.postMessage({ sourceName, @@ -7678,8 +9974,8 @@ class MessageHandler { reason: wrapReason(reason) }); }); - this.streamSinks[streamId].sinkCapability.reject(wrapReason(data.reason)); - this.streamSinks[streamId].isCancelled = true; + streamSink.sinkCapability.reject(wrapReason(data.reason)); + streamSink.isCancelled = true; delete this.streamSinks[streamId]; break; @@ -7688,21 +9984,11 @@ class MessageHandler { } } - async _deleteStreamController(streamId) { - await Promise.allSettled([this.streamControllers[streamId].startCall, this.streamControllers[streamId].pullCall, this.streamControllers[streamId].cancelCall].map(function (capability) { - return capability && capability.promise; - })); + async _deleteStreamController(streamController, streamId) { + await Promise.allSettled([streamController.startCall && streamController.startCall.promise, streamController.pullCall && streamController.pullCall.promise, streamController.cancelCall && streamController.cancelCall.promise]); delete this.streamControllers[streamId]; } - _postMessage(message, transfers) { - if (transfers && this.postMessageTransfers) { - this.comObj.postMessage(message, transfers); - } else { - this.comObj.postMessage(message); - } - } - destroy() { this.comObj.removeEventListener("message", this._onComObjOnMessage); } @@ -7712,121 +9998,44 @@ class MessageHandler { exports.MessageHandler = MessageHandler; /***/ }), -/* 14 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 17 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.Metadata = void 0; -var _util = __w_pdfjs_require__(2); - -var _xml_parser = __w_pdfjs_require__(15); +var _util = __w_pdfjs_require__(1); class Metadata { - constructor(data) { - (0, _util.assert)(typeof data === "string", "Metadata: input is not a string"); - data = this._repair(data); - const parser = new _xml_parser.SimpleXMLParser(); - const xmlDocument = parser.parseFromString(data); - this._metadataMap = new Map(); + #metadataMap; + #data; - if (xmlDocument) { - this._parse(xmlDocument); - } + constructor({ + parsedData, + rawData + }) { + this.#metadataMap = parsedData; + this.#data = rawData; } - _repair(data) { - return data.replace(/^[^<]+/, "").replace(/>\\376\\377([^<]+)/g, function (all, codes) { - const bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g, function (code, d1, d2, d3) { - return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1); - }).replace(/&(amp|apos|gt|lt|quot);/g, function (str, name) { - switch (name) { - case "amp": - return "&"; - - case "apos": - return "'"; - - case "gt": - return ">"; - - case "lt": - return "<"; - - case "quot": - return '"'; - } - - throw new Error(`_repair: ${name} isn't defined.`); - }); - let chars = ""; - - for (let i = 0, ii = bytes.length; i < ii; i += 2) { - const code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1); - - if (code >= 32 && code < 127 && code !== 60 && code !== 62 && code !== 38) { - chars += String.fromCharCode(code); - } else { - chars += "&#x" + (0x10000 + code).toString(16).substring(1) + ";"; - } - } - - return ">" + chars; - }); - } - - _parse(xmlDocument) { - let rdf = xmlDocument.documentElement; - - if (rdf.nodeName.toLowerCase() !== "rdf:rdf") { - rdf = rdf.firstChild; - - while (rdf && rdf.nodeName.toLowerCase() !== "rdf:rdf") { - rdf = rdf.nextSibling; - } - } - - const nodeName = rdf ? rdf.nodeName.toLowerCase() : null; - - if (!rdf || nodeName !== "rdf:rdf" || !rdf.hasChildNodes()) { - return; - } - - const children = rdf.childNodes; - - for (let i = 0, ii = children.length; i < ii; i++) { - const desc = children[i]; - - if (desc.nodeName.toLowerCase() !== "rdf:description") { - continue; - } - - for (let j = 0, jj = desc.childNodes.length; j < jj; j++) { - if (desc.childNodes[j].nodeName.toLowerCase() !== "#text") { - const entry = desc.childNodes[j]; - const name = entry.nodeName.toLowerCase(); - - this._metadataMap.set(name, entry.textContent.trim()); - } - } - } + getRaw() { + return this.#data; } get(name) { - return this._metadataMap.has(name) ? this._metadataMap.get(name) : null; + return this.#metadataMap.get(name) ?? null; } getAll() { - return Object.fromEntries(this._metadataMap); + return (0, _util.objectFromMap)(this.#metadataMap); } has(name) { - return this._metadataMap.has(name); + return this.#metadataMap.has(name); } } @@ -7834,477 +10043,51 @@ class Metadata { exports.Metadata = Metadata; /***/ }), -/* 15 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 18 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.SimpleXMLParser = void 0; -const XMLParserErrorCode = { - NoError: 0, - EndOfDocument: -1, - UnterminatedCdat: -2, - UnterminatedXmlDeclaration: -3, - UnterminatedDoctypeDeclaration: -4, - UnterminatedComment: -5, - MalformedElement: -6, - OutOfMemory: -7, - UnterminatedAttributeValue: -8, - UnterminatedElement: -9, - ElementNeverBegun: -10 -}; - -function isWhitespace(s, index) { - const ch = s[index]; - return ch === " " || ch === "\n" || ch === "\r" || ch === "\t"; -} - -function isWhitespaceString(s) { - for (let i = 0, ii = s.length; i < ii; i++) { - if (!isWhitespace(s, i)) { - return false; - } - } - - return true; -} - -class XMLParserBase { - _resolveEntities(s) { - return s.replace(/&([^;]+);/g, (all, entity) => { - if (entity.substring(0, 2) === "#x") { - return String.fromCharCode(parseInt(entity.substring(2), 16)); - } else if (entity.substring(0, 1) === "#") { - return String.fromCharCode(parseInt(entity.substring(1), 10)); - } - - switch (entity) { - case "lt": - return "<"; - - case "gt": - return ">"; - - case "amp": - return "&"; - - case "quot": - return '"'; - } - - return this.onResolveEntity(entity); - }); - } - - _parseContent(s, start) { - const attributes = []; - let pos = start; - - function skipWs() { - while (pos < s.length && isWhitespace(s, pos)) { - ++pos; - } - } - - while (pos < s.length && !isWhitespace(s, pos) && s[pos] !== ">" && s[pos] !== "/") { - ++pos; - } - - const name = s.substring(start, pos); - skipWs(); - - while (pos < s.length && s[pos] !== ">" && s[pos] !== "/" && s[pos] !== "?") { - skipWs(); - let attrName = "", - attrValue = ""; - - while (pos < s.length && !isWhitespace(s, pos) && s[pos] !== "=") { - attrName += s[pos]; - ++pos; - } - - skipWs(); - - if (s[pos] !== "=") { - return null; - } - - ++pos; - skipWs(); - const attrEndChar = s[pos]; - - if (attrEndChar !== '"' && attrEndChar !== "'") { - return null; - } - - const attrEndIndex = s.indexOf(attrEndChar, ++pos); - - if (attrEndIndex < 0) { - return null; - } - - attrValue = s.substring(pos, attrEndIndex); - attributes.push({ - name: attrName, - value: this._resolveEntities(attrValue) - }); - pos = attrEndIndex + 1; - skipWs(); - } - - return { - name, - attributes, - parsed: pos - start - }; - } - - _parseProcessingInstruction(s, start) { - let pos = start; - - function skipWs() { - while (pos < s.length && isWhitespace(s, pos)) { - ++pos; - } - } - - while (pos < s.length && !isWhitespace(s, pos) && s[pos] !== ">" && s[pos] !== "/") { - ++pos; - } - - const name = s.substring(start, pos); - skipWs(); - const attrStart = pos; - - while (pos < s.length && (s[pos] !== "?" || s[pos + 1] !== ">")) { - ++pos; - } - - const value = s.substring(attrStart, pos); - return { - name, - value, - parsed: pos - start - }; - } - - parseXml(s) { - let i = 0; - - while (i < s.length) { - const ch = s[i]; - let j = i; - - if (ch === "<") { - ++j; - const ch2 = s[j]; - let q; - - switch (ch2) { - case "/": - ++j; - q = s.indexOf(">", j); - - if (q < 0) { - this.onError(XMLParserErrorCode.UnterminatedElement); - return; - } - - this.onEndElement(s.substring(j, q)); - j = q + 1; - break; - - case "?": - ++j; - - const pi = this._parseProcessingInstruction(s, j); - - if (s.substring(j + pi.parsed, j + pi.parsed + 2) !== "?>") { - this.onError(XMLParserErrorCode.UnterminatedXmlDeclaration); - return; - } - - this.onPi(pi.name, pi.value); - j += pi.parsed + 2; - break; - - case "!": - if (s.substring(j + 1, j + 3) === "--") { - q = s.indexOf("-->", j + 3); - - if (q < 0) { - this.onError(XMLParserErrorCode.UnterminatedComment); - return; - } - - this.onComment(s.substring(j + 3, q)); - j = q + 3; - } else if (s.substring(j + 1, j + 8) === "[CDATA[") { - q = s.indexOf("]]>", j + 8); - - if (q < 0) { - this.onError(XMLParserErrorCode.UnterminatedCdat); - return; - } - - this.onCdata(s.substring(j + 8, q)); - j = q + 3; - } else if (s.substring(j + 1, j + 8) === "DOCTYPE") { - const q2 = s.indexOf("[", j + 8); - let complexDoctype = false; - q = s.indexOf(">", j + 8); - - if (q < 0) { - this.onError(XMLParserErrorCode.UnterminatedDoctypeDeclaration); - return; - } - - if (q2 > 0 && q > q2) { - q = s.indexOf("]>", j + 8); - - if (q < 0) { - this.onError(XMLParserErrorCode.UnterminatedDoctypeDeclaration); - return; - } - - complexDoctype = true; - } - - const doctypeContent = s.substring(j + 8, q + (complexDoctype ? 1 : 0)); - this.onDoctype(doctypeContent); - j = q + (complexDoctype ? 2 : 1); - } else { - this.onError(XMLParserErrorCode.MalformedElement); - return; - } - - break; - - default: - const content = this._parseContent(s, j); - - if (content === null) { - this.onError(XMLParserErrorCode.MalformedElement); - return; - } - - let isClosed = false; - - if (s.substring(j + content.parsed, j + content.parsed + 2) === "/>") { - isClosed = true; - } else if (s.substring(j + content.parsed, j + content.parsed + 1) !== ">") { - this.onError(XMLParserErrorCode.UnterminatedElement); - return; - } - - this.onBeginElement(content.name, content.attributes, isClosed); - j += content.parsed + (isClosed ? 2 : 1); - break; - } - } else { - while (j < s.length && s[j] !== "<") { - j++; - } - - const text = s.substring(i, j); - this.onText(this._resolveEntities(text)); - } - - i = j; - } - } - - onResolveEntity(name) { - return `&${name};`; - } - - onPi(name, value) {} - - onComment(text) {} - - onCdata(text) {} - - onDoctype(doctypeContent) {} - - onText(text) {} - - onBeginElement(name, attributes, isEmpty) {} - - onEndElement(name) {} - - onError(code) {} - -} - -class SimpleDOMNode { - constructor(nodeName, nodeValue) { - this.nodeName = nodeName; - this.nodeValue = nodeValue; - Object.defineProperty(this, "parentNode", { - value: null, - writable: true - }); - } - - get firstChild() { - return this.childNodes && this.childNodes[0]; - } - - get nextSibling() { - const childNodes = this.parentNode.childNodes; - - if (!childNodes) { - return undefined; - } - - const index = childNodes.indexOf(this); - - if (index === -1) { - return undefined; - } - - return childNodes[index + 1]; - } - - get textContent() { - if (!this.childNodes) { - return this.nodeValue || ""; - } - - return this.childNodes.map(function (child) { - return child.textContent; - }).join(""); - } - - hasChildNodes() { - return this.childNodes && this.childNodes.length > 0; - } - -} - -class SimpleXMLParser extends XMLParserBase { - constructor() { - super(); - this._currentFragment = null; - this._stack = null; - this._errorCode = XMLParserErrorCode.NoError; - } - - parseFromString(data) { - this._currentFragment = []; - this._stack = []; - this._errorCode = XMLParserErrorCode.NoError; - this.parseXml(data); - - if (this._errorCode !== XMLParserErrorCode.NoError) { - return undefined; - } - - const [documentElement] = this._currentFragment; - - if (!documentElement) { - return undefined; - } - - return { - documentElement - }; - } - - onResolveEntity(name) { - switch (name) { - case "apos": - return "'"; - } - - return super.onResolveEntity(name); - } - - onText(text) { - if (isWhitespaceString(text)) { - return; - } - - const node = new SimpleDOMNode("#text", text); - - this._currentFragment.push(node); - } - - onCdata(text) { - const node = new SimpleDOMNode("#text", text); - - this._currentFragment.push(node); - } - - onBeginElement(name, attributes, isEmpty) { - const node = new SimpleDOMNode(name); - node.childNodes = []; - - this._currentFragment.push(node); - - if (isEmpty) { - return; - } - - this._stack.push(this._currentFragment); - - this._currentFragment = node.childNodes; - } - - onEndElement(name) { - this._currentFragment = this._stack.pop() || []; - const lastElement = this._currentFragment[this._currentFragment.length - 1]; - - if (!lastElement) { - return; - } - - for (let i = 0, ii = lastElement.childNodes.length; i < ii; i++) { - lastElement.childNodes[i].parentNode = lastElement; - } - } - - onError(code) { - this._errorCode = code; - } - -} - -exports.SimpleXMLParser = SimpleXMLParser; - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); +})); exports.OptionalContentConfig = void 0; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); + +const INTERNAL = Symbol("INTERNAL"); class OptionalContentGroup { + #visible = true; + constructor(name, intent) { - this.visible = true; this.name = name; this.intent = intent; } + get visible() { + return this.#visible; + } + + _setVisible(internal, visible) { + if (internal !== INTERNAL) { + (0, _util.unreachable)("Internal method `_setVisible` called."); + } + + this.#visible = visible; + } + } class OptionalContentConfig { + #cachedHasInitialVisibility = true; + #groups = new Map(); + #initialVisibility = null; + #order = null; + constructor(data) { this.name = null; this.creator = null; - this._order = null; - this._groups = new Map(); if (data === null) { return; @@ -8312,48 +10095,111 @@ class OptionalContentConfig { this.name = data.name; this.creator = data.creator; - this._order = data.order; + this.#order = data.order; for (const group of data.groups) { - this._groups.set(group.id, new OptionalContentGroup(group.name, group.intent)); + this.#groups.set(group.id, new OptionalContentGroup(group.name, group.intent)); } if (data.baseState === "OFF") { - for (const group of this._groups) { - group.visible = false; + for (const group of this.#groups.values()) { + group._setVisible(INTERNAL, false); } } for (const on of data.on) { - this._groups.get(on).visible = true; + this.#groups.get(on)._setVisible(INTERNAL, true); } for (const off of data.off) { - this._groups.get(off).visible = false; + this.#groups.get(off)._setVisible(INTERNAL, false); + } + + this.#initialVisibility = new Map(); + + for (const [id, group] of this.#groups) { + this.#initialVisibility.set(id, group.visible); } } + #evaluateVisibilityExpression(array) { + const length = array.length; + + if (length < 2) { + return true; + } + + const operator = array[0]; + + for (let i = 1; i < length; i++) { + const element = array[i]; + let state; + + if (Array.isArray(element)) { + state = this.#evaluateVisibilityExpression(element); + } else if (this.#groups.has(element)) { + state = this.#groups.get(element).visible; + } else { + (0, _util.warn)(`Optional content group not found: ${element}`); + return true; + } + + switch (operator) { + case "And": + if (!state) { + return false; + } + + break; + + case "Or": + if (state) { + return true; + } + + break; + + case "Not": + return !state; + + default: + return true; + } + } + + return operator === "And"; + } + isVisible(group) { + if (this.#groups.size === 0) { + return true; + } + + if (!group) { + (0, _util.warn)("Optional content group not defined."); + return true; + } + if (group.type === "OCG") { - if (!this._groups.has(group.id)) { + if (!this.#groups.has(group.id)) { (0, _util.warn)(`Optional content group not found: ${group.id}`); return true; } - return this._groups.get(group.id).visible; + return this.#groups.get(group.id).visible; } else if (group.type === "OCMD") { if (group.expression) { - (0, _util.warn)("Visibility expression not supported yet."); + return this.#evaluateVisibilityExpression(group.expression); } if (!group.policy || group.policy === "AnyOn") { for (const id of group.ids) { - if (!this._groups.has(id)) { + if (!this.#groups.has(id)) { (0, _util.warn)(`Optional content group not found: ${id}`); return true; } - if (this._groups.get(id).visible) { + if (this.#groups.get(id).visible) { return true; } } @@ -8361,12 +10207,12 @@ class OptionalContentConfig { return false; } else if (group.policy === "AllOn") { for (const id of group.ids) { - if (!this._groups.has(id)) { + if (!this.#groups.has(id)) { (0, _util.warn)(`Optional content group not found: ${id}`); return true; } - if (!this._groups.get(id).visible) { + if (!this.#groups.get(id).visible) { return false; } } @@ -8374,12 +10220,12 @@ class OptionalContentConfig { return true; } else if (group.policy === "AnyOff") { for (const id of group.ids) { - if (!this._groups.has(id)) { + if (!this.#groups.has(id)) { (0, _util.warn)(`Optional content group not found: ${id}`); return true; } - if (!this._groups.get(id).visible) { + if (!this.#groups.get(id).visible) { return true; } } @@ -8387,12 +10233,12 @@ class OptionalContentConfig { return false; } else if (group.policy === "AllOff") { for (const id of group.ids) { - if (!this._groups.has(id)) { + if (!this.#groups.has(id)) { (0, _util.warn)(`Optional content group not found: ${id}`); return true; } - if (this._groups.get(id).visible) { + if (this.#groups.get(id).visible) { return false; } } @@ -8409,36 +10255,50 @@ class OptionalContentConfig { } setVisibility(id, visible = true) { - if (!this._groups.has(id)) { + if (!this.#groups.has(id)) { (0, _util.warn)(`Optional content group not found: ${id}`); return; } - this._groups.get(id).visible = !!visible; + this.#groups.get(id)._setVisible(INTERNAL, !!visible); + + this.#cachedHasInitialVisibility = null; + } + + get hasInitialVisibility() { + if (this.#cachedHasInitialVisibility !== null) { + return this.#cachedHasInitialVisibility; + } + + for (const [id, group] of this.#groups) { + const visible = this.#initialVisibility.get(id); + + if (group.visible !== visible) { + return this.#cachedHasInitialVisibility = false; + } + } + + return this.#cachedHasInitialVisibility = true; } getOrder() { - if (!this._groups.size) { + if (!this.#groups.size) { return null; } - if (this._order) { - return this._order.slice(); + if (this.#order) { + return this.#order.slice(); } - return Array.from(this._groups.keys()); + return [...this.#groups.keys()]; } getGroups() { - if (!this._groups.size) { - return null; - } - - return Object.fromEntries(this._groups); + return this.#groups.size > 0 ? (0, _util.objectFromMap)(this.#groups) : null; } getGroup(id) { - return this._groups.get(id) || null; + return this.#groups.get(id) || null; } } @@ -8446,27 +10306,29 @@ class OptionalContentConfig { exports.OptionalContentConfig = OptionalContentConfig; /***/ }), -/* 17 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 19 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFDataTransportStream = void 0; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); + +var _display_utils = __w_pdfjs_require__(8); class PDFDataTransportStream { constructor(params, pdfDataRangeTransport) { (0, _util.assert)(pdfDataRangeTransport, 'PDFDataTransportStream - missing required "pdfDataRangeTransport" argument.'); this._queuedChunks = []; this._progressiveDone = params.progressiveDone || false; + this._contentDispositionFilename = params.contentDispositionFilename || null; const initialData = params.initialData; - if (initialData && initialData.length > 0) { + if (initialData?.length > 0) { const buffer = new Uint8Array(initialData).buffer; this._queuedChunks.push(buffer); @@ -8531,14 +10393,14 @@ class PDFDataTransportStream { } get _progressiveDataLength() { - return this._fullRequestReader ? this._fullRequestReader._loaded : 0; + return this._fullRequestReader?._loaded ?? 0; } _onProgress(evt) { if (evt.total === undefined) { const firstReader = this._rangeReaders[0]; - if (firstReader && firstReader.onProgress) { + if (firstReader?.onProgress) { firstReader.onProgress({ loaded: evt.loaded }); @@ -8546,7 +10408,7 @@ class PDFDataTransportStream { } else { const fullReader = this._fullRequestReader; - if (fullReader && fullReader.onProgress) { + if (fullReader?.onProgress) { fullReader.onProgress({ loaded: evt.loaded, total: evt.total @@ -8575,7 +10437,7 @@ class PDFDataTransportStream { (0, _util.assert)(!this._fullRequestReader, "PDFDataTransportStream.getFullReader can only be called once."); const queuedChunks = this._queuedChunks; this._queuedChunks = null; - return new PDFDataTransportStreamReader(this, queuedChunks, this._progressiveDone); + return new PDFDataTransportStreamReader(this, queuedChunks, this._progressiveDone, this._contentDispositionFilename); } getRangeReader(begin, end) { @@ -8597,11 +10459,9 @@ class PDFDataTransportStream { this._fullRequestReader.cancel(reason); } - const readers = this._rangeReaders.slice(0); - - readers.forEach(function (rangeReader) { - rangeReader.cancel(reason); - }); + for (const reader of this._rangeReaders.slice(0)) { + reader.cancel(reason); + } this._pdfDataRangeTransport.abort(); } @@ -8611,10 +10471,10 @@ class PDFDataTransportStream { exports.PDFDataTransportStream = PDFDataTransportStream; class PDFDataTransportStreamReader { - constructor(stream, queuedChunks, progressiveDone = false) { + constructor(stream, queuedChunks, progressiveDone = false, contentDispositionFilename = null) { this._stream = stream; this._done = progressiveDone || false; - this._filename = null; + this._filename = (0, _display_utils.isPdfFile)(contentDispositionFilename) ? contentDispositionFilename : null; this._queuedChunks = queuedChunks || []; this._loaded = 0; @@ -8694,14 +10554,14 @@ class PDFDataTransportStreamReader { cancel(reason) { this._done = true; - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } - this._requests = []; + this._requests.length = 0; } progressiveDone() { @@ -8740,14 +10600,14 @@ class PDFDataTransportStreamRangeReader { done: false }); - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } - this._requests = []; + this._requests.length = 0; } this._done = true; @@ -8786,14 +10646,14 @@ class PDFDataTransportStreamRangeReader { cancel(reason) { this._done = true; - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } - this._requests = []; + this._requests.length = 0; this._stream._removeRangeReader(this); } @@ -8801,469 +10661,2165 @@ class PDFDataTransportStreamRangeReader { } /***/ }), -/* 18 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 20 */ +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.WebGLContext = void 0; +})); +exports.XfaText = void 0; -var _util = __w_pdfjs_require__(2); +class XfaText { + static textContent(xfa) { + const items = []; + const output = { + items, + styles: Object.create(null) + }; -class WebGLContext { - constructor({ - enable = false - }) { - this._enabled = enable === true; - } + function walk(node) { + if (!node) { + return; + } - get isEnabled() { - let enabled = this._enabled; + let str = null; + const name = node.name; - if (enabled) { - enabled = WebGLUtils.tryInitGL(); + if (name === "#text") { + str = node.value; + } else if (!XfaText.shouldBuildText(name)) { + return; + } else if (node?.attributes?.textContent) { + str = node.attributes.textContent; + } else if (node.value) { + str = node.value; + } + + if (str !== null) { + items.push({ + str + }); + } + + if (!node.children) { + return; + } + + for (const child of node.children) { + walk(child); + } } - return (0, _util.shadow)(this, "isEnabled", enabled); + walk(xfa); + return output; } - composeSMask({ - layer, - mask, - properties - }) { - return WebGLUtils.composeSMask(layer, mask, properties); - } - - drawFigures({ - width, - height, - backgroundColor, - figures, - context - }) { - return WebGLUtils.drawFigures(width, height, backgroundColor, figures, context); - } - - clear() { - WebGLUtils.cleanup(); + static shouldBuildText(name) { + return !(name === "textarea" || name === "input" || name === "option" || name === "select"); } } -exports.WebGLContext = WebGLContext; +exports.XfaText = XfaText; -var WebGLUtils = function WebGLUtilsClosure() { - function loadShader(gl, code, shaderType) { - var shader = gl.createShader(shaderType); - gl.shaderSource(shader, code); - gl.compileShader(shader); - var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); +/***/ }), +/* 21 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { - if (!compiled) { - var errorMsg = gl.getShaderInfoLog(shader); - throw new Error("Error during shader compilation: " + errorMsg); - } - return shader; + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.NodeStandardFontDataFactory = exports.NodeCanvasFactory = exports.NodeCMapReaderFactory = void 0; + +var _base_factory = __w_pdfjs_require__(9); + +; + +const fetchData = function (url) { + return new Promise((resolve, reject) => { + const fs = require("fs"); + + fs.readFile(url, (error, data) => { + if (error || !data) { + reject(new Error(error)); + return; + } + + resolve(new Uint8Array(data)); + }); + }); +}; + +class NodeCanvasFactory extends _base_factory.BaseCanvasFactory { + _createCanvas(width, height) { + const Canvas = require("canvas"); + + return Canvas.createCanvas(width, height); } - function createVertexShader(gl, code) { - return loadShader(gl, code, gl.VERTEX_SHADER); - } +} - function createFragmentShader(gl, code) { - return loadShader(gl, code, gl.FRAGMENT_SHADER); - } +exports.NodeCanvasFactory = NodeCanvasFactory; - function createProgram(gl, shaders) { - var program = gl.createProgram(); - - for (var i = 0, ii = shaders.length; i < ii; ++i) { - gl.attachShader(program, shaders[i]); - } - - gl.linkProgram(program); - var linked = gl.getProgramParameter(program, gl.LINK_STATUS); - - if (!linked) { - var errorMsg = gl.getProgramInfoLog(program); - throw new Error("Error during program linking: " + errorMsg); - } - - return program; - } - - function createTexture(gl, image, textureId) { - gl.activeTexture(textureId); - var texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); - return texture; - } - - var currentGL, currentCanvas; - - function generateGL() { - if (currentGL) { - return; - } - - currentCanvas = document.createElement("canvas"); - currentGL = currentCanvas.getContext("webgl", { - premultipliedalpha: false +class NodeCMapReaderFactory extends _base_factory.BaseCMapReaderFactory { + _fetchData(url, compressionType) { + return fetchData(url).then(data => { + return { + cMapData: data, + compressionType + }; }); } - var smaskVertexShaderCode = "\ - attribute vec2 a_position; \ - attribute vec2 a_texCoord; \ - \ - uniform vec2 u_resolution; \ - \ - varying vec2 v_texCoord; \ - \ - void main() { \ - vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \ - gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \ - \ - v_texCoord = a_texCoord; \ - } "; - var smaskFragmentShaderCode = "\ - precision mediump float; \ - \ - uniform vec4 u_backdrop; \ - uniform int u_subtype; \ - uniform sampler2D u_image; \ - uniform sampler2D u_mask; \ - \ - varying vec2 v_texCoord; \ - \ - void main() { \ - vec4 imageColor = texture2D(u_image, v_texCoord); \ - vec4 maskColor = texture2D(u_mask, v_texCoord); \ - if (u_backdrop.a > 0.0) { \ - maskColor.rgb = maskColor.rgb * maskColor.a + \ - u_backdrop.rgb * (1.0 - maskColor.a); \ - } \ - float lum; \ - if (u_subtype == 0) { \ - lum = maskColor.a; \ - } else { \ - lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \ - maskColor.b * 0.11; \ - } \ - imageColor.a *= lum; \ - imageColor.rgb *= imageColor.a; \ - gl_FragColor = imageColor; \ - } "; - var smaskCache = null; +} - function initSmaskGL() { - var canvas, gl; - generateGL(); - canvas = currentCanvas; - currentCanvas = null; - gl = currentGL; - currentGL = null; - var vertexShader = createVertexShader(gl, smaskVertexShaderCode); - var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode); - var program = createProgram(gl, [vertexShader, fragmentShader]); - gl.useProgram(program); - var cache = {}; - cache.gl = gl; - cache.canvas = canvas; - cache.resolutionLocation = gl.getUniformLocation(program, "u_resolution"); - cache.positionLocation = gl.getAttribLocation(program, "a_position"); - cache.backdropLocation = gl.getUniformLocation(program, "u_backdrop"); - cache.subtypeLocation = gl.getUniformLocation(program, "u_subtype"); - var texCoordLocation = gl.getAttribLocation(program, "a_texCoord"); - var texLayerLocation = gl.getUniformLocation(program, "u_image"); - var texMaskLocation = gl.getUniformLocation(program, "u_mask"); - var texCoordBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]), gl.STATIC_DRAW); - gl.enableVertexAttribArray(texCoordLocation); - gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0); - gl.uniform1i(texLayerLocation, 0); - gl.uniform1i(texMaskLocation, 1); - smaskCache = cache; +exports.NodeCMapReaderFactory = NodeCMapReaderFactory; + +class NodeStandardFontDataFactory extends _base_factory.BaseStandardFontDataFactory { + _fetchData(url) { + return fetchData(url); } - function composeSMask(layer, mask, properties) { - var width = layer.width, - height = layer.height; +} - if (!smaskCache) { - initSmaskGL(); - } - - var cache = smaskCache, - canvas = cache.canvas, - gl = cache.gl; - canvas.width = width; - canvas.height = height; - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - gl.uniform2f(cache.resolutionLocation, width, height); - - if (properties.backdrop) { - gl.uniform4f(cache.resolutionLocation, properties.backdrop[0], properties.backdrop[1], properties.backdrop[2], 1); - } else { - gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0); - } - - gl.uniform1i(cache.subtypeLocation, properties.subtype === "Luminosity" ? 1 : 0); - var texture = createTexture(gl, layer, gl.TEXTURE0); - var maskTexture = createTexture(gl, mask, gl.TEXTURE1); - var buffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, width, 0, 0, height, 0, height, width, 0, width, height]), gl.STATIC_DRAW); - gl.enableVertexAttribArray(cache.positionLocation); - gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0); - gl.clearColor(0, 0, 0, 0); - gl.enable(gl.BLEND); - gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - gl.clear(gl.COLOR_BUFFER_BIT); - gl.drawArrays(gl.TRIANGLES, 0, 6); - gl.flush(); - gl.deleteTexture(texture); - gl.deleteTexture(maskTexture); - gl.deleteBuffer(buffer); - return canvas; - } - - var figuresVertexShaderCode = "\ - attribute vec2 a_position; \ - attribute vec3 a_color; \ - \ - uniform vec2 u_resolution; \ - uniform vec2 u_scale; \ - uniform vec2 u_offset; \ - \ - varying vec4 v_color; \ - \ - void main() { \ - vec2 position = (a_position + u_offset) * u_scale; \ - vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \ - gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \ - \ - v_color = vec4(a_color / 255.0, 1.0); \ - } "; - var figuresFragmentShaderCode = "\ - precision mediump float; \ - \ - varying vec4 v_color; \ - \ - void main() { \ - gl_FragColor = v_color; \ - } "; - var figuresCache = null; - - function initFiguresGL() { - var canvas, gl; - generateGL(); - canvas = currentCanvas; - currentCanvas = null; - gl = currentGL; - currentGL = null; - var vertexShader = createVertexShader(gl, figuresVertexShaderCode); - var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode); - var program = createProgram(gl, [vertexShader, fragmentShader]); - gl.useProgram(program); - var cache = {}; - cache.gl = gl; - cache.canvas = canvas; - cache.resolutionLocation = gl.getUniformLocation(program, "u_resolution"); - cache.scaleLocation = gl.getUniformLocation(program, "u_scale"); - cache.offsetLocation = gl.getUniformLocation(program, "u_offset"); - cache.positionLocation = gl.getAttribLocation(program, "a_position"); - cache.colorLocation = gl.getAttribLocation(program, "a_color"); - figuresCache = cache; - } - - function drawFigures(width, height, backgroundColor, figures, context) { - if (!figuresCache) { - initFiguresGL(); - } - - var cache = figuresCache, - canvas = cache.canvas, - gl = cache.gl; - canvas.width = width; - canvas.height = height; - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - gl.uniform2f(cache.resolutionLocation, width, height); - var count = 0; - var i, ii, rows; - - for (i = 0, ii = figures.length; i < ii; i++) { - switch (figures[i].type) { - case "lattice": - rows = figures[i].coords.length / figures[i].verticesPerRow | 0; - count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6; - break; - - case "triangles": - count += figures[i].coords.length; - break; - } - } - - var coords = new Float32Array(count * 2); - var colors = new Uint8Array(count * 3); - var coordsMap = context.coords, - colorsMap = context.colors; - var pIndex = 0, - cIndex = 0; - - for (i = 0, ii = figures.length; i < ii; i++) { - var figure = figures[i], - ps = figure.coords, - cs = figure.colors; - - switch (figure.type) { - case "lattice": - var cols = figure.verticesPerRow; - rows = ps.length / cols | 0; - - for (var row = 1; row < rows; row++) { - var offset = row * cols + 1; - - for (var col = 1; col < cols; col++, offset++) { - coords[pIndex] = coordsMap[ps[offset - cols - 1]]; - coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1]; - coords[pIndex + 2] = coordsMap[ps[offset - cols]]; - coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1]; - coords[pIndex + 4] = coordsMap[ps[offset - 1]]; - coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1]; - colors[cIndex] = colorsMap[cs[offset - cols - 1]]; - colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1]; - colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2]; - colors[cIndex + 3] = colorsMap[cs[offset - cols]]; - colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1]; - colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2]; - colors[cIndex + 6] = colorsMap[cs[offset - 1]]; - colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1]; - colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2]; - coords[pIndex + 6] = coords[pIndex + 2]; - coords[pIndex + 7] = coords[pIndex + 3]; - coords[pIndex + 8] = coords[pIndex + 4]; - coords[pIndex + 9] = coords[pIndex + 5]; - coords[pIndex + 10] = coordsMap[ps[offset]]; - coords[pIndex + 11] = coordsMap[ps[offset] + 1]; - colors[cIndex + 9] = colors[cIndex + 3]; - colors[cIndex + 10] = colors[cIndex + 4]; - colors[cIndex + 11] = colors[cIndex + 5]; - colors[cIndex + 12] = colors[cIndex + 6]; - colors[cIndex + 13] = colors[cIndex + 7]; - colors[cIndex + 14] = colors[cIndex + 8]; - colors[cIndex + 15] = colorsMap[cs[offset]]; - colors[cIndex + 16] = colorsMap[cs[offset] + 1]; - colors[cIndex + 17] = colorsMap[cs[offset] + 2]; - pIndex += 12; - cIndex += 18; - } - } - - break; - - case "triangles": - for (var j = 0, jj = ps.length; j < jj; j++) { - coords[pIndex] = coordsMap[ps[j]]; - coords[pIndex + 1] = coordsMap[ps[j] + 1]; - colors[cIndex] = colorsMap[cs[j]]; - colors[cIndex + 1] = colorsMap[cs[j] + 1]; - colors[cIndex + 2] = colorsMap[cs[j] + 2]; - pIndex += 2; - cIndex += 3; - } - - break; - } - } - - if (backgroundColor) { - gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255, backgroundColor[2] / 255, 1.0); - } else { - gl.clearColor(0, 0, 0, 0); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - var coordsBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer); - gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW); - gl.enableVertexAttribArray(cache.positionLocation); - gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0); - var colorsBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer); - gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); - gl.enableVertexAttribArray(cache.colorLocation); - gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false, 0, 0); - gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY); - gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY); - gl.drawArrays(gl.TRIANGLES, 0, count); - gl.flush(); - gl.deleteBuffer(coordsBuffer); - gl.deleteBuffer(colorsBuffer); - return canvas; - } - - return { - tryInitGL() { - try { - generateGL(); - return !!currentGL; - } catch (ex) {} - - return false; - }, - - composeSMask, - drawFigures, - - cleanup() { - if (smaskCache && smaskCache.canvas) { - smaskCache.canvas.width = 0; - smaskCache.canvas.height = 0; - } - - if (figuresCache && figuresCache.canvas) { - figuresCache.canvas.width = 0; - figuresCache.canvas.height = 0; - } - - smaskCache = null; - figuresCache = null; - } - - }; -}(); +exports.NodeStandardFontDataFactory = NodeStandardFontDataFactory; /***/ }), -/* 19 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 22 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.AnnotationEditorLayer = void 0; + +var _tools = __w_pdfjs_require__(7); + +var _util = __w_pdfjs_require__(1); + +var _freetext = __w_pdfjs_require__(23); + +var _ink = __w_pdfjs_require__(24); + +class AnnotationEditorLayer { + #accessibilityManager; + #allowClick = false; + #boundPointerup = this.pointerup.bind(this); + #boundPointerdown = this.pointerdown.bind(this); + #editors = new Map(); + #hadPointerDown = false; + #isCleaningUp = false; + #uiManager; + static _initialized = false; + + constructor(options) { + if (!AnnotationEditorLayer._initialized) { + AnnotationEditorLayer._initialized = true; + + _freetext.FreeTextEditor.initialize(options.l10n); + + _ink.InkEditor.initialize(options.l10n); + + options.uiManager.registerEditorTypes([_freetext.FreeTextEditor, _ink.InkEditor]); + } + + this.#uiManager = options.uiManager; + this.annotationStorage = options.annotationStorage; + this.pageIndex = options.pageIndex; + this.div = options.div; + this.#accessibilityManager = options.accessibilityManager; + this.#uiManager.addLayer(this); + } + + updateToolbar(mode) { + this.#uiManager.updateToolbar(mode); + } + + updateMode(mode = this.#uiManager.getMode()) { + this.#cleanup(); + + if (mode === _util.AnnotationEditorType.INK) { + this.addInkEditorIfNeeded(false); + this.disableClick(); + } else { + this.enableClick(); + } + + this.#uiManager.unselectAll(); + } + + addInkEditorIfNeeded(isCommitting) { + if (!isCommitting && this.#uiManager.getMode() !== _util.AnnotationEditorType.INK) { + return; + } + + if (!isCommitting) { + for (const editor of this.#editors.values()) { + if (editor.isEmpty()) { + editor.setInBackground(); + return; + } + } + } + + const editor = this.#createAndAddNewEditor({ + offsetX: 0, + offsetY: 0 + }); + editor.setInBackground(); + } + + setEditingState(isEditing) { + this.#uiManager.setEditingState(isEditing); + } + + addCommands(params) { + this.#uiManager.addCommands(params); + } + + enable() { + this.div.style.pointerEvents = "auto"; + + for (const editor of this.#editors.values()) { + editor.enableEditing(); + } + } + + disable() { + this.div.style.pointerEvents = "none"; + + for (const editor of this.#editors.values()) { + editor.disableEditing(); + } + } + + setActiveEditor(editor) { + const currentActive = this.#uiManager.getActive(); + + if (currentActive === editor) { + return; + } + + this.#uiManager.setActiveEditor(editor); + } + + enableClick() { + this.div.addEventListener("pointerdown", this.#boundPointerdown); + this.div.addEventListener("pointerup", this.#boundPointerup); + } + + disableClick() { + this.div.removeEventListener("pointerdown", this.#boundPointerdown); + this.div.removeEventListener("pointerup", this.#boundPointerup); + } + + attach(editor) { + this.#editors.set(editor.id, editor); + } + + detach(editor) { + this.#editors.delete(editor.id); + this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv); + } + + remove(editor) { + this.#uiManager.removeEditor(editor); + this.detach(editor); + this.annotationStorage.remove(editor.id); + editor.div.style.display = "none"; + setTimeout(() => { + editor.div.style.display = ""; + editor.div.remove(); + editor.isAttachedToDOM = false; + + if (document.activeElement === document.body) { + this.#uiManager.focusMainContainer(); + } + }, 0); + + if (!this.#isCleaningUp) { + this.addInkEditorIfNeeded(false); + } + } + + #changeParent(editor) { + if (editor.parent === this) { + return; + } + + this.attach(editor); + editor.pageIndex = this.pageIndex; + editor.parent?.detach(editor); + editor.parent = this; + + if (editor.div && editor.isAttachedToDOM) { + editor.div.remove(); + this.div.append(editor.div); + } + } + + add(editor) { + this.#changeParent(editor); + this.#uiManager.addEditor(editor); + this.attach(editor); + + if (!editor.isAttachedToDOM) { + const div = editor.render(); + this.div.append(div); + editor.isAttachedToDOM = true; + } + + this.moveEditorInDOM(editor); + editor.onceAdded(); + this.addToAnnotationStorage(editor); + } + + moveEditorInDOM(editor) { + this.#accessibilityManager?.moveElementInDOM(this.div, editor.div, editor.contentDiv, true); + } + + addToAnnotationStorage(editor) { + if (!editor.isEmpty() && !this.annotationStorage.has(editor.id)) { + this.annotationStorage.setValue(editor.id, editor); + } + } + + addOrRebuild(editor) { + if (editor.needsToBeRebuilt()) { + editor.rebuild(); + } else { + this.add(editor); + } + } + + addANewEditor(editor) { + const cmd = () => { + this.addOrRebuild(editor); + }; + + const undo = () => { + editor.remove(); + }; + + this.addCommands({ + cmd, + undo, + mustExec: true + }); + } + + addUndoableEditor(editor) { + const cmd = () => { + this.addOrRebuild(editor); + }; + + const undo = () => { + editor.remove(); + }; + + this.addCommands({ + cmd, + undo, + mustExec: false + }); + } + + getNextId() { + return this.#uiManager.getId(); + } + + #createNewEditor(params) { + switch (this.#uiManager.getMode()) { + case _util.AnnotationEditorType.FREETEXT: + return new _freetext.FreeTextEditor(params); + + case _util.AnnotationEditorType.INK: + return new _ink.InkEditor(params); + } + + return null; + } + + deserialize(data) { + switch (data.annotationType) { + case _util.AnnotationEditorType.FREETEXT: + return _freetext.FreeTextEditor.deserialize(data, this); + + case _util.AnnotationEditorType.INK: + return _ink.InkEditor.deserialize(data, this); + } + + return null; + } + + #createAndAddNewEditor(event) { + const id = this.getNextId(); + const editor = this.#createNewEditor({ + parent: this, + id, + x: event.offsetX, + y: event.offsetY + }); + + if (editor) { + this.add(editor); + } + + return editor; + } + + setSelected(editor) { + this.#uiManager.setSelected(editor); + } + + toggleSelected(editor) { + this.#uiManager.toggleSelected(editor); + } + + isSelected(editor) { + return this.#uiManager.isSelected(editor); + } + + unselect(editor) { + this.#uiManager.unselect(editor); + } + + pointerup(event) { + const isMac = _tools.KeyboardManager.platform.isMac; + + if (event.button !== 0 || event.ctrlKey && isMac) { + return; + } + + if (event.target !== this.div) { + return; + } + + if (!this.#hadPointerDown) { + return; + } + + this.#hadPointerDown = false; + + if (!this.#allowClick) { + this.#allowClick = true; + return; + } + + this.#createAndAddNewEditor(event); + } + + pointerdown(event) { + const isMac = _tools.KeyboardManager.platform.isMac; + + if (event.button !== 0 || event.ctrlKey && isMac) { + return; + } + + if (event.target !== this.div) { + return; + } + + this.#hadPointerDown = true; + const editor = this.#uiManager.getActive(); + this.#allowClick = !editor || editor.isEmpty(); + } + + drop(event) { + const id = event.dataTransfer.getData("text/plain"); + const editor = this.#uiManager.getEditor(id); + + if (!editor) { + return; + } + + event.preventDefault(); + event.dataTransfer.dropEffect = "move"; + this.#changeParent(editor); + const rect = this.div.getBoundingClientRect(); + const endX = event.clientX - rect.x; + const endY = event.clientY - rect.y; + editor.translate(endX - editor.startX, endY - editor.startY); + this.moveEditorInDOM(editor); + editor.div.focus(); + } + + dragover(event) { + event.preventDefault(); + } + + destroy() { + if (this.#uiManager.getActive()?.parent === this) { + this.#uiManager.setActiveEditor(null); + } + + for (const editor of this.#editors.values()) { + this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv); + editor.isAttachedToDOM = false; + editor.div.remove(); + editor.parent = null; + } + + this.div = null; + this.#editors.clear(); + this.#uiManager.removeLayer(this); + } + + #cleanup() { + this.#isCleaningUp = true; + + for (const editor of this.#editors.values()) { + if (editor.isEmpty()) { + editor.remove(); + } + } + + this.#isCleaningUp = false; + } + + render(parameters) { + this.viewport = parameters.viewport; + (0, _tools.bindEvents)(this, this.div, ["dragover", "drop"]); + this.setDimensions(); + + for (const editor of this.#uiManager.getEditors(this.pageIndex)) { + this.add(editor); + } + + this.updateMode(); + } + + update(parameters) { + this.viewport = parameters.viewport; + this.setDimensions(); + this.updateMode(); + } + + get scaleFactor() { + return this.viewport.scale; + } + + get pageDimensions() { + const [pageLLx, pageLLy, pageURx, pageURy] = this.viewport.viewBox; + const width = pageURx - pageLLx; + const height = pageURy - pageLLy; + return [width, height]; + } + + get viewportBaseDimensions() { + const { + width, + height, + rotation + } = this.viewport; + return rotation % 180 === 0 ? [width, height] : [height, width]; + } + + setDimensions() { + const { + width, + height, + rotation + } = this.viewport; + const flipOrientation = rotation % 180 !== 0, + widthStr = Math.floor(width) + "px", + heightStr = Math.floor(height) + "px"; + this.div.style.width = flipOrientation ? heightStr : widthStr; + this.div.style.height = flipOrientation ? widthStr : heightStr; + this.div.setAttribute("data-main-rotation", rotation); + } + +} + +exports.AnnotationEditorLayer = AnnotationEditorLayer; + +/***/ }), +/* 23 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.FreeTextEditor = void 0; + +var _util = __w_pdfjs_require__(1); + +var _tools = __w_pdfjs_require__(7); + +var _editor = __w_pdfjs_require__(6); + +class FreeTextEditor extends _editor.AnnotationEditor { + #boundEditorDivBlur = this.editorDivBlur.bind(this); + #boundEditorDivFocus = this.editorDivFocus.bind(this); + #boundEditorDivKeydown = this.editorDivKeydown.bind(this); + #color; + #content = ""; + #hasAlreadyBeenCommitted = false; + #fontSize; + static _freeTextDefaultContent = ""; + static _l10nPromise; + static _internalPadding = 0; + static _defaultColor = null; + static _defaultFontSize = 10; + static _keyboardManager = new _tools.KeyboardManager([[["ctrl+Enter", "mac+meta+Enter", "Escape", "mac+Escape"], FreeTextEditor.prototype.commitOrRemove]]); + static _type = "freetext"; + + constructor(params) { + super({ ...params, + name: "freeTextEditor" + }); + this.#color = params.color || FreeTextEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor; + this.#fontSize = params.fontSize || FreeTextEditor._defaultFontSize; + } + + static initialize(l10n) { + this._l10nPromise = new Map(["free_text_default_content", "editor_free_text_aria_label"].map(str => [str, l10n.get(str)])); + const style = getComputedStyle(document.documentElement); + this._internalPadding = parseFloat(style.getPropertyValue("--freetext-padding")); + } + + static updateDefaultParams(type, value) { + switch (type) { + case _util.AnnotationEditorParamsType.FREETEXT_SIZE: + FreeTextEditor._defaultFontSize = value; + break; + + case _util.AnnotationEditorParamsType.FREETEXT_COLOR: + FreeTextEditor._defaultColor = value; + break; + } + } + + updateParams(type, value) { + switch (type) { + case _util.AnnotationEditorParamsType.FREETEXT_SIZE: + this.#updateFontSize(value); + break; + + case _util.AnnotationEditorParamsType.FREETEXT_COLOR: + this.#updateColor(value); + break; + } + } + + static get defaultPropertiesToUpdate() { + return [[_util.AnnotationEditorParamsType.FREETEXT_SIZE, FreeTextEditor._defaultFontSize], [_util.AnnotationEditorParamsType.FREETEXT_COLOR, FreeTextEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor]]; + } + + get propertiesToUpdate() { + return [[_util.AnnotationEditorParamsType.FREETEXT_SIZE, this.#fontSize], [_util.AnnotationEditorParamsType.FREETEXT_COLOR, this.#color]]; + } + + #updateFontSize(fontSize) { + const setFontsize = size => { + this.editorDiv.style.fontSize = `calc(${size}px * var(--scale-factor))`; + this.translate(0, -(size - this.#fontSize) * this.parent.scaleFactor); + this.#fontSize = size; + this.#setEditorDimensions(); + }; + + const savedFontsize = this.#fontSize; + this.parent.addCommands({ + cmd: () => { + setFontsize(fontSize); + }, + undo: () => { + setFontsize(savedFontsize); + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.FREETEXT_SIZE, + overwriteIfSameType: true, + keepUndo: true + }); + } + + #updateColor(color) { + const savedColor = this.#color; + this.parent.addCommands({ + cmd: () => { + this.#color = color; + this.editorDiv.style.color = color; + }, + undo: () => { + this.#color = savedColor; + this.editorDiv.style.color = savedColor; + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.FREETEXT_COLOR, + overwriteIfSameType: true, + keepUndo: true + }); + } + + getInitialTranslation() { + return [-FreeTextEditor._internalPadding * this.parent.scaleFactor, -(FreeTextEditor._internalPadding + this.#fontSize) * this.parent.scaleFactor]; + } + + rebuild() { + super.rebuild(); + + if (this.div === null) { + return; + } + + if (!this.isAttachedToDOM) { + this.parent.add(this); + } + } + + enableEditMode() { + if (this.isInEditMode()) { + return; + } + + this.parent.setEditingState(false); + this.parent.updateToolbar(_util.AnnotationEditorType.FREETEXT); + super.enableEditMode(); + this.enableEditing(); + this.overlayDiv.classList.remove("enabled"); + this.editorDiv.contentEditable = true; + this.div.draggable = false; + this.editorDiv.addEventListener("keydown", this.#boundEditorDivKeydown); + this.editorDiv.addEventListener("focus", this.#boundEditorDivFocus); + this.editorDiv.addEventListener("blur", this.#boundEditorDivBlur); + } + + disableEditMode() { + if (!this.isInEditMode()) { + return; + } + + this.parent.setEditingState(true); + super.disableEditMode(); + this.disableEditing(); + this.overlayDiv.classList.add("enabled"); + this.editorDiv.contentEditable = false; + this.div.draggable = true; + this.editorDiv.removeEventListener("keydown", this.#boundEditorDivKeydown); + this.editorDiv.removeEventListener("focus", this.#boundEditorDivFocus); + this.editorDiv.removeEventListener("blur", this.#boundEditorDivBlur); + this.div.focus(); + this.isEditing = false; + } + + focusin(event) { + super.focusin(event); + + if (event.target !== this.editorDiv) { + this.editorDiv.focus(); + } + } + + onceAdded() { + if (this.width) { + return; + } + + this.enableEditMode(); + this.editorDiv.focus(); + } + + isEmpty() { + return !this.editorDiv || this.editorDiv.innerText.trim() === ""; + } + + remove() { + this.isEditing = false; + this.parent.setEditingState(true); + super.remove(); + } + + #extractText() { + const divs = this.editorDiv.getElementsByTagName("div"); + + if (divs.length === 0) { + return this.editorDiv.innerText; + } + + const buffer = []; + + for (let i = 0, ii = divs.length; i < ii; i++) { + const div = divs[i]; + const first = div.firstChild; + + if (first?.nodeName === "#text") { + buffer.push(first.data); + } else { + buffer.push(""); + } + } + + return buffer.join("\n"); + } + + #setEditorDimensions() { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + const rect = this.div.getBoundingClientRect(); + this.width = rect.width / parentWidth; + this.height = rect.height / parentHeight; + } + + commit() { + super.commit(); + + if (!this.#hasAlreadyBeenCommitted) { + this.#hasAlreadyBeenCommitted = true; + this.parent.addUndoableEditor(this); + } + + this.disableEditMode(); + this.#content = this.#extractText().trimEnd(); + this.#setEditorDimensions(); + } + + shouldGetKeyboardEvents() { + return this.isInEditMode(); + } + + dblclick(event) { + this.enableEditMode(); + this.editorDiv.focus(); + } + + keydown(event) { + if (event.target === this.div && event.key === "Enter") { + this.enableEditMode(); + this.editorDiv.focus(); + } + } + + editorDivKeydown(event) { + FreeTextEditor._keyboardManager.exec(this, event); + } + + editorDivFocus(event) { + this.isEditing = true; + } + + editorDivBlur(event) { + this.isEditing = false; + } + + disableEditing() { + this.editorDiv.setAttribute("role", "comment"); + this.editorDiv.removeAttribute("aria-multiline"); + } + + enableEditing() { + this.editorDiv.setAttribute("role", "textbox"); + this.editorDiv.setAttribute("aria-multiline", true); + } + + render() { + if (this.div) { + return this.div; + } + + let baseX, baseY; + + if (this.width) { + baseX = this.x; + baseY = this.y; + } + + super.render(); + this.editorDiv = document.createElement("div"); + this.editorDiv.className = "internal"; + this.editorDiv.setAttribute("id", `${this.id}-editor`); + this.enableEditing(); + + FreeTextEditor._l10nPromise.get("editor_free_text_aria_label").then(msg => this.editorDiv?.setAttribute("aria-label", msg)); + + FreeTextEditor._l10nPromise.get("free_text_default_content").then(msg => this.editorDiv?.setAttribute("default-content", msg)); + + this.editorDiv.contentEditable = true; + const { + style + } = this.editorDiv; + style.fontSize = `calc(${this.#fontSize}px * var(--scale-factor))`; + style.color = this.#color; + this.div.append(this.editorDiv); + this.overlayDiv = document.createElement("div"); + this.overlayDiv.classList.add("overlay", "enabled"); + this.div.append(this.overlayDiv); + (0, _tools.bindEvents)(this, this.div, ["dblclick", "keydown"]); + + if (this.width) { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight); + + for (const line of this.#content.split("\n")) { + const div = document.createElement("div"); + div.append(line ? document.createTextNode(line) : document.createElement("br")); + this.editorDiv.append(div); + } + + this.div.draggable = true; + this.editorDiv.contentEditable = false; + } else { + this.div.draggable = false; + this.editorDiv.contentEditable = true; + } + + return this.div; + } + + get contentDiv() { + return this.editorDiv; + } + + static deserialize(data, parent) { + const editor = super.deserialize(data, parent); + editor.#fontSize = data.fontSize; + editor.#color = _util.Util.makeHexColor(...data.color); + editor.#content = data.value; + return editor; + } + + serialize() { + if (this.isEmpty()) { + return null; + } + + const padding = FreeTextEditor._internalPadding * this.parent.scaleFactor; + const rect = this.getRect(padding, padding); + + const color = _editor.AnnotationEditor._colorManager.convert(getComputedStyle(this.editorDiv).color); + + return { + annotationType: _util.AnnotationEditorType.FREETEXT, + color, + fontSize: this.#fontSize, + value: this.#content, + pageIndex: this.parent.pageIndex, + rect, + rotation: this.rotation + }; + } + +} + +exports.FreeTextEditor = FreeTextEditor; + +/***/ }), +/* 24 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.InkEditor = void 0; +Object.defineProperty(exports, "fitCurve", ({ + enumerable: true, + get: function () { + return _pdfjsFitCurve.fitCurve; + } +})); + +var _util = __w_pdfjs_require__(1); + +var _editor = __w_pdfjs_require__(6); + +var _pdfjsFitCurve = __w_pdfjs_require__(25); + +var _tools = __w_pdfjs_require__(7); + +const RESIZER_SIZE = 16; + +class InkEditor extends _editor.AnnotationEditor { + #aspectRatio = 0; + #baseHeight = 0; + #baseWidth = 0; + #boundCanvasPointermove = this.canvasPointermove.bind(this); + #boundCanvasPointerleave = this.canvasPointerleave.bind(this); + #boundCanvasPointerup = this.canvasPointerup.bind(this); + #boundCanvasPointerdown = this.canvasPointerdown.bind(this); + #disableEditing = false; + #isCanvasInitialized = false; + #lastPoint = null; + #observer = null; + #realWidth = 0; + #realHeight = 0; + #requestFrameCallback = null; + static _defaultColor = null; + static _defaultOpacity = 1; + static _defaultThickness = 1; + static _l10nPromise; + static _type = "ink"; + + constructor(params) { + super({ ...params, + name: "inkEditor" + }); + this.color = params.color || null; + this.thickness = params.thickness || null; + this.opacity = params.opacity || null; + this.paths = []; + this.bezierPath2D = []; + this.currentPath = []; + this.scaleFactor = 1; + this.translationX = this.translationY = 0; + this.x = 0; + this.y = 0; + } + + static initialize(l10n) { + this._l10nPromise = new Map(["editor_ink_canvas_aria_label", "editor_ink_aria_label"].map(str => [str, l10n.get(str)])); + } + + static updateDefaultParams(type, value) { + switch (type) { + case _util.AnnotationEditorParamsType.INK_THICKNESS: + InkEditor._defaultThickness = value; + break; + + case _util.AnnotationEditorParamsType.INK_COLOR: + InkEditor._defaultColor = value; + break; + + case _util.AnnotationEditorParamsType.INK_OPACITY: + InkEditor._defaultOpacity = value / 100; + break; + } + } + + updateParams(type, value) { + switch (type) { + case _util.AnnotationEditorParamsType.INK_THICKNESS: + this.#updateThickness(value); + break; + + case _util.AnnotationEditorParamsType.INK_COLOR: + this.#updateColor(value); + break; + + case _util.AnnotationEditorParamsType.INK_OPACITY: + this.#updateOpacity(value); + break; + } + } + + static get defaultPropertiesToUpdate() { + return [[_util.AnnotationEditorParamsType.INK_THICKNESS, InkEditor._defaultThickness], [_util.AnnotationEditorParamsType.INK_COLOR, InkEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor], [_util.AnnotationEditorParamsType.INK_OPACITY, Math.round(InkEditor._defaultOpacity * 100)]]; + } + + get propertiesToUpdate() { + return [[_util.AnnotationEditorParamsType.INK_THICKNESS, this.thickness || InkEditor._defaultThickness], [_util.AnnotationEditorParamsType.INK_COLOR, this.color || InkEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor], [_util.AnnotationEditorParamsType.INK_OPACITY, Math.round(100 * (this.opacity ?? InkEditor._defaultOpacity))]]; + } + + #updateThickness(thickness) { + const savedThickness = this.thickness; + this.parent.addCommands({ + cmd: () => { + this.thickness = thickness; + this.#fitToContent(); + }, + undo: () => { + this.thickness = savedThickness; + this.#fitToContent(); + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.INK_THICKNESS, + overwriteIfSameType: true, + keepUndo: true + }); + } + + #updateColor(color) { + const savedColor = this.color; + this.parent.addCommands({ + cmd: () => { + this.color = color; + this.#redraw(); + }, + undo: () => { + this.color = savedColor; + this.#redraw(); + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.INK_COLOR, + overwriteIfSameType: true, + keepUndo: true + }); + } + + #updateOpacity(opacity) { + opacity /= 100; + const savedOpacity = this.opacity; + this.parent.addCommands({ + cmd: () => { + this.opacity = opacity; + this.#redraw(); + }, + undo: () => { + this.opacity = savedOpacity; + this.#redraw(); + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.INK_OPACITY, + overwriteIfSameType: true, + keepUndo: true + }); + } + + rebuild() { + super.rebuild(); + + if (this.div === null) { + return; + } + + if (!this.canvas) { + this.#createCanvas(); + this.#createObserver(); + } + + if (!this.isAttachedToDOM) { + this.parent.add(this); + this.#setCanvasDims(); + } + + this.#fitToContent(); + } + + remove() { + if (this.canvas === null) { + return; + } + + if (!this.isEmpty()) { + this.commit(); + } + + this.canvas.width = this.canvas.height = 0; + this.canvas.remove(); + this.canvas = null; + this.#observer.disconnect(); + this.#observer = null; + super.remove(); + } + + enableEditMode() { + if (this.#disableEditing || this.canvas === null) { + return; + } + + super.enableEditMode(); + this.div.draggable = false; + this.canvas.addEventListener("pointerdown", this.#boundCanvasPointerdown); + this.canvas.addEventListener("pointerup", this.#boundCanvasPointerup); + } + + disableEditMode() { + if (!this.isInEditMode() || this.canvas === null) { + return; + } + + super.disableEditMode(); + this.div.draggable = !this.isEmpty(); + this.div.classList.remove("editing"); + this.canvas.removeEventListener("pointerdown", this.#boundCanvasPointerdown); + this.canvas.removeEventListener("pointerup", this.#boundCanvasPointerup); + } + + onceAdded() { + this.div.draggable = !this.isEmpty(); + } + + isEmpty() { + return this.paths.length === 0 || this.paths.length === 1 && this.paths[0].length === 0; + } + + #getInitialBBox() { + const { + width, + height, + rotation + } = this.parent.viewport; + + switch (rotation) { + case 90: + return [0, width, width, height]; + + case 180: + return [width, height, width, height]; + + case 270: + return [height, 0, width, height]; + + default: + return [0, 0, width, height]; + } + } + + #setStroke() { + this.ctx.lineWidth = this.thickness * this.parent.scaleFactor / this.scaleFactor; + this.ctx.lineCap = "round"; + this.ctx.lineJoin = "round"; + this.ctx.miterLimit = 10; + this.ctx.strokeStyle = `${this.color}${(0, _tools.opacityToHex)(this.opacity)}`; + } + + #startDrawing(x, y) { + this.isEditing = true; + + if (!this.#isCanvasInitialized) { + this.#isCanvasInitialized = true; + this.#setCanvasDims(); + this.thickness ||= InkEditor._defaultThickness; + this.color ||= InkEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor; + this.opacity ??= InkEditor._defaultOpacity; + } + + this.currentPath.push([x, y]); + this.#lastPoint = null; + this.#setStroke(); + this.ctx.beginPath(); + this.ctx.moveTo(x, y); + + this.#requestFrameCallback = () => { + if (!this.#requestFrameCallback) { + return; + } + + if (this.#lastPoint) { + if (this.isEmpty()) { + this.ctx.setTransform(1, 0, 0, 1, 0, 0); + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + } else { + this.#redraw(); + } + + this.ctx.lineTo(...this.#lastPoint); + this.#lastPoint = null; + this.ctx.stroke(); + } + + window.requestAnimationFrame(this.#requestFrameCallback); + }; + + window.requestAnimationFrame(this.#requestFrameCallback); + } + + #draw(x, y) { + const [lastX, lastY] = this.currentPath.at(-1); + + if (x === lastX && y === lastY) { + return; + } + + this.currentPath.push([x, y]); + this.#lastPoint = [x, y]; + } + + #stopDrawing(x, y) { + this.ctx.closePath(); + this.#requestFrameCallback = null; + x = Math.min(Math.max(x, 0), this.canvas.width); + y = Math.min(Math.max(y, 0), this.canvas.height); + const [lastX, lastY] = this.currentPath.at(-1); + + if (x !== lastX || y !== lastY) { + this.currentPath.push([x, y]); + } + + let bezier; + + if (this.currentPath.length !== 1) { + bezier = (0, _pdfjsFitCurve.fitCurve)(this.currentPath, 30, null); + } else { + const xy = [x, y]; + bezier = [[xy, xy.slice(), xy.slice(), xy]]; + } + + const path2D = InkEditor.#buildPath2D(bezier); + this.currentPath.length = 0; + + const cmd = () => { + this.paths.push(bezier); + this.bezierPath2D.push(path2D); + this.rebuild(); + }; + + const undo = () => { + this.paths.pop(); + this.bezierPath2D.pop(); + + if (this.paths.length === 0) { + this.remove(); + } else { + if (!this.canvas) { + this.#createCanvas(); + this.#createObserver(); + } + + this.#fitToContent(); + } + }; + + this.parent.addCommands({ + cmd, + undo, + mustExec: true + }); + } + + #redraw() { + if (this.isEmpty()) { + this.#updateTransform(); + return; + } + + this.#setStroke(); + const { + canvas, + ctx + } = this; + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, canvas.width, canvas.height); + this.#updateTransform(); + + for (const path of this.bezierPath2D) { + ctx.stroke(path); + } + } + + commit() { + if (this.#disableEditing) { + return; + } + + super.commit(); + this.isEditing = false; + this.disableEditMode(); + this.setInForeground(); + this.#disableEditing = true; + this.div.classList.add("disabled"); + this.#fitToContent(true); + this.parent.addInkEditorIfNeeded(true); + this.parent.moveEditorInDOM(this); + this.div.focus(); + } + + focusin(event) { + super.focusin(event); + this.enableEditMode(); + } + + canvasPointerdown(event) { + if (event.button !== 0 || !this.isInEditMode() || this.#disableEditing) { + return; + } + + this.setInForeground(); + + if (event.type !== "mouse") { + this.div.focus(); + } + + event.stopPropagation(); + this.canvas.addEventListener("pointerleave", this.#boundCanvasPointerleave); + this.canvas.addEventListener("pointermove", this.#boundCanvasPointermove); + this.#startDrawing(event.offsetX, event.offsetY); + } + + canvasPointermove(event) { + event.stopPropagation(); + this.#draw(event.offsetX, event.offsetY); + } + + canvasPointerup(event) { + if (event.button !== 0) { + return; + } + + if (this.isInEditMode() && this.currentPath.length !== 0) { + event.stopPropagation(); + this.#endDrawing(event); + this.setInBackground(); + } + } + + canvasPointerleave(event) { + this.#endDrawing(event); + this.setInBackground(); + } + + #endDrawing(event) { + this.#stopDrawing(event.offsetX, event.offsetY); + this.canvas.removeEventListener("pointerleave", this.#boundCanvasPointerleave); + this.canvas.removeEventListener("pointermove", this.#boundCanvasPointermove); + this.parent.addToAnnotationStorage(this); + } + + #createCanvas() { + this.canvas = document.createElement("canvas"); + this.canvas.width = this.canvas.height = 0; + this.canvas.className = "inkEditorCanvas"; + + InkEditor._l10nPromise.get("editor_ink_canvas_aria_label").then(msg => this.canvas?.setAttribute("aria-label", msg)); + + this.div.append(this.canvas); + this.ctx = this.canvas.getContext("2d"); + } + + #createObserver() { + this.#observer = new ResizeObserver(entries => { + const rect = entries[0].contentRect; + + if (rect.width && rect.height) { + this.setDimensions(rect.width, rect.height); + } + }); + this.#observer.observe(this.div); + } + + render() { + if (this.div) { + return this.div; + } + + let baseX, baseY; + + if (this.width) { + baseX = this.x; + baseY = this.y; + } + + super.render(); + + InkEditor._l10nPromise.get("editor_ink_aria_label").then(msg => this.div?.setAttribute("aria-label", msg)); + + const [x, y, w, h] = this.#getInitialBBox(); + this.setAt(x, y, 0, 0); + this.setDims(w, h); + this.#createCanvas(); + + if (this.width) { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight); + this.#isCanvasInitialized = true; + this.#setCanvasDims(); + this.setDims(this.width * parentWidth, this.height * parentHeight); + this.#redraw(); + this.#setMinDims(); + this.div.classList.add("disabled"); + } else { + this.div.classList.add("editing"); + this.enableEditMode(); + } + + this.#createObserver(); + return this.div; + } + + #setCanvasDims() { + if (!this.#isCanvasInitialized) { + return; + } + + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.canvas.width = Math.ceil(this.width * parentWidth); + this.canvas.height = Math.ceil(this.height * parentHeight); + this.#updateTransform(); + } + + setDimensions(width, height) { + const roundedWidth = Math.round(width); + const roundedHeight = Math.round(height); + + if (this.#realWidth === roundedWidth && this.#realHeight === roundedHeight) { + return; + } + + this.#realWidth = roundedWidth; + this.#realHeight = roundedHeight; + this.canvas.style.visibility = "hidden"; + + if (this.#aspectRatio && Math.abs(this.#aspectRatio - width / height) > 1e-2) { + height = Math.ceil(width / this.#aspectRatio); + this.setDims(width, height); + } + + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.width = width / parentWidth; + this.height = height / parentHeight; + + if (this.#disableEditing) { + this.#setScaleFactor(width, height); + } + + this.#setCanvasDims(); + this.#redraw(); + this.canvas.style.visibility = "visible"; + } + + #setScaleFactor(width, height) { + const padding = this.#getPadding(); + const scaleFactorW = (width - padding) / this.#baseWidth; + const scaleFactorH = (height - padding) / this.#baseHeight; + this.scaleFactor = Math.min(scaleFactorW, scaleFactorH); + } + + #updateTransform() { + const padding = this.#getPadding() / 2; + this.ctx.setTransform(this.scaleFactor, 0, 0, this.scaleFactor, this.translationX * this.scaleFactor + padding, this.translationY * this.scaleFactor + padding); + } + + static #buildPath2D(bezier) { + const path2D = new Path2D(); + + for (let i = 0, ii = bezier.length; i < ii; i++) { + const [first, control1, control2, second] = bezier[i]; + + if (i === 0) { + path2D.moveTo(...first); + } + + path2D.bezierCurveTo(control1[0], control1[1], control2[0], control2[1], second[0], second[1]); + } + + return path2D; + } + + #serializePaths(s, tx, ty, h) { + const NUMBER_OF_POINTS_ON_BEZIER_CURVE = 4; + const paths = []; + const padding = this.thickness / 2; + let buffer, points; + + for (const bezier of this.paths) { + buffer = []; + points = []; + + for (let i = 0, ii = bezier.length; i < ii; i++) { + const [first, control1, control2, second] = bezier[i]; + const p10 = s * (first[0] + tx) + padding; + const p11 = h - s * (first[1] + ty) - padding; + const p20 = s * (control1[0] + tx) + padding; + const p21 = h - s * (control1[1] + ty) - padding; + const p30 = s * (control2[0] + tx) + padding; + const p31 = h - s * (control2[1] + ty) - padding; + const p40 = s * (second[0] + tx) + padding; + const p41 = h - s * (second[1] + ty) - padding; + + if (i === 0) { + buffer.push(p10, p11); + points.push(p10, p11); + } + + buffer.push(p20, p21, p30, p31, p40, p41); + this.#extractPointsOnBezier(p10, p11, p20, p21, p30, p31, p40, p41, NUMBER_OF_POINTS_ON_BEZIER_CURVE, points); + } + + paths.push({ + bezier: buffer, + points + }); + } + + return paths; + } + + #extractPointsOnBezier(p10, p11, p20, p21, p30, p31, p40, p41, n, points) { + if (this.#isAlmostFlat(p10, p11, p20, p21, p30, p31, p40, p41)) { + points.push(p40, p41); + return; + } + + for (let i = 1; i < n - 1; i++) { + const t = i / n; + const mt = 1 - t; + let q10 = t * p10 + mt * p20; + let q11 = t * p11 + mt * p21; + let q20 = t * p20 + mt * p30; + let q21 = t * p21 + mt * p31; + const q30 = t * p30 + mt * p40; + const q31 = t * p31 + mt * p41; + q10 = t * q10 + mt * q20; + q11 = t * q11 + mt * q21; + q20 = t * q20 + mt * q30; + q21 = t * q21 + mt * q31; + q10 = t * q10 + mt * q20; + q11 = t * q11 + mt * q21; + points.push(q10, q11); + } + + points.push(p40, p41); + } + + #isAlmostFlat(p10, p11, p20, p21, p30, p31, p40, p41) { + const tol = 10; + const ax = (3 * p20 - 2 * p10 - p40) ** 2; + const ay = (3 * p21 - 2 * p11 - p41) ** 2; + const bx = (3 * p30 - p10 - 2 * p40) ** 2; + const by = (3 * p31 - p11 - 2 * p41) ** 2; + return Math.max(ax, bx) + Math.max(ay, by) <= tol; + } + + #getBbox() { + let xMin = Infinity; + let xMax = -Infinity; + let yMin = Infinity; + let yMax = -Infinity; + + for (const path of this.paths) { + for (const [first, control1, control2, second] of path) { + const bbox = _util.Util.bezierBoundingBox(...first, ...control1, ...control2, ...second); + + xMin = Math.min(xMin, bbox[0]); + yMin = Math.min(yMin, bbox[1]); + xMax = Math.max(xMax, bbox[2]); + yMax = Math.max(yMax, bbox[3]); + } + } + + return [xMin, yMin, xMax, yMax]; + } + + #getPadding() { + return this.#disableEditing ? Math.ceil(this.thickness * this.parent.scaleFactor) : 0; + } + + #fitToContent(firstTime = false) { + if (this.isEmpty()) { + return; + } + + if (!this.#disableEditing) { + this.#redraw(); + return; + } + + const bbox = this.#getBbox(); + const padding = this.#getPadding(); + this.#baseWidth = Math.max(RESIZER_SIZE, bbox[2] - bbox[0]); + this.#baseHeight = Math.max(RESIZER_SIZE, bbox[3] - bbox[1]); + const width = Math.ceil(padding + this.#baseWidth * this.scaleFactor); + const height = Math.ceil(padding + this.#baseHeight * this.scaleFactor); + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.width = width / parentWidth; + this.height = height / parentHeight; + this.#aspectRatio = width / height; + this.#setMinDims(); + const prevTranslationX = this.translationX; + const prevTranslationY = this.translationY; + this.translationX = -bbox[0]; + this.translationY = -bbox[1]; + this.#setCanvasDims(); + this.#redraw(); + this.#realWidth = width; + this.#realHeight = height; + this.setDims(width, height); + const unscaledPadding = firstTime ? padding / this.scaleFactor / 2 : 0; + this.translate(prevTranslationX - this.translationX - unscaledPadding, prevTranslationY - this.translationY - unscaledPadding); + } + + #setMinDims() { + const { + style + } = this.div; + + if (this.#aspectRatio >= 1) { + style.minHeight = `${RESIZER_SIZE}px`; + style.minWidth = `${Math.round(this.#aspectRatio * RESIZER_SIZE)}px`; + } else { + style.minWidth = `${RESIZER_SIZE}px`; + style.minHeight = `${Math.round(RESIZER_SIZE / this.#aspectRatio)}px`; + } + } + + static deserialize(data, parent) { + const editor = super.deserialize(data, parent); + editor.thickness = data.thickness; + editor.color = _util.Util.makeHexColor(...data.color); + editor.opacity = data.opacity; + const [pageWidth, pageHeight] = parent.pageDimensions; + const width = editor.width * pageWidth; + const height = editor.height * pageHeight; + const scaleFactor = parent.scaleFactor; + const padding = data.thickness / 2; + editor.#aspectRatio = width / height; + editor.#disableEditing = true; + editor.#realWidth = Math.round(width); + editor.#realHeight = Math.round(height); + + for (const { + bezier + } of data.paths) { + const path = []; + editor.paths.push(path); + let p0 = scaleFactor * (bezier[0] - padding); + let p1 = scaleFactor * (height - bezier[1] - padding); + + for (let i = 2, ii = bezier.length; i < ii; i += 6) { + const p10 = scaleFactor * (bezier[i] - padding); + const p11 = scaleFactor * (height - bezier[i + 1] - padding); + const p20 = scaleFactor * (bezier[i + 2] - padding); + const p21 = scaleFactor * (height - bezier[i + 3] - padding); + const p30 = scaleFactor * (bezier[i + 4] - padding); + const p31 = scaleFactor * (height - bezier[i + 5] - padding); + path.push([[p0, p1], [p10, p11], [p20, p21], [p30, p31]]); + p0 = p30; + p1 = p31; + } + + const path2D = this.#buildPath2D(path); + editor.bezierPath2D.push(path2D); + } + + const bbox = editor.#getBbox(); + editor.#baseWidth = Math.max(RESIZER_SIZE, bbox[2] - bbox[0]); + editor.#baseHeight = Math.max(RESIZER_SIZE, bbox[3] - bbox[1]); + editor.#setScaleFactor(width, height); + return editor; + } + + serialize() { + if (this.isEmpty()) { + return null; + } + + const rect = this.getRect(0, 0); + const height = this.rotation % 180 === 0 ? rect[3] - rect[1] : rect[2] - rect[0]; + + const color = _editor.AnnotationEditor._colorManager.convert(this.ctx.strokeStyle); + + return { + annotationType: _util.AnnotationEditorType.INK, + color, + thickness: this.thickness, + opacity: this.opacity, + paths: this.#serializePaths(this.scaleFactor / this.parent.scaleFactor, this.translationX, this.translationY, height), + pageIndex: this.parent.pageIndex, + rect, + rotation: this.rotation + }; + } + +} + +exports.InkEditor = InkEditor; + +/***/ }), +/* 25 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.fitCurve = void 0; + +const fitCurve = __w_pdfjs_require__(26); + +exports.fitCurve = fitCurve; + +/***/ }), +/* 26 */ +/***/ ((module) => { + + + +function fitCurve(points, maxError, progressCallback) { + if (!Array.isArray(points)) { + throw new TypeError("First argument should be an array"); + } + + points.forEach(point => { + if (!Array.isArray(point) || point.some(item => typeof item !== 'number') || point.length !== points[0].length) { + throw Error("Each point should be an array of numbers. Each point should have the same amount of numbers."); + } + }); + points = points.filter((point, i) => i === 0 || !point.every((val, j) => val === points[i - 1][j])); + + if (points.length < 2) { + return []; + } + + const len = points.length; + const leftTangent = createTangent(points[1], points[0]); + const rightTangent = createTangent(points[len - 2], points[len - 1]); + return fitCubic(points, leftTangent, rightTangent, maxError, progressCallback); +} + +function fitCubic(points, leftTangent, rightTangent, error, progressCallback) { + const MaxIterations = 20; + var bezCurve, u, uPrime, maxError, prevErr, splitPoint, prevSplit, centerVector, toCenterTangent, fromCenterTangent, beziers, dist, i; + + if (points.length === 2) { + dist = maths.vectorLen(maths.subtract(points[0], points[1])) / 3.0; + bezCurve = [points[0], maths.addArrays(points[0], maths.mulItems(leftTangent, dist)), maths.addArrays(points[1], maths.mulItems(rightTangent, dist)), points[1]]; + return [bezCurve]; + } + + u = chordLengthParameterize(points); + [bezCurve, maxError, splitPoint] = generateAndReport(points, u, u, leftTangent, rightTangent, progressCallback); + + if (maxError === 0 || maxError < error) { + return [bezCurve]; + } + + if (maxError < error * error) { + uPrime = u; + prevErr = maxError; + prevSplit = splitPoint; + + for (i = 0; i < MaxIterations; i++) { + uPrime = reparameterize(bezCurve, points, uPrime); + [bezCurve, maxError, splitPoint] = generateAndReport(points, u, uPrime, leftTangent, rightTangent, progressCallback); + + if (maxError < error) { + return [bezCurve]; + } else if (splitPoint === prevSplit) { + let errChange = maxError / prevErr; + + if (errChange > .9999 && errChange < 1.0001) { + break; + } + } + + prevErr = maxError; + prevSplit = splitPoint; + } + } + + beziers = []; + centerVector = maths.subtract(points[splitPoint - 1], points[splitPoint + 1]); + + if (centerVector.every(val => val === 0)) { + centerVector = maths.subtract(points[splitPoint - 1], points[splitPoint]); + [centerVector[0], centerVector[1]] = [-centerVector[1], centerVector[0]]; + } + + toCenterTangent = maths.normalize(centerVector); + fromCenterTangent = maths.mulItems(toCenterTangent, -1); + beziers = beziers.concat(fitCubic(points.slice(0, splitPoint + 1), leftTangent, toCenterTangent, error, progressCallback)); + beziers = beziers.concat(fitCubic(points.slice(splitPoint), fromCenterTangent, rightTangent, error, progressCallback)); + return beziers; +} + +; + +function generateAndReport(points, paramsOrig, paramsPrime, leftTangent, rightTangent, progressCallback) { + var bezCurve, maxError, splitPoint; + bezCurve = generateBezier(points, paramsPrime, leftTangent, rightTangent, progressCallback); + [maxError, splitPoint] = computeMaxError(points, bezCurve, paramsOrig); + + if (progressCallback) { + progressCallback({ + bez: bezCurve, + points: points, + params: paramsOrig, + maxErr: maxError, + maxPoint: splitPoint + }); + } + + return [bezCurve, maxError, splitPoint]; +} + +function generateBezier(points, parameters, leftTangent, rightTangent) { + var bezCurve, + A, + a, + C, + X, + det_C0_C1, + det_C0_X, + det_X_C1, + alpha_l, + alpha_r, + epsilon, + segLength, + i, + len, + tmp, + u, + ux, + firstPoint = points[0], + lastPoint = points[points.length - 1]; + bezCurve = [firstPoint, null, null, lastPoint]; + A = maths.zeros_Xx2x2(parameters.length); + + for (i = 0, len = parameters.length; i < len; i++) { + u = parameters[i]; + ux = 1 - u; + a = A[i]; + a[0] = maths.mulItems(leftTangent, 3 * u * (ux * ux)); + a[1] = maths.mulItems(rightTangent, 3 * ux * (u * u)); + } + + C = [[0, 0], [0, 0]]; + X = [0, 0]; + + for (i = 0, len = points.length; i < len; i++) { + u = parameters[i]; + a = A[i]; + C[0][0] += maths.dot(a[0], a[0]); + C[0][1] += maths.dot(a[0], a[1]); + C[1][0] += maths.dot(a[0], a[1]); + C[1][1] += maths.dot(a[1], a[1]); + tmp = maths.subtract(points[i], bezier.q([firstPoint, firstPoint, lastPoint, lastPoint], u)); + X[0] += maths.dot(a[0], tmp); + X[1] += maths.dot(a[1], tmp); + } + + det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]; + det_C0_X = C[0][0] * X[1] - C[1][0] * X[0]; + det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1]; + alpha_l = det_C0_C1 === 0 ? 0 : det_X_C1 / det_C0_C1; + alpha_r = det_C0_C1 === 0 ? 0 : det_C0_X / det_C0_C1; + segLength = maths.vectorLen(maths.subtract(firstPoint, lastPoint)); + epsilon = 1.0e-6 * segLength; + + if (alpha_l < epsilon || alpha_r < epsilon) { + bezCurve[1] = maths.addArrays(firstPoint, maths.mulItems(leftTangent, segLength / 3.0)); + bezCurve[2] = maths.addArrays(lastPoint, maths.mulItems(rightTangent, segLength / 3.0)); + } else { + bezCurve[1] = maths.addArrays(firstPoint, maths.mulItems(leftTangent, alpha_l)); + bezCurve[2] = maths.addArrays(lastPoint, maths.mulItems(rightTangent, alpha_r)); + } + + return bezCurve; +} + +; + +function reparameterize(bezier, points, parameters) { + return parameters.map((p, i) => newtonRaphsonRootFind(bezier, points[i], p)); +} + +; + +function newtonRaphsonRootFind(bez, point, u) { + var d = maths.subtract(bezier.q(bez, u), point), + qprime = bezier.qprime(bez, u), + numerator = maths.mulMatrix(d, qprime), + denominator = maths.sum(maths.squareItems(qprime)) + 2 * maths.mulMatrix(d, bezier.qprimeprime(bez, u)); + + if (denominator === 0) { + return u; + } else { + return u - numerator / denominator; + } +} + +; + +function chordLengthParameterize(points) { + var u = [], + currU, + prevU, + prevP; + points.forEach((p, i) => { + currU = i ? prevU + maths.vectorLen(maths.subtract(p, prevP)) : 0; + u.push(currU); + prevU = currU; + prevP = p; + }); + u = u.map(x => x / prevU); + return u; +} + +; + +function computeMaxError(points, bez, parameters) { + var dist, maxDist, splitPoint, v, i, count, point, t; + maxDist = 0; + splitPoint = Math.floor(points.length / 2); + const t_distMap = mapTtoRelativeDistances(bez, 10); + + for (i = 0, count = points.length; i < count; i++) { + point = points[i]; + t = find_t(bez, parameters[i], t_distMap, 10); + v = maths.subtract(bezier.q(bez, t), point); + dist = v[0] * v[0] + v[1] * v[1]; + + if (dist > maxDist) { + maxDist = dist; + splitPoint = i; + } + } + + return [maxDist, splitPoint]; +} + +; + +var mapTtoRelativeDistances = function (bez, B_parts) { + var B_t_curr; + var B_t_dist = [0]; + var B_t_prev = bez[0]; + var sumLen = 0; + + for (var i = 1; i <= B_parts; i++) { + B_t_curr = bezier.q(bez, i / B_parts); + sumLen += maths.vectorLen(maths.subtract(B_t_curr, B_t_prev)); + B_t_dist.push(sumLen); + B_t_prev = B_t_curr; + } + + B_t_dist = B_t_dist.map(x => x / sumLen); + return B_t_dist; +}; + +function find_t(bez, param, t_distMap, B_parts) { + if (param < 0) { + return 0; + } + + if (param > 1) { + return 1; + } + + var lenMax, lenMin, tMax, tMin, t; + + for (var i = 1; i <= B_parts; i++) { + if (param <= t_distMap[i]) { + tMin = (i - 1) / B_parts; + tMax = i / B_parts; + lenMin = t_distMap[i - 1]; + lenMax = t_distMap[i]; + t = (param - lenMin) / (lenMax - lenMin) * (tMax - tMin) + tMin; + break; + } + } + + return t; +} + +function createTangent(pointA, pointB) { + return maths.normalize(maths.subtract(pointA, pointB)); +} + +class maths { + static zeros_Xx2x2(x) { + var zs = []; + + while (x--) { + zs.push([0, 0]); + } + + return zs; + } + + static mulItems(items, multiplier) { + return items.map(x => x * multiplier); + } + + static mulMatrix(m1, m2) { + return m1.reduce((sum, x1, i) => sum + x1 * m2[i], 0); + } + + static subtract(arr1, arr2) { + return arr1.map((x1, i) => x1 - arr2[i]); + } + + static addArrays(arr1, arr2) { + return arr1.map((x1, i) => x1 + arr2[i]); + } + + static addItems(items, addition) { + return items.map(x => x + addition); + } + + static sum(items) { + return items.reduce((sum, x) => sum + x); + } + + static dot(m1, m2) { + return maths.mulMatrix(m1, m2); + } + + static vectorLen(v) { + return Math.hypot(...v); + } + + static divItems(items, divisor) { + return items.map(x => x / divisor); + } + + static squareItems(items) { + return items.map(x => x * x); + } + + static normalize(v) { + return this.divItems(v, this.vectorLen(v)); + } + +} + +class bezier { + static q(ctrlPoly, t) { + var tx = 1.0 - t; + var pA = maths.mulItems(ctrlPoly[0], tx * tx * tx), + pB = maths.mulItems(ctrlPoly[1], 3 * tx * tx * t), + pC = maths.mulItems(ctrlPoly[2], 3 * tx * t * t), + pD = maths.mulItems(ctrlPoly[3], t * t * t); + return maths.addArrays(maths.addArrays(pA, pB), maths.addArrays(pC, pD)); + } + + static qprime(ctrlPoly, t) { + var tx = 1.0 - t; + var pA = maths.mulItems(maths.subtract(ctrlPoly[1], ctrlPoly[0]), 3 * tx * tx), + pB = maths.mulItems(maths.subtract(ctrlPoly[2], ctrlPoly[1]), 6 * tx * t), + pC = maths.mulItems(maths.subtract(ctrlPoly[3], ctrlPoly[2]), 3 * t * t); + return maths.addArrays(maths.addArrays(pA, pB), pC); + } + + static qprimeprime(ctrlPoly, t) { + return maths.addArrays(maths.mulItems(maths.addArrays(maths.subtract(ctrlPoly[2], maths.mulItems(ctrlPoly[1], 2)), ctrlPoly[0]), 6 * (1.0 - t)), maths.mulItems(maths.addArrays(maths.subtract(ctrlPoly[3], maths.mulItems(ctrlPoly[2], 2)), ctrlPoly[1]), 6 * t)); + } + +} + +module.exports = fitCurve; +module.exports.fitCubic = fitCubic; +module.exports.createTangent = createTangent; + +/***/ }), +/* 27 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.AnnotationLayer = void 0; -var _display_utils = __w_pdfjs_require__(1); +var _util = __w_pdfjs_require__(1); -var _util = __w_pdfjs_require__(2); +var _display_utils = __w_pdfjs_require__(8); -var _annotation_storage = __w_pdfjs_require__(8); +var _annotation_storage = __w_pdfjs_require__(5); + +var _scripting_utils = __w_pdfjs_require__(28); + +var _xfa_layer = __w_pdfjs_require__(29); + +const DEFAULT_TAB_INDEX = 1000; +const DEFAULT_FONT_SIZE = 9; +const GetElementsByNameSet = new WeakSet(); + +function getRectDims(rect) { + return { + width: rect[2] - rect[0], + height: rect[3] - rect[1] + }; +} class AnnotationElementFactory { static create(parameters) { @@ -9351,7 +12907,11 @@ class AnnotationElementFactory { } class AnnotationElement { - constructor(parameters, isRenderable = false, ignoreBorder = false) { + constructor(parameters, { + isRenderable = false, + ignoreBorder = false, + createQuadrilaterals = false + } = {}) { this.isRenderable = isRenderable; this.data = parameters.data; this.layer = parameters.layer; @@ -9360,13 +12920,21 @@ class AnnotationElement { this.linkService = parameters.linkService; this.downloadManager = parameters.downloadManager; this.imageResourcesPath = parameters.imageResourcesPath; - this.renderInteractiveForms = parameters.renderInteractiveForms; + this.renderForms = parameters.renderForms; this.svgFactory = parameters.svgFactory; this.annotationStorage = parameters.annotationStorage; + this.enableScripting = parameters.enableScripting; + this.hasJSActions = parameters.hasJSActions; + this._fieldObjects = parameters.fieldObjects; + this._mouseState = parameters.mouseState; if (isRenderable) { this.container = this._createContainer(ignoreBorder); } + + if (createQuadrilaterals) { + this.quadrilaterals = this._createQuadrilaterals(ignoreBorder); + } } _createContainer(ignoreBorder = false) { @@ -9374,28 +12942,27 @@ class AnnotationElement { page = this.page, viewport = this.viewport; const container = document.createElement("section"); - let width = data.rect[2] - data.rect[0]; - let height = data.rect[3] - data.rect[1]; + const { + width, + height + } = getRectDims(data.rect); + const [pageLLx, pageLLy, pageURx, pageURy] = viewport.viewBox; + const pageWidth = pageURx - pageLLx; + const pageHeight = pageURy - pageLLy; container.setAttribute("data-annotation-id", data.id); const rect = _util.Util.normalizeRect([data.rect[0], page.view[3] - data.rect[1] + page.view[1], data.rect[2], page.view[3] - data.rect[3] + page.view[1]]); - container.style.transform = `matrix(${viewport.transform.join(",")})`; - container.style.transformOrigin = `-${rect[0]}px -${rect[1]}px`; - if (!ignoreBorder && data.borderStyle.width > 0) { container.style.borderWidth = `${data.borderStyle.width}px`; - - if (data.borderStyle.style !== _util.AnnotationBorderStyleType.UNDERLINE) { - width = width - 2 * data.borderStyle.width; - height = height - 2 * data.borderStyle.width; - } - const horizontalRadius = data.borderStyle.horizontalCornerRadius; const verticalRadius = data.borderStyle.verticalCornerRadius; if (horizontalRadius > 0 || verticalRadius > 0) { - const radius = `${horizontalRadius}px / ${verticalRadius}px`; + const radius = `calc(${horizontalRadius}px * var(--scale-factor)) / calc(${verticalRadius}px * var(--scale-factor))`; + container.style.borderRadius = radius; + } else if (this instanceof RadioButtonWidgetAnnotationElement) { + const radius = `calc(${width}px * var(--scale-factor)) / calc(${height}px * var(--scale-factor))`; container.style.borderRadius = radius; } @@ -9424,76 +12991,360 @@ class AnnotationElement { break; } - if (data.color) { - container.style.borderColor = _util.Util.makeCssRgb(data.color[0] | 0, data.color[1] | 0, data.color[2] | 0); + const borderColor = data.borderColor || null; + + if (borderColor) { + container.style.borderColor = _util.Util.makeHexColor(borderColor[0] | 0, borderColor[1] | 0, borderColor[2] | 0); } else { container.style.borderWidth = 0; } } - container.style.left = `${rect[0]}px`; - container.style.top = `${rect[1]}px`; - container.style.width = `${width}px`; - container.style.height = `${height}px`; + container.style.left = `${100 * (rect[0] - pageLLx) / pageWidth}%`; + container.style.top = `${100 * (rect[1] - pageLLy) / pageHeight}%`; + const { + rotation + } = data; + + if (data.hasOwnCanvas || rotation === 0) { + container.style.width = `${100 * width / pageWidth}%`; + container.style.height = `${100 * height / pageHeight}%`; + } else { + this.setRotation(rotation, container); + } + return container; } - _createPopup(container, trigger, data) { + setRotation(angle, container = this.container) { + const [pageLLx, pageLLy, pageURx, pageURy] = this.viewport.viewBox; + const pageWidth = pageURx - pageLLx; + const pageHeight = pageURy - pageLLy; + const { + width, + height + } = getRectDims(this.data.rect); + let elementWidth, elementHeight; + + if (angle % 180 === 0) { + elementWidth = 100 * width / pageWidth; + elementHeight = 100 * height / pageHeight; + } else { + elementWidth = 100 * height / pageWidth; + elementHeight = 100 * width / pageHeight; + } + + container.style.width = `${elementWidth}%`; + container.style.height = `${elementHeight}%`; + container.setAttribute("data-main-rotation", (360 - angle) % 360); + } + + get _commonActions() { + const setColor = (jsName, styleName, event) => { + const color = event.detail[jsName]; + event.target.style[styleName] = _scripting_utils.ColorConverters[`${color[0]}_HTML`](color.slice(1)); + }; + + return (0, _util.shadow)(this, "_commonActions", { + display: event => { + const hidden = event.detail.display % 2 === 1; + this.container.style.visibility = hidden ? "hidden" : "visible"; + this.annotationStorage.setValue(this.data.id, { + hidden, + print: event.detail.display === 0 || event.detail.display === 3 + }); + }, + print: event => { + this.annotationStorage.setValue(this.data.id, { + print: event.detail.print + }); + }, + hidden: event => { + this.container.style.visibility = event.detail.hidden ? "hidden" : "visible"; + this.annotationStorage.setValue(this.data.id, { + hidden: event.detail.hidden + }); + }, + focus: event => { + setTimeout(() => event.target.focus({ + preventScroll: false + }), 0); + }, + userName: event => { + event.target.title = event.detail.userName; + }, + readonly: event => { + if (event.detail.readonly) { + event.target.setAttribute("readonly", ""); + } else { + event.target.removeAttribute("readonly"); + } + }, + required: event => { + this._setRequired(event.target, event.detail.required); + }, + bgColor: event => { + setColor("bgColor", "backgroundColor", event); + }, + fillColor: event => { + setColor("fillColor", "backgroundColor", event); + }, + fgColor: event => { + setColor("fgColor", "color", event); + }, + textColor: event => { + setColor("textColor", "color", event); + }, + borderColor: event => { + setColor("borderColor", "borderColor", event); + }, + strokeColor: event => { + setColor("strokeColor", "borderColor", event); + }, + rotation: event => { + const angle = event.detail.rotation; + this.setRotation(angle); + this.annotationStorage.setValue(this.data.id, { + rotation: angle + }); + } + }); + } + + _dispatchEventFromSandbox(actions, jsEvent) { + const commonActions = this._commonActions; + + for (const name of Object.keys(jsEvent.detail)) { + const action = actions[name] || commonActions[name]; + + if (action) { + action(jsEvent); + } + } + } + + _setDefaultPropertiesFromJS(element) { + if (!this.enableScripting) { + return; + } + + const storedData = this.annotationStorage.getRawValue(this.data.id); + + if (!storedData) { + return; + } + + const commonActions = this._commonActions; + + for (const [actionName, detail] of Object.entries(storedData)) { + const action = commonActions[actionName]; + + if (action) { + const eventProxy = { + detail: { + [actionName]: detail + }, + target: element + }; + action(eventProxy); + delete storedData[actionName]; + } + } + } + + _createQuadrilaterals(ignoreBorder = false) { + if (!this.data.quadPoints) { + return null; + } + + const quadrilaterals = []; + const savedRect = this.data.rect; + + for (const quadPoint of this.data.quadPoints) { + this.data.rect = [quadPoint[2].x, quadPoint[2].y, quadPoint[1].x, quadPoint[1].y]; + quadrilaterals.push(this._createContainer(ignoreBorder)); + } + + this.data.rect = savedRect; + return quadrilaterals; + } + + _createPopup(trigger, data) { + let container = this.container; + + if (this.quadrilaterals) { + trigger = trigger || this.quadrilaterals; + container = this.quadrilaterals[0]; + } + if (!trigger) { trigger = document.createElement("div"); - trigger.style.height = container.style.height; - trigger.style.width = container.style.width; - container.appendChild(trigger); + trigger.className = "popupTriggerArea"; + container.append(trigger); } const popupElement = new PopupElement({ container, trigger, color: data.color, - title: data.title, + titleObj: data.titleObj, modificationDate: data.modificationDate, - contents: data.contents, + contentsObj: data.contentsObj, + richText: data.richText, hideWrapper: true }); const popup = popupElement.render(); - popup.style.left = container.style.width; - container.appendChild(popup); + popup.style.left = "100%"; + container.append(popup); + } + + _renderQuadrilaterals(className) { + for (const quadrilateral of this.quadrilaterals) { + quadrilateral.className = className; + } + + return this.quadrilaterals; } render() { (0, _util.unreachable)("Abstract method `AnnotationElement.render` called"); } + _getElementsByName(name, skipId = null) { + const fields = []; + + if (this._fieldObjects) { + const fieldObj = this._fieldObjects[name]; + + if (fieldObj) { + for (const { + page, + id, + exportValues + } of fieldObj) { + if (page === -1) { + continue; + } + + if (id === skipId) { + continue; + } + + const exportValue = typeof exportValues === "string" ? exportValues : null; + const domElement = document.querySelector(`[data-element-id="${id}"]`); + + if (domElement && !GetElementsByNameSet.has(domElement)) { + (0, _util.warn)(`_getElementsByName - element not allowed: ${id}`); + continue; + } + + fields.push({ + id, + exportValue, + domElement + }); + } + } + + return fields; + } + + for (const domElement of document.getElementsByName(name)) { + const { + id, + exportValue + } = domElement; + + if (id === skipId) { + continue; + } + + if (!GetElementsByNameSet.has(domElement)) { + continue; + } + + fields.push({ + id, + exportValue, + domElement + }); + } + + return fields; + } + + static get platform() { + const platform = typeof navigator !== "undefined" ? navigator.platform : ""; + return (0, _util.shadow)(this, "platform", { + isWin: platform.includes("Win"), + isMac: platform.includes("Mac") + }); + } + } class LinkAnnotationElement extends AnnotationElement { - constructor(parameters) { - const isRenderable = !!(parameters.data.url || parameters.data.dest || parameters.data.action); - super(parameters, isRenderable); + constructor(parameters, options = null) { + super(parameters, { + isRenderable: true, + ignoreBorder: !!options?.ignoreBorder, + createQuadrilaterals: true + }); + this.isTooltipOnly = parameters.data.isTooltipOnly; } render() { - this.container.className = "linkAnnotation"; const { data, linkService } = this; const link = document.createElement("a"); + link.setAttribute("data-element-id", data.id); + let isBound = false; if (data.url) { - (0, _display_utils.addLinkAttributes)(link, { - url: data.url, - target: data.newWindow ? _display_utils.LinkTarget.BLANK : linkService.externalLinkTarget, - rel: linkService.externalLinkRel, - enabled: linkService.externalLinkEnabled - }); + linkService.addLinkAttributes(link, data.url, data.newWindow); + isBound = true; } else if (data.action) { this._bindNamedAction(link, data.action); - } else { + + isBound = true; + } else if (data.dest) { this._bindLink(link, data.dest); + + isBound = true; + } else { + if (data.actions && (data.actions.Action || data.actions["Mouse Up"] || data.actions["Mouse Down"]) && this.enableScripting && this.hasJSActions) { + this._bindJSAction(link, data); + + isBound = true; + } + + if (data.resetForm) { + this._bindResetFormAction(link, data.resetForm); + + isBound = true; + } else if (this.isTooltipOnly && !isBound) { + this._bindLink(link, ""); + + isBound = true; + } + } + + if (this.quadrilaterals) { + return this._renderQuadrilaterals("linkAnnotation").map((quadrilateral, index) => { + const linkElement = index === 0 ? link : link.cloneNode(); + quadrilateral.append(linkElement); + return quadrilateral; + }); + } + + this.container.className = "linkAnnotation"; + + if (isBound) { + this.container.append(link); } - this.container.appendChild(link); return this.container; } @@ -9502,13 +13353,13 @@ class LinkAnnotationElement extends AnnotationElement { link.onclick = () => { if (destination) { - this.linkService.navigateTo(destination); + this.linkService.goToDestination(destination); } return false; }; - if (destination) { + if (destination || destination === "") { link.className = "internalLink"; } } @@ -9524,19 +13375,176 @@ class LinkAnnotationElement extends AnnotationElement { link.className = "internalLink"; } + _bindJSAction(link, data) { + link.href = this.linkService.getAnchorUrl(""); + const map = new Map([["Action", "onclick"], ["Mouse Up", "onmouseup"], ["Mouse Down", "onmousedown"]]); + + for (const name of Object.keys(data.actions)) { + const jsName = map.get(name); + + if (!jsName) { + continue; + } + + link[jsName] = () => { + this.linkService.eventBus?.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id: data.id, + name + } + }); + return false; + }; + } + + if (!link.onclick) { + link.onclick = () => false; + } + + link.className = "internalLink"; + } + + _bindResetFormAction(link, resetForm) { + const otherClickAction = link.onclick; + + if (!otherClickAction) { + link.href = this.linkService.getAnchorUrl(""); + } + + link.className = "internalLink"; + + if (!this._fieldObjects) { + (0, _util.warn)(`_bindResetFormAction - "resetForm" action not supported, ` + "ensure that the `fieldObjects` parameter is provided."); + + if (!otherClickAction) { + link.onclick = () => false; + } + + return; + } + + link.onclick = () => { + if (otherClickAction) { + otherClickAction(); + } + + const { + fields: resetFormFields, + refs: resetFormRefs, + include + } = resetForm; + const allFields = []; + + if (resetFormFields.length !== 0 || resetFormRefs.length !== 0) { + const fieldIds = new Set(resetFormRefs); + + for (const fieldName of resetFormFields) { + const fields = this._fieldObjects[fieldName] || []; + + for (const { + id + } of fields) { + fieldIds.add(id); + } + } + + for (const fields of Object.values(this._fieldObjects)) { + for (const field of fields) { + if (fieldIds.has(field.id) === include) { + allFields.push(field); + } + } + } + } else { + for (const fields of Object.values(this._fieldObjects)) { + allFields.push(...fields); + } + } + + const storage = this.annotationStorage; + const allIds = []; + + for (const field of allFields) { + const { + id + } = field; + allIds.push(id); + + switch (field.type) { + case "text": + { + const value = field.defaultValue || ""; + storage.setValue(id, { + value + }); + break; + } + + case "checkbox": + case "radiobutton": + { + const value = field.defaultValue === field.exportValues; + storage.setValue(id, { + value + }); + break; + } + + case "combobox": + case "listbox": + { + const value = field.defaultValue || ""; + storage.setValue(id, { + value + }); + break; + } + + default: + continue; + } + + const domElement = document.querySelector(`[data-element-id="${id}"]`); + + if (!domElement) { + continue; + } else if (!GetElementsByNameSet.has(domElement)) { + (0, _util.warn)(`_bindResetFormAction - element not allowed: ${id}`); + continue; + } + + domElement.dispatchEvent(new Event("resetform")); + } + + if (this.enableScripting) { + this.linkService.eventBus?.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id: "app", + ids: allIds, + name: "ResetForm" + } + }); + } + + return false; + }; + } + } class TextAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable + }); } render() { this.container.className = "textAnnotation"; const image = document.createElement("img"); - image.style.height = this.container.style.height; - image.style.width = this.container.style.width; image.src = this.imageResourcesPath + "annotation-" + this.data.name.toLowerCase() + ".svg"; image.alt = "[{{type}} Annotation]"; image.dataset.l10nId = "text_annotation_type"; @@ -9545,10 +13553,10 @@ class TextAnnotationElement extends AnnotationElement { }); if (!this.data.hasPopup) { - this._createPopup(this.container, image, this.data); + this._createPopup(image, this.data); } - this.container.appendChild(image); + this.container.append(image); return this.container; } @@ -9556,124 +13564,532 @@ class TextAnnotationElement extends AnnotationElement { class WidgetAnnotationElement extends AnnotationElement { render() { + if (this.data.alternativeText) { + this.container.title = this.data.alternativeText; + } + return this.container; } + _getKeyModifier(event) { + const { + isWin, + isMac + } = AnnotationElement.platform; + return isWin && event.ctrlKey || isMac && event.metaKey; + } + + _setEventListener(element, baseName, eventName, valueGetter) { + if (baseName.includes("mouse")) { + element.addEventListener(baseName, event => { + this.linkService.eventBus?.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id: this.data.id, + name: eventName, + value: valueGetter(event), + shift: event.shiftKey, + modifier: this._getKeyModifier(event) + } + }); + }); + } else { + element.addEventListener(baseName, event => { + this.linkService.eventBus?.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id: this.data.id, + name: eventName, + value: valueGetter(event) + } + }); + }); + } + } + + _setEventListeners(element, names, getter) { + for (const [baseName, eventName] of names) { + if (eventName === "Action" || this.data.actions?.[eventName]) { + this._setEventListener(element, baseName, eventName, getter); + } + } + } + + _setBackgroundColor(element) { + const color = this.data.backgroundColor || null; + element.style.backgroundColor = color === null ? "transparent" : _util.Util.makeHexColor(color[0], color[1], color[2]); + } + + _setTextStyle(element) { + const TEXT_ALIGNMENT = ["left", "center", "right"]; + const { + fontColor + } = this.data.defaultAppearanceData; + const fontSize = this.data.defaultAppearanceData.fontSize || DEFAULT_FONT_SIZE; + const style = element.style; + let computedFontSize; + + if (this.data.multiLine) { + const height = Math.abs(this.data.rect[3] - this.data.rect[1]); + const numberOfLines = Math.round(height / (_util.LINE_FACTOR * fontSize)) || 1; + const lineHeight = height / numberOfLines; + computedFontSize = Math.min(fontSize, Math.round(lineHeight / _util.LINE_FACTOR)); + } else { + const height = Math.abs(this.data.rect[3] - this.data.rect[1]); + computedFontSize = Math.min(fontSize, Math.round(height / _util.LINE_FACTOR)); + } + + style.fontSize = `calc(${computedFontSize}px * var(--scale-factor))`; + style.color = _util.Util.makeHexColor(fontColor[0], fontColor[1], fontColor[2]); + + if (this.data.textAlignment !== null) { + style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment]; + } + } + + _setRequired(element, isRequired) { + if (isRequired) { + element.setAttribute("required", true); + } else { + element.removeAttribute("required"); + } + + element.setAttribute("aria-required", isRequired); + } + } class TextWidgetAnnotationElement extends WidgetAnnotationElement { constructor(parameters) { - const isRenderable = parameters.renderInteractiveForms || !parameters.data.hasAppearance && !!parameters.data.fieldValue; - super(parameters, isRenderable); + const isRenderable = parameters.renderForms || !parameters.data.hasAppearance && !!parameters.data.fieldValue; + super(parameters, { + isRenderable + }); + } + + setPropertyOnSiblings(base, key, value, keyInStorage) { + const storage = this.annotationStorage; + + for (const element of this._getElementsByName(base.name, base.id)) { + if (element.domElement) { + element.domElement[key] = value; + } + + storage.setValue(element.id, { + [keyInStorage]: value + }); + } } render() { - const TEXT_ALIGNMENT = ["left", "center", "right"]; const storage = this.annotationStorage; const id = this.data.id; this.container.className = "textWidgetAnnotation"; let element = null; - if (this.renderInteractiveForms) { - const textContent = storage.getOrCreateValue(id, this.data.fieldValue); + if (this.renderForms) { + const storedData = storage.getValue(id, { + value: this.data.fieldValue + }); + let textContent = storedData.formattedValue || storedData.value || ""; + const maxLen = storage.getValue(id, { + charLimit: this.data.maxLen + }).charLimit; + + if (maxLen && textContent.length > maxLen) { + textContent = textContent.slice(0, maxLen); + } + + const elementData = { + userValue: textContent, + formattedValue: null, + valueOnFocus: "" + }; if (this.data.multiLine) { element = document.createElement("textarea"); element.textContent = textContent; + + if (this.data.doNotScroll) { + element.style.overflowY = "hidden"; + } } else { element = document.createElement("input"); element.type = "text"; element.setAttribute("value", textContent); + + if (this.data.doNotScroll) { + element.style.overflowX = "hidden"; + } } - element.addEventListener("input", function (event) { - storage.setValue(id, event.target.value); - }); + GetElementsByNameSet.add(element); + element.setAttribute("data-element-id", id); element.disabled = this.data.readOnly; element.name = this.data.fieldName; + element.tabIndex = DEFAULT_TAB_INDEX; - if (this.data.maxLen !== null) { - element.maxLength = this.data.maxLen; + this._setRequired(element, this.data.required); + + if (maxLen) { + element.maxLength = maxLen; + } + + element.addEventListener("input", event => { + storage.setValue(id, { + value: event.target.value + }); + this.setPropertyOnSiblings(element, "value", event.target.value, "value"); + }); + element.addEventListener("resetform", event => { + const defaultValue = this.data.defaultFieldValue ?? ""; + element.value = elementData.userValue = defaultValue; + elementData.formattedValue = null; + }); + + let blurListener = event => { + const { + formattedValue + } = elementData; + + if (formattedValue !== null && formattedValue !== undefined) { + event.target.value = formattedValue; + } + + event.target.scrollLeft = 0; + }; + + if (this.enableScripting && this.hasJSActions) { + element.addEventListener("focus", event => { + if (elementData.userValue) { + event.target.value = elementData.userValue; + } + + elementData.valueOnFocus = event.target.value; + }); + element.addEventListener("updatefromsandbox", jsEvent => { + const actions = { + value(event) { + elementData.userValue = event.detail.value ?? ""; + storage.setValue(id, { + value: elementData.userValue.toString() + }); + event.target.value = elementData.userValue; + }, + + formattedValue(event) { + const { + formattedValue + } = event.detail; + elementData.formattedValue = formattedValue; + + if (formattedValue !== null && formattedValue !== undefined && event.target !== document.activeElement) { + event.target.value = formattedValue; + } + + storage.setValue(id, { + formattedValue + }); + }, + + selRange(event) { + event.target.setSelectionRange(...event.detail.selRange); + }, + + charLimit: event => { + const { + charLimit + } = event.detail; + const { + target + } = event; + + if (charLimit === 0) { + target.removeAttribute("maxLength"); + return; + } + + target.setAttribute("maxLength", charLimit); + let value = elementData.userValue; + + if (!value || value.length <= charLimit) { + return; + } + + value = value.slice(0, charLimit); + target.value = elementData.userValue = value; + storage.setValue(id, { + value + }); + this.linkService.eventBus?.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + willCommit: true, + commitKey: 1, + selStart: target.selectionStart, + selEnd: target.selectionEnd + } + }); + } + }; + + this._dispatchEventFromSandbox(actions, jsEvent); + }); + element.addEventListener("keydown", event => { + let commitKey = -1; + + if (event.key === "Escape") { + commitKey = 0; + } else if (event.key === "Enter") { + commitKey = 2; + } else if (event.key === "Tab") { + commitKey = 3; + } + + if (commitKey === -1) { + return; + } + + const { + value + } = event.target; + + if (elementData.valueOnFocus === value) { + return; + } + + elementData.userValue = value; + this.linkService.eventBus?.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + willCommit: true, + commitKey, + selStart: event.target.selectionStart, + selEnd: event.target.selectionEnd + } + }); + }); + const _blurListener = blurListener; + blurListener = null; + element.addEventListener("blur", event => { + const { + value + } = event.target; + elementData.userValue = value; + + if (this._mouseState.isDown && elementData.valueOnFocus !== value) { + this.linkService.eventBus?.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + willCommit: true, + commitKey: 1, + selStart: event.target.selectionStart, + selEnd: event.target.selectionEnd + } + }); + } + + _blurListener(event); + }); + + if (this.data.actions?.Keystroke) { + element.addEventListener("beforeinput", event => { + const { + data, + target + } = event; + const { + value, + selectionStart, + selectionEnd + } = target; + let selStart = selectionStart, + selEnd = selectionEnd; + + switch (event.inputType) { + case "deleteWordBackward": + { + const match = value.substring(0, selectionStart).match(/\w*[^\w]*$/); + + if (match) { + selStart -= match[0].length; + } + + break; + } + + case "deleteWordForward": + { + const match = value.substring(selectionStart).match(/^[^\w]*\w*/); + + if (match) { + selEnd += match[0].length; + } + + break; + } + + case "deleteContentBackward": + if (selectionStart === selectionEnd) { + selStart -= 1; + } + + break; + + case "deleteContentForward": + if (selectionStart === selectionEnd) { + selEnd += 1; + } + + break; + } + + event.preventDefault(); + this.linkService.eventBus?.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + change: data || "", + willCommit: false, + selStart, + selEnd + } + }); + }); + } + + this._setEventListeners(element, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.value); + } + + if (blurListener) { + element.addEventListener("blur", blurListener); } if (this.data.comb) { const fieldWidth = this.data.rect[2] - this.data.rect[0]; - const combWidth = fieldWidth / this.data.maxLen; + const combWidth = fieldWidth / maxLen; element.classList.add("comb"); - element.style.letterSpacing = `calc(${combWidth}px - 1ch)`; + element.style.letterSpacing = `calc(${combWidth}px * var(--scale-factor) - 1ch)`; } } else { element = document.createElement("div"); element.textContent = this.data.fieldValue; element.style.verticalAlign = "middle"; element.style.display = "table-cell"; - let font = null; - - if (this.data.fontRefName && this.page.commonObjs.has(this.data.fontRefName)) { - font = this.page.commonObjs.get(this.data.fontRefName); - } - - this._setTextStyle(element, font); } - if (this.data.textAlignment !== null) { - element.style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment]; - } + this._setTextStyle(element); - this.container.appendChild(element); + this._setBackgroundColor(element); + + this._setDefaultPropertiesFromJS(element); + + this.container.append(element); return this.container; } - _setTextStyle(element, font) { - const style = element.style; - style.fontSize = `${this.data.fontSize}px`; - style.direction = this.data.fontDirection < 0 ? "rtl" : "ltr"; - - if (!font) { - return; - } - - let bold = "normal"; - - if (font.black) { - bold = "900"; - } else if (font.bold) { - bold = "bold"; - } - - style.fontWeight = bold; - style.fontStyle = font.italic ? "italic" : "normal"; - const fontFamily = font.loadedName ? `"${font.loadedName}", ` : ""; - const fallbackName = font.fallbackName || "Helvetica, sans-serif"; - style.fontFamily = fontFamily + fallbackName; - } - } class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement { constructor(parameters) { - super(parameters, parameters.renderInteractiveForms); + super(parameters, { + isRenderable: parameters.renderForms + }); } render() { const storage = this.annotationStorage; const data = this.data; const id = data.id; - const value = storage.getOrCreateValue(id, data.fieldValue && data.fieldValue !== "Off"); + let value = storage.getValue(id, { + value: data.exportValue === data.fieldValue + }).value; + + if (typeof value === "string") { + value = value !== "Off"; + storage.setValue(id, { + value + }); + } + this.container.className = "buttonWidgetAnnotation checkBox"; const element = document.createElement("input"); + GetElementsByNameSet.add(element); + element.setAttribute("data-element-id", id); element.disabled = data.readOnly; + + this._setRequired(element, this.data.required); + element.type = "checkbox"; - element.name = this.data.fieldName; + element.name = data.fieldName; if (value) { element.setAttribute("checked", true); } - element.addEventListener("change", function (event) { - storage.setValue(id, event.target.checked); + element.setAttribute("exportValue", data.exportValue); + element.tabIndex = DEFAULT_TAB_INDEX; + element.addEventListener("change", event => { + const { + name, + checked + } = event.target; + + for (const checkbox of this._getElementsByName(name, id)) { + const curChecked = checked && checkbox.exportValue === data.exportValue; + + if (checkbox.domElement) { + checkbox.domElement.checked = curChecked; + } + + storage.setValue(checkbox.id, { + value: curChecked + }); + } + + storage.setValue(id, { + value: checked + }); }); - this.container.appendChild(element); + element.addEventListener("resetform", event => { + const defaultValue = data.defaultFieldValue || "Off"; + event.target.checked = defaultValue === data.exportValue; + }); + + if (this.enableScripting && this.hasJSActions) { + element.addEventListener("updatefromsandbox", jsEvent => { + const actions = { + value(event) { + event.target.checked = event.detail.value !== "Off"; + storage.setValue(id, { + value: event.target.checked + }); + } + + }; + + this._dispatchEventFromSandbox(actions, jsEvent); + }); + + this._setEventListeners(element, [["change", "Validate"], ["change", "Action"], ["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.checked); + } + + this._setBackgroundColor(element); + + this._setDefaultPropertiesFromJS(element); + + this.container.append(element); return this.container; } @@ -9681,7 +14097,9 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement { class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement { constructor(parameters) { - super(parameters, parameters.renderInteractiveForms); + super(parameters, { + isRenderable: parameters.renderForms + }); } render() { @@ -9689,9 +14107,24 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement { const storage = this.annotationStorage; const data = this.data; const id = data.id; - const value = storage.getOrCreateValue(id, data.fieldValue === data.buttonValue); + let value = storage.getValue(id, { + value: data.fieldValue === data.buttonValue + }).value; + + if (typeof value === "string") { + value = value !== data.buttonValue; + storage.setValue(id, { + value + }); + } + const element = document.createElement("input"); + GetElementsByNameSet.add(element); + element.setAttribute("data-element-id", id); element.disabled = data.readOnly; + + this._setRequired(element, this.data.required); + element.type = "radio"; element.name = data.fieldName; @@ -9699,27 +14132,90 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement { element.setAttribute("checked", true); } - element.addEventListener("change", function (event) { - const name = event.target.name; + element.tabIndex = DEFAULT_TAB_INDEX; + element.addEventListener("change", event => { + const { + name, + checked + } = event.target; - for (const radio of document.getElementsByName(name)) { - if (radio !== event.target) { - storage.setValue(radio.parentNode.getAttribute("data-annotation-id"), false); - } + for (const radio of this._getElementsByName(name, id)) { + storage.setValue(radio.id, { + value: false + }); } - storage.setValue(id, event.target.checked); + storage.setValue(id, { + value: checked + }); }); - this.container.appendChild(element); + element.addEventListener("resetform", event => { + const defaultValue = data.defaultFieldValue; + event.target.checked = defaultValue !== null && defaultValue !== undefined && defaultValue === data.buttonValue; + }); + + if (this.enableScripting && this.hasJSActions) { + const pdfButtonValue = data.buttonValue; + element.addEventListener("updatefromsandbox", jsEvent => { + const actions = { + value: event => { + const checked = pdfButtonValue === event.detail.value; + + for (const radio of this._getElementsByName(event.target.name)) { + const curChecked = checked && radio.id === id; + + if (radio.domElement) { + radio.domElement.checked = curChecked; + } + + storage.setValue(radio.id, { + value: curChecked + }); + } + } + }; + + this._dispatchEventFromSandbox(actions, jsEvent); + }); + + this._setEventListeners(element, [["change", "Validate"], ["change", "Action"], ["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.checked); + } + + this._setBackgroundColor(element); + + this._setDefaultPropertiesFromJS(element); + + this.container.append(element); return this.container; } } class PushButtonWidgetAnnotationElement extends LinkAnnotationElement { + constructor(parameters) { + super(parameters, { + ignoreBorder: parameters.data.hasAppearance + }); + } + render() { const container = super.render(); container.className = "buttonWidgetAnnotation pushButton"; + + if (this.data.alternativeText) { + container.title = this.data.alternativeText; + } + + const linkElement = container.lastChild; + + if (this.enableScripting && this.hasJSActions && linkElement) { + this._setDefaultPropertiesFromJS(linkElement); + + linkElement.addEventListener("updatefromsandbox", jsEvent => { + this._dispatchEventFromSandbox({}, jsEvent); + }); + } + return container; } @@ -9727,17 +14223,28 @@ class PushButtonWidgetAnnotationElement extends LinkAnnotationElement { class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { constructor(parameters) { - super(parameters, parameters.renderInteractiveForms); + super(parameters, { + isRenderable: parameters.renderForms + }); } render() { this.container.className = "choiceWidgetAnnotation"; const storage = this.annotationStorage; const id = this.data.id; - storage.getOrCreateValue(id, this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : null); + const storedData = storage.getValue(id, { + value: this.data.fieldValue + }); const selectElement = document.createElement("select"); + GetElementsByNameSet.add(selectElement); + selectElement.setAttribute("data-element-id", id); selectElement.disabled = this.data.readOnly; + + this._setRequired(selectElement, this.data.required); + selectElement.name = this.data.fieldName; + selectElement.tabIndex = DEFAULT_TAB_INDEX; + let addAnEmptyEntry = this.data.combo && this.data.options.length > 0; if (!this.data.combo) { selectElement.size = this.data.options.length; @@ -9747,24 +14254,229 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { } } + selectElement.addEventListener("resetform", event => { + const defaultValue = this.data.defaultFieldValue; + + for (const option of selectElement.options) { + option.selected = option.value === defaultValue; + } + }); + for (const option of this.data.options) { const optionElement = document.createElement("option"); optionElement.textContent = option.displayValue; optionElement.value = option.exportValue; - if (this.data.fieldValue.includes(option.exportValue)) { + if (storedData.value.includes(option.exportValue)) { optionElement.setAttribute("selected", true); + addAnEmptyEntry = false; } - selectElement.appendChild(optionElement); + selectElement.append(optionElement); } - selectElement.addEventListener("input", function (event) { + let removeEmptyEntry = null; + + if (addAnEmptyEntry) { + const noneOptionElement = document.createElement("option"); + noneOptionElement.value = " "; + noneOptionElement.setAttribute("hidden", true); + noneOptionElement.setAttribute("selected", true); + selectElement.prepend(noneOptionElement); + + removeEmptyEntry = () => { + noneOptionElement.remove(); + selectElement.removeEventListener("input", removeEmptyEntry); + removeEmptyEntry = null; + }; + + selectElement.addEventListener("input", removeEmptyEntry); + } + + const getValue = (event, isExport) => { + const name = isExport ? "value" : "textContent"; const options = event.target.options; - const value = options[options.selectedIndex].value; - storage.setValue(id, value); - }); - this.container.appendChild(selectElement); + + if (!event.target.multiple) { + return options.selectedIndex === -1 ? null : options[options.selectedIndex][name]; + } + + return Array.prototype.filter.call(options, option => option.selected).map(option => option[name]); + }; + + const getItems = event => { + const options = event.target.options; + return Array.prototype.map.call(options, option => { + return { + displayValue: option.textContent, + exportValue: option.value + }; + }); + }; + + if (this.enableScripting && this.hasJSActions) { + selectElement.addEventListener("updatefromsandbox", jsEvent => { + const actions = { + value(event) { + removeEmptyEntry?.(); + const value = event.detail.value; + const values = new Set(Array.isArray(value) ? value : [value]); + + for (const option of selectElement.options) { + option.selected = values.has(option.value); + } + + storage.setValue(id, { + value: getValue(event, true) + }); + }, + + multipleSelection(event) { + selectElement.multiple = true; + }, + + remove(event) { + const options = selectElement.options; + const index = event.detail.remove; + options[index].selected = false; + selectElement.remove(index); + + if (options.length > 0) { + const i = Array.prototype.findIndex.call(options, option => option.selected); + + if (i === -1) { + options[0].selected = true; + } + } + + storage.setValue(id, { + value: getValue(event, true), + items: getItems(event) + }); + }, + + clear(event) { + while (selectElement.length !== 0) { + selectElement.remove(0); + } + + storage.setValue(id, { + value: null, + items: [] + }); + }, + + insert(event) { + const { + index, + displayValue, + exportValue + } = event.detail.insert; + const selectChild = selectElement.children[index]; + const optionElement = document.createElement("option"); + optionElement.textContent = displayValue; + optionElement.value = exportValue; + + if (selectChild) { + selectChild.before(optionElement); + } else { + selectElement.append(optionElement); + } + + storage.setValue(id, { + value: getValue(event, true), + items: getItems(event) + }); + }, + + items(event) { + const { + items + } = event.detail; + + while (selectElement.length !== 0) { + selectElement.remove(0); + } + + for (const item of items) { + const { + displayValue, + exportValue + } = item; + const optionElement = document.createElement("option"); + optionElement.textContent = displayValue; + optionElement.value = exportValue; + selectElement.append(optionElement); + } + + if (selectElement.options.length > 0) { + selectElement.options[0].selected = true; + } + + storage.setValue(id, { + value: getValue(event, true), + items: getItems(event) + }); + }, + + indices(event) { + const indices = new Set(event.detail.indices); + + for (const option of event.target.options) { + option.selected = indices.has(option.index); + } + + storage.setValue(id, { + value: getValue(event, true) + }); + }, + + editable(event) { + event.target.disabled = !event.detail.editable; + } + + }; + + this._dispatchEventFromSandbox(actions, jsEvent); + }); + selectElement.addEventListener("input", event => { + const exportValue = getValue(event, true); + const value = getValue(event, false); + storage.setValue(id, { + value: exportValue + }); + this.linkService.eventBus?.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + changeEx: exportValue, + willCommit: true, + commitKey: 1, + keyDown: false + } + }); + }); + + this._setEventListeners(selectElement, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"], ["input", "Action"]], event => event.target.checked); + } else { + selectElement.addEventListener("input", function (event) { + storage.setValue(id, { + value: getValue(event, true) + }); + }); + } + + if (this.data.combo) { + this._setTextStyle(selectElement); + } else {} + + this._setBackgroundColor(selectElement); + + this._setDefaultPropertiesFromJS(selectElement); + + this.container.append(selectElement); return this.container; } @@ -9772,8 +14484,10 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { class PopupAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.title || parameters.data.contents); - super(parameters, isRenderable); + const isRenderable = !!(parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable + }); } render() { @@ -9785,25 +14499,33 @@ class PopupAnnotationElement extends AnnotationElement { } const selector = `[data-annotation-id="${this.data.parentId}"]`; - const parentElement = this.layer.querySelector(selector); + const parentElements = this.layer.querySelectorAll(selector); - if (!parentElement) { + if (parentElements.length === 0) { return this.container; } const popup = new PopupElement({ container: this.container, - trigger: parentElement, + trigger: Array.from(parentElements), color: this.data.color, - title: this.data.title, + titleObj: this.data.titleObj, modificationDate: this.data.modificationDate, - contents: this.data.contents + contentsObj: this.data.contentsObj, + richText: this.data.richText }); - const parentLeft = parseFloat(parentElement.style.left); - const parentWidth = parseFloat(parentElement.style.width); - this.container.style.transformOrigin = `-${parentLeft + parentWidth}px -${parentElement.style.top}`; - this.container.style.left = `${parentLeft + parentWidth}px`; - this.container.appendChild(popup.render()); + const page = this.page; + + const rect = _util.Util.normalizeRect([this.data.parentRect[0], page.view[3] - this.data.parentRect[1] + page.view[1], this.data.parentRect[2], page.view[3] - this.data.parentRect[3] + page.view[1]]); + + const popupLeft = rect[0] + this.data.parentRect[2] - this.data.parentRect[0]; + const popupTop = rect[1]; + const [pageLLx, pageLLy, pageURx, pageURy] = this.viewport.viewBox; + const pageWidth = pageURx - pageLLx; + const pageHeight = pageURy - pageLLy; + this.container.style.left = `${100 * (popupLeft - pageLLx) / pageWidth}%`; + this.container.style.top = `${100 * (popupTop - pageLLy) / pageHeight}%`; + this.container.append(popup.render()); return this.container; } @@ -9814,9 +14536,10 @@ class PopupElement { this.container = parameters.container; this.trigger = parameters.trigger; this.color = parameters.color; - this.title = parameters.title; + this.titleObj = parameters.titleObj; this.modificationDate = parameters.modificationDate; - this.contents = parameters.contents; + this.contentsObj = parameters.contentsObj; + this.richText = parameters.richText; this.hideWrapper = parameters.hideWrapper || false; this.pinned = false; } @@ -9826,7 +14549,7 @@ class PopupElement { const wrapper = document.createElement("div"); wrapper.className = "popupWrapper"; this.hideElement = this.hideWrapper ? wrapper : this.container; - this.hideElement.setAttribute("hidden", true); + this.hideElement.hidden = true; const popup = document.createElement("div"); popup.className = "popup"; const color = this.color; @@ -9835,47 +14558,72 @@ class PopupElement { const r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0]; const g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1]; const b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2]; - popup.style.backgroundColor = _util.Util.makeCssRgb(r | 0, g | 0, b | 0); + popup.style.backgroundColor = _util.Util.makeHexColor(r | 0, g | 0, b | 0); } const title = document.createElement("h1"); - title.textContent = this.title; - popup.appendChild(title); + title.dir = this.titleObj.dir; + title.textContent = this.titleObj.str; + popup.append(title); const dateObject = _display_utils.PDFDateString.toDateObject(this.modificationDate); if (dateObject) { const modificationDate = document.createElement("span"); + modificationDate.className = "popupDate"; modificationDate.textContent = "{{date}}, {{time}}"; modificationDate.dataset.l10nId = "annotation_date_string"; modificationDate.dataset.l10nArgs = JSON.stringify({ date: dateObject.toLocaleDateString(), time: dateObject.toLocaleTimeString() }); - popup.appendChild(modificationDate); + popup.append(modificationDate); } - const contents = this._formatContents(this.contents); + if (this.richText?.str && (!this.contentsObj?.str || this.contentsObj.str === this.richText.str)) { + _xfa_layer.XfaLayer.render({ + xfaHtml: this.richText.html, + intent: "richText", + div: popup + }); + + popup.lastChild.className = "richText popupContent"; + } else { + const contents = this._formatContents(this.contentsObj); + + popup.append(contents); + } + + if (!Array.isArray(this.trigger)) { + this.trigger = [this.trigger]; + } + + for (const element of this.trigger) { + element.addEventListener("click", this._toggle.bind(this)); + element.addEventListener("mouseover", this._show.bind(this, false)); + element.addEventListener("mouseout", this._hide.bind(this, false)); + } - popup.appendChild(contents); - this.trigger.addEventListener("click", this._toggle.bind(this)); - this.trigger.addEventListener("mouseover", this._show.bind(this, false)); - this.trigger.addEventListener("mouseout", this._hide.bind(this, false)); popup.addEventListener("click", this._hide.bind(this, true)); - wrapper.appendChild(popup); + wrapper.append(popup); return wrapper; } - _formatContents(contents) { + _formatContents({ + str, + dir + }) { const p = document.createElement("p"); - const lines = contents.split(/(?:\r\n?|\n)/); + p.className = "popupContent"; + p.dir = dir; + const lines = str.split(/(?:\r\n?|\n)/); for (let i = 0, ii = lines.length; i < ii; ++i) { const line = lines[i]; - p.appendChild(document.createTextNode(line)); + p.append(document.createTextNode(line)); if (i < ii - 1) { - p.appendChild(document.createElement("br")); + p.append(document.createElement("br")); } } @@ -9895,9 +14643,9 @@ class PopupElement { this.pinned = true; } - if (this.hideElement.hasAttribute("hidden")) { - this.hideElement.removeAttribute("hidden"); - this.container.style.zIndex += 1; + if (this.hideElement.hidden) { + this.hideElement.hidden = false; + this.container.style.zIndex = parseInt(this.container.style.zIndex) + 1000; } } @@ -9906,9 +14654,9 @@ class PopupElement { this.pinned = false; } - if (!this.hideElement.hasAttribute("hidden") && !this.pinned) { - this.hideElement.setAttribute("hidden", true); - this.container.style.zIndex -= 1; + if (!this.hideElement.hidden && !this.pinned) { + this.hideElement.hidden = true; + this.container.style.zIndex = parseInt(this.container.style.zIndex) - 1000; } } @@ -9916,15 +14664,33 @@ class PopupElement { class FreeTextAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); + this.textContent = parameters.data.textContent; } render() { this.container.className = "freeTextAnnotation"; + if (this.textContent) { + const content = document.createElement("div"); + content.className = "annotationTextContent"; + content.setAttribute("role", "comment"); + + for (const line of this.textContent) { + const lineSpan = document.createElement("span"); + lineSpan.textContent = line; + content.append(lineSpan); + } + + this.container.append(content); + } + if (!this.data.hasPopup) { - this._createPopup(this.container, null, this.data); + this._createPopup(null, this.data); } return this.container; @@ -9934,16 +14700,21 @@ class FreeTextAnnotationElement extends AnnotationElement { class LineAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); } render() { this.container.className = "lineAnnotation"; const data = this.data; - const width = data.rect[2] - data.rect[0]; - const height = data.rect[3] - data.rect[1]; - const svg = this.svgFactory.create(width, height); + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); const line = this.svgFactory.createElement("svg:line"); line.setAttribute("x1", data.rect[2] - data.lineCoordinates[0]); line.setAttribute("y1", data.rect[3] - data.lineCoordinates[1]); @@ -9951,10 +14722,11 @@ class LineAnnotationElement extends AnnotationElement { line.setAttribute("y2", data.rect[3] - data.lineCoordinates[3]); line.setAttribute("stroke-width", data.borderStyle.width || 1); line.setAttribute("stroke", "transparent"); - svg.appendChild(line); + line.setAttribute("fill", "transparent"); + svg.append(line); this.container.append(svg); - this._createPopup(this.container, line, data); + this._createPopup(line, data); return this.container; } @@ -9963,16 +14735,21 @@ class LineAnnotationElement extends AnnotationElement { class SquareAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); } render() { this.container.className = "squareAnnotation"; const data = this.data; - const width = data.rect[2] - data.rect[0]; - const height = data.rect[3] - data.rect[1]; - const svg = this.svgFactory.create(width, height); + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); const borderWidth = data.borderStyle.width; const square = this.svgFactory.createElement("svg:rect"); square.setAttribute("x", borderWidth / 2); @@ -9981,11 +14758,11 @@ class SquareAnnotationElement extends AnnotationElement { square.setAttribute("height", height - borderWidth); square.setAttribute("stroke-width", borderWidth || 1); square.setAttribute("stroke", "transparent"); - square.setAttribute("fill", "none"); - svg.appendChild(square); + square.setAttribute("fill", "transparent"); + svg.append(square); this.container.append(svg); - this._createPopup(this.container, square, data); + this._createPopup(square, data); return this.container; } @@ -9994,16 +14771,21 @@ class SquareAnnotationElement extends AnnotationElement { class CircleAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); } render() { this.container.className = "circleAnnotation"; const data = this.data; - const width = data.rect[2] - data.rect[0]; - const height = data.rect[3] - data.rect[1]; - const svg = this.svgFactory.create(width, height); + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); const borderWidth = data.borderStyle.width; const circle = this.svgFactory.createElement("svg:ellipse"); circle.setAttribute("cx", width / 2); @@ -10012,11 +14794,11 @@ class CircleAnnotationElement extends AnnotationElement { circle.setAttribute("ry", height / 2 - borderWidth / 2); circle.setAttribute("stroke-width", borderWidth || 1); circle.setAttribute("stroke", "transparent"); - circle.setAttribute("fill", "none"); - svg.appendChild(circle); + circle.setAttribute("fill", "transparent"); + svg.append(circle); this.container.append(svg); - this._createPopup(this.container, circle, data); + this._createPopup(circle, data); return this.container; } @@ -10025,8 +14807,11 @@ class CircleAnnotationElement extends AnnotationElement { class PolylineAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); this.containerClassName = "polylineAnnotation"; this.svgElementName = "svg:polyline"; } @@ -10034,9 +14819,11 @@ class PolylineAnnotationElement extends AnnotationElement { render() { this.container.className = this.containerClassName; const data = this.data; - const width = data.rect[2] - data.rect[0]; - const height = data.rect[3] - data.rect[1]; - const svg = this.svgFactory.create(width, height); + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); let points = []; for (const coordinate of data.vertices) { @@ -10050,11 +14837,11 @@ class PolylineAnnotationElement extends AnnotationElement { polyline.setAttribute("points", points); polyline.setAttribute("stroke-width", data.borderStyle.width || 1); polyline.setAttribute("stroke", "transparent"); - polyline.setAttribute("fill", "none"); - svg.appendChild(polyline); + polyline.setAttribute("fill", "transparent"); + svg.append(polyline); this.container.append(svg); - this._createPopup(this.container, polyline, data); + this._createPopup(polyline, data); return this.container; } @@ -10072,15 +14859,18 @@ class PolygonAnnotationElement extends PolylineAnnotationElement { class CaretAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); } render() { this.container.className = "caretAnnotation"; if (!this.data.hasPopup) { - this._createPopup(this.container, null, this.data); + this._createPopup(null, this.data); } return this.container; @@ -10090,8 +14880,11 @@ class CaretAnnotationElement extends AnnotationElement { class InkAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); this.containerClassName = "inkAnnotation"; this.svgElementName = "svg:polyline"; } @@ -10099,9 +14892,11 @@ class InkAnnotationElement extends AnnotationElement { render() { this.container.className = this.containerClassName; const data = this.data; - const width = data.rect[2] - data.rect[0]; - const height = data.rect[3] - data.rect[1]; - const svg = this.svgFactory.create(width, height); + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); for (const inkList of data.inkLists) { let points = []; @@ -10117,11 +14912,11 @@ class InkAnnotationElement extends AnnotationElement { polyline.setAttribute("points", points); polyline.setAttribute("stroke-width", data.borderStyle.width || 1); polyline.setAttribute("stroke", "transparent"); - polyline.setAttribute("fill", "none"); + polyline.setAttribute("fill", "transparent"); - this._createPopup(this.container, polyline, data); + this._createPopup(polyline, data); - svg.appendChild(polyline); + svg.append(polyline); } this.container.append(svg); @@ -10132,17 +14927,24 @@ class InkAnnotationElement extends AnnotationElement { class HighlightAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true, + createQuadrilaterals: true + }); } render() { - this.container.className = "highlightAnnotation"; - if (!this.data.hasPopup) { - this._createPopup(this.container, null, this.data); + this._createPopup(null, this.data); } + if (this.quadrilaterals) { + return this._renderQuadrilaterals("highlightAnnotation"); + } + + this.container.className = "highlightAnnotation"; return this.container; } @@ -10150,17 +14952,24 @@ class HighlightAnnotationElement extends AnnotationElement { class UnderlineAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true, + createQuadrilaterals: true + }); } render() { - this.container.className = "underlineAnnotation"; - if (!this.data.hasPopup) { - this._createPopup(this.container, null, this.data); + this._createPopup(null, this.data); } + if (this.quadrilaterals) { + return this._renderQuadrilaterals("underlineAnnotation"); + } + + this.container.className = "underlineAnnotation"; return this.container; } @@ -10168,17 +14977,24 @@ class UnderlineAnnotationElement extends AnnotationElement { class SquigglyAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true, + createQuadrilaterals: true + }); } render() { - this.container.className = "squigglyAnnotation"; - if (!this.data.hasPopup) { - this._createPopup(this.container, null, this.data); + this._createPopup(null, this.data); } + if (this.quadrilaterals) { + return this._renderQuadrilaterals("squigglyAnnotation"); + } + + this.container.className = "squigglyAnnotation"; return this.container; } @@ -10186,17 +15002,24 @@ class SquigglyAnnotationElement extends AnnotationElement { class StrikeOutAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true, + createQuadrilaterals: true + }); } render() { - this.container.className = "strikeoutAnnotation"; - if (!this.data.hasPopup) { - this._createPopup(this.container, null, this.data); + this._createPopup(null, this.data); } + if (this.quadrilaterals) { + return this._renderQuadrilaterals("strikeoutAnnotation"); + } + + this.container.className = "strikeoutAnnotation"; return this.container; } @@ -10204,15 +15027,18 @@ class StrikeOutAnnotationElement extends AnnotationElement { class StampAnnotationElement extends AnnotationElement { constructor(parameters) { - const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); - super(parameters, isRenderable, true); + const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); } render() { this.container.className = "stampAnnotation"; if (!this.data.hasPopup) { - this._createPopup(this.container, null, this.data); + this._createPopup(null, this.data); } return this.container; @@ -10222,102 +15048,171 @@ class StampAnnotationElement extends AnnotationElement { class FileAttachmentAnnotationElement extends AnnotationElement { constructor(parameters) { - super(parameters, true); + super(parameters, { + isRenderable: true + }); const { filename, content } = this.data.file; this.filename = (0, _display_utils.getFilenameFromUrl)(filename); this.content = content; - - if (this.linkService.eventBus) { - this.linkService.eventBus.dispatch("fileattachmentannotation", { - source: this, - id: (0, _util.stringToPDFString)(filename), - filename, - content - }); - } + this.linkService.eventBus?.dispatch("fileattachmentannotation", { + source: this, + filename, + content + }); } render() { this.container.className = "fileAttachmentAnnotation"; const trigger = document.createElement("div"); - trigger.style.height = this.container.style.height; - trigger.style.width = this.container.style.width; + trigger.className = "popupTriggerArea"; trigger.addEventListener("dblclick", this._download.bind(this)); - if (!this.data.hasPopup && (this.data.title || this.data.contents)) { - this._createPopup(this.container, trigger, this.data); + if (!this.data.hasPopup && (this.data.titleObj?.str || this.data.contentsObj?.str || this.data.richText)) { + this._createPopup(trigger, this.data); } - this.container.appendChild(trigger); + this.container.append(trigger); return this.container; } _download() { - if (!this.downloadManager) { - (0, _util.warn)("Download cannot be started due to unavailable download manager"); - return; - } - - this.downloadManager.downloadData(this.content, this.filename, ""); + this.downloadManager?.openOrDownloadData(this.container, this.content, this.filename); } } class AnnotationLayer { + static #appendElement(element, id, div, accessibilityManager) { + const contentElement = element.firstChild || element; + contentElement.id = `${_display_utils.AnnotationPrefix}${id}`; + div.append(element); + accessibilityManager?.moveElementInDOM(div, element, contentElement, false); + } + static render(parameters) { - const sortedAnnotations = [], - popupAnnotations = []; + const { + annotations, + div, + viewport, + accessibilityManager + } = parameters; + this.#setDimensions(div, viewport); + let zIndex = 0; - for (const data of parameters.annotations) { - if (!data) { - continue; + for (const data of annotations) { + if (data.annotationType !== _util.AnnotationType.POPUP) { + const { + width, + height + } = getRectDims(data.rect); + + if (width <= 0 || height <= 0) { + continue; + } } - if (data.annotationType === _util.AnnotationType.POPUP) { - popupAnnotations.push(data); - continue; - } - - sortedAnnotations.push(data); - } - - if (popupAnnotations.length) { - sortedAnnotations.push(...popupAnnotations); - } - - for (const data of sortedAnnotations) { const element = AnnotationElementFactory.create({ data, - layer: parameters.div, + layer: div, page: parameters.page, - viewport: parameters.viewport, + viewport, linkService: parameters.linkService, downloadManager: parameters.downloadManager, imageResourcesPath: parameters.imageResourcesPath || "", - renderInteractiveForms: typeof parameters.renderInteractiveForms === "boolean" ? parameters.renderInteractiveForms : true, + renderForms: parameters.renderForms !== false, svgFactory: new _display_utils.DOMSVGFactory(), - annotationStorage: parameters.annotationStorage || new _annotation_storage.AnnotationStorage() + annotationStorage: parameters.annotationStorage || new _annotation_storage.AnnotationStorage(), + enableScripting: parameters.enableScripting, + hasJSActions: parameters.hasJSActions, + fieldObjects: parameters.fieldObjects, + mouseState: parameters.mouseState || { + isDown: false + } }); if (element.isRenderable) { - parameters.div.appendChild(element.render()); + const rendered = element.render(); + + if (data.hidden) { + rendered.style.visibility = "hidden"; + } + + if (Array.isArray(rendered)) { + for (const renderedElement of rendered) { + renderedElement.style.zIndex = zIndex++; + AnnotationLayer.#appendElement(renderedElement, data.id, div, accessibilityManager); + } + } else { + rendered.style.zIndex = zIndex++; + + if (element instanceof PopupAnnotationElement) { + div.prepend(rendered); + } else { + AnnotationLayer.#appendElement(rendered, data.id, div, accessibilityManager); + } + } } } + + this.#setAnnotationCanvasMap(div, parameters.annotationCanvasMap); } static update(parameters) { - for (const data of parameters.annotations) { - const element = parameters.div.querySelector(`[data-annotation-id="${data.id}"]`); + const { + annotationCanvasMap, + div, + viewport + } = parameters; + this.#setDimensions(div, viewport); + this.#setAnnotationCanvasMap(div, annotationCanvasMap); + div.hidden = false; + } - if (element) { - element.style.transform = `matrix(${parameters.viewport.transform.join(",")})`; + static #setDimensions(div, { + width, + height, + rotation + }) { + const { + style + } = div; + const flipOrientation = rotation % 180 !== 0, + widthStr = Math.floor(width) + "px", + heightStr = Math.floor(height) + "px"; + style.width = flipOrientation ? heightStr : widthStr; + style.height = flipOrientation ? widthStr : heightStr; + div.setAttribute("data-main-rotation", rotation); + } + + static #setAnnotationCanvasMap(div, annotationCanvasMap) { + if (!annotationCanvasMap) { + return; + } + + for (const [id, canvas] of annotationCanvasMap) { + const element = div.querySelector(`[data-annotation-id="${id}"]`); + + if (!element) { + continue; + } + + const { + firstChild + } = element; + + if (!firstChild) { + element.append(canvas); + } else if (firstChild.nodeName === "CANVAS") { + firstChild.replaceWith(canvas); + } else { + firstChild.before(canvas); } } - parameters.div.removeAttribute("hidden"); + annotationCanvasMap.clear(); } } @@ -10325,442 +15220,833 @@ class AnnotationLayer { exports.AnnotationLayer = AnnotationLayer; /***/ }), -/* 20 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 28 */ +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.renderTextLayer = void 0; +})); +exports.ColorConverters = void 0; -var _util = __w_pdfjs_require__(2); +function makeColorComp(n) { + return Math.floor(Math.max(0, Math.min(1, n)) * 255).toString(16).padStart(2, "0"); +} -var renderTextLayer = function renderTextLayerClosure() { - var MAX_TEXT_DIVS_TO_RENDER = 100000; - var NonWhitespaceRegexp = /\S/; - - function isAllWhitespace(str) { - return !NonWhitespaceRegexp.test(str); +class ColorConverters { + static CMYK_G([c, y, m, k]) { + return ["G", 1 - Math.min(1, 0.3 * c + 0.59 * m + 0.11 * y + k)]; } - function appendText(task, geom, styles) { - var textDiv = document.createElement("span"); - var textDivProperties = { - angle: 0, - canvasWidth: 0, - isWhitespace: false, - originalTransform: null, - paddingBottom: 0, - paddingLeft: 0, - paddingRight: 0, - paddingTop: 0, - scale: 1 - }; + static G_CMYK([g]) { + return ["CMYK", 0, 0, 0, 1 - g]; + } - task._textDivs.push(textDiv); + static G_RGB([g]) { + return ["RGB", g, g, g]; + } - if (isAllWhitespace(geom.str)) { - textDivProperties.isWhitespace = true; + static G_HTML([g]) { + const G = makeColorComp(g); + return `#${G}${G}${G}`; + } - task._textDivProperties.set(textDiv, textDivProperties); + static RGB_G([r, g, b]) { + return ["G", 0.3 * r + 0.59 * g + 0.11 * b]; + } - return; - } + static RGB_HTML([r, g, b]) { + const R = makeColorComp(r); + const G = makeColorComp(g); + const B = makeColorComp(b); + return `#${R}${G}${B}`; + } - var tx = _util.Util.transform(task._viewport.transform, geom.transform); + static T_HTML() { + return "#00000000"; + } - var angle = Math.atan2(tx[1], tx[0]); - var style = styles[geom.fontName]; + static CMYK_RGB([c, y, m, k]) { + return ["RGB", 1 - Math.min(1, c + k), 1 - Math.min(1, m + k), 1 - Math.min(1, y + k)]; + } - if (style.vertical) { - angle += Math.PI / 2; - } + static CMYK_HTML(components) { + const rgb = this.CMYK_RGB(components).slice(1); + return this.RGB_HTML(rgb); + } - var fontHeight = Math.sqrt(tx[2] * tx[2] + tx[3] * tx[3]); - var fontAscent = fontHeight; + static RGB_CMYK([r, g, b]) { + const c = 1 - r; + const m = 1 - g; + const y = 1 - b; + const k = Math.min(c, m, y); + return ["CMYK", c, m, y, k]; + } - if (style.ascent) { - fontAscent = style.ascent * fontAscent; - } else if (style.descent) { - fontAscent = (1 + style.descent) * fontAscent; - } +} - let left, top; +exports.ColorConverters = ColorConverters; - if (angle === 0) { - left = tx[4]; - top = tx[5] - fontAscent; - } else { - left = tx[4] + fontAscent * Math.sin(angle); - top = tx[5] - fontAscent * Math.cos(angle); - } +/***/ }), +/* 29 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { - textDiv.style.left = `${left}px`; - textDiv.style.top = `${top}px`; - textDiv.style.fontSize = `${fontHeight}px`; - textDiv.style.fontFamily = style.fontFamily; - textDiv.textContent = geom.str; - if (task._fontInspectorEnabled) { - textDiv.dataset.fontName = geom.fontName; - } - if (angle !== 0) { - textDivProperties.angle = angle * (180 / Math.PI); - } +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XfaLayer = void 0; - let shouldScaleText = false; +var _xfa_text = __w_pdfjs_require__(20); - if (geom.str.length > 1) { - shouldScaleText = true; - } else if (geom.transform[0] !== geom.transform[3]) { - const absScaleX = Math.abs(geom.transform[0]), - absScaleY = Math.abs(geom.transform[3]); +class XfaLayer { + static setupStorage(html, id, element, storage, intent) { + const storedData = storage.getValue(id, { + value: null + }); - if (absScaleX !== absScaleY && Math.max(absScaleX, absScaleY) / Math.min(absScaleX, absScaleY) > 1.5) { - shouldScaleText = true; - } - } + switch (element.name) { + case "textarea": + if (storedData.value !== null) { + html.textContent = storedData.value; + } - if (shouldScaleText) { - if (style.vertical) { - textDivProperties.canvasWidth = geom.height * task._viewport.scale; - } else { - textDivProperties.canvasWidth = geom.width * task._viewport.scale; - } - } + if (intent === "print") { + break; + } - task._textDivProperties.set(textDiv, textDivProperties); + html.addEventListener("input", event => { + storage.setValue(id, { + value: event.target.value + }); + }); + break; - if (task._textContentStream) { - task._layoutText(textDiv); - } + case "input": + if (element.attributes.type === "radio" || element.attributes.type === "checkbox") { + if (storedData.value === element.attributes.xfaOn) { + html.setAttribute("checked", true); + } else if (storedData.value === element.attributes.xfaOff) { + html.removeAttribute("checked"); + } - if (task._enhanceTextSelection) { - var angleCos = 1, - angleSin = 0; + if (intent === "print") { + break; + } - if (angle !== 0) { - angleCos = Math.cos(angle); - angleSin = Math.sin(angle); - } + html.addEventListener("change", event => { + storage.setValue(id, { + value: event.target.checked ? event.target.getAttribute("xfaOn") : event.target.getAttribute("xfaOff") + }); + }); + } else { + if (storedData.value !== null) { + html.setAttribute("value", storedData.value); + } - var divWidth = (style.vertical ? geom.height : geom.width) * task._viewport.scale; - var divHeight = fontHeight; - var m, b; + if (intent === "print") { + break; + } - if (angle !== 0) { - m = [angleCos, angleSin, -angleSin, angleCos, left, top]; - b = _util.Util.getAxialAlignedBoundingBox([0, 0, divWidth, divHeight], m); - } else { - b = [left, top, left + divWidth, top + divHeight]; - } + html.addEventListener("input", event => { + storage.setValue(id, { + value: event.target.value + }); + }); + } - task._bounds.push({ - left: b[0], - top: b[1], - right: b[2], - bottom: b[3], - div: textDiv, - size: [divWidth, divHeight], - m - }); + break; + + case "select": + if (storedData.value !== null) { + for (const option of element.children) { + if (option.attributes.value === storedData.value) { + option.attributes.selected = true; + } + } + } + + html.addEventListener("input", event => { + const options = event.target.options; + const value = options.selectedIndex === -1 ? "" : options[options.selectedIndex].value; + storage.setValue(id, { + value + }); + }); + break; } } - function render(task) { - if (task._canceled) { - return; + static setAttributes({ + html, + element, + storage = null, + intent, + linkService + }) { + const { + attributes + } = element; + const isHTMLAnchorElement = html instanceof HTMLAnchorElement; + + if (attributes.type === "radio") { + attributes.name = `${attributes.name}-${intent}`; } - var textDivs = task._textDivs; - var capability = task._capability; - var textDivsLength = textDivs.length; - - if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) { - task._renderingDone = true; - capability.resolve(); - return; - } - - if (!task._textContentStream) { - for (var i = 0; i < textDivsLength; i++) { - task._layoutText(textDivs[i]); - } - } - - task._renderingDone = true; - capability.resolve(); - } - - function findPositiveMin(ts, offset, count) { - let result = 0; - - for (let i = 0; i < count; i++) { - const t = ts[offset++]; - - if (t > 0) { - result = result ? Math.min(t, result) : t; - } - } - - return result; - } - - function expand(task) { - var bounds = task._bounds; - var viewport = task._viewport; - var expanded = expandBounds(viewport.width, viewport.height, bounds); - - for (var i = 0; i < expanded.length; i++) { - var div = bounds[i].div; - - var divProperties = task._textDivProperties.get(div); - - if (divProperties.angle === 0) { - divProperties.paddingLeft = bounds[i].left - expanded[i].left; - divProperties.paddingTop = bounds[i].top - expanded[i].top; - divProperties.paddingRight = expanded[i].right - bounds[i].right; - divProperties.paddingBottom = expanded[i].bottom - bounds[i].bottom; - - task._textDivProperties.set(div, divProperties); - + for (const [key, value] of Object.entries(attributes)) { + if (value === null || value === undefined) { continue; } - var e = expanded[i], - b = bounds[i]; - var m = b.m, - c = m[0], - s = m[1]; - var points = [[0, 0], [0, b.size[1]], [b.size[0], 0], b.size]; - var ts = new Float64Array(64); - points.forEach(function (p, j) { - var t = _util.Util.applyTransform(p, m); + switch (key) { + case "class": + if (value.length) { + html.setAttribute(key, value.join(" ")); + } - ts[j + 0] = c && (e.left - t[0]) / c; - ts[j + 4] = s && (e.top - t[1]) / s; - ts[j + 8] = c && (e.right - t[0]) / c; - ts[j + 12] = s && (e.bottom - t[1]) / s; - ts[j + 16] = s && (e.left - t[0]) / -s; - ts[j + 20] = c && (e.top - t[1]) / c; - ts[j + 24] = s && (e.right - t[0]) / -s; - ts[j + 28] = c && (e.bottom - t[1]) / c; - ts[j + 32] = c && (e.left - t[0]) / -c; - ts[j + 36] = s && (e.top - t[1]) / -s; - ts[j + 40] = c && (e.right - t[0]) / -c; - ts[j + 44] = s && (e.bottom - t[1]) / -s; - ts[j + 48] = s && (e.left - t[0]) / s; - ts[j + 52] = c && (e.top - t[1]) / -c; - ts[j + 56] = s && (e.right - t[0]) / s; - ts[j + 60] = c && (e.bottom - t[1]) / -c; - }); - var boxScale = 1 + Math.min(Math.abs(c), Math.abs(s)); - divProperties.paddingLeft = findPositiveMin(ts, 32, 16) / boxScale; - divProperties.paddingTop = findPositiveMin(ts, 48, 16) / boxScale; - divProperties.paddingRight = findPositiveMin(ts, 0, 16) / boxScale; - divProperties.paddingBottom = findPositiveMin(ts, 16, 16) / boxScale; + break; - task._textDivProperties.set(div, divProperties); + case "dataId": + break; + + case "id": + html.setAttribute("data-element-id", value); + break; + + case "style": + Object.assign(html.style, value); + break; + + case "textContent": + html.textContent = value; + break; + + default: + if (!isHTMLAnchorElement || key !== "href" && key !== "newWindow") { + html.setAttribute(key, value); + } + + } + } + + if (isHTMLAnchorElement) { + linkService.addLinkAttributes(html, attributes.href, attributes.newWindow); + } + + if (storage && attributes.dataId) { + this.setupStorage(html, attributes.dataId, element, storage); } } - function expandBounds(width, height, boxes) { - var bounds = boxes.map(function (box, i) { - return { - x1: box.left, - y1: box.top, - x2: box.right, - y2: box.bottom, - index: i, - x1New: undefined, - x2New: undefined - }; - }); - expandBoundsLTR(width, bounds); - var expanded = new Array(boxes.length); - bounds.forEach(function (b) { - var i = b.index; - expanded[i] = { - left: b.x1New, - top: 0, - right: b.x2New, - bottom: 0 - }; - }); - boxes.map(function (box, i) { - var e = expanded[i], - b = bounds[i]; - b.x1 = box.top; - b.y1 = width - e.right; - b.x2 = box.bottom; - b.y2 = width - e.left; - b.index = i; - b.x1New = undefined; - b.x2New = undefined; - }); - expandBoundsLTR(height, bounds); - bounds.forEach(function (b) { - var i = b.index; - expanded[i].top = b.x1New; - expanded[i].bottom = b.x2New; - }); - return expanded; + static render(parameters) { + const storage = parameters.annotationStorage; + const linkService = parameters.linkService; + const root = parameters.xfaHtml; + const intent = parameters.intent || "display"; + const rootHtml = document.createElement(root.name); + + if (root.attributes) { + this.setAttributes({ + html: rootHtml, + element: root, + intent, + linkService + }); + } + + const stack = [[root, -1, rootHtml]]; + const rootDiv = parameters.div; + rootDiv.append(rootHtml); + + if (parameters.viewport) { + const transform = `matrix(${parameters.viewport.transform.join(",")})`; + rootDiv.style.transform = transform; + } + + if (intent !== "richText") { + rootDiv.setAttribute("class", "xfaLayer xfaFont"); + } + + const textDivs = []; + + while (stack.length > 0) { + const [parent, i, html] = stack.at(-1); + + if (i + 1 === parent.children.length) { + stack.pop(); + continue; + } + + const child = parent.children[++stack.at(-1)[1]]; + + if (child === null) { + continue; + } + + const { + name + } = child; + + if (name === "#text") { + const node = document.createTextNode(child.value); + textDivs.push(node); + html.append(node); + continue; + } + + let childHtml; + + if (child?.attributes?.xmlns) { + childHtml = document.createElementNS(child.attributes.xmlns, name); + } else { + childHtml = document.createElement(name); + } + + html.append(childHtml); + + if (child.attributes) { + this.setAttributes({ + html: childHtml, + element: child, + storage, + intent, + linkService + }); + } + + if (child.children && child.children.length > 0) { + stack.push([child, -1, childHtml]); + } else if (child.value) { + const node = document.createTextNode(child.value); + + if (_xfa_text.XfaText.shouldBuildText(name)) { + textDivs.push(node); + } + + childHtml.append(node); + } + } + + for (const el of rootDiv.querySelectorAll(".xfaNonInteractive input, .xfaNonInteractive textarea")) { + el.setAttribute("readOnly", true); + } + + return { + textDivs + }; } - function expandBoundsLTR(width, bounds) { - bounds.sort(function (a, b) { - return a.x1 - b.x1 || a.index - b.index; + static update(parameters) { + const transform = `matrix(${parameters.viewport.transform.join(",")})`; + parameters.div.style.transform = transform; + parameters.div.hidden = false; + } + +} + +exports.XfaLayer = XfaLayer; + +/***/ }), +/* 30 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TextLayerRenderTask = void 0; +exports.renderTextLayer = renderTextLayer; + +var _util = __w_pdfjs_require__(1); + +var _display_utils = __w_pdfjs_require__(8); + +const MAX_TEXT_DIVS_TO_RENDER = 100000; +const DEFAULT_FONT_SIZE = 30; +const DEFAULT_FONT_ASCENT = 0.8; +const ascentCache = new Map(); +const AllWhitespaceRegexp = /^\s+$/g; + +function getAscent(fontFamily, ctx) { + const cachedAscent = ascentCache.get(fontFamily); + + if (cachedAscent) { + return cachedAscent; + } + + ctx.save(); + ctx.font = `${DEFAULT_FONT_SIZE}px ${fontFamily}`; + const metrics = ctx.measureText(""); + let ascent = metrics.fontBoundingBoxAscent; + let descent = Math.abs(metrics.fontBoundingBoxDescent); + + if (ascent) { + ctx.restore(); + const ratio = ascent / (ascent + descent); + ascentCache.set(fontFamily, ratio); + return ratio; + } + + ctx.strokeStyle = "red"; + ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE); + ctx.strokeText("g", 0, 0); + let pixels = ctx.getImageData(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE).data; + descent = 0; + + for (let i = pixels.length - 1 - 3; i >= 0; i -= 4) { + if (pixels[i] > 0) { + descent = Math.ceil(i / 4 / DEFAULT_FONT_SIZE); + break; + } + } + + ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE); + ctx.strokeText("A", 0, DEFAULT_FONT_SIZE); + pixels = ctx.getImageData(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE).data; + ascent = 0; + + for (let i = 0, ii = pixels.length; i < ii; i += 4) { + if (pixels[i] > 0) { + ascent = DEFAULT_FONT_SIZE - Math.floor(i / 4 / DEFAULT_FONT_SIZE); + break; + } + } + + ctx.restore(); + + if (ascent) { + const ratio = ascent / (ascent + descent); + ascentCache.set(fontFamily, ratio); + return ratio; + } + + ascentCache.set(fontFamily, DEFAULT_FONT_ASCENT); + return DEFAULT_FONT_ASCENT; +} + +function appendText(task, geom, styles, ctx) { + const textDiv = document.createElement("span"); + const textDivProperties = task._enhanceTextSelection ? { + angle: 0, + canvasWidth: 0, + hasText: geom.str !== "", + hasEOL: geom.hasEOL, + originalTransform: null, + paddingBottom: 0, + paddingLeft: 0, + paddingRight: 0, + paddingTop: 0, + scale: 1, + fontSize: 0 + } : { + angle: 0, + canvasWidth: 0, + hasText: geom.str !== "", + hasEOL: geom.hasEOL, + fontSize: 0 + }; + + task._textDivs.push(textDiv); + + const tx = _util.Util.transform(task._viewport.transform, geom.transform); + + let angle = Math.atan2(tx[1], tx[0]); + const style = styles[geom.fontName]; + + if (style.vertical) { + angle += Math.PI / 2; + } + + const fontHeight = Math.hypot(tx[2], tx[3]); + const fontAscent = fontHeight * getAscent(style.fontFamily, ctx); + let left, top; + + if (angle === 0) { + left = tx[4]; + top = tx[5] - fontAscent; + } else { + left = tx[4] + fontAscent * Math.sin(angle); + top = tx[5] - fontAscent * Math.cos(angle); + } + + textDiv.style.left = `${left}px`; + textDiv.style.top = `${top}px`; + textDiv.style.fontSize = `${fontHeight}px`; + textDiv.style.fontFamily = style.fontFamily; + textDivProperties.fontSize = fontHeight; + textDiv.setAttribute("role", "presentation"); + textDiv.textContent = geom.str; + textDiv.dir = geom.dir; + + if (task._fontInspectorEnabled) { + textDiv.dataset.fontName = geom.fontName; + } + + if (angle !== 0) { + textDivProperties.angle = angle * (180 / Math.PI); + } + + let shouldScaleText = false; + + if (geom.str.length > 1 || task._enhanceTextSelection && AllWhitespaceRegexp.test(geom.str)) { + shouldScaleText = true; + } else if (geom.str !== " " && geom.transform[0] !== geom.transform[3]) { + const absScaleX = Math.abs(geom.transform[0]), + absScaleY = Math.abs(geom.transform[3]); + + if (absScaleX !== absScaleY && Math.max(absScaleX, absScaleY) / Math.min(absScaleX, absScaleY) > 1.5) { + shouldScaleText = true; + } + } + + if (shouldScaleText) { + if (style.vertical) { + textDivProperties.canvasWidth = geom.height * task._viewport.scale; + } else { + textDivProperties.canvasWidth = geom.width * task._viewport.scale; + } + } + + task._textDivProperties.set(textDiv, textDivProperties); + + if (task._textContentStream) { + task._layoutText(textDiv); + } + + if (task._enhanceTextSelection && textDivProperties.hasText) { + let angleCos = 1, + angleSin = 0; + + if (angle !== 0) { + angleCos = Math.cos(angle); + angleSin = Math.sin(angle); + } + + const divWidth = (style.vertical ? geom.height : geom.width) * task._viewport.scale; + const divHeight = fontHeight; + let m, b; + + if (angle !== 0) { + m = [angleCos, angleSin, -angleSin, angleCos, left, top]; + b = _util.Util.getAxialAlignedBoundingBox([0, 0, divWidth, divHeight], m); + } else { + b = [left, top, left + divWidth, top + divHeight]; + } + + task._bounds.push({ + left: b[0], + top: b[1], + right: b[2], + bottom: b[3], + div: textDiv, + size: [divWidth, divHeight], + m }); - var fakeBoundary = { - x1: -Infinity, - y1: -Infinity, - x2: 0, - y2: Infinity, - index: -1, - x1New: 0, - x2New: 0 + } +} + +function render(task) { + if (task._canceled) { + return; + } + + const textDivs = task._textDivs; + const capability = task._capability; + const textDivsLength = textDivs.length; + + if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) { + task._renderingDone = true; + capability.resolve(); + return; + } + + if (!task._textContentStream) { + for (let i = 0; i < textDivsLength; i++) { + task._layoutText(textDivs[i]); + } + } + + task._renderingDone = true; + capability.resolve(); +} + +function findPositiveMin(ts, offset, count) { + let result = 0; + + for (let i = 0; i < count; i++) { + const t = ts[offset++]; + + if (t > 0) { + result = result ? Math.min(t, result) : t; + } + } + + return result; +} + +function expand(task) { + const bounds = task._bounds; + const viewport = task._viewport; + const expanded = expandBounds(viewport.width, viewport.height, bounds); + + for (let i = 0; i < expanded.length; i++) { + const div = bounds[i].div; + + const divProperties = task._textDivProperties.get(div); + + if (divProperties.angle === 0) { + divProperties.paddingLeft = bounds[i].left - expanded[i].left; + divProperties.paddingTop = bounds[i].top - expanded[i].top; + divProperties.paddingRight = expanded[i].right - bounds[i].right; + divProperties.paddingBottom = expanded[i].bottom - bounds[i].bottom; + + task._textDivProperties.set(div, divProperties); + + continue; + } + + const e = expanded[i], + b = bounds[i]; + const m = b.m, + c = m[0], + s = m[1]; + const points = [[0, 0], [0, b.size[1]], [b.size[0], 0], b.size]; + const ts = new Float64Array(64); + + for (let j = 0, jj = points.length; j < jj; j++) { + const t = _util.Util.applyTransform(points[j], m); + + ts[j + 0] = c && (e.left - t[0]) / c; + ts[j + 4] = s && (e.top - t[1]) / s; + ts[j + 8] = c && (e.right - t[0]) / c; + ts[j + 12] = s && (e.bottom - t[1]) / s; + ts[j + 16] = s && (e.left - t[0]) / -s; + ts[j + 20] = c && (e.top - t[1]) / c; + ts[j + 24] = s && (e.right - t[0]) / -s; + ts[j + 28] = c && (e.bottom - t[1]) / c; + ts[j + 32] = c && (e.left - t[0]) / -c; + ts[j + 36] = s && (e.top - t[1]) / -s; + ts[j + 40] = c && (e.right - t[0]) / -c; + ts[j + 44] = s && (e.bottom - t[1]) / -s; + ts[j + 48] = s && (e.left - t[0]) / s; + ts[j + 52] = c && (e.top - t[1]) / -c; + ts[j + 56] = s && (e.right - t[0]) / s; + ts[j + 60] = c && (e.bottom - t[1]) / -c; + } + + const boxScale = 1 + Math.min(Math.abs(c), Math.abs(s)); + divProperties.paddingLeft = findPositiveMin(ts, 32, 16) / boxScale; + divProperties.paddingTop = findPositiveMin(ts, 48, 16) / boxScale; + divProperties.paddingRight = findPositiveMin(ts, 0, 16) / boxScale; + divProperties.paddingBottom = findPositiveMin(ts, 16, 16) / boxScale; + + task._textDivProperties.set(div, divProperties); + } +} + +function expandBounds(width, height, boxes) { + const bounds = boxes.map(function (box, i) { + return { + x1: box.left, + y1: box.top, + x2: box.right, + y2: box.bottom, + index: i, + x1New: undefined, + x2New: undefined }; - var horizon = [{ - start: -Infinity, - end: Infinity, - boundary: fakeBoundary - }]; - bounds.forEach(function (boundary) { - var i = 0; + }); + expandBoundsLTR(width, bounds); + const expanded = new Array(boxes.length); - while (i < horizon.length && horizon[i].end <= boundary.y1) { - i++; + for (const b of bounds) { + const i = b.index; + expanded[i] = { + left: b.x1New, + top: 0, + right: b.x2New, + bottom: 0 + }; + } + + boxes.map(function (box, i) { + const e = expanded[i], + b = bounds[i]; + b.x1 = box.top; + b.y1 = width - e.right; + b.x2 = box.bottom; + b.y2 = width - e.left; + b.index = i; + b.x1New = undefined; + b.x2New = undefined; + }); + expandBoundsLTR(height, bounds); + + for (const b of bounds) { + const i = b.index; + expanded[i].top = b.x1New; + expanded[i].bottom = b.x2New; + } + + return expanded; +} + +function expandBoundsLTR(width, bounds) { + bounds.sort(function (a, b) { + return a.x1 - b.x1 || a.index - b.index; + }); + const fakeBoundary = { + x1: -Infinity, + y1: -Infinity, + x2: 0, + y2: Infinity, + index: -1, + x1New: 0, + x2New: 0 + }; + const horizon = [{ + start: -Infinity, + end: Infinity, + boundary: fakeBoundary + }]; + + for (const boundary of bounds) { + let i = 0; + + while (i < horizon.length && horizon[i].end <= boundary.y1) { + i++; + } + + let j = horizon.length - 1; + + while (j >= 0 && horizon[j].start >= boundary.y2) { + j--; + } + + let horizonPart, affectedBoundary; + let q, + k, + maxXNew = -Infinity; + + for (q = i; q <= j; q++) { + horizonPart = horizon[q]; + affectedBoundary = horizonPart.boundary; + let xNew; + + if (affectedBoundary.x2 > boundary.x1) { + xNew = affectedBoundary.index > boundary.index ? affectedBoundary.x1New : boundary.x1; + } else if (affectedBoundary.x2New === undefined) { + xNew = (affectedBoundary.x2 + boundary.x1) / 2; + } else { + xNew = affectedBoundary.x2New; } - var j = horizon.length - 1; - - while (j >= 0 && horizon[j].start >= boundary.y2) { - j--; + if (xNew > maxXNew) { + maxXNew = xNew; } + } - var horizonPart, affectedBoundary; - var q, - k, - maxXNew = -Infinity; + boundary.x1New = maxXNew; - for (q = i; q <= j; q++) { - horizonPart = horizon[q]; - affectedBoundary = horizonPart.boundary; - var xNew; - - if (affectedBoundary.x2 > boundary.x1) { - xNew = affectedBoundary.index > boundary.index ? affectedBoundary.x1New : boundary.x1; - } else if (affectedBoundary.x2New === undefined) { - xNew = (affectedBoundary.x2 + boundary.x1) / 2; - } else { - xNew = affectedBoundary.x2New; - } - - if (xNew > maxXNew) { - maxXNew = xNew; - } - } - - boundary.x1New = maxXNew; - - for (q = i; q <= j; q++) { - horizonPart = horizon[q]; - affectedBoundary = horizonPart.boundary; - - if (affectedBoundary.x2New === undefined) { - if (affectedBoundary.x2 > boundary.x1) { - if (affectedBoundary.index > boundary.index) { - affectedBoundary.x2New = affectedBoundary.x2; - } - } else { - affectedBoundary.x2New = maxXNew; - } - } else if (affectedBoundary.x2New > maxXNew) { - affectedBoundary.x2New = Math.max(maxXNew, affectedBoundary.x2); - } - } - - var changedHorizon = [], - lastBoundary = null; - - for (q = i; q <= j; q++) { - horizonPart = horizon[q]; - affectedBoundary = horizonPart.boundary; - var useBoundary = affectedBoundary.x2 > boundary.x2 ? affectedBoundary : boundary; - - if (lastBoundary === useBoundary) { - changedHorizon[changedHorizon.length - 1].end = horizonPart.end; - } else { - changedHorizon.push({ - start: horizonPart.start, - end: horizonPart.end, - boundary: useBoundary - }); - lastBoundary = useBoundary; - } - } - - if (horizon[i].start < boundary.y1) { - changedHorizon[0].start = boundary.y1; - changedHorizon.unshift({ - start: horizon[i].start, - end: boundary.y1, - boundary: horizon[i].boundary - }); - } - - if (boundary.y2 < horizon[j].end) { - changedHorizon[changedHorizon.length - 1].end = boundary.y2; - changedHorizon.push({ - start: boundary.y2, - end: horizon[j].end, - boundary: horizon[j].boundary - }); - } - - for (q = i; q <= j; q++) { - horizonPart = horizon[q]; - affectedBoundary = horizonPart.boundary; - - if (affectedBoundary.x2New !== undefined) { - continue; - } - - var used = false; - - for (k = i - 1; !used && k >= 0 && horizon[k].start >= affectedBoundary.y1; k--) { - used = horizon[k].boundary === affectedBoundary; - } - - for (k = j + 1; !used && k < horizon.length && horizon[k].end <= affectedBoundary.y2; k++) { - used = horizon[k].boundary === affectedBoundary; - } - - for (k = 0; !used && k < changedHorizon.length; k++) { - used = changedHorizon[k].boundary === affectedBoundary; - } - - if (!used) { - affectedBoundary.x2New = maxXNew; - } - } - - Array.prototype.splice.apply(horizon, [i, j - i + 1].concat(changedHorizon)); - }); - horizon.forEach(function (horizonPart) { - var affectedBoundary = horizonPart.boundary; + for (q = i; q <= j; q++) { + horizonPart = horizon[q]; + affectedBoundary = horizonPart.boundary; if (affectedBoundary.x2New === undefined) { - affectedBoundary.x2New = Math.max(width, affectedBoundary.x2); + if (affectedBoundary.x2 > boundary.x1) { + if (affectedBoundary.index > boundary.index) { + affectedBoundary.x2New = affectedBoundary.x2; + } + } else { + affectedBoundary.x2New = maxXNew; + } + } else if (affectedBoundary.x2New > maxXNew) { + affectedBoundary.x2New = Math.max(maxXNew, affectedBoundary.x2); } - }); + } + + const changedHorizon = []; + let lastBoundary = null; + + for (q = i; q <= j; q++) { + horizonPart = horizon[q]; + affectedBoundary = horizonPart.boundary; + const useBoundary = affectedBoundary.x2 > boundary.x2 ? affectedBoundary : boundary; + + if (lastBoundary === useBoundary) { + changedHorizon.at(-1).end = horizonPart.end; + } else { + changedHorizon.push({ + start: horizonPart.start, + end: horizonPart.end, + boundary: useBoundary + }); + lastBoundary = useBoundary; + } + } + + if (horizon[i].start < boundary.y1) { + changedHorizon[0].start = boundary.y1; + changedHorizon.unshift({ + start: horizon[i].start, + end: boundary.y1, + boundary: horizon[i].boundary + }); + } + + if (boundary.y2 < horizon[j].end) { + changedHorizon.at(-1).end = boundary.y2; + changedHorizon.push({ + start: boundary.y2, + end: horizon[j].end, + boundary: horizon[j].boundary + }); + } + + for (q = i; q <= j; q++) { + horizonPart = horizon[q]; + affectedBoundary = horizonPart.boundary; + + if (affectedBoundary.x2New !== undefined) { + continue; + } + + let used = false; + + for (k = i - 1; !used && k >= 0 && horizon[k].start >= affectedBoundary.y1; k--) { + used = horizon[k].boundary === affectedBoundary; + } + + for (k = j + 1; !used && k < horizon.length && horizon[k].end <= affectedBoundary.y2; k++) { + used = horizon[k].boundary === affectedBoundary; + } + + for (k = 0; !used && k < changedHorizon.length; k++) { + used = changedHorizon[k].boundary === affectedBoundary; + } + + if (!used) { + affectedBoundary.x2New = maxXNew; + } + } + + Array.prototype.splice.apply(horizon, [i, j - i + 1, ...changedHorizon]); } - function TextLayerRenderTask({ + for (const horizonPart of horizon) { + const affectedBoundary = horizonPart.boundary; + + if (affectedBoundary.x2New === undefined) { + affectedBoundary.x2New = Math.max(width, affectedBoundary.x2); + } + } +} + +class TextLayerRenderTask { + constructor({ textContent, textContentStream, container, @@ -10769,6 +16055,10 @@ var renderTextLayer = function renderTextLayerClosure() { textContentItemsStr, enhanceTextSelection }) { + if (enhanceTextSelection) { + (0, _display_utils.deprecated)("The `enhanceTextSelection` functionality will be removed in the future."); + } + this._textContent = textContent; this._textContentStream = textContentStream; this._container = container; @@ -10777,7 +16067,7 @@ var renderTextLayer = function renderTextLayerClosure() { this._textDivs = textDivs || []; this._textContentItemsStr = textContentItemsStr || []; this._enhanceTextSelection = !!enhanceTextSelection; - this._fontInspectorEnabled = !!(globalThis.FontInspector && globalThis.FontInspector.enabled); + this._fontInspectorEnabled = !!globalThis.FontInspector?.enabled; this._reader = null; this._layoutTextLastFontSize = null; this._layoutTextLastFontFamily = null; @@ -10788,8 +16078,13 @@ var renderTextLayer = function renderTextLayerClosure() { this._capability = (0, _util.createPromiseCapability)(); this._renderTimer = null; this._bounds = []; + this._devicePixelRatio = globalThis.devicePixelRatio || 1; this._capability.promise.finally(() => { + if (!this._enhanceTextSelection) { + this._textDivProperties = null; + } + if (this._layoutTextCtx) { this._layoutTextCtx.canvas.width = 0; this._layoutTextCtx.canvas.height = 0; @@ -10798,252 +16093,280 @@ var renderTextLayer = function renderTextLayerClosure() { }).catch(() => {}); } - TextLayerRenderTask.prototype = { - get promise() { - return this._capability.promise; - }, - - cancel: function TextLayer_cancel() { - this._canceled = true; - - if (this._reader) { - this._reader.cancel(new _util.AbortException("TextLayer task cancelled.")); - - this._reader = null; - } - - if (this._renderTimer !== null) { - clearTimeout(this._renderTimer); - this._renderTimer = null; - } - - this._capability.reject(new Error("TextLayer task cancelled.")); - }, - - _processItems(items, styleCache) { - for (let i = 0, len = items.length; i < len; i++) { - this._textContentItemsStr.push(items[i].str); - - appendText(this, items[i], styleCache); - } - }, - - _layoutText(textDiv) { - const textDivProperties = this._textDivProperties.get(textDiv); - - if (textDivProperties.isWhitespace) { - return; - } - - let transform = ""; - - if (textDivProperties.canvasWidth !== 0) { - const { - fontSize, - fontFamily - } = textDiv.style; - - if (fontSize !== this._layoutTextLastFontSize || fontFamily !== this._layoutTextLastFontFamily) { - this._layoutTextCtx.font = `${fontSize} ${fontFamily}`; - this._layoutTextLastFontSize = fontSize; - this._layoutTextLastFontFamily = fontFamily; - } - - const { - width - } = this._layoutTextCtx.measureText(textDiv.textContent); - - if (width > 0) { - textDivProperties.scale = textDivProperties.canvasWidth / width; - transform = `scaleX(${textDivProperties.scale})`; - } - } - - if (textDivProperties.angle !== 0) { - transform = `rotate(${textDivProperties.angle}deg) ${transform}`; - } - - if (transform.length > 0) { - if (this._enhanceTextSelection) { - textDivProperties.originalTransform = transform; - } - - textDiv.style.transform = transform; - } - - this._textDivProperties.set(textDiv, textDivProperties); - - this._container.appendChild(textDiv); - }, - - _render: function TextLayer_render(timeout) { - const capability = (0, _util.createPromiseCapability)(); - let styleCache = Object.create(null); - - const canvas = this._document.createElement("canvas"); - - canvas.mozOpaque = true; - this._layoutTextCtx = canvas.getContext("2d", { - alpha: false - }); - - if (this._textContent) { - const textItems = this._textContent.items; - const textStyles = this._textContent.styles; - - this._processItems(textItems, textStyles); - - capability.resolve(); - } else if (this._textContentStream) { - const pump = () => { - this._reader.read().then(({ - value, - done - }) => { - if (done) { - capability.resolve(); - return; - } - - Object.assign(styleCache, value.styles); - - this._processItems(value.items, styleCache); - - pump(); - }, capability.reject); - }; - - this._reader = this._textContentStream.getReader(); - pump(); - } else { - throw new Error('Neither "textContent" nor "textContentStream"' + " parameters specified."); - } - - capability.promise.then(() => { - styleCache = null; - - if (!timeout) { - render(this); - } else { - this._renderTimer = setTimeout(() => { - render(this); - this._renderTimer = null; - }, timeout); - } - }, this._capability.reject); - }, - expandTextDivs: function TextLayer_expandTextDivs(expandDivs) { - if (!this._enhanceTextSelection || !this._renderingDone) { - return; - } - - if (this._bounds !== null) { - expand(this); - this._bounds = null; - } - - const transformBuf = [], - paddingBuf = []; - - for (var i = 0, ii = this._textDivs.length; i < ii; i++) { - const div = this._textDivs[i]; - - const divProps = this._textDivProperties.get(div); - - if (divProps.isWhitespace) { - continue; - } - - if (expandDivs) { - transformBuf.length = 0; - paddingBuf.length = 0; - - if (divProps.originalTransform) { - transformBuf.push(divProps.originalTransform); - } - - if (divProps.paddingTop > 0) { - paddingBuf.push(`${divProps.paddingTop}px`); - transformBuf.push(`translateY(${-divProps.paddingTop}px)`); - } else { - paddingBuf.push(0); - } - - if (divProps.paddingRight > 0) { - paddingBuf.push(`${divProps.paddingRight / divProps.scale}px`); - } else { - paddingBuf.push(0); - } - - if (divProps.paddingBottom > 0) { - paddingBuf.push(`${divProps.paddingBottom}px`); - } else { - paddingBuf.push(0); - } - - if (divProps.paddingLeft > 0) { - paddingBuf.push(`${divProps.paddingLeft / divProps.scale}px`); - transformBuf.push(`translateX(${-divProps.paddingLeft / divProps.scale}px)`); - } else { - paddingBuf.push(0); - } - - div.style.padding = paddingBuf.join(" "); - - if (transformBuf.length) { - div.style.transform = transformBuf.join(" "); - } - } else { - div.style.padding = null; - div.style.transform = divProps.originalTransform; - } - } - } - }; - - function renderTextLayer(renderParameters) { - var task = new TextLayerRenderTask({ - textContent: renderParameters.textContent, - textContentStream: renderParameters.textContentStream, - container: renderParameters.container, - viewport: renderParameters.viewport, - textDivs: renderParameters.textDivs, - textContentItemsStr: renderParameters.textContentItemsStr, - enhanceTextSelection: renderParameters.enhanceTextSelection - }); - - task._render(renderParameters.timeout); - - return task; + get promise() { + return this._capability.promise; } - return renderTextLayer; -}(); + cancel() { + this._canceled = true; -exports.renderTextLayer = renderTextLayer; + if (this._reader) { + this._reader.cancel(new _util.AbortException("TextLayer task cancelled.")).catch(() => {}); + + this._reader = null; + } + + if (this._renderTimer !== null) { + clearTimeout(this._renderTimer); + this._renderTimer = null; + } + + this._capability.reject(new Error("TextLayer task cancelled.")); + } + + _processItems(items, styleCache) { + for (let i = 0, len = items.length; i < len; i++) { + if (items[i].str === undefined) { + if (items[i].type === "beginMarkedContentProps" || items[i].type === "beginMarkedContent") { + const parent = this._container; + this._container = document.createElement("span"); + + this._container.classList.add("markedContent"); + + if (items[i].id !== null) { + this._container.setAttribute("id", `${items[i].id}`); + } + + parent.append(this._container); + } else if (items[i].type === "endMarkedContent") { + this._container = this._container.parentNode; + } + + continue; + } + + this._textContentItemsStr.push(items[i].str); + + appendText(this, items[i], styleCache, this._layoutTextCtx); + } + } + + _layoutText(textDiv) { + const textDivProperties = this._textDivProperties.get(textDiv); + + let transform = ""; + + if (textDivProperties.canvasWidth !== 0 && textDivProperties.hasText) { + const { + fontFamily + } = textDiv.style; + const { + fontSize + } = textDivProperties; + + if (fontSize !== this._layoutTextLastFontSize || fontFamily !== this._layoutTextLastFontFamily) { + this._layoutTextCtx.font = `${fontSize * this._devicePixelRatio}px ${fontFamily}`; + this._layoutTextLastFontSize = fontSize; + this._layoutTextLastFontFamily = fontFamily; + } + + const { + width + } = this._layoutTextCtx.measureText(textDiv.textContent); + + if (width > 0) { + const scale = this._devicePixelRatio * textDivProperties.canvasWidth / width; + + if (this._enhanceTextSelection) { + textDivProperties.scale = scale; + } + + transform = `scaleX(${scale})`; + } + } + + if (textDivProperties.angle !== 0) { + transform = `rotate(${textDivProperties.angle}deg) ${transform}`; + } + + if (transform.length > 0) { + if (this._enhanceTextSelection) { + textDivProperties.originalTransform = transform; + } + + textDiv.style.transform = transform; + } + + if (textDivProperties.hasText) { + this._container.append(textDiv); + } + + if (textDivProperties.hasEOL) { + const br = document.createElement("br"); + br.setAttribute("role", "presentation"); + + this._container.append(br); + } + } + + _render(timeout = 0) { + const capability = (0, _util.createPromiseCapability)(); + let styleCache = Object.create(null); + + const canvas = this._document.createElement("canvas"); + + canvas.height = canvas.width = DEFAULT_FONT_SIZE; + this._layoutTextCtx = canvas.getContext("2d", { + alpha: false + }); + + if (this._textContent) { + const textItems = this._textContent.items; + const textStyles = this._textContent.styles; + + this._processItems(textItems, textStyles); + + capability.resolve(); + } else if (this._textContentStream) { + const pump = () => { + this._reader.read().then(({ + value, + done + }) => { + if (done) { + capability.resolve(); + return; + } + + Object.assign(styleCache, value.styles); + + this._processItems(value.items, styleCache); + + pump(); + }, capability.reject); + }; + + this._reader = this._textContentStream.getReader(); + pump(); + } else { + throw new Error('Neither "textContent" nor "textContentStream" parameters specified.'); + } + + capability.promise.then(() => { + styleCache = null; + + if (!timeout) { + render(this); + } else { + this._renderTimer = setTimeout(() => { + render(this); + this._renderTimer = null; + }, timeout); + } + }, this._capability.reject); + } + + expandTextDivs(expandDivs = false) { + if (!this._enhanceTextSelection || !this._renderingDone) { + return; + } + + if (this._bounds !== null) { + expand(this); + this._bounds = null; + } + + const transformBuf = [], + paddingBuf = []; + + for (let i = 0, ii = this._textDivs.length; i < ii; i++) { + const div = this._textDivs[i]; + + const divProps = this._textDivProperties.get(div); + + if (!divProps.hasText) { + continue; + } + + if (expandDivs) { + transformBuf.length = 0; + paddingBuf.length = 0; + + if (divProps.originalTransform) { + transformBuf.push(divProps.originalTransform); + } + + if (divProps.paddingTop > 0) { + paddingBuf.push(`${divProps.paddingTop}px`); + transformBuf.push(`translateY(${-divProps.paddingTop}px)`); + } else { + paddingBuf.push(0); + } + + if (divProps.paddingRight > 0) { + paddingBuf.push(`${divProps.paddingRight / divProps.scale}px`); + } else { + paddingBuf.push(0); + } + + if (divProps.paddingBottom > 0) { + paddingBuf.push(`${divProps.paddingBottom}px`); + } else { + paddingBuf.push(0); + } + + if (divProps.paddingLeft > 0) { + paddingBuf.push(`${divProps.paddingLeft / divProps.scale}px`); + transformBuf.push(`translateX(${-divProps.paddingLeft / divProps.scale}px)`); + } else { + paddingBuf.push(0); + } + + div.style.padding = paddingBuf.join(" "); + + if (transformBuf.length) { + div.style.transform = transformBuf.join(" "); + } + } else { + div.style.padding = null; + div.style.transform = divProps.originalTransform; + } + } + } + +} + +exports.TextLayerRenderTask = TextLayerRenderTask; + +function renderTextLayer(renderParameters) { + const task = new TextLayerRenderTask({ + textContent: renderParameters.textContent, + textContentStream: renderParameters.textContentStream, + container: renderParameters.container, + viewport: renderParameters.viewport, + textDivs: renderParameters.textDivs, + textContentItemsStr: renderParameters.textContentItemsStr, + enhanceTextSelection: renderParameters.enhanceTextSelection + }); + + task._render(renderParameters.timeout); + + return task; +} /***/ }), -/* 21 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 31 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.SVGGraphics = void 0; -var _util = __w_pdfjs_require__(2); +var _display_utils = __w_pdfjs_require__(8); -var _display_utils = __w_pdfjs_require__(1); +var _util = __w_pdfjs_require__(1); -var _is_node = __w_pdfjs_require__(4); +var _is_node = __w_pdfjs_require__(3); + +let SVGGraphics = class { + constructor() { + (0, _util.unreachable)("Not implemented: SVGGraphics"); + } -let SVGGraphics = function () { - throw new Error("Not implemented: SVGGraphics"); }; - exports.SVGGraphics = SVGGraphics; { const SVG_DEFAULTS = { @@ -11056,6 +16379,30 @@ exports.SVGGraphics = SVGGraphics; const LINE_CAP_STYLES = ["butt", "round", "square"]; const LINE_JOIN_STYLES = ["miter", "round", "bevel"]; + const createObjectURL = function (data, contentType = "", forceDataSchema = false) { + if (URL.createObjectURL && typeof Blob !== "undefined" && !forceDataSchema) { + return URL.createObjectURL(new Blob([data], { + type: contentType + })); + } + + const digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + let buffer = `data:${contentType};base64,`; + + for (let i = 0, ii = data.length; i < ii; i += 3) { + const b1 = data[i] & 0xff; + const b2 = data[i + 1] & 0xff; + const b3 = data[i + 2] & 0xff; + const d1 = b1 >> 2, + d2 = (b1 & 3) << 4 | b2 >> 4; + const d3 = i + 1 < ii ? (b2 & 0xf) << 2 | b3 >> 6 : 64; + const d4 = i + 2 < ii ? b3 & 0x3f : 64; + buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; + } + + return buffer; + }; + const convertImgDataToPng = function () { const PNG_HEADER = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); const CHUNK_WRAPPER_SIZE = 12; @@ -11248,7 +16595,7 @@ exports.SVGGraphics = SVGGraphics; writePngChunk("IDATA", idat, data, offset); offset += CHUNK_WRAPPER_SIZE + idat.length; writePngChunk("IEND", new Uint8Array(0), data, offset); - return (0, _util.createObjectURL)(data, "image/png", forceDataSchema); + return createObjectURL(data, "image/png", forceDataSchema); } return function convertImgDataToPng(imgData, forceDataSchema, isMask) { @@ -11314,7 +16661,7 @@ exports.SVGGraphics = SVGGraphics; items: [] }); tmp.push(opTree); - opTree = opTree[opTree.length - 1].items; + opTree = opTree.at(-1).items; continue; } @@ -11373,8 +16720,9 @@ exports.SVGGraphics = SVGGraphics; let clipCount = 0; let maskCount = 0; let shadingCount = 0; - exports.SVGGraphics = SVGGraphics = class SVGGraphics { + exports.SVGGraphics = SVGGraphics = class { constructor(commonObjs, objs, forceDataSchema = false) { + (0, _display_utils.deprecated)("The SVG back-end is no longer maintained and *may* be removed in the future."); this.svgFactory = new _display_utils.DOMSVGFactory(); this.current = new SVGExtraState(); this.transformMatrix = _util.IDENTITY_MATRIX; @@ -11700,7 +17048,7 @@ exports.SVGGraphics = SVGGraphics; setTextMatrix(a, b, c, d, e, f) { const current = this.current; current.textMatrix = current.lineMatrix = [a, b, c, d, e, f]; - current.textMatrixScale = Math.sqrt(a * a + b * b); + current.textMatrixScale = Math.hypot(a, b); current.x = current.lineX = 0; current.y = current.lineY = 0; current.xcoords = []; @@ -11710,7 +17058,7 @@ exports.SVGGraphics = SVGGraphics; current.tspan.setAttributeNS(null, "font-size", `${pf(current.fontSize)}px`); current.tspan.setAttributeNS(null, "y", pf(-current.y)); current.txtElement = this.svgFactory.createElement("svg:text"); - current.txtElement.appendChild(current.tspan); + current.txtElement.append(current.tspan); } beginText() { @@ -11763,7 +17111,7 @@ exports.SVGGraphics = SVGGraphics; if (glyph === null) { x += fontDirection * wordSpacing; continue; - } else if ((0, _util.isNum)(glyph)) { + } else if (typeof glyph === "number") { x += spacingDir * glyph * fontSize / 1000; continue; } @@ -11864,10 +17212,10 @@ exports.SVGGraphics = SVGGraphics; current.txtElement.setAttributeNS(null, "transform", `${pm(textMatrix)} scale(${pf(textHScale)}, -1)`); current.txtElement.setAttributeNS(XML_NS, "xml:space", "preserve"); - current.txtElement.appendChild(current.tspan); - current.txtgrp.appendChild(current.txtElement); + current.txtElement.append(current.tspan); + current.txtgrp.append(current.txtElement); - this._ensureTransformGroup().appendChild(current.txtElement); + this._ensureTransformGroup().append(current.txtElement); } setLeadingMoveText(x, y) { @@ -11883,10 +17231,10 @@ exports.SVGGraphics = SVGGraphics; if (!this.cssStyle) { this.cssStyle = this.svgFactory.createElement("svg:style"); this.cssStyle.setAttributeNS(null, "type", "text/css"); - this.defs.appendChild(this.cssStyle); + this.defs.append(this.cssStyle); } - const url = (0, _util.createObjectURL)(fontObj.data, fontObj.mimetype, this.forceDataSchema); + const url = createObjectURL(fontObj.data, fontObj.mimetype, this.forceDataSchema); this.cssStyle.textContent += `@font-face { font-family: "${fontObj.loadedName}";` + ` src: url(${url}); }\n`; } @@ -11901,7 +17249,7 @@ exports.SVGGraphics = SVGGraphics; this.embeddedFonts[fontObj.loadedName] = fontObj; } - current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix : _util.FONT_IDENTITY_MATRIX; + current.fontMatrix = fontObj.fontMatrix || _util.FONT_IDENTITY_MATRIX; let bold = "normal"; if (fontObj.black) { @@ -11932,7 +17280,7 @@ exports.SVGGraphics = SVGGraphics; endText() { const current = this.current; - if (current.textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG && current.txtElement && current.txtElement.hasChildNodes()) { + if (current.textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG && current.txtElement?.hasChildNodes()) { current.element = current.txtElement; this.clip("nonzero"); this.endPath(); @@ -11962,7 +17310,7 @@ exports.SVGGraphics = SVGGraphics; } setStrokeRGBColor(r, g, b) { - this.current.strokeColor = _util.Util.makeCssRgb(r, g, b); + this.current.strokeColor = _util.Util.makeHexColor(r, g, b); } setFillAlpha(fillAlpha) { @@ -11970,7 +17318,7 @@ exports.SVGGraphics = SVGGraphics; } setFillRGBColor(r, g, b) { - this.current.fillColor = _util.Util.makeCssRgb(r, g, b); + this.current.fillColor = _util.Util.makeHexColor(r, g, b); this.current.tspan = this.svgFactory.createElement("svg:tspan"); this.current.xcoords = []; this.current.ycoords = []; @@ -12013,7 +17361,7 @@ exports.SVGGraphics = SVGGraphics; rect.setAttributeNS(null, "fill-opacity", this.current.fillAlpha); } - this._ensureTransformGroup().appendChild(rect); + this._ensureTransformGroup().append(rect); } _makeColorN_Pattern(args) { @@ -12034,9 +17382,7 @@ exports.SVGGraphics = SVGGraphics; const paintType = args[7]; const tilingId = `shading${shadingCount++}`; - const [tx0, ty0] = _util.Util.applyTransform([x0, y0], matrix); - - const [tx1, ty1] = _util.Util.applyTransform([x1, y1], matrix); + const [tx0, ty0, tx1, ty1] = _util.Util.normalizeRect([..._util.Util.applyTransform([x0, y0], matrix), ..._util.Util.applyTransform([x1, y1], matrix)]); const [xscale, yscale] = _util.Util.singularValueDecompose2dScale(matrix); @@ -12058,7 +17404,7 @@ exports.SVGGraphics = SVGGraphics; this.transformMatrix = matrix; if (paintType === 2) { - const cssColor = _util.Util.makeCssRgb(...color); + const cssColor = _util.Util.makeHexColor(...color); this.current.fillColor = cssColor; this.current.strokeColor = cssColor; @@ -12069,12 +17415,16 @@ exports.SVGGraphics = SVGGraphics; this.transformMatrix = transformMatrix; this.current.fillColor = fillColor; this.current.strokeColor = strokeColor; - tiling.appendChild(bbox.childNodes[0]); - this.defs.appendChild(tiling); + tiling.append(bbox.childNodes[0]); + this.defs.append(tiling); return `url(#${tilingId})`; } _makeShadingPattern(args) { + if (typeof args === "string") { + args = this.objs.get(args); + } + switch (args[0]) { case "RadialAxial": const shadingId = `shading${shadingCount++}`; @@ -12118,10 +17468,10 @@ exports.SVGGraphics = SVGGraphics; const stop = this.svgFactory.createElement("svg:stop"); stop.setAttributeNS(null, "offset", colorStop[0]); stop.setAttributeNS(null, "stop-color", colorStop[1]); - gradient.appendChild(stop); + gradient.append(stop); } - this.defs.appendChild(gradient); + this.defs.append(gradient); return `url(#${shadingId})`; case "Mesh": @@ -12206,7 +17556,7 @@ exports.SVGGraphics = SVGGraphics; } else { current.path = this.svgFactory.createElement("svg:path"); - this._ensureTransformGroup().appendChild(current.path); + this._ensureTransformGroup().append(current.path); } current.path.setAttributeNS(null, "d", d); @@ -12241,14 +17591,16 @@ exports.SVGGraphics = SVGGraphics; } this.pendingClip = null; - clipPath.appendChild(clipElement); - this.defs.appendChild(clipPath); + clipPath.append(clipElement); + this.defs.append(clipPath); if (current.activeClipUrl) { current.clipGroup = null; - this.extraStack.forEach(function (prev) { + + for (const prev of this.extraStack) { prev.clipGroup = null; - }); + } + clipPath.setAttributeNS(null, "clip-path", current.activeClipUrl); } @@ -12424,7 +17776,7 @@ exports.SVGGraphics = SVGGraphics; rect.setAttributeNS(null, "height", "1px"); rect.setAttributeNS(null, "fill", this.current.fillColor); - this._ensureTransformGroup().appendChild(rect); + this._ensureTransformGroup().append(rect); } paintImageXObject(objId) { @@ -12458,9 +17810,9 @@ exports.SVGGraphics = SVGGraphics; imgEl.setAttributeNS(null, "transform", `scale(${pf(1 / width)} ${pf(-1 / height)})`); if (mask) { - mask.appendChild(imgEl); + mask.append(imgEl); } else { - this._ensureTransformGroup().appendChild(imgEl); + this._ensureTransformGroup().append(imgEl); } } @@ -12479,9 +17831,9 @@ exports.SVGGraphics = SVGGraphics; rect.setAttributeNS(null, "height", pf(height)); rect.setAttributeNS(null, "fill", fillColor); rect.setAttributeNS(null, "mask", `url(#${current.maskId})`); - this.defs.appendChild(mask); + this.defs.append(mask); - this._ensureTransformGroup().appendChild(rect); + this._ensureTransformGroup().append(rect); this.paintInlineImageXObject(imgData, mask); } @@ -12510,11 +17862,11 @@ exports.SVGGraphics = SVGGraphics; _initialize(viewport) { const svg = this.svgFactory.create(viewport.width, viewport.height); const definitions = this.svgFactory.createElement("svg:defs"); - svg.appendChild(definitions); + svg.append(definitions); this.defs = definitions; const rootGroup = this.svgFactory.createElement("svg:g"); rootGroup.setAttributeNS(null, "transform", pm(viewport.transform)); - svg.appendChild(rootGroup); + svg.append(rootGroup); this.svg = rootGroup; return svg; } @@ -12523,7 +17875,7 @@ exports.SVGGraphics = SVGGraphics; if (!this.current.clipGroup) { const clipGroup = this.svgFactory.createElement("svg:g"); clipGroup.setAttributeNS(null, "clip-path", this.current.activeClipUrl); - this.svg.appendChild(clipGroup); + this.svg.append(clipGroup); this.current.clipGroup = clipGroup; } @@ -12536,9 +17888,9 @@ exports.SVGGraphics = SVGGraphics; this.tgrp.setAttributeNS(null, "transform", pm(this.transformMatrix)); if (this.current.activeClipUrl) { - this._ensureClipGroup().appendChild(this.tgrp); + this._ensureClipGroup().append(this.tgrp); } else { - this.svg.appendChild(this.tgrp); + this.svg.append(this.tgrp); } } @@ -12549,20 +17901,19 @@ exports.SVGGraphics = SVGGraphics; } /***/ }), -/* 22 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 32 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFNodeStream = void 0; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); -var _network_utils = __w_pdfjs_require__(23); +var _network_utils = __w_pdfjs_require__(33); ; @@ -12606,7 +17957,7 @@ class PDFNodeStream { } get _progressiveDataLength() { - return this._fullRequestReader ? this._fullRequestReader._loaded : 0; + return this._fullRequestReader?._loaded ?? 0; } getFullReader() { @@ -12632,11 +17983,9 @@ class PDFNodeStream { this._fullRequestReader.cancel(reason); } - const readers = this._rangeRequestReaders.slice(0); - - readers.forEach(function (reader) { + for (const reader of this._rangeRequestReaders.slice(0)) { reader.cancel(reason); - }); + } } } @@ -13018,23 +18367,24 @@ class PDFNodeStreamFsRangeReader extends BaseRangeReader { } /***/ }), -/* 23 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 33 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.createResponseStatusError = createResponseStatusError; exports.extractFilenameFromHeader = extractFilenameFromHeader; exports.validateRangeRequestCapabilities = validateRangeRequestCapabilities; exports.validateResponseStatus = validateResponseStatus; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); -var _content_disposition = __w_pdfjs_require__(24); +var _content_disposition = __w_pdfjs_require__(34); + +var _display_utils = __w_pdfjs_require__(8); function validateRangeRequestCapabilities({ getResponseHeader, @@ -13042,7 +18392,6 @@ function validateRangeRequestCapabilities({ rangeChunkSize, disableRange }) { - (0, _util.assert)(rangeChunkSize > 0, "Range chunk size must be larger than zero"); const returnValues = { allowRangeRequests: false, suggestedLength: undefined @@ -13089,7 +18438,7 @@ function extractFilenameFromHeader(getResponseHeader) { } catch (ex) {} } - if (/\.pdf$/i.test(filename)) { + if ((0, _display_utils.isPdfFile)(filename)) { return filename; } } @@ -13102,7 +18451,7 @@ function createResponseStatusError(status, url) { return new _util.MissingPDFException('Missing PDF "' + url + '".'); } - return new _util.UnexpectedResponseException("Unexpected server response (" + status + ') while retrieving PDF "' + url + '".', status); + return new _util.UnexpectedResponseException(`Unexpected server response (${status}) while retrieving PDF "${url}".`, status); } function validateResponseStatus(status) { @@ -13110,17 +18459,18 @@ function validateResponseStatus(status) { } /***/ }), -/* 24 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 34 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.getFilenameFromContentDispositionHeader = getFilenameFromContentDispositionHeader; +var _util = __w_pdfjs_require__(1); + function getFilenameFromContentDispositionHeader(contentDisposition) { let needsEncodingFixup = true; let tmp = toParamRegExp("filename\\*", "i").exec(contentDisposition); @@ -13164,19 +18514,10 @@ function getFilenameFromContentDispositionHeader(contentDisposition) { const decoder = new TextDecoder(encoding, { fatal: true }); - const bytes = Array.from(value, function (ch) { - return ch.charCodeAt(0) & 0xff; - }); - value = decoder.decode(new Uint8Array(bytes)); + const buffer = (0, _util.stringToBytes)(value); + value = decoder.decode(buffer); needsEncodingFixup = false; - } catch (e) { - if (/^utf-?8$/i.test(encoding)) { - try { - value = decodeURIComponent(escape(value)); - needsEncodingFixup = false; - } catch (err) {} - } - } + } catch (e) {} } return value; @@ -13298,20 +18639,19 @@ function getFilenameFromContentDispositionHeader(contentDisposition) { } /***/ }), -/* 25 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 35 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFNetworkStream = void 0; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); -var _network_utils = __w_pdfjs_require__(23); +var _network_utils = __w_pdfjs_require__(33); ; const OK_RESPONSE = 200; @@ -13329,11 +18669,10 @@ function getArrayBuffer(xhr) { } class NetworkManager { - constructor(url, args) { + constructor(url, args = {}) { this.url = url; - args = args || {}; this.isHttp = /^https?:/i.test(url); - this.httpHeaders = this.isHttp && args.httpHeaders || {}; + this.httpHeaders = this.isHttp && args.httpHeaders || Object.create(null); this.withCredentials = args.withCredentials || false; this.getXhr = args.getXhr || function NetworkManager_getXhr() { @@ -13412,9 +18751,7 @@ class NetworkManager { return; } - if (pendingRequest.onProgress) { - pendingRequest.onProgress(evt); - } + pendingRequest.onProgress?.(evt); } onStateChange(xhrId, evt) { @@ -13442,10 +18779,7 @@ class NetworkManager { delete this.pendingRequests[xhrId]; if (xhr.status === 0 && this.isHttp) { - if (pendingRequest.onError) { - pendingRequest.onError(xhr.status); - } - + pendingRequest.onError?.(xhr.status); return; } @@ -13453,10 +18787,7 @@ class NetworkManager { const ok_response_on_range_request = xhrStatus === OK_RESPONSE && pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE; if (!ok_response_on_range_request && xhrStatus !== pendingRequest.expectedStatus) { - if (pendingRequest.onError) { - pendingRequest.onError(xhr.status); - } - + pendingRequest.onError?.(xhr.status); return; } @@ -13474,8 +18805,8 @@ class NetworkManager { begin: 0, chunk }); - } else if (pendingRequest.onError) { - pendingRequest.onError(xhr.status); + } else { + pendingRequest.onError?.(xhr.status); } } @@ -13531,15 +18862,11 @@ class PDFNetworkStream { } cancelAllRequests(reason) { - if (this._fullRequestReader) { - this._fullRequestReader.cancel(reason); - } + this._fullRequestReader?.cancel(reason); - const readers = this._rangeRequestReaders.slice(0); - - readers.forEach(function (reader) { + for (const reader of this._rangeRequestReaders.slice(0)) { reader.cancel(reason); - }); + } } } @@ -13609,17 +18936,17 @@ class PDFNetworkStreamFullRequestReader { this._headersReceivedCapability.resolve(); } - _onDone(args) { - if (args) { + _onDone(data) { + if (data) { if (this._requests.length > 0) { const requestCapability = this._requests.shift(); requestCapability.resolve({ - value: args.chunk, + value: data.chunk, done: false }); } else { - this._cachedChunks.push(args.chunk); + this._cachedChunks.push(data.chunk); } } @@ -13629,38 +18956,34 @@ class PDFNetworkStreamFullRequestReader { return; } - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } - this._requests = []; + this._requests.length = 0; } _onError(status) { - const url = this._url; - const exception = (0, _network_utils.createResponseStatusError)(status, url); - this._storedError = exception; + this._storedError = (0, _network_utils.createResponseStatusError)(status, this._url); - this._headersReceivedCapability.reject(exception); + this._headersReceivedCapability.reject(this._storedError); - this._requests.forEach(function (requestCapability) { - requestCapability.reject(exception); - }); + for (const requestCapability of this._requests) { + requestCapability.reject(this._storedError); + } - this._requests = []; - this._cachedChunks = []; + this._requests.length = 0; + this._cachedChunks.length = 0; } - _onProgress(data) { - if (this.onProgress) { - this.onProgress({ - loaded: data.loaded, - total: data.lengthComputable ? data.total : this._contentLength - }); - } + _onProgress(evt) { + this.onProgress?.({ + loaded: evt.loaded, + total: evt.lengthComputable ? evt.total : this._contentLength + }); } get filename() { @@ -13716,14 +19039,14 @@ class PDFNetworkStreamFullRequestReader { this._headersReceivedCapability.reject(reason); - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } - this._requests = []; + this._requests.length = 0; if (this._manager.isPendingRequest(this._fullRequestId)) { this._manager.abortRequest(this._fullRequestId); @@ -13739,20 +19062,21 @@ class PDFNetworkStreamRangeRequestReader { this._manager = manager; const args = { onDone: this._onDone.bind(this), + onError: this._onError.bind(this), onProgress: this._onProgress.bind(this) }; + this._url = manager.url; this._requestId = manager.requestRange(begin, end, args); this._requests = []; this._queuedChunk = null; this._done = false; + this._storedError = undefined; this.onProgress = null; this.onClosed = null; } _close() { - if (this.onClosed) { - this.onClosed(this); - } + this.onClosed?.(this); } _onDone(data) { @@ -13771,21 +19095,32 @@ class PDFNetworkStreamRangeRequestReader { this._done = true; - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } - this._requests = []; + this._requests.length = 0; this._close(); } + _onError(status) { + this._storedError = (0, _network_utils.createResponseStatusError)(status, this._url); + + for (const requestCapability of this._requests) { + requestCapability.reject(this._storedError); + } + + this._requests.length = 0; + this._queuedChunk = null; + } + _onProgress(evt) { - if (!this.isStreamingSupported && this.onProgress) { - this.onProgress({ + if (!this.isStreamingSupported) { + this.onProgress?.({ loaded: evt.loaded }); } @@ -13796,6 +19131,10 @@ class PDFNetworkStreamRangeRequestReader { } async read() { + if (this._storedError) { + throw this._storedError; + } + if (this._queuedChunk !== null) { const chunk = this._queuedChunk; this._queuedChunk = null; @@ -13822,14 +19161,14 @@ class PDFNetworkStreamRangeRequestReader { cancel(reason) { this._done = true; - this._requests.forEach(function (requestCapability) { + for (const requestCapability of this._requests) { requestCapability.resolve({ value: undefined, done: true }); - }); + } - this._requests = []; + this._requests.length = 0; if (this._manager.isPendingRequest(this._requestId)) { this._manager.abortRequest(this._requestId); @@ -13841,20 +19180,19 @@ class PDFNetworkStreamRangeRequestReader { } /***/ }), -/* 26 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 36 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFFetchStream = void 0; -var _util = __w_pdfjs_require__(2); +var _util = __w_pdfjs_require__(1); -var _network_utils = __w_pdfjs_require__(23); +var _network_utils = __w_pdfjs_require__(33); ; @@ -13862,7 +19200,7 @@ function createFetchOptions(headers, withCredentials, abortController) { return { method: "GET", headers, - signal: abortController && abortController.signal, + signal: abortController.signal, mode: "cors", credentials: withCredentials ? "include" : "same-origin", redirect: "follow" @@ -13895,7 +19233,7 @@ class PDFFetchStream { } get _progressiveDataLength() { - return this._fullRequestReader ? this._fullRequestReader._loaded : 0; + return this._fullRequestReader?._loaded ?? 0; } getFullReader() { @@ -13921,11 +19259,9 @@ class PDFFetchStream { this._fullRequestReader.cancel(reason); } - const readers = this._rangeRequestReaders.slice(0); - - readers.forEach(function (reader) { + for (const reader of this._rangeRequestReaders.slice(0)) { reader.cancel(reason); - }); + } } } @@ -13949,10 +19285,7 @@ class PDFFetchStreamReader { this._disableRange = true; } - if (typeof AbortController !== "undefined") { - this._abortController = new AbortController(); - } - + this._abortController = new AbortController(); this._isStreamingSupported = !source.disableStream; this._isRangeSupported = !source.disableRange; this._headers = createHeaders(this._stream.httpHeaders); @@ -14045,9 +19378,7 @@ class PDFFetchStreamReader { this._reader.cancel(reason); } - if (this._abortController) { - this._abortController.abort(); - } + this._abortController.abort(); } } @@ -14061,11 +19392,7 @@ class PDFFetchStreamRangeReader { this._withCredentials = source.withCredentials || false; this._readCapability = (0, _util.createPromiseCapability)(); this._isStreamingSupported = !source.disableStream; - - if (typeof AbortController !== "undefined") { - this._abortController = new AbortController(); - } - + this._abortController = new AbortController(); this._headers = createHeaders(this._stream.httpHeaders); this._headers.append("Range", `bytes=${begin}-${end - 1}`); @@ -14079,13 +19406,7 @@ class PDFFetchStreamRangeReader { this._readCapability.resolve(); this._reader = response.body.getReader(); - }).catch(reason => { - if (reason && reason.name === "AbortError") { - return; - } - - throw reason; - }); + }).catch(this._readCapability.reject); this.onProgress = null; } @@ -14127,14 +19448,326 @@ class PDFFetchStreamRangeReader { this._reader.cancel(reason); } - if (this._abortController) { - this._abortController.abort(); - } + this._abortController.abort(); } } /***/ }) -/******/ ]); +/******/ ]); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __w_pdfjs_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __w_pdfjs_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +var exports = __webpack_exports__; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +Object.defineProperty(exports, "AnnotationEditorLayer", ({ + enumerable: true, + get: function () { + return _annotation_editor_layer.AnnotationEditorLayer; + } +})); +Object.defineProperty(exports, "AnnotationEditorParamsType", ({ + enumerable: true, + get: function () { + return _util.AnnotationEditorParamsType; + } +})); +Object.defineProperty(exports, "AnnotationEditorType", ({ + enumerable: true, + get: function () { + return _util.AnnotationEditorType; + } +})); +Object.defineProperty(exports, "AnnotationEditorUIManager", ({ + enumerable: true, + get: function () { + return _tools.AnnotationEditorUIManager; + } +})); +Object.defineProperty(exports, "AnnotationLayer", ({ + enumerable: true, + get: function () { + return _annotation_layer.AnnotationLayer; + } +})); +Object.defineProperty(exports, "AnnotationMode", ({ + enumerable: true, + get: function () { + return _util.AnnotationMode; + } +})); +Object.defineProperty(exports, "CMapCompressionType", ({ + enumerable: true, + get: function () { + return _util.CMapCompressionType; + } +})); +Object.defineProperty(exports, "GlobalWorkerOptions", ({ + enumerable: true, + get: function () { + return _worker_options.GlobalWorkerOptions; + } +})); +Object.defineProperty(exports, "InvalidPDFException", ({ + enumerable: true, + get: function () { + return _util.InvalidPDFException; + } +})); +Object.defineProperty(exports, "LoopbackPort", ({ + enumerable: true, + get: function () { + return _api.LoopbackPort; + } +})); +Object.defineProperty(exports, "MissingPDFException", ({ + enumerable: true, + get: function () { + return _util.MissingPDFException; + } +})); +Object.defineProperty(exports, "OPS", ({ + enumerable: true, + get: function () { + return _util.OPS; + } +})); +Object.defineProperty(exports, "PDFDataRangeTransport", ({ + enumerable: true, + get: function () { + return _api.PDFDataRangeTransport; + } +})); +Object.defineProperty(exports, "PDFDateString", ({ + enumerable: true, + get: function () { + return _display_utils.PDFDateString; + } +})); +Object.defineProperty(exports, "PDFWorker", ({ + enumerable: true, + get: function () { + return _api.PDFWorker; + } +})); +Object.defineProperty(exports, "PasswordResponses", ({ + enumerable: true, + get: function () { + return _util.PasswordResponses; + } +})); +Object.defineProperty(exports, "PermissionFlag", ({ + enumerable: true, + get: function () { + return _util.PermissionFlag; + } +})); +Object.defineProperty(exports, "PixelsPerInch", ({ + enumerable: true, + get: function () { + return _display_utils.PixelsPerInch; + } +})); +Object.defineProperty(exports, "RenderingCancelledException", ({ + enumerable: true, + get: function () { + return _display_utils.RenderingCancelledException; + } +})); +Object.defineProperty(exports, "SVGGraphics", ({ + enumerable: true, + get: function () { + return _svg.SVGGraphics; + } +})); +Object.defineProperty(exports, "UNSUPPORTED_FEATURES", ({ + enumerable: true, + get: function () { + return _util.UNSUPPORTED_FEATURES; + } +})); +Object.defineProperty(exports, "UnexpectedResponseException", ({ + enumerable: true, + get: function () { + return _util.UnexpectedResponseException; + } +})); +Object.defineProperty(exports, "Util", ({ + enumerable: true, + get: function () { + return _util.Util; + } +})); +Object.defineProperty(exports, "VerbosityLevel", ({ + enumerable: true, + get: function () { + return _util.VerbosityLevel; + } +})); +Object.defineProperty(exports, "XfaLayer", ({ + enumerable: true, + get: function () { + return _xfa_layer.XfaLayer; + } +})); +Object.defineProperty(exports, "build", ({ + enumerable: true, + get: function () { + return _api.build; + } +})); +Object.defineProperty(exports, "createPromiseCapability", ({ + enumerable: true, + get: function () { + return _util.createPromiseCapability; + } +})); +Object.defineProperty(exports, "createValidAbsoluteUrl", ({ + enumerable: true, + get: function () { + return _util.createValidAbsoluteUrl; + } +})); +Object.defineProperty(exports, "getDocument", ({ + enumerable: true, + get: function () { + return _api.getDocument; + } +})); +Object.defineProperty(exports, "getFilenameFromUrl", ({ + enumerable: true, + get: function () { + return _display_utils.getFilenameFromUrl; + } +})); +Object.defineProperty(exports, "getPdfFilenameFromUrl", ({ + enumerable: true, + get: function () { + return _display_utils.getPdfFilenameFromUrl; + } +})); +Object.defineProperty(exports, "getXfaPageViewport", ({ + enumerable: true, + get: function () { + return _display_utils.getXfaPageViewport; + } +})); +Object.defineProperty(exports, "isPdfFile", ({ + enumerable: true, + get: function () { + return _display_utils.isPdfFile; + } +})); +Object.defineProperty(exports, "loadScript", ({ + enumerable: true, + get: function () { + return _display_utils.loadScript; + } +})); +Object.defineProperty(exports, "renderTextLayer", ({ + enumerable: true, + get: function () { + return _text_layer.renderTextLayer; + } +})); +Object.defineProperty(exports, "shadow", ({ + enumerable: true, + get: function () { + return _util.shadow; + } +})); +Object.defineProperty(exports, "version", ({ + enumerable: true, + get: function () { + return _api.version; + } +})); + +var _util = __w_pdfjs_require__(1); + +var _api = __w_pdfjs_require__(4); + +var _display_utils = __w_pdfjs_require__(8); + +var _annotation_editor_layer = __w_pdfjs_require__(22); + +var _tools = __w_pdfjs_require__(7); + +var _annotation_layer = __w_pdfjs_require__(27); + +var _worker_options = __w_pdfjs_require__(15); + +var _is_node = __w_pdfjs_require__(3); + +var _text_layer = __w_pdfjs_require__(30); + +var _svg = __w_pdfjs_require__(31); + +var _xfa_layer = __w_pdfjs_require__(29); + +const pdfjsVersion = '2.16.105'; +const pdfjsBuild = '172ccdbe5'; +{ + if (_is_node.isNodeJS) { + const { + PDFNodeStream + } = __w_pdfjs_require__(32); + + (0, _api.setPDFNetworkStreamFactory)(params => { + return new PDFNodeStream(params); + }); + } else { + const { + PDFNetworkStream + } = __w_pdfjs_require__(35); + + const { + PDFFetchStream + } = __w_pdfjs_require__(36); + + (0, _api.setPDFNetworkStreamFactory)(params => { + if ((0, _display_utils.isValidFetchUrl)(params.url)) { + return new PDFFetchStream(params); + } + + return new PDFNetworkStream(params); + }); + } +} +})(); + +/******/ return __webpack_exports__; +/******/ })() +; }); //# sourceMappingURL=pdf.js.map \ No newline at end of file diff --git a/cps/static/js/libs/pdf.worker.js b/cps/static/js/libs/pdf.worker.js index 58bdf7c19..878da521a 100644 --- a/cps/static/js/libs/pdf.worker.js +++ b/cps/static/js/libs/pdf.worker.js @@ -1,8 +1,8 @@ /** * @licstart The following is the entire license notice for the - * Javascript code in this page + * JavaScript code in this page * - * Copyright 2020 Mozilla Foundation + * Copyright 2022 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ * limitations under the License. * * @licend The above is the entire license notice for the - * Javascript code in this page + * JavaScript code in this page */ (function webpackUniversalModuleDefinition(root, factory) { @@ -29,142 +29,38 @@ exports["pdfjs-dist/build/pdf.worker"] = factory(); else root["pdfjs-dist/build/pdf.worker"] = root.pdfjsWorker = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __w_pdfjs_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __w_pdfjs_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __w_pdfjs_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __w_pdfjs_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __w_pdfjs_require__.d = function(exports, name, getter) { -/******/ if(!__w_pdfjs_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __w_pdfjs_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __w_pdfjs_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __w_pdfjs_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __w_pdfjs_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __w_pdfjs_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __w_pdfjs_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __w_pdfjs_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __w_pdfjs_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __w_pdfjs_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __w_pdfjs_require__(__w_pdfjs_require__.s = 0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -Object.defineProperty(exports, "WorkerMessageHandler", { - enumerable: true, - get: function () { - return _worker.WorkerMessageHandler; - } -}); - -var _worker = __w_pdfjs_require__(1); - -const pdfjsVersion = '2.6.347'; -const pdfjsBuild = '3be9c65f'; - -/***/ }), +})(globalThis, () => { +return /******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ([ +/* 0 */, /* 1 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.WorkerMessageHandler = exports.WorkerTask = void 0; +})); +exports.WorkerTask = exports.WorkerMessageHandler = void 0; var _util = __w_pdfjs_require__(2); var _primitives = __w_pdfjs_require__(5); -var _pdf_manager = __w_pdfjs_require__(6); +var _core_utils = __w_pdfjs_require__(6); -var _writer = __w_pdfjs_require__(27); +var _pdf_manager = __w_pdfjs_require__(8); + +var _cleanup_helper = __w_pdfjs_require__(71); + +var _writer = __w_pdfjs_require__(65); var _is_node = __w_pdfjs_require__(4); -var _message_handler = __w_pdfjs_require__(46); +var _message_handler = __w_pdfjs_require__(102); -var _worker_stream = __w_pdfjs_require__(47); - -var _core_utils = __w_pdfjs_require__(8); +var _worker_stream = __w_pdfjs_require__(103); class WorkerTask { constructor(name) { @@ -197,24 +93,14 @@ exports.WorkerTask = WorkerTask; class WorkerMessageHandler { static setup(handler, port) { - var testMessageProcessed = false; + let testMessageProcessed = false; handler.on("test", function wphSetupTest(data) { if (testMessageProcessed) { return; } testMessageProcessed = true; - - if (!(data instanceof Uint8Array)) { - handler.send("test", null); - return; - } - - const supportTransfers = data[0] === 255; - handler.postMessageTransfers = supportTransfers; - handler.send("test", { - supportTransfers - }); + handler.send("test", data instanceof Uint8Array); }); handler.on("configure", function wphConfigure(data) { (0, _util.setVerbosityLevel)(data.verbosity); @@ -225,13 +111,13 @@ class WorkerMessageHandler { } static createDocumentHandler(docParams, port) { - var pdfManager; - var terminated = false; - var cancelXHRs = null; - var WorkerTasks = []; + let pdfManager; + let terminated = false; + let cancelXHRs = null; + const WorkerTasks = []; const verbosity = (0, _util.getVerbosityLevel)(); const apiVersion = docParams.apiVersion; - const workerVersion = '2.6.347'; + const workerVersion = '2.16.105'; if (apiVersion !== workerVersion) { throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`); @@ -247,15 +133,20 @@ class WorkerMessageHandler { throw new Error("The `Array.prototype` contains unexpected enumerable properties: " + enumerableProperties.join(", ") + "; thus breaking e.g. `for...in` iteration of `Array`s."); } - if (typeof ReadableStream === "undefined" || typeof Promise.allSettled === "undefined") { - throw new Error("The browser/environment lacks native support for critical " + "functionality used by the PDF.js library (e.g. " + "`ReadableStream` and/or `Promise.allSettled`); " + "please use an ES5-compatible build instead."); + if (typeof ReadableStream === "undefined") { + const partialMsg = "The browser/environment lacks native support for critical " + "functionality used by the PDF.js library (e.g. `ReadableStream`); "; + + if (_is_node.isNodeJS) { + throw new Error(partialMsg + "please use a `legacy`-build instead."); + } + + throw new Error(partialMsg + "please update to a supported browser."); } - var docId = docParams.docId; - var docBaseUrl = docParams.docBaseUrl; - var workerHandlerName = docParams.docId + "_worker"; - var handler = new _message_handler.MessageHandler(workerHandlerName, docId, port); - handler.postMessageTransfers = docParams.postMessageTransfers; + const docId = docParams.docId; + const docBaseUrl = docParams.docBaseUrl; + const workerHandlerName = docParams.docId + "_worker"; + let handler = new _message_handler.MessageHandler(workerHandlerName, docId, port); function ensureNotTerminated() { if (terminated) { @@ -269,7 +160,7 @@ class WorkerMessageHandler { function finishWorkerTask(task) { task.finish(); - var i = WorkerTasks.indexOf(task); + const i = WorkerTasks.indexOf(task); WorkerTasks.splice(i, 1); } @@ -277,26 +168,33 @@ class WorkerMessageHandler { await pdfManager.ensureDoc("checkHeader"); await pdfManager.ensureDoc("parseStartXRef"); await pdfManager.ensureDoc("parse", [recoveryMode]); + await pdfManager.ensureDoc("checkFirstPage", [recoveryMode]); + await pdfManager.ensureDoc("checkLastPage", [recoveryMode]); + const isPureXfa = await pdfManager.ensureDoc("isPureXfa"); - if (!recoveryMode) { - await pdfManager.ensureDoc("checkFirstPage"); + if (isPureXfa) { + const task = new WorkerTask("loadXfaFonts"); + startWorkerTask(task); + await Promise.all([pdfManager.loadXfaFonts(handler, task).catch(reason => {}).then(() => finishWorkerTask(task)), pdfManager.loadXfaImages()]); } - const [numPages, fingerprint] = await Promise.all([pdfManager.ensureDoc("numPages"), pdfManager.ensureDoc("fingerprint")]); + const [numPages, fingerprints] = await Promise.all([pdfManager.ensureDoc("numPages"), pdfManager.ensureDoc("fingerprints")]); + const htmlForXfa = isPureXfa ? await pdfManager.ensureDoc("htmlForXfa") : null; return { numPages, - fingerprint + fingerprints, + htmlForXfa }; } - function getPdfManager(data, evaluatorOptions) { - var pdfManagerCapability = (0, _util.createPromiseCapability)(); + function getPdfManager(data, evaluatorOptions, enableXfa) { + const pdfManagerCapability = (0, _util.createPromiseCapability)(); let newPdfManager; - var source = data.source; + const source = data.source; if (source.data) { try { - newPdfManager = new _pdf_manager.LocalPdfManager(docId, source.data, source.password, evaluatorOptions, docBaseUrl); + newPdfManager = new _pdf_manager.LocalPdfManager(docId, source.data, source.password, handler, evaluatorOptions, enableXfa, docBaseUrl); pdfManagerCapability.resolve(newPdfManager); } catch (ex) { pdfManagerCapability.reject(ex); @@ -305,7 +203,7 @@ class WorkerMessageHandler { return pdfManagerCapability.promise; } - var pdfStream, + let pdfStream, cachedChunks = []; try { @@ -315,23 +213,23 @@ class WorkerMessageHandler { return pdfManagerCapability.promise; } - var fullRequest = pdfStream.getFullReader(); + const fullRequest = pdfStream.getFullReader(); fullRequest.headersReady.then(function () { if (!fullRequest.isRangeSupported) { return; } - var disableAutoFetch = source.disableAutoFetch || fullRequest.isStreamingSupported; + const disableAutoFetch = source.disableAutoFetch || fullRequest.isStreamingSupported; newPdfManager = new _pdf_manager.NetworkPdfManager(docId, pdfStream, { msgHandler: handler, password: source.password, length: fullRequest.contentLength, disableAutoFetch, rangeChunkSize: source.rangeChunkSize - }, evaluatorOptions, docBaseUrl); + }, evaluatorOptions, enableXfa, docBaseUrl); - for (let i = 0; i < cachedChunks.length; i++) { - newPdfManager.sendProgressiveData(cachedChunks[i]); + for (const chunk of cachedChunks) { + newPdfManager.sendProgressiveData(chunk); } cachedChunks = []; @@ -341,17 +239,17 @@ class WorkerMessageHandler { pdfManagerCapability.reject(reason); cancelXHRs = null; }); - var loaded = 0; + let loaded = 0; - var flushChunks = function () { - var pdfFile = (0, _util.arraysToBytes)(cachedChunks); + const flushChunks = function () { + const pdfFile = (0, _util.arraysToBytes)(cachedChunks); if (source.length && pdfFile.length !== source.length) { (0, _util.warn)("reported HTTP length is different from actual"); } try { - newPdfManager = new _pdf_manager.LocalPdfManager(docId, pdfFile, source.password, evaluatorOptions, docBaseUrl); + newPdfManager = new _pdf_manager.LocalPdfManager(docId, pdfFile, source.password, handler, evaluatorOptions, enableXfa, docBaseUrl); pdfManagerCapability.resolve(newPdfManager); } catch (ex) { pdfManagerCapability.reject(ex); @@ -360,8 +258,8 @@ class WorkerMessageHandler { cachedChunks = []; }; - var readPromise = new Promise(function (resolve, reject) { - var readChunk = function ({ + const readPromise = new Promise(function (resolve, reject) { + const readChunk = function ({ value, done }) { @@ -424,7 +322,7 @@ class WorkerMessageHandler { ensureNotTerminated(); if (ex instanceof _util.PasswordException) { - var task = new WorkerTask(`PasswordException: response ${ex.code}`); + const task = new WorkerTask(`PasswordException: response ${ex.code}`); startWorkerTask(task); handler.sendWithPromise("PasswordRequest", ex).then(function ({ password @@ -462,14 +360,17 @@ class WorkerMessageHandler { } ensureNotTerminated(); - var evaluatorOptions = { + const evaluatorOptions = { maxImageSize: data.maxImageSize, disableFontFace: data.disableFontFace, ignoreErrors: data.ignoreErrors, isEvalSupported: data.isEvalSupported, - fontExtraProperties: data.fontExtraProperties + fontExtraProperties: data.fontExtraProperties, + useSystemFonts: data.useSystemFonts, + cMapUrl: data.cMapUrl, + standardFontDataUrl: data.standardFontDataUrl }; - getPdfManager(data, evaluatorOptions).then(function (newPdfManager) { + getPdfManager(data, evaluatorOptions, data.enableXfa).then(function (newPdfManager) { if (terminated) { newPdfManager.terminate(new _util.AbortException("Worker was terminated.")); throw new Error("Worker was terminated"); @@ -496,10 +397,8 @@ class WorkerMessageHandler { }); }); }); - handler.on("GetPageIndex", function wphSetupGetPageIndex({ - ref - }) { - const pageRef = _primitives.Ref.get(ref.num, ref.gen); + handler.on("GetPageIndex", function wphSetupGetPageIndex(data) { + const pageRef = _primitives.Ref.get(data.num, data.gen); return pdfManager.ensureCatalog("getPageIndex", [pageRef]); }); @@ -530,6 +429,16 @@ class WorkerMessageHandler { handler.on("GetJavaScript", function wphSetupGetJavaScript(data) { return pdfManager.ensureCatalog("javaScript"); }); + handler.on("GetDocJSActions", function wphSetupGetDocJSActions(data) { + return pdfManager.ensureCatalog("jsActions"); + }); + handler.on("GetPageJSActions", function ({ + pageIndex + }) { + return pdfManager.getPage(pageIndex).then(function (page) { + return pdfManager.ensure(page, "jsActions"); + }); + }); handler.on("GetOutline", function wphSetupGetOutline(data) { return pdfManager.ensureCatalog("documentOutline"); }); @@ -542,86 +451,157 @@ class WorkerMessageHandler { handler.on("GetMetadata", function wphSetupGetMetadata(data) { return Promise.all([pdfManager.ensureDoc("documentInfo"), pdfManager.ensureCatalog("metadata")]); }); + handler.on("GetMarkInfo", function wphSetupGetMarkInfo(data) { + return pdfManager.ensureCatalog("markInfo"); + }); handler.on("GetData", function wphSetupGetData(data) { pdfManager.requestLoadedStream(); return pdfManager.onLoadedStream().then(function (stream) { return stream.bytes; }); }); - handler.on("GetStats", function wphSetupGetStats(data) { - return pdfManager.ensureXRef("stats"); - }); handler.on("GetAnnotations", function ({ pageIndex, intent }) { return pdfManager.getPage(pageIndex).then(function (page) { - return page.getAnnotationsData(intent); + const task = new WorkerTask(`GetAnnotations: page ${pageIndex}`); + startWorkerTask(task); + return page.getAnnotationsData(handler, task, intent).then(data => { + finishWorkerTask(task); + return data; + }, reason => { + finishWorkerTask(task); + }); }); }); + handler.on("GetFieldObjects", function (data) { + return pdfManager.ensureDoc("fieldObjects"); + }); + handler.on("HasJSActions", function (data) { + return pdfManager.ensureDoc("hasJSActions"); + }); + handler.on("GetCalculationOrderIds", function (data) { + return pdfManager.ensureDoc("calculationOrderIds"); + }); handler.on("SaveDocument", function ({ + isPureXfa, numPages, annotationStorage, filename }) { pdfManager.requestLoadedStream(); - const promises = [pdfManager.onLoadedStream()]; - const document = pdfManager.pdfDocument; + const newAnnotationsByPage = !isPureXfa ? (0, _core_utils.getNewAnnotationsMap)(annotationStorage) : null; + const promises = [pdfManager.onLoadedStream(), pdfManager.ensureCatalog("acroForm"), pdfManager.ensureCatalog("acroFormRef"), pdfManager.ensureDoc("xref"), pdfManager.ensureDoc("startXRef")]; - for (let pageIndex = 0; pageIndex < numPages; pageIndex++) { - promises.push(pdfManager.getPage(pageIndex).then(function (page) { - const task = new WorkerTask(`Save: page ${pageIndex}`); - return page.save(handler, task, annotationStorage); - })); + if (newAnnotationsByPage) { + for (const [pageIndex, annotations] of newAnnotationsByPage) { + promises.push(pdfManager.getPage(pageIndex).then(page => { + const task = new WorkerTask(`Save (editor): page ${pageIndex}`); + return page.saveNewAnnotations(handler, task, annotations).finally(function () { + finishWorkerTask(task); + }); + })); + } } - return Promise.all(promises).then(([stream, ...refs]) => { + if (isPureXfa) { + promises.push(pdfManager.serializeXfaData(annotationStorage)); + } else { + for (let pageIndex = 0; pageIndex < numPages; pageIndex++) { + promises.push(pdfManager.getPage(pageIndex).then(function (page) { + const task = new WorkerTask(`Save: page ${pageIndex}`); + return page.save(handler, task, annotationStorage).finally(function () { + finishWorkerTask(task); + }); + })); + } + } + + return Promise.all(promises).then(function ([stream, acroForm, acroFormRef, xref, startXRef, ...refs]) { let newRefs = []; + let xfaData = null; - for (const ref of refs) { - newRefs = ref.filter(x => x !== null).reduce((a, b) => a.concat(b), newRefs); + if (isPureXfa) { + xfaData = refs[0]; + + if (!xfaData) { + return stream.bytes; + } + } else { + newRefs = refs.flat(2); + + if (newRefs.length === 0) { + return stream.bytes; + } } - if (newRefs.length === 0) { - return stream.bytes; + const xfa = acroForm instanceof _primitives.Dict && acroForm.get("XFA") || null; + let xfaDatasetsRef = null; + let hasXfaDatasetsEntry = false; + + if (Array.isArray(xfa)) { + for (let i = 0, ii = xfa.length; i < ii; i += 2) { + if (xfa[i] === "datasets") { + xfaDatasetsRef = xfa[i + 1]; + acroFormRef = null; + hasXfaDatasetsEntry = true; + } + } + + if (xfaDatasetsRef === null) { + xfaDatasetsRef = xref.getNewRef(); + } + } else if (xfa) { + acroFormRef = null; + (0, _util.warn)("Unsupported XFA type."); } - const xref = document.xref; let newXrefInfo = Object.create(null); if (xref.trailer) { - const _info = Object.create(null); - + const infoObj = Object.create(null); const xrefInfo = xref.trailer.get("Info") || null; - if (xrefInfo) { + if (xrefInfo instanceof _primitives.Dict) { xrefInfo.forEach((key, value) => { - if ((0, _util.isString)(key) && (0, _util.isString)(value)) { - _info[key] = (0, _util.stringToPDFString)(value); + if (typeof value === "string") { + infoObj[key] = (0, _util.stringToPDFString)(value); } }); } newXrefInfo = { rootRef: xref.trailer.getRaw("Root") || null, - encrypt: xref.trailer.getRaw("Encrypt") || null, + encryptRef: xref.trailer.getRaw("Encrypt") || null, newRef: xref.getNewRef(), infoRef: xref.trailer.getRaw("Info") || null, - info: _info, - fileIds: xref.trailer.getRaw("ID") || null, - startXRef: document.startXRef, + info: infoObj, + fileIds: xref.trailer.get("ID") || null, + startXRef, filename }; } xref.resetNewRef(); - return (0, _writer.incrementalUpdate)(stream.bytes, newXrefInfo, newRefs); + return (0, _writer.incrementalUpdate)({ + originalData: stream.bytes, + xrefInfo: newXrefInfo, + newRefs, + xref, + hasXfa: !!xfa, + xfaDatasetsRef, + hasXfaDatasetsEntry, + acroFormRef, + acroForm, + xfaData + }); }); }); handler.on("GetOperatorList", function wphSetupRenderPage(data, sink) { - var pageIndex = data.pageIndex; + const pageIndex = data.pageIndex; pdfManager.getPage(pageIndex).then(function (page) { - var task = new WorkerTask(`GetOperatorList: page ${pageIndex}`); + const task = new WorkerTask(`GetOperatorList: page ${pageIndex}`); startWorkerTask(task); const start = verbosity >= _util.VerbosityLevel.INFOS ? Date.now() : 0; page.getOperatorList({ @@ -629,7 +609,7 @@ class WorkerMessageHandler { sink, task, intent: data.intent, - renderInteractiveForms: data.renderInteractiveForms, + cacheKey: data.cacheKey, annotationStorage: data.annotationStorage }).then(function (operatorListInfo) { finishWorkerTask(task); @@ -652,23 +632,18 @@ class WorkerMessageHandler { sink.error(reason); }); }); - }, this); + }); handler.on("GetTextContent", function wphExtractText(data, sink) { - var pageIndex = data.pageIndex; - - sink.onPull = function (desiredSize) {}; - - sink.onCancel = function (reason) {}; - + const pageIndex = data.pageIndex; pdfManager.getPage(pageIndex).then(function (page) { - var task = new WorkerTask("GetTextContent: page " + pageIndex); + const task = new WorkerTask("GetTextContent: page " + pageIndex); startWorkerTask(task); const start = verbosity >= _util.VerbosityLevel.INFOS ? Date.now() : 0; page.extractTextContent({ handler, task, sink, - normalizeWhitespace: data.normalizeWhitespace, + includeMarkedContent: data.includeMarkedContent, combineTextItems: data.combineTextItems }).then(function () { finishWorkerTask(task); @@ -689,6 +664,11 @@ class WorkerMessageHandler { }); }); }); + handler.on("GetStructTree", function wphGetStructTree(data) { + return pdfManager.getPage(data.pageIndex).then(function (page) { + return pdfManager.ensure(page, "getStructTree"); + }); + }); handler.on("FontFallback", function (data) { return pdfManager.fontFallback(data.id, handler); }); @@ -705,17 +685,18 @@ class WorkerMessageHandler { waitOn.push(cleanupPromise); pdfManager = null; } else { - (0, _primitives.clearPrimitiveCaches)(); + (0, _cleanup_helper.clearGlobalCaches)(); } if (cancelXHRs) { cancelXHRs(new _util.AbortException("Worker was terminated.")); } - WorkerTasks.forEach(function (task) { + for (const task of WorkerTasks) { waitOn.push(task.finished); task.terminate(); - }); + } + return Promise.all(waitOn).then(function () { handler.destroy(); handler = null; @@ -729,7 +710,7 @@ class WorkerMessageHandler { } static initializeFromPort(port) { - var handler = new _message_handler.MessageHandler("worker", "main", port); + const handler = new _message_handler.MessageHandler("worker", "main", port); WorkerMessageHandler.setup(handler, port); handler.send("ready", null); } @@ -748,41 +729,39 @@ if (typeof window === "undefined" && !_is_node.isNodeJS && typeof self !== "unde /***/ }), /* 2 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.VerbosityLevel = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.UNSUPPORTED_FEATURES = exports.TextRenderingMode = exports.StreamType = exports.RenderingIntentFlag = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.PageActionEventType = exports.OPS = exports.MissingPDFException = exports.LINE_FACTOR = exports.LINE_DESCENT_FACTOR = exports.InvalidPDFException = exports.ImageKind = exports.IDENTITY_MATRIX = exports.FormatError = exports.FontType = exports.FeatureTest = exports.FONT_IDENTITY_MATRIX = exports.DocumentActionEventType = exports.CMapCompressionType = exports.BaseException = exports.AnnotationType = exports.AnnotationStateModelType = exports.AnnotationReviewState = exports.AnnotationReplyType = exports.AnnotationMode = exports.AnnotationMarkedState = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationEditorType = exports.AnnotationEditorPrefix = exports.AnnotationEditorParamsType = exports.AnnotationBorderStyleType = exports.AnnotationActionEventType = exports.AbortException = void 0; exports.arrayByteLength = arrayByteLength; exports.arraysToBytes = arraysToBytes; exports.assert = assert; exports.bytesToString = bytesToString; exports.createPromiseCapability = createPromiseCapability; +exports.createValidAbsoluteUrl = createValidAbsoluteUrl; exports.escapeString = escapeString; exports.getModificationDate = getModificationDate; exports.getVerbosityLevel = getVerbosityLevel; exports.info = info; exports.isArrayBuffer = isArrayBuffer; exports.isArrayEqual = isArrayEqual; -exports.isBool = isBool; -exports.isNum = isNum; -exports.isString = isString; -exports.isSameOrigin = isSameOrigin; -exports.createValidAbsoluteUrl = createValidAbsoluteUrl; -exports.removeNullCharacters = removeNullCharacters; +exports.isAscii = isAscii; +exports.objectFromMap = objectFromMap; +exports.objectSize = objectSize; exports.setVerbosityLevel = setVerbosityLevel; exports.shadow = shadow; exports.string32 = string32; exports.stringToBytes = stringToBytes; exports.stringToPDFString = stringToPDFString; +exports.stringToUTF16BEString = stringToUTF16BEString; exports.stringToUTF8String = stringToUTF8String; +exports.unreachable = unreachable; exports.utf8StringToString = utf8StringToString; exports.warn = warn; -exports.unreachable = unreachable; -exports.IsEvalSupportedCached = exports.IsLittleEndianCached = exports.createObjectURL = exports.FormatError = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.MissingPDFException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationStateModelType = exports.AnnotationReviewState = exports.AnnotationReplyType = exports.AnnotationMarkedState = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = exports.BaseException = void 0; __w_pdfjs_require__(3); @@ -790,6 +769,45 @@ const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; exports.IDENTITY_MATRIX = IDENTITY_MATRIX; const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX; +const LINE_FACTOR = 1.35; +exports.LINE_FACTOR = LINE_FACTOR; +const LINE_DESCENT_FACTOR = 0.35; +exports.LINE_DESCENT_FACTOR = LINE_DESCENT_FACTOR; +const RenderingIntentFlag = { + ANY: 0x01, + DISPLAY: 0x02, + PRINT: 0x04, + ANNOTATIONS_FORMS: 0x10, + ANNOTATIONS_STORAGE: 0x20, + ANNOTATIONS_DISABLE: 0x40, + OPLIST: 0x100 +}; +exports.RenderingIntentFlag = RenderingIntentFlag; +const AnnotationMode = { + DISABLE: 0, + ENABLE: 1, + ENABLE_FORMS: 2, + ENABLE_STORAGE: 3 +}; +exports.AnnotationMode = AnnotationMode; +const AnnotationEditorPrefix = "pdfjs_internal_editor_"; +exports.AnnotationEditorPrefix = AnnotationEditorPrefix; +const AnnotationEditorType = { + DISABLE: -1, + NONE: 0, + FREETEXT: 3, + INK: 15 +}; +exports.AnnotationEditorType = AnnotationEditorType; +const AnnotationEditorParamsType = { + FREETEXT_SIZE: 1, + FREETEXT_COLOR: 2, + FREETEXT_OPACITY: 3, + INK_COLOR: 11, + INK_THICKNESS: 12, + INK_OPACITY: 13 +}; +exports.AnnotationEditorParamsType = AnnotationEditorParamsType; const PermissionFlag = { PRINT: 0x04, MODIFY_CONTENTS: 0x08, @@ -915,6 +933,36 @@ const AnnotationBorderStyleType = { UNDERLINE: 5 }; exports.AnnotationBorderStyleType = AnnotationBorderStyleType; +const AnnotationActionEventType = { + E: "Mouse Enter", + X: "Mouse Exit", + D: "Mouse Down", + U: "Mouse Up", + Fo: "Focus", + Bl: "Blur", + PO: "PageOpen", + PC: "PageClose", + PV: "PageVisible", + PI: "PageInvisible", + K: "Keystroke", + F: "Format", + V: "Validate", + C: "Calculate" +}; +exports.AnnotationActionEventType = AnnotationActionEventType; +const DocumentActionEventType = { + WC: "WillClose", + WS: "WillSave", + DS: "DidSave", + WP: "WillPrint", + DP: "DidPrint" +}; +exports.DocumentActionEventType = DocumentActionEventType; +const PageActionEventType = { + O: "PageOpen", + C: "PageClose" +}; +exports.PageActionEventType = PageActionEventType; const StreamType = { UNKNOWN: "UNKNOWN", FLATE: "FLATE", @@ -931,6 +979,7 @@ exports.StreamType = StreamType; const FontType = { UNKNOWN: "UNKNOWN", TYPE1: "TYPE1", + TYPE1STANDARD: "TYPE1STANDARD", TYPE1C: "TYPE1C", CIDFONTTYPE0: "CIDFONTTYPE0", CIDFONTTYPE0C: "CIDFONTTYPE0C", @@ -1052,6 +1101,7 @@ const UNSUPPORTED_FEATURES = { unknown: "unknown", forms: "forms", javaScript: "javaScript", + signatures: "signatures", smask: "smask", shadingPattern: "shadingPattern", font: "font", @@ -1066,8 +1116,10 @@ const UNSUPPORTED_FEATURES = { errorOperatorList: "errorOperatorList", errorFontToUnicode: "errorFontToUnicode", errorFontLoadNative: "errorFontLoadNative", + errorFontBuildPath: "errorFontBuildPath", errorFontGetPath: "errorFontGetPath", - errorMarkedContent: "errorMarkedContent" + errorMarkedContent: "errorMarkedContent", + errorContentSubStream: "errorContentSubStream" }; exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; const PasswordResponses = { @@ -1109,23 +1161,6 @@ function assert(cond, msg) { } } -function isSameOrigin(baseUrl, otherUrl) { - let base; - - try { - base = new URL(baseUrl); - - if (!base.origin || base.origin === "null") { - return false; - } - } catch (e) { - return false; - } - - const other = new URL(otherUrl, base); - return base.origin === other.origin; -} - function _isValidProtocol(url) { if (!url) { return false; @@ -1144,12 +1179,28 @@ function _isValidProtocol(url) { } } -function createValidAbsoluteUrl(url, baseUrl) { +function createValidAbsoluteUrl(url, baseUrl = null, options = null) { if (!url) { return null; } try { + if (options && typeof url === "string") { + if (options.addDefaultProtocol && url.startsWith("www.")) { + const dots = url.match(/\./g); + + if (dots && dots.length >= 2) { + url = `http://${url}`; + } + } + + if (options.tryConvertEncoding) { + try { + url = stringToUTF8String(url); + } catch (ex) {} + } + } + const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); if (_isValidProtocol(absoluteUrl)) { @@ -1171,13 +1222,13 @@ function shadow(obj, prop, value) { } const BaseException = function BaseExceptionClosure() { - function BaseException(message) { + function BaseException(message, name) { if (this.constructor === BaseException) { unreachable("Cannot initialize BaseException."); } this.message = message; - this.name = this.constructor.name; + this.name = name; } BaseException.prototype = new Error(); @@ -1189,7 +1240,7 @@ exports.BaseException = BaseException; class PasswordException extends BaseException { constructor(msg, code) { - super(msg); + super(msg, "PasswordException"); this.code = code; } @@ -1199,7 +1250,7 @@ exports.PasswordException = PasswordException; class UnknownErrorException extends BaseException { constructor(msg, details) { - super(msg); + super(msg, "UnknownErrorException"); this.details = details; } @@ -1207,17 +1258,27 @@ class UnknownErrorException extends BaseException { exports.UnknownErrorException = UnknownErrorException; -class InvalidPDFException extends BaseException {} +class InvalidPDFException extends BaseException { + constructor(msg) { + super(msg, "InvalidPDFException"); + } + +} exports.InvalidPDFException = InvalidPDFException; -class MissingPDFException extends BaseException {} +class MissingPDFException extends BaseException { + constructor(msg) { + super(msg, "MissingPDFException"); + } + +} exports.MissingPDFException = MissingPDFException; class UnexpectedResponseException extends BaseException { constructor(msg, status) { - super(msg); + super(msg, "UnexpectedResponseException"); this.status = status; } @@ -1225,26 +1286,29 @@ class UnexpectedResponseException extends BaseException { exports.UnexpectedResponseException = UnexpectedResponseException; -class FormatError extends BaseException {} +class FormatError extends BaseException { + constructor(msg) { + super(msg, "FormatError"); + } + +} exports.FormatError = FormatError; -class AbortException extends BaseException {} - -exports.AbortException = AbortException; -const NullCharactersRegExp = /\x00/g; - -function removeNullCharacters(str) { - if (typeof str !== "string") { - warn("The argument for removeNullCharacters must be a string."); - return str; +class AbortException extends BaseException { + constructor(msg) { + super(msg, "AbortException"); } - return str.replace(NullCharactersRegExp, ""); } +exports.AbortException = AbortException; + function bytesToString(bytes) { - assert(bytes !== null && typeof bytes === "object" && bytes.length !== undefined, "Invalid argument for bytesToString"); + if (typeof bytes !== "object" || bytes === null || bytes.length === undefined) { + unreachable("Invalid argument for bytesToString"); + } + const length = bytes.length; const MAX_ARGUMENT_COUNT = 8192; @@ -1264,7 +1328,10 @@ function bytesToString(bytes) { } function stringToBytes(str) { - assert(typeof str === "string", "Invalid argument for stringToBytes"); + if (typeof str !== "string") { + unreachable("Invalid argument for stringToBytes"); + } + const length = str.length; const bytes = new Uint8Array(length); @@ -1280,8 +1347,11 @@ function arrayByteLength(arr) { return arr.length; } - assert(arr.byteLength !== undefined, "arrayByteLength - invalid argument."); - return arr.byteLength; + if (arr.byteLength !== undefined) { + return arr.byteLength; + } + + unreachable("Invalid argument for arrayByteLength"); } function arraysToBytes(arr) { @@ -1323,6 +1393,20 @@ function string32(value) { return String.fromCharCode(value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff); } +function objectSize(obj) { + return Object.keys(obj).length; +} + +function objectFromMap(map) { + const obj = Object.create(null); + + for (const [key, value] of map) { + obj[key] = value; + } + + return obj; +} + function isLittleEndian() { const buffer8 = new Uint8Array(4); buffer8[0] = 1; @@ -1330,14 +1414,6 @@ function isLittleEndian() { return view32[0] === 1; } -const IsLittleEndianCached = { - get value() { - return shadow(this, "value", isLittleEndian()); - } - -}; -exports.IsLittleEndianCached = IsLittleEndianCached; - function isEvalSupported() { try { new Function(""); @@ -1347,21 +1423,81 @@ function isEvalSupported() { } } -const IsEvalSupportedCached = { - get value() { - return shadow(this, "value", isEvalSupported()); +class FeatureTest { + static get isLittleEndian() { + return shadow(this, "isLittleEndian", isLittleEndian()); } -}; -exports.IsEvalSupportedCached = IsEvalSupportedCached; -const rgbBuf = ["rgb(", 0, ",", 0, ",", 0, ")"]; + static get isEvalSupported() { + return shadow(this, "isEvalSupported", isEvalSupported()); + } + + static get isOffscreenCanvasSupported() { + return shadow(this, "isOffscreenCanvasSupported", typeof OffscreenCanvas !== "undefined"); + } + +} + +exports.FeatureTest = FeatureTest; +const hexNumbers = [...Array(256).keys()].map(n => n.toString(16).padStart(2, "0")); class Util { - static makeCssRgb(r, g, b) { - rgbBuf[1] = r; - rgbBuf[3] = g; - rgbBuf[5] = b; - return rgbBuf.join(""); + static makeHexColor(r, g, b) { + return `#${hexNumbers[r]}${hexNumbers[g]}${hexNumbers[b]}`; + } + + static scaleMinMax(transform, minMax) { + let temp; + + if (transform[0]) { + if (transform[0] < 0) { + temp = minMax[0]; + minMax[0] = minMax[1]; + minMax[1] = temp; + } + + minMax[0] *= transform[0]; + minMax[1] *= transform[0]; + + if (transform[3] < 0) { + temp = minMax[2]; + minMax[2] = minMax[3]; + minMax[3] = temp; + } + + minMax[2] *= transform[3]; + minMax[3] *= transform[3]; + } else { + temp = minMax[0]; + minMax[0] = minMax[2]; + minMax[2] = temp; + temp = minMax[1]; + minMax[1] = minMax[3]; + minMax[3] = temp; + + if (transform[1] < 0) { + temp = minMax[2]; + minMax[2] = minMax[3]; + minMax[3] = temp; + } + + minMax[2] *= transform[1]; + minMax[3] *= transform[1]; + + if (transform[2] < 0) { + temp = minMax[0]; + minMax[0] = minMax[1]; + minMax[1] = temp; + } + + minMax[0] *= transform[2]; + minMax[1] *= transform[2]; + } + + minMax[0] += transform[4]; + minMax[1] += transform[4]; + minMax[2] += transform[5]; + minMax[3] += transform[5]; } static transform(m1, m2) { @@ -1405,7 +1541,7 @@ class Util { const c = m[2] * transpose[0] + m[3] * transpose[2]; const d = m[2] * transpose[1] + m[3] * transpose[3]; const first = (a + d) / 2; - const second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; + const second = Math.sqrt((a + d) ** 2 - 4 * (a * d - c * b)) / 2; const sx = first + second || 1; const sy = first - second || 1; return [Math.sqrt(sx), Math.sqrt(sy)]; @@ -1428,62 +1564,157 @@ class Util { } static intersect(rect1, rect2) { - function compare(a, b) { - return a - b; - } + const xLow = Math.max(Math.min(rect1[0], rect1[2]), Math.min(rect2[0], rect2[2])); + const xHigh = Math.min(Math.max(rect1[0], rect1[2]), Math.max(rect2[0], rect2[2])); - const orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare); - const orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare); - const result = []; - rect1 = Util.normalizeRect(rect1); - rect2 = Util.normalizeRect(rect2); - - if (orderedX[0] === rect1[0] && orderedX[1] === rect2[0] || orderedX[0] === rect2[0] && orderedX[1] === rect1[0]) { - result[0] = orderedX[1]; - result[2] = orderedX[2]; - } else { + if (xLow > xHigh) { return null; } - if (orderedY[0] === rect1[1] && orderedY[1] === rect2[1] || orderedY[0] === rect2[1] && orderedY[1] === rect1[1]) { - result[1] = orderedY[1]; - result[3] = orderedY[2]; - } else { + const yLow = Math.max(Math.min(rect1[1], rect1[3]), Math.min(rect2[1], rect2[3])); + const yHigh = Math.min(Math.max(rect1[1], rect1[3]), Math.max(rect2[1], rect2[3])); + + if (yLow > yHigh) { return null; } - return result; + return [xLow, yLow, xHigh, yHigh]; + } + + static bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3) { + const tvalues = [], + bounds = [[], []]; + let a, b, c, t, t1, t2, b2ac, sqrtb2ac; + + for (let i = 0; i < 2; ++i) { + if (i === 0) { + b = 6 * x0 - 12 * x1 + 6 * x2; + a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; + c = 3 * x1 - 3 * x0; + } else { + b = 6 * y0 - 12 * y1 + 6 * y2; + a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; + c = 3 * y1 - 3 * y0; + } + + if (Math.abs(a) < 1e-12) { + if (Math.abs(b) < 1e-12) { + continue; + } + + t = -c / b; + + if (0 < t && t < 1) { + tvalues.push(t); + } + + continue; + } + + b2ac = b * b - 4 * c * a; + sqrtb2ac = Math.sqrt(b2ac); + + if (b2ac < 0) { + continue; + } + + t1 = (-b + sqrtb2ac) / (2 * a); + + if (0 < t1 && t1 < 1) { + tvalues.push(t1); + } + + t2 = (-b - sqrtb2ac) / (2 * a); + + if (0 < t2 && t2 < 1) { + tvalues.push(t2); + } + } + + let j = tvalues.length, + mt; + const jlen = j; + + while (j--) { + t = tvalues[j]; + mt = 1 - t; + bounds[0][j] = mt * mt * mt * x0 + 3 * mt * mt * t * x1 + 3 * mt * t * t * x2 + t * t * t * x3; + bounds[1][j] = mt * mt * mt * y0 + 3 * mt * mt * t * y1 + 3 * mt * t * t * y2 + t * t * t * y3; + } + + bounds[0][jlen] = x0; + bounds[1][jlen] = y0; + bounds[0][jlen + 1] = x3; + bounds[1][jlen + 1] = y3; + bounds[0].length = bounds[1].length = jlen + 2; + return [Math.min(...bounds[0]), Math.min(...bounds[1]), Math.max(...bounds[0]), Math.max(...bounds[1])]; } } exports.Util = Util; -const PDFStringTranslateTable = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160, 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC]; +const PDFStringTranslateTable = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2d8, 0x2c7, 0x2c6, 0x2d9, 0x2dd, 0x2db, 0x2da, 0x2dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x141, 0x152, 0x160, 0x178, 0x17d, 0x131, 0x142, 0x153, 0x161, 0x17e, 0, 0x20ac]; function stringToPDFString(str) { - const length = str.length, - strBuf = []; + if (str[0] >= "\xEF") { + let encoding; - if (str[0] === "\xFE" && str[1] === "\xFF") { - for (let i = 2; i < length; i += 2) { - strBuf.push(String.fromCharCode(str.charCodeAt(i) << 8 | str.charCodeAt(i + 1))); + if (str[0] === "\xFE" && str[1] === "\xFF") { + encoding = "utf-16be"; + } else if (str[0] === "\xFF" && str[1] === "\xFE") { + encoding = "utf-16le"; + } else if (str[0] === "\xEF" && str[1] === "\xBB" && str[2] === "\xBF") { + encoding = "utf-8"; } - } else if (str[0] === "\xFF" && str[1] === "\xFE") { - for (let i = 2; i < length; i += 2) { - strBuf.push(String.fromCharCode(str.charCodeAt(i + 1) << 8 | str.charCodeAt(i))); - } - } else { - for (let i = 0; i < length; ++i) { - const code = PDFStringTranslateTable[str.charCodeAt(i)]; - strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); + + if (encoding) { + try { + const decoder = new TextDecoder(encoding, { + fatal: true + }); + const buffer = stringToBytes(str); + return decoder.decode(buffer); + } catch (ex) { + warn(`stringToPDFString: "${ex}".`); + } } } + const strBuf = []; + + for (let i = 0, ii = str.length; i < ii; i++) { + const code = PDFStringTranslateTable[str.charCodeAt(i)]; + strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); + } + return strBuf.join(""); } function escapeString(str) { - return str.replace(/([\(\)\\])/g, "\\$1"); + return str.replace(/([()\\\n\r])/g, match => { + if (match === "\n") { + return "\\n"; + } else if (match === "\r") { + return "\\r"; + } + + return `\\${match}`; + }); +} + +function isAscii(str) { + return /^[\x00-\x7F]*$/.test(str); +} + +function stringToUTF16BEString(str) { + const buf = ["\xFE\xFF"]; + + for (let i = 0, ii = str.length; i < ii; i++) { + const char = str.charCodeAt(i); + buf.push(String.fromCharCode(char >> 8 & 0xff), String.fromCharCode(char & 0xff)); + } + + return buf.join(""); } function stringToUTF8String(str) { @@ -1494,18 +1725,6 @@ function utf8StringToString(str) { return unescape(encodeURIComponent(str)); } -function isBool(v) { - return typeof v === "boolean"; -} - -function isNum(v) { - return typeof v === "number"; -} - -function isString(v) { - return typeof v === "string"; -} - function isArrayBuffer(v) { return typeof v === "object" && v !== null && v.byteLength !== undefined; } @@ -1515,13 +1734,17 @@ function isArrayEqual(arr1, arr2) { return false; } - return arr1.every(function (element, index) { - return element === arr2[index]; - }); + for (let i = 0, ii = arr1.length; i < ii; i++) { + if (arr1[i] !== arr2[i]) { + return false; + } + } + + return true; } -function getModificationDate(date = new Date(Date.now())) { - const buffer = [date.getUTCFullYear().toString(), (date.getUTCMonth() + 1).toString().padStart(2, "0"), (date.getUTCDate() + 1).toString().padStart(2, "0"), date.getUTCHours().toString().padStart(2, "0"), date.getUTCMinutes().toString().padStart(2, "0"), date.getUTCSeconds().toString().padStart(2, "0")]; +function getModificationDate(date = new Date()) { + const buffer = [date.getUTCFullYear().toString(), (date.getUTCMonth() + 1).toString().padStart(2, "0"), date.getUTCDate().toString().padStart(2, "0"), date.getUTCHours().toString().padStart(2, "0"), date.getUTCMinutes().toString().padStart(2, "0"), date.getUTCSeconds().toString().padStart(2, "0")]; return buffer.join(""); } @@ -1548,40 +1771,10 @@ function createPromiseCapability() { return capability; } -const createObjectURL = function createObjectURLClosure() { - const digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - return function createObjectURL(data, contentType, forceDataSchema = false) { - if (!forceDataSchema && URL.createObjectURL) { - const blob = new Blob([data], { - type: contentType - }); - return URL.createObjectURL(blob); - } - - let buffer = `data:${contentType};base64,`; - - for (let i = 0, ii = data.length; i < ii; i += 3) { - const b1 = data[i] & 0xff; - const b2 = data[i + 1] & 0xff; - const b3 = data[i + 2] & 0xff; - const d1 = b1 >> 2, - d2 = (b1 & 3) << 4 | b2 >> 4; - const d3 = i + 1 < ii ? (b2 & 0xf) << 2 | b3 >> 6 : 64; - const d4 = i + 2 < ii ? b3 & 0x3f : 64; - buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; - } - - return buffer; - }; -}(); - -exports.createObjectURL = createObjectURL; - /***/ }), /* 3 */ -/***/ (function(module, exports, __w_pdfjs_require__) { +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { -"use strict"; var _is_node = __w_pdfjs_require__(4); @@ -1590,95 +1783,92 @@ var _is_node = __w_pdfjs_require__(4); /***/ }), /* 4 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.isNodeJS = void 0; const isNodeJS = typeof process === "object" && process + "" === "[object process]" && !process.versions.nw && !(process.versions.electron && process.type && process.type !== "browser"); exports.isNodeJS = isNodeJS; /***/ }), /* 5 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.RefSetCache = exports.RefSet = exports.Ref = exports.Name = exports.EOF = exports.Dict = exports.Cmd = exports.CIRCULAR_REF = void 0; exports.clearPrimitiveCaches = clearPrimitiveCaches; -exports.isEOF = isEOF; exports.isCmd = isCmd; exports.isDict = isDict; exports.isName = isName; -exports.isRef = isRef; exports.isRefsEqual = isRefsEqual; -exports.isStream = isStream; -exports.RefSetCache = exports.RefSet = exports.Ref = exports.Name = exports.Dict = exports.Cmd = exports.EOF = void 0; var _util = __w_pdfjs_require__(2); -var EOF = {}; +const CIRCULAR_REF = Symbol("CIRCULAR_REF"); +exports.CIRCULAR_REF = CIRCULAR_REF; +const EOF = Symbol("EOF"); exports.EOF = EOF; -var Name = function NameClosure() { +const Name = function NameClosure() { let nameCache = Object.create(null); - function Name(name) { - this.name = name; + class Name { + constructor(name) { + this.name = name; + } + + static get(name) { + return nameCache[name] || (nameCache[name] = new Name(name)); + } + + static _clearCache() { + nameCache = Object.create(null); + } + } - Name.prototype = {}; - - Name.get = function Name_get(name) { - var nameValue = nameCache[name]; - return nameValue ? nameValue : nameCache[name] = new Name(name); - }; - - Name._clearCache = function () { - nameCache = Object.create(null); - }; - return Name; }(); exports.Name = Name; -var Cmd = function CmdClosure() { +const Cmd = function CmdClosure() { let cmdCache = Object.create(null); - function Cmd(cmd) { - this.cmd = cmd; + class Cmd { + constructor(cmd) { + this.cmd = cmd; + } + + static get(cmd) { + return cmdCache[cmd] || (cmdCache[cmd] = new Cmd(cmd)); + } + + static _clearCache() { + cmdCache = Object.create(null); + } + } - Cmd.prototype = {}; - - Cmd.get = function Cmd_get(cmd) { - var cmdValue = cmdCache[cmd]; - return cmdValue ? cmdValue : cmdCache[cmd] = new Cmd(cmd); - }; - - Cmd._clearCache = function () { - cmdCache = Object.create(null); - }; - return Cmd; }(); exports.Cmd = Cmd; -var Dict = function DictClosure() { - var nonSerializable = function nonSerializableClosure() { - return nonSerializable; - }; +const nonSerializable = function nonSerializableClosure() { + return nonSerializable; +}; - function Dict(xref) { +class Dict { + constructor(xref = null) { this._map = Object.create(null); this.xref = xref; this.objId = null; @@ -1686,118 +1876,121 @@ var Dict = function DictClosure() { this.__nonSerializable__ = nonSerializable; } - Dict.prototype = { - assignXref: function Dict_assignXref(newXref) { - this.xref = newXref; - }, + assignXref(newXref) { + this.xref = newXref; + } - get size() { - return Object.keys(this._map).length; - }, + get size() { + return Object.keys(this._map).length; + } - get(key1, key2, key3) { - let value = this._map[key1]; + get(key1, key2, key3) { + let value = this._map[key1]; - if (value === undefined && key2 !== undefined) { - value = this._map[key2]; + if (value === undefined && key2 !== undefined) { + value = this._map[key2]; - if (value === undefined && key3 !== undefined) { - value = this._map[key3]; - } + if (value === undefined && key3 !== undefined) { + value = this._map[key3]; } + } - if (value instanceof Ref && this.xref) { - return this.xref.fetch(value, this.suppressEncryption); + if (value instanceof Ref && this.xref) { + return this.xref.fetch(value, this.suppressEncryption); + } + + return value; + } + + async getAsync(key1, key2, key3) { + let value = this._map[key1]; + + if (value === undefined && key2 !== undefined) { + value = this._map[key2]; + + if (value === undefined && key3 !== undefined) { + value = this._map[key3]; } + } - return value; - }, + if (value instanceof Ref && this.xref) { + return this.xref.fetchAsync(value, this.suppressEncryption); + } - async getAsync(key1, key2, key3) { - let value = this._map[key1]; + return value; + } - if (value === undefined && key2 !== undefined) { - value = this._map[key2]; + getArray(key1, key2, key3) { + let value = this._map[key1]; - if (value === undefined && key3 !== undefined) { - value = this._map[key3]; - } + if (value === undefined && key2 !== undefined) { + value = this._map[key2]; + + if (value === undefined && key3 !== undefined) { + value = this._map[key3]; } + } - if (value instanceof Ref && this.xref) { - return this.xref.fetchAsync(value, this.suppressEncryption); - } - - return value; - }, - - getArray(key1, key2, key3) { - let value = this.get(key1, key2, key3); - - if (!Array.isArray(value) || !this.xref) { - return value; - } + if (value instanceof Ref && this.xref) { + value = this.xref.fetch(value, this.suppressEncryption); + } + if (Array.isArray(value)) { value = value.slice(); for (let i = 0, ii = value.length; i < ii; i++) { - if (!(value[i] instanceof Ref)) { - continue; + if (value[i] instanceof Ref && this.xref) { + value[i] = this.xref.fetch(value[i], this.suppressEncryption); } - - value[i] = this.xref.fetch(value[i], this.suppressEncryption); - } - - return value; - }, - - getRaw: function Dict_getRaw(key) { - return this._map[key]; - }, - getKeys: function Dict_getKeys() { - return Object.keys(this._map); - }, - getRawValues: function Dict_getRawValues() { - return Object.values(this._map); - }, - set: function Dict_set(key, value) { - this._map[key] = value; - }, - has: function Dict_has(key) { - return this._map[key] !== undefined; - }, - forEach: function Dict_forEach(callback) { - for (var key in this._map) { - callback(key, this.get(key)); } } - }; - Dict.empty = new Dict(null); - Dict.merge = function ({ + return value; + } + + getRaw(key) { + return this._map[key]; + } + + getKeys() { + return Object.keys(this._map); + } + + getRawValues() { + return Object.values(this._map); + } + + set(key, value) { + this._map[key] = value; + } + + has(key) { + return this._map[key] !== undefined; + } + + forEach(callback) { + for (const key in this._map) { + callback(key, this.get(key)); + } + } + + static get empty() { + const emptyDict = new Dict(null); + + emptyDict.set = (key, value) => { + (0, _util.unreachable)("Should not call `set` on the empty dictionary."); + }; + + return (0, _util.shadow)(this, "empty", emptyDict); + } + + static merge({ xref, dictArray, mergeSubDicts = false }) { - const mergedDict = new Dict(xref); - - if (!mergeSubDicts) { - for (const dict of dictArray) { - if (!(dict instanceof Dict)) { - continue; - } - - for (const [key, value] of Object.entries(dict._map)) { - if (mergedDict._map[key] === undefined) { - mergedDict._map[key] = value; - } - } - } - - return mergedDict.size > 0 ? mergedDict : Dict.empty; - } - - const properties = new Map(); + const mergedDict = new Dict(xref), + properties = new Map(); for (const dict of dictArray) { if (!(dict instanceof Dict)) { @@ -1810,6 +2003,8 @@ var Dict = function DictClosure() { if (property === undefined) { property = []; properties.set(key, property); + } else if (!mergeSubDicts || !(value instanceof Dict)) { + continue; } property.push(value); @@ -1825,10 +2020,6 @@ var Dict = function DictClosure() { const subDict = new Dict(xref); for (const dict of values) { - if (!(dict instanceof Dict)) { - continue; - } - for (const [key, value] of Object.entries(dict._map)) { if (subDict._map[key] === undefined) { subDict._map[key] = value; @@ -1843,40 +2034,39 @@ var Dict = function DictClosure() { properties.clear(); return mergedDict.size > 0 ? mergedDict : Dict.empty; - }; + } - return Dict; -}(); +} exports.Dict = Dict; -var Ref = function RefClosure() { +const Ref = function RefClosure() { let refCache = Object.create(null); - function Ref(num, gen) { - this.num = num; - this.gen = gen; - } + class Ref { + constructor(num, gen) { + this.num = num; + this.gen = gen; + } - Ref.prototype = { - toString: function Ref_toString() { + toString() { if (this.gen === 0) { return `${this.num}R`; } return `${this.num}R${this.gen}`; } - }; - Ref.get = function (num, gen) { - const key = gen === 0 ? `${num}R` : `${num}R${gen}`; - const refValue = refCache[key]; - return refValue ? refValue : refCache[key] = new Ref(num, gen); - }; + static get(num, gen) { + const key = gen === 0 ? `${num}R` : `${num}R${gen}`; + return refCache[key] || (refCache[key] = new Ref(num, gen)); + } - Ref._clearCache = function () { - refCache = Object.create(null); - }; + static _clearCache() { + refCache = Object.create(null); + } + + } return Ref; }(); @@ -1884,8 +2074,8 @@ var Ref = function RefClosure() { exports.Ref = Ref; class RefSet { - constructor() { - this._set = new Set(); + constructor(parent = null) { + this._set = new Set(parent && parent._set); } has(ref) { @@ -1900,6 +2090,14 @@ class RefSet { this._set.delete(ref.toString()); } + [Symbol.iterator]() { + return this._set.values(); + } + + clear() { + this._set.clear(); + } + } exports.RefSet = RefSet; @@ -1929,10 +2127,8 @@ class RefSetCache { this._map.set(ref.toString(), this.get(aliasRef)); } - forEach(callback) { - for (const value of this._map.values()) { - callback(value); - } + [Symbol.iterator]() { + return this._map.values(); } clear() { @@ -1943,10 +2139,6 @@ class RefSetCache { exports.RefSetCache = RefSetCache; -function isEOF(v) { - return v === EOF; -} - function isName(v, name) { return v instanceof Name && (name === undefined || v.name === name); } @@ -1959,18 +2151,10 @@ function isDict(v, type) { return v instanceof Dict && (type === undefined || isName(v.get("Type"), type)); } -function isRef(v) { - return v instanceof Ref; -} - function isRefsEqual(v1, v2) { return v1.num === v2.num && v1.gen === v2.gen; } -function isStream(v) { - return typeof v === "object" && v !== null && v.getBytes !== undefined; -} - function clearPrimitiveCaches() { Cmd._clearCache(); @@ -1981,25 +2165,677 @@ function clearPrimitiveCaches() { /***/ }), /* 6 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.XRefParseException = exports.XRefEntryException = exports.ParserEOFException = exports.MissingDataException = exports.DocStats = void 0; +exports.collectActions = collectActions; +exports.encodeToXmlString = encodeToXmlString; +exports.escapePDFName = escapePDFName; +exports.getArrayLookupTableFactory = getArrayLookupTableFactory; +exports.getInheritableProperty = getInheritableProperty; +exports.getLookupTableFactory = getLookupTableFactory; +exports.getNewAnnotationsMap = getNewAnnotationsMap; +exports.isWhiteSpace = isWhiteSpace; +exports.log2 = log2; +exports.numberToString = numberToString; +exports.parseXFAPath = parseXFAPath; +exports.readInt8 = readInt8; +exports.readUint16 = readUint16; +exports.readUint32 = readUint32; +exports.recoverJsURL = recoverJsURL; +exports.toRomanNumerals = toRomanNumerals; +exports.validateCSSFont = validateCSSFont; + +var _util = __w_pdfjs_require__(2); + +var _primitives = __w_pdfjs_require__(5); + +var _base_stream = __w_pdfjs_require__(7); + +function getLookupTableFactory(initializer) { + let lookup; + return function () { + if (initializer) { + lookup = Object.create(null); + initializer(lookup); + initializer = null; + } + + return lookup; + }; +} + +function getArrayLookupTableFactory(initializer) { + let lookup; + return function () { + if (initializer) { + let arr = initializer(); + initializer = null; + lookup = Object.create(null); + + for (let i = 0, ii = arr.length; i < ii; i += 2) { + lookup[arr[i]] = arr[i + 1]; + } + + arr = null; + } + + return lookup; + }; +} + +class MissingDataException extends _util.BaseException { + constructor(begin, end) { + super(`Missing data [${begin}, ${end})`, "MissingDataException"); + this.begin = begin; + this.end = end; + } + +} + +exports.MissingDataException = MissingDataException; + +class ParserEOFException extends _util.BaseException { + constructor(msg) { + super(msg, "ParserEOFException"); + } + +} + +exports.ParserEOFException = ParserEOFException; + +class XRefEntryException extends _util.BaseException { + constructor(msg) { + super(msg, "XRefEntryException"); + } + +} + +exports.XRefEntryException = XRefEntryException; + +class XRefParseException extends _util.BaseException { + constructor(msg) { + super(msg, "XRefParseException"); + } + +} + +exports.XRefParseException = XRefParseException; + +class DocStats { + constructor(handler) { + this._handler = handler; + this._streamTypes = new Set(); + this._fontTypes = new Set(); + } + + _send() { + const streamTypes = Object.create(null), + fontTypes = Object.create(null); + + for (const type of this._streamTypes) { + streamTypes[type] = true; + } + + for (const type of this._fontTypes) { + fontTypes[type] = true; + } + + this._handler.send("DocStats", { + streamTypes, + fontTypes + }); + } + + addStreamType(type) { + if (this._streamTypes.has(type)) { + return; + } + + this._streamTypes.add(type); + + this._send(); + } + + addFontType(type) { + if (this._fontTypes.has(type)) { + return; + } + + this._fontTypes.add(type); + + this._send(); + } + +} + +exports.DocStats = DocStats; + +function getInheritableProperty({ + dict, + key, + getArray = false, + stopWhenFound = true +}) { + let values; + const visited = new _primitives.RefSet(); + + while (dict instanceof _primitives.Dict && !(dict.objId && visited.has(dict.objId))) { + if (dict.objId) { + visited.put(dict.objId); + } + + const value = getArray ? dict.getArray(key) : dict.get(key); + + if (value !== undefined) { + if (stopWhenFound) { + return value; + } + + if (!values) { + values = []; + } + + values.push(value); + } + + dict = dict.get("Parent"); + } + + return values; +} + +const ROMAN_NUMBER_MAP = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; + +function toRomanNumerals(number, lowerCase = false) { + (0, _util.assert)(Number.isInteger(number) && number > 0, "The number should be a positive integer."); + const romanBuf = []; + let pos; + + while (number >= 1000) { + number -= 1000; + romanBuf.push("M"); + } + + pos = number / 100 | 0; + number %= 100; + romanBuf.push(ROMAN_NUMBER_MAP[pos]); + pos = number / 10 | 0; + number %= 10; + romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]); + romanBuf.push(ROMAN_NUMBER_MAP[20 + number]); + const romanStr = romanBuf.join(""); + return lowerCase ? romanStr.toLowerCase() : romanStr; +} + +function log2(x) { + if (x <= 0) { + return 0; + } + + return Math.ceil(Math.log2(x)); +} + +function readInt8(data, offset) { + return data[offset] << 24 >> 24; +} + +function readUint16(data, offset) { + return data[offset] << 8 | data[offset + 1]; +} + +function readUint32(data, offset) { + return (data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0; +} + +function isWhiteSpace(ch) { + return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a; +} + +function parseXFAPath(path) { + const positionPattern = /(.+)\[(\d+)\]$/; + return path.split(".").map(component => { + const m = component.match(positionPattern); + + if (m) { + return { + name: m[1], + pos: parseInt(m[2], 10) + }; + } + + return { + name: component, + pos: 0 + }; + }); +} + +function escapePDFName(str) { + const buffer = []; + let start = 0; + + for (let i = 0, ii = str.length; i < ii; i++) { + const char = str.charCodeAt(i); + + if (char < 0x21 || char > 0x7e || char === 0x23 || char === 0x28 || char === 0x29 || char === 0x3c || char === 0x3e || char === 0x5b || char === 0x5d || char === 0x7b || char === 0x7d || char === 0x2f || char === 0x25) { + if (start < i) { + buffer.push(str.substring(start, i)); + } + + buffer.push(`#${char.toString(16)}`); + start = i + 1; + } + } + + if (buffer.length === 0) { + return str; + } + + if (start < str.length) { + buffer.push(str.substring(start, str.length)); + } + + return buffer.join(""); +} + +function _collectJS(entry, xref, list, parents) { + if (!entry) { + return; + } + + let parent = null; + + if (entry instanceof _primitives.Ref) { + if (parents.has(entry)) { + return; + } + + parent = entry; + parents.put(parent); + entry = xref.fetch(entry); + } + + if (Array.isArray(entry)) { + for (const element of entry) { + _collectJS(element, xref, list, parents); + } + } else if (entry instanceof _primitives.Dict) { + if ((0, _primitives.isName)(entry.get("S"), "JavaScript")) { + const js = entry.get("JS"); + let code; + + if (js instanceof _base_stream.BaseStream) { + code = js.getString(); + } else if (typeof js === "string") { + code = js; + } + + code = code && (0, _util.stringToPDFString)(code).replace(/\u0000/g, ""); + + if (code) { + list.push(code); + } + } + + _collectJS(entry.getRaw("Next"), xref, list, parents); + } + + if (parent) { + parents.remove(parent); + } +} + +function collectActions(xref, dict, eventType) { + const actions = Object.create(null); + const additionalActionsDicts = getInheritableProperty({ + dict, + key: "AA", + stopWhenFound: false + }); + + if (additionalActionsDicts) { + for (let i = additionalActionsDicts.length - 1; i >= 0; i--) { + const additionalActions = additionalActionsDicts[i]; + + if (!(additionalActions instanceof _primitives.Dict)) { + continue; + } + + for (const key of additionalActions.getKeys()) { + const action = eventType[key]; + + if (!action) { + continue; + } + + const actionDict = additionalActions.getRaw(key); + const parents = new _primitives.RefSet(); + const list = []; + + _collectJS(actionDict, xref, list, parents); + + if (list.length > 0) { + actions[action] = list; + } + } + } + } + + if (dict.has("A")) { + const actionDict = dict.get("A"); + const parents = new _primitives.RefSet(); + const list = []; + + _collectJS(actionDict, xref, list, parents); + + if (list.length > 0) { + actions.Action = list; + } + } + + return (0, _util.objectSize)(actions) > 0 ? actions : null; +} + +const XMLEntities = { + 0x3c: "<", + 0x3e: ">", + 0x26: "&", + 0x22: """, + 0x27: "'" +}; + +function encodeToXmlString(str) { + const buffer = []; + let start = 0; + + for (let i = 0, ii = str.length; i < ii; i++) { + const char = str.codePointAt(i); + + if (0x20 <= char && char <= 0x7e) { + const entity = XMLEntities[char]; + + if (entity) { + if (start < i) { + buffer.push(str.substring(start, i)); + } + + buffer.push(entity); + start = i + 1; + } + } else { + if (start < i) { + buffer.push(str.substring(start, i)); + } + + buffer.push(`&#x${char.toString(16).toUpperCase()};`); + + if (char > 0xd7ff && (char < 0xe000 || char > 0xfffd)) { + i++; + } + + start = i + 1; + } + } + + if (buffer.length === 0) { + return str; + } + + if (start < str.length) { + buffer.push(str.substring(start, str.length)); + } + + return buffer.join(""); +} + +function validateCSSFont(cssFontInfo) { + const DEFAULT_CSS_FONT_OBLIQUE = "14"; + const DEFAULT_CSS_FONT_WEIGHT = "400"; + const CSS_FONT_WEIGHT_VALUES = new Set(["100", "200", "300", "400", "500", "600", "700", "800", "900", "1000", "normal", "bold", "bolder", "lighter"]); + const { + fontFamily, + fontWeight, + italicAngle + } = cssFontInfo; + + if (/^".*"$/.test(fontFamily)) { + if (/[^\\]"/.test(fontFamily.slice(1, fontFamily.length - 1))) { + (0, _util.warn)(`XFA - FontFamily contains some unescaped ": ${fontFamily}.`); + return false; + } + } else if (/^'.*'$/.test(fontFamily)) { + if (/[^\\]'/.test(fontFamily.slice(1, fontFamily.length - 1))) { + (0, _util.warn)(`XFA - FontFamily contains some unescaped ': ${fontFamily}.`); + return false; + } + } else { + for (const ident of fontFamily.split(/[ \t]+/)) { + if (/^(\d|(-(\d|-)))/.test(ident) || !/^[\w-\\]+$/.test(ident)) { + (0, _util.warn)(`XFA - FontFamily contains some invalid : ${fontFamily}.`); + return false; + } + } + } + + const weight = fontWeight ? fontWeight.toString() : ""; + cssFontInfo.fontWeight = CSS_FONT_WEIGHT_VALUES.has(weight) ? weight : DEFAULT_CSS_FONT_WEIGHT; + const angle = parseFloat(italicAngle); + cssFontInfo.italicAngle = isNaN(angle) || angle < -90 || angle > 90 ? DEFAULT_CSS_FONT_OBLIQUE : italicAngle.toString(); + return true; +} + +function recoverJsURL(str) { + const URL_OPEN_METHODS = ["app.launchURL", "window.open", "xfa.host.gotoURL"]; + const regex = new RegExp("^\\s*(" + URL_OPEN_METHODS.join("|").split(".").join("\\.") + ")\\((?:'|\")([^'\"]*)(?:'|\")(?:,\\s*(\\w+)\\)|\\))", "i"); + const jsUrl = regex.exec(str); + + if (jsUrl && jsUrl[2]) { + const url = jsUrl[2]; + let newWindow = false; + + if (jsUrl[3] === "true" && jsUrl[1] === "app.launchURL") { + newWindow = true; + } + + return { + url, + newWindow + }; + } + + return null; +} + +function numberToString(value) { + if (Number.isInteger(value)) { + return value.toString(); + } + + const roundedValue = Math.round(value * 100); + + if (roundedValue % 100 === 0) { + return (roundedValue / 100).toString(); + } + + if (roundedValue % 10 === 0) { + return value.toFixed(1); + } + + return value.toFixed(2); +} + +function getNewAnnotationsMap(annotationStorage) { + if (!annotationStorage) { + return null; + } + + const newAnnotationsByPage = new Map(); + + for (const [key, value] of annotationStorage) { + if (!key.startsWith(_util.AnnotationEditorPrefix)) { + continue; + } + + let annotations = newAnnotationsByPage.get(value.pageIndex); + + if (!annotations) { + annotations = []; + newAnnotationsByPage.set(value.pageIndex, annotations); + } + + annotations.push(value); + } + + return newAnnotationsByPage.size > 0 ? newAnnotationsByPage : null; +} + +/***/ }), +/* 7 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.BaseStream = void 0; + +var _util = __w_pdfjs_require__(2); + +class BaseStream { + constructor() { + if (this.constructor === BaseStream) { + (0, _util.unreachable)("Cannot initialize BaseStream."); + } + } + + get length() { + (0, _util.unreachable)("Abstract getter `length` accessed"); + } + + get isEmpty() { + (0, _util.unreachable)("Abstract getter `isEmpty` accessed"); + } + + get isDataLoaded() { + return (0, _util.shadow)(this, "isDataLoaded", true); + } + + getByte() { + (0, _util.unreachable)("Abstract method `getByte` called"); + } + + getBytes(length) { + (0, _util.unreachable)("Abstract method `getBytes` called"); + } + + peekByte() { + const peekedByte = this.getByte(); + + if (peekedByte !== -1) { + this.pos--; + } + + return peekedByte; + } + + peekBytes(length) { + const bytes = this.getBytes(length); + this.pos -= bytes.length; + return bytes; + } + + getUint16() { + const b0 = this.getByte(); + const b1 = this.getByte(); + + if (b0 === -1 || b1 === -1) { + return -1; + } + + return (b0 << 8) + b1; + } + + getInt32() { + const b0 = this.getByte(); + const b1 = this.getByte(); + const b2 = this.getByte(); + const b3 = this.getByte(); + return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; + } + + getByteRange(begin, end) { + (0, _util.unreachable)("Abstract method `getByteRange` called"); + } + + getString(length) { + return (0, _util.bytesToString)(this.getBytes(length)); + } + + skip(n) { + this.pos += n || 1; + } + + reset() { + (0, _util.unreachable)("Abstract method `reset` called"); + } + + moveStart() { + (0, _util.unreachable)("Abstract method `moveStart` called"); + } + + makeSubStream(start, length, dict = null) { + (0, _util.unreachable)("Abstract method `makeSubStream` called"); + } + + getBaseStreams() { + return null; + } + +} + +exports.BaseStream = BaseStream; + +/***/ }), +/* 8 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.NetworkPdfManager = exports.LocalPdfManager = void 0; var _util = __w_pdfjs_require__(2); -var _chunked_stream = __w_pdfjs_require__(7); +var _chunked_stream = __w_pdfjs_require__(9); -var _core_utils = __w_pdfjs_require__(8); +var _core_utils = __w_pdfjs_require__(6); -var _document = __w_pdfjs_require__(9); +var _document = __w_pdfjs_require__(11); -var _stream = __w_pdfjs_require__(12); +var _stream = __w_pdfjs_require__(10); + +function parseDocBaseUrl(url) { + if (url) { + const absoluteUrl = (0, _util.createValidAbsoluteUrl)(url); + + if (absoluteUrl) { + return absoluteUrl.href; + } + + (0, _util.warn)(`Invalid absolute docBaseUrl: "${url}".`); + } + + return null; +} class BasePdfManager { constructor() { @@ -2017,19 +2853,8 @@ class BasePdfManager { } get docBaseUrl() { - let docBaseUrl = null; - - if (this._docBaseUrl) { - const absoluteUrl = (0, _util.createValidAbsoluteUrl)(this._docBaseUrl); - - if (absoluteUrl) { - docBaseUrl = absoluteUrl.href; - } else { - (0, _util.warn)(`Invalid absolute docBaseUrl: "${this._docBaseUrl}".`); - } - } - - return (0, _util.shadow)(this, "docBaseUrl", docBaseUrl); + const catalog = this.pdfDocument.catalog; + return (0, _util.shadow)(this, "docBaseUrl", catalog.baseUrl || this._docBaseUrl); } onLoadedStream() { @@ -2056,6 +2881,18 @@ class BasePdfManager { return this.pdfDocument.fontFallback(id, handler); } + loadXfaFonts(handler, task) { + return this.pdfDocument.loadXfaFonts(handler, task); + } + + loadXfaImages() { + return this.pdfDocument.loadXfaImages(); + } + + serializeXfaData(annotationStorage) { + return this.pdfDocument.serializeXfaData(annotationStorage); + } + cleanup(manuallyTriggered = false) { return this.pdfDocument.cleanup(manuallyTriggered); } @@ -2087,12 +2924,14 @@ class BasePdfManager { } class LocalPdfManager extends BasePdfManager { - constructor(docId, data, password, evaluatorOptions, docBaseUrl) { + constructor(docId, data, password, msgHandler, evaluatorOptions, enableXfa, docBaseUrl) { super(); this._docId = docId; this._password = password; - this._docBaseUrl = docBaseUrl; + this._docBaseUrl = parseDocBaseUrl(docBaseUrl); + this.msgHandler = msgHandler; this.evaluatorOptions = evaluatorOptions; + this.enableXfa = enableXfa; const stream = new _stream.Stream(data); this.pdfDocument = new _document.PDFDocument(this, stream); this._loadedStreamPromise = Promise.resolve(stream); @@ -2125,13 +2964,14 @@ class LocalPdfManager extends BasePdfManager { exports.LocalPdfManager = LocalPdfManager; class NetworkPdfManager extends BasePdfManager { - constructor(docId, pdfNetworkStream, args, evaluatorOptions, docBaseUrl) { + constructor(docId, pdfNetworkStream, args, evaluatorOptions, enableXfa, docBaseUrl) { super(); this._docId = docId; this._password = args.password; - this._docBaseUrl = docBaseUrl; + this._docBaseUrl = parseDocBaseUrl(docBaseUrl); this.msgHandler = args.msgHandler; this.evaluatorOptions = evaluatorOptions; + this.enableXfa = enableXfa; this.streamManager = new _chunked_stream.ChunkedStreamManager(pdfNetworkStream, { msgHandler: args.msgHandler, length: args.length, @@ -2187,27 +3027,25 @@ class NetworkPdfManager extends BasePdfManager { exports.NetworkPdfManager = NetworkPdfManager; /***/ }), -/* 7 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 9 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.ChunkedStreamManager = exports.ChunkedStream = void 0; var _util = __w_pdfjs_require__(2); -var _core_utils = __w_pdfjs_require__(8); +var _core_utils = __w_pdfjs_require__(6); -class ChunkedStream { +var _stream = __w_pdfjs_require__(10); + +class ChunkedStream extends _stream.Stream { constructor(length, chunkSize, manager) { - this.bytes = new Uint8Array(length); - this.start = 0; - this.pos = 0; - this.end = length; + super(new Uint8Array(length), 0, length, null); this.chunkSize = chunkSize; this._loadedChunks = new Set(); this.numChunks = Math.ceil(length / chunkSize); @@ -2228,15 +3066,11 @@ class ChunkedStream { return chunks; } - getBaseStreams() { - return [this]; - } - get numChunksLoaded() { return this._loadedChunks.size; } - allChunksLoaded() { + get isDataLoaded() { return this.numChunksLoaded === this.numChunks; } @@ -2282,6 +3116,10 @@ class ChunkedStream { const chunk = Math.floor(pos / this.chunkSize); + if (chunk > this.numChunks) { + return; + } + if (chunk === this.lastSuccessfulEnsureByteChunk) { return; } @@ -2302,9 +3140,13 @@ class ChunkedStream { return; } - const chunkSize = this.chunkSize; - const beginChunk = Math.floor(begin / chunkSize); - const endChunk = Math.floor((end - 1) / chunkSize) + 1; + const beginChunk = Math.floor(begin / this.chunkSize); + + if (beginChunk > this.numChunks) { + return; + } + + const endChunk = Math.min(Math.floor((end - 1) / this.chunkSize) + 1, this.numChunks); for (let chunk = beginChunk; chunk < endChunk; ++chunk) { if (!this._loadedChunks.has(chunk)) { @@ -2331,14 +3173,6 @@ class ChunkedStream { return this._loadedChunks.has(chunk); } - get length() { - return this.end - this.start; - } - - get isEmpty() { - return this.length === 0; - } - getByte() { const pos = this.pos; @@ -2353,26 +3187,7 @@ class ChunkedStream { return this.bytes[this.pos++]; } - getUint16() { - const b0 = this.getByte(); - const b1 = this.getByte(); - - if (b0 === -1 || b1 === -1) { - return -1; - } - - return (b0 << 8) + b1; - } - - getInt32() { - const b0 = this.getByte(); - const b1 = this.getByte(); - const b2 = this.getByte(); - const b3 = this.getByte(); - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - } - - getBytes(length, forceClamped = false) { + getBytes(length) { const bytes = this.bytes; const pos = this.pos; const strEnd = this.end; @@ -2382,8 +3197,7 @@ class ChunkedStream { this.ensureRange(pos, strEnd); } - const subarray = bytes.subarray(pos, strEnd); - return forceClamped ? new Uint8ClampedArray(subarray) : subarray; + return bytes.subarray(pos, strEnd); } let end = pos + length; @@ -2397,24 +3211,7 @@ class ChunkedStream { } this.pos = end; - const subarray = bytes.subarray(pos, end); - return forceClamped ? new Uint8ClampedArray(subarray) : subarray; - } - - peekByte() { - const peekedByte = this.getByte(); - - if (peekedByte !== -1) { - this.pos--; - } - - return peekedByte; - } - - peekBytes(length, forceClamped = false) { - const bytes = this.getBytes(length, forceClamped); - this.pos -= bytes.length; - return bytes; + return bytes.subarray(pos, end); } getByteRange(begin, end) { @@ -2433,23 +3230,7 @@ class ChunkedStream { return this.bytes.subarray(begin, end); } - skip(n) { - if (!n) { - n = 1; - } - - this.pos += n; - } - - reset() { - this.pos = this.start; - } - - moveStart() { - this.start = this.pos; - } - - makeSubStream(start, length, dict) { + makeSubStream(start, length, dict = null) { if (length) { if (start + length > this.progressiveDataLength) { this.ensureRange(start, start + length); @@ -2479,14 +3260,17 @@ class ChunkedStream { return missingChunks; }; - ChunkedStreamSubstream.prototype.allChunksLoaded = function () { - if (this.numChunksLoaded === this.numChunks) { - return true; - } + Object.defineProperty(ChunkedStreamSubstream.prototype, "isDataLoaded", { + get() { + if (this.numChunksLoaded === this.numChunks) { + return true; + } - return this.getMissingChunks().length === 0; - }; + return this.getMissingChunks().length === 0; + }, + configurable: true + }); const subStream = new ChunkedStreamSubstream(); subStream.pos = subStream.start = start; subStream.end = start + length || this.end; @@ -2494,6 +3278,10 @@ class ChunkedStream { return subStream; } + getBaseStreams() { + return [this]; + } + } exports.ChunkedStream = ChunkedStream; @@ -2528,7 +3316,7 @@ class ChunkedStreamManager { let chunks = [], loaded = 0; - const promise = new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const readChunk = chunk => { try { if (!chunk.done) { @@ -2555,8 +3343,7 @@ class ChunkedStreamManager { }; rangeReader.read().then(readChunk, reject); - }); - promise.then(data => { + }).then(data => { if (this.aborted) { return; } @@ -2618,7 +3405,7 @@ class ChunkedStreamManager { for (const groupedChunk of groupedChunksToRequest) { const begin = groupedChunk.beginChunk * this.chunkSize; const end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length); - this.sendRequest(begin, end); + this.sendRequest(begin, end).catch(capability.reject); } } @@ -2723,7 +3510,7 @@ class ChunkedStreamManager { this.stream.onReceiveData(begin, chunk); } - if (this.stream.allChunksLoaded()) { + if (this.stream.isDataLoaded) { this._loadedStreamCapability.resolve(this.stream); } @@ -2814,181 +3601,165 @@ class ChunkedStreamManager { exports.ChunkedStreamManager = ChunkedStreamManager; /***/ }), -/* 8 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 10 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.getLookupTableFactory = getLookupTableFactory; -exports.getInheritableProperty = getInheritableProperty; -exports.toRomanNumerals = toRomanNumerals; -exports.log2 = log2; -exports.readInt8 = readInt8; -exports.readUint16 = readUint16; -exports.readUint32 = readUint32; -exports.isWhiteSpace = isWhiteSpace; -exports.XRefParseException = exports.XRefEntryException = exports.MissingDataException = void 0; +})); +exports.StringStream = exports.Stream = exports.NullStream = void 0; + +var _base_stream = __w_pdfjs_require__(7); var _util = __w_pdfjs_require__(2); -function getLookupTableFactory(initializer) { - let lookup; - return function () { - if (initializer) { - lookup = Object.create(null); - initializer(lookup); - initializer = null; +class Stream extends _base_stream.BaseStream { + constructor(arrayBuffer, start, length, dict) { + super(); + this.bytes = arrayBuffer instanceof Uint8Array ? arrayBuffer : new Uint8Array(arrayBuffer); + this.start = start || 0; + this.pos = this.start; + this.end = start + length || this.bytes.length; + this.dict = dict; + } + + get length() { + return this.end - this.start; + } + + get isEmpty() { + return this.length === 0; + } + + getByte() { + if (this.pos >= this.end) { + return -1; } - return lookup; - }; -} - -class MissingDataException extends _util.BaseException { - constructor(begin, end) { - super(`Missing data [${begin}, ${end})`); - this.begin = begin; - this.end = end; + return this.bytes[this.pos++]; } -} + getBytes(length) { + const bytes = this.bytes; + const pos = this.pos; + const strEnd = this.end; -exports.MissingDataException = MissingDataException; - -class XRefEntryException extends _util.BaseException {} - -exports.XRefEntryException = XRefEntryException; - -class XRefParseException extends _util.BaseException {} - -exports.XRefParseException = XRefParseException; - -function getInheritableProperty({ - dict, - key, - getArray = false, - stopWhenFound = true -}) { - const LOOP_LIMIT = 100; - let loopCount = 0; - let values; - - while (dict) { - const value = getArray ? dict.getArray(key) : dict.get(key); - - if (value !== undefined) { - if (stopWhenFound) { - return value; - } - - if (!values) { - values = []; - } - - values.push(value); + if (!length) { + return bytes.subarray(pos, strEnd); } - if (++loopCount > LOOP_LIMIT) { - (0, _util.warn)(`getInheritableProperty: maximum loop count exceeded for "${key}"`); - break; + let end = pos + length; + + if (end > strEnd) { + end = strEnd; } - dict = dict.get("Parent"); + this.pos = end; + return bytes.subarray(pos, end); } - return values; -} + getByteRange(begin, end) { + if (begin < 0) { + begin = 0; + } -const ROMAN_NUMBER_MAP = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; + if (end > this.end) { + end = this.end; + } -function toRomanNumerals(number, lowerCase = false) { - (0, _util.assert)(Number.isInteger(number) && number > 0, "The number should be a positive integer."); - const romanBuf = []; - let pos; - - while (number >= 1000) { - number -= 1000; - romanBuf.push("M"); + return this.bytes.subarray(begin, end); } - pos = number / 100 | 0; - number %= 100; - romanBuf.push(ROMAN_NUMBER_MAP[pos]); - pos = number / 10 | 0; - number %= 10; - romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]); - romanBuf.push(ROMAN_NUMBER_MAP[20 + number]); - const romanStr = romanBuf.join(""); - return lowerCase ? romanStr.toLowerCase() : romanStr; -} - -function log2(x) { - if (x <= 0) { - return 0; + reset() { + this.pos = this.start; + } + + moveStart() { + this.start = this.pos; + } + + makeSubStream(start, length, dict = null) { + return new Stream(this.bytes.buffer, start, length, dict); } - return Math.ceil(Math.log2(x)); } -function readInt8(data, offset) { - return data[offset] << 24 >> 24; +exports.Stream = Stream; + +class StringStream extends Stream { + constructor(str) { + super((0, _util.stringToBytes)(str)); + } + } -function readUint16(data, offset) { - return data[offset] << 8 | data[offset + 1]; +exports.StringStream = StringStream; + +class NullStream extends Stream { + constructor() { + super(new Uint8Array(0)); + } + } -function readUint32(data, offset) { - return (data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0; -} - -function isWhiteSpace(ch) { - return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a; -} +exports.NullStream = NullStream; /***/ }), -/* 9 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 11 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.PDFDocument = exports.Page = void 0; +})); +exports.Page = exports.PDFDocument = void 0; + +var _annotation = __w_pdfjs_require__(12); var _util = __w_pdfjs_require__(2); -var _obj = __w_pdfjs_require__(10); +var _core_utils = __w_pdfjs_require__(6); var _primitives = __w_pdfjs_require__(5); -var _core_utils = __w_pdfjs_require__(8); +var _xfa_fonts = __w_pdfjs_require__(51); -var _stream = __w_pdfjs_require__(12); +var _base_stream = __w_pdfjs_require__(7); -var _annotation = __w_pdfjs_require__(25); +var _crypto = __w_pdfjs_require__(67); -var _crypto = __w_pdfjs_require__(22); +var _catalog = __w_pdfjs_require__(69); -var _parser = __w_pdfjs_require__(11); +var _cleanup_helper = __w_pdfjs_require__(71); -var _operator_list = __w_pdfjs_require__(26); +var _dataset_reader = __w_pdfjs_require__(100); -var _evaluator = __w_pdfjs_require__(28); +var _parser = __w_pdfjs_require__(17); + +var _stream = __w_pdfjs_require__(10); + +var _object_loader = __w_pdfjs_require__(75); + +var _operator_list = __w_pdfjs_require__(62); + +var _evaluator = __w_pdfjs_require__(15); + +var _decode_stream = __w_pdfjs_require__(19); + +var _struct_tree = __w_pdfjs_require__(74); + +var _writer = __w_pdfjs_require__(65); + +var _factory = __w_pdfjs_require__(76); + +var _xref = __w_pdfjs_require__(101); const DEFAULT_USER_UNIT = 1.0; const LETTER_SIZE_MEDIABOX = [0, 0, 612, 792]; -function isAnnotationRenderable(annotation, intent) { - return intent === "display" && annotation.viewable || intent === "print" && annotation.printable; -} - class Page { constructor({ pdfManager, @@ -2999,7 +3770,10 @@ class Page { globalIdFactory, fontCache, builtInCMapCache, - globalImageCache + standardFontDataCache, + globalImageCache, + nonBlendModesSet, + xfaFactory }) { this.pdfManager = pdfManager; this.pageIndex = pageIndex; @@ -3008,9 +3782,12 @@ class Page { this.ref = ref; this.fontCache = fontCache; this.builtInCMapCache = builtInCMapCache; + this.standardFontDataCache = standardFontDataCache; this.globalImageCache = globalImageCache; + this.nonBlendModesSet = nonBlendModesSet; this.evaluatorOptions = pdfManager.evaluatorOptions; this.resourcesPromise = null; + this.xfaFactory = xfaFactory; const idCounters = { obj: 0 }; @@ -3019,6 +3796,10 @@ class Page { return `p${pageIndex}_${++idCounters.obj}`; } + static getPageObjId() { + return `page${ref.toString()}`; + } + }; } @@ -3034,7 +3815,7 @@ class Page { return value; } - if (value.length === 1 || !(0, _primitives.isDict)(value[0])) { + if (value.length === 1 || !(value[0] instanceof _primitives.Dict)) { return value[0]; } @@ -3045,14 +3826,20 @@ class Page { } get content() { - return this.pageDict.get("Contents"); + return this.pageDict.getArray("Contents"); } get resources() { - return (0, _util.shadow)(this, "resources", this._getInheritableProperty("Resources") || _primitives.Dict.empty); + const resources = this._getInheritableProperty("Resources"); + + return (0, _util.shadow)(this, "resources", resources instanceof _primitives.Dict ? resources : _primitives.Dict.empty); } _getBoundingBox(name) { + if (this.xfaData) { + return this.xfaData.bbox; + } + const box = this._getInheritableProperty(name, true); if (Array.isArray(box) && box.length === 4) { @@ -3077,7 +3864,7 @@ class Page { get userUnit() { let obj = this.pageDict.get("UserUnit"); - if (!(0, _util.isNum)(obj) || obj <= 0) { + if (typeof obj !== "number" || obj <= 0) { obj = DEFAULT_USER_UNIT; } @@ -3112,7 +3899,7 @@ class Page { if (rotate % 90 !== 0) { rotate = 0; } else if (rotate >= 360) { - rotate = rotate % 360; + rotate %= 360; } else if (rotate < 0) { rotate = (rotate % 360 + 360) % 360; } @@ -3120,26 +3907,85 @@ class Page { return (0, _util.shadow)(this, "rotate", rotate); } - getContentStream() { - const content = this.content; - let stream; - - if (Array.isArray(content)) { - const xref = this.xref; - const streams = []; - - for (const subStream of content) { - streams.push(xref.fetchIfRef(subStream)); - } - - stream = new _stream.StreamsSequenceStream(streams); - } else if ((0, _primitives.isStream)(content)) { - stream = content; - } else { - stream = new _stream.NullStream(); + _onSubStreamError(handler, reason, objId) { + if (this.evaluatorOptions.ignoreErrors) { + handler.send("UnsupportedFeature", { + featureId: _util.UNSUPPORTED_FEATURES.errorContentSubStream + }); + (0, _util.warn)(`getContentStream - ignoring sub-stream (${objId}): "${reason}".`); + return; } - return stream; + throw reason; + } + + getContentStream(handler) { + return this.pdfManager.ensure(this, "content").then(content => { + if (content instanceof _base_stream.BaseStream) { + return content; + } + + if (Array.isArray(content)) { + return new _decode_stream.StreamsSequenceStream(content, this._onSubStreamError.bind(this, handler)); + } + + return new _stream.NullStream(); + }); + } + + get xfaData() { + return (0, _util.shadow)(this, "xfaData", this.xfaFactory ? { + bbox: this.xfaFactory.getBoundingBox(this.pageIndex) + } : null); + } + + async saveNewAnnotations(handler, task, annotations) { + if (this.xfaFactory) { + throw new Error("XFA: Cannot save new annotations."); + } + + const partialEvaluator = new _evaluator.PartialEvaluator({ + xref: this.xref, + handler, + pageIndex: this.pageIndex, + idFactory: this._localIdFactory, + fontCache: this.fontCache, + builtInCMapCache: this.builtInCMapCache, + standardFontDataCache: this.standardFontDataCache, + globalImageCache: this.globalImageCache, + options: this.evaluatorOptions + }); + const pageDict = this.pageDict; + const annotationsArray = this.annotations.slice(); + const newData = await _annotation.AnnotationFactory.saveNewAnnotations(partialEvaluator, task, annotations); + + for (const { + ref + } of newData.annotations) { + annotationsArray.push(ref); + } + + const savedDict = pageDict.get("Annots"); + pageDict.set("Annots", annotationsArray); + const buffer = []; + let transform = null; + + if (this.xref.encrypt) { + transform = this.xref.encrypt.createCipherTransform(this.ref.num, this.ref.gen); + } + + (0, _writer.writeObject)(this.ref, pageDict, buffer, transform); + + if (savedDict) { + pageDict.set("Annots", savedDict); + } + + const objects = newData.dependencies; + objects.push({ + ref: this.ref, + data: buffer.join("") + }, ...newData.annotations); + return objects; } save(handler, task, annotationStorage) { @@ -3150,6 +3996,7 @@ class Page { idFactory: this._localIdFactory, fontCache: this.fontCache, builtInCMapCache: this.builtInCMapCache, + standardFontDataCache: this.standardFontDataCache, globalImageCache: this.globalImageCache, options: this.evaluatorOptions }); @@ -3157,7 +4004,7 @@ class Page { const newRefsPromises = []; for (const annotation of annotations) { - if (!isAnnotationRenderable(annotation, "print")) { + if (!annotation.mustBePrinted(annotationStorage)) { continue; } @@ -3167,7 +4014,9 @@ class Page { })); } - return Promise.all(newRefsPromises); + return Promise.all(newRefsPromises).then(function (newRefs) { + return newRefs.filter(newRef => !!newRef); + }); }); } @@ -3177,7 +4026,7 @@ class Page { } return this.resourcesPromise.then(() => { - const objectLoader = new _obj.ObjectLoader(this.resources, keys, this.xref); + const objectLoader = new _object_loader.ObjectLoader(this.resources, keys, this.xref); return objectLoader.load(); }); } @@ -3187,11 +4036,11 @@ class Page { sink, task, intent, - renderInteractiveForms, - annotationStorage + cacheKey, + annotationStorage = null }) { - const contentStreamPromise = this.pdfManager.ensure(this, "getContentStream"); - const resourcesPromise = this.loadResources(["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"]); + const contentStreamPromise = this.getContentStream(handler); + const resourcesPromise = this.loadResources(["ColorSpace", "ExtGState", "Font", "Pattern", "Properties", "Shading", "XObject"]); const partialEvaluator = new _evaluator.PartialEvaluator({ xref: this.xref, handler, @@ -3199,16 +4048,28 @@ class Page { idFactory: this._localIdFactory, fontCache: this.fontCache, builtInCMapCache: this.builtInCMapCache, + standardFontDataCache: this.standardFontDataCache, globalImageCache: this.globalImageCache, options: this.evaluatorOptions }); + const newAnnotationsByPage = !this.xfaFactory ? (0, _core_utils.getNewAnnotationsMap)(annotationStorage) : null; + let newAnnotationsPromise = Promise.resolve(null); + + if (newAnnotationsByPage) { + const newAnnotations = newAnnotationsByPage.get(this.pageIndex); + + if (newAnnotations) { + newAnnotationsPromise = _annotation.AnnotationFactory.printNewAnnotations(partialEvaluator, task, newAnnotations); + } + } + const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); const pageListPromise = dataPromises.then(([contentStream]) => { const opList = new _operator_list.OperatorList(intent, sink); handler.send("StartRenderPage", { - transparency: partialEvaluator.hasBlendModes(this.resources), + transparency: partialEvaluator.hasBlendModes(this.resources, this.nonBlendModesSet), pageIndex: this.pageIndex, - intent + cacheKey }); return partialEvaluator.getOperatorList({ stream: contentStream, @@ -3219,19 +4080,27 @@ class Page { return opList; }); }); - return Promise.all([pageListPromise, this._parsedAnnotations]).then(function ([pageOpList, annotations]) { - if (annotations.length === 0) { + return Promise.all([pageListPromise, this._parsedAnnotations, newAnnotationsPromise]).then(function ([pageOpList, annotations, newAnnotations]) { + if (newAnnotations) { + annotations = annotations.concat(newAnnotations); + } + + if (annotations.length === 0 || intent & _util.RenderingIntentFlag.ANNOTATIONS_DISABLE) { pageOpList.flush(true); return { length: pageOpList.totalLength }; } + const renderForms = !!(intent & _util.RenderingIntentFlag.ANNOTATIONS_FORMS), + intentAny = !!(intent & _util.RenderingIntentFlag.ANY), + intentDisplay = !!(intent & _util.RenderingIntentFlag.DISPLAY), + intentPrint = !!(intent & _util.RenderingIntentFlag.PRINT); const opListPromises = []; for (const annotation of annotations) { - if (isAnnotationRenderable(annotation, intent)) { - opListPromises.push(annotation.getOperatorList(partialEvaluator, task, renderInteractiveForms, annotationStorage).catch(function (reason) { + if (intentAny || intentDisplay && annotation.mustBeViewed(annotationStorage) || intentPrint && annotation.mustBePrinted(annotationStorage)) { + opListPromises.push(annotation.getOperatorList(partialEvaluator, task, intent, renderForms, annotationStorage).catch(function (reason) { (0, _util.warn)("getOperatorList - ignoring annotation data during " + `"${task.name}" task: "${reason}".`); return null; })); @@ -3239,14 +4108,29 @@ class Page { } return Promise.all(opListPromises).then(function (opLists) { - pageOpList.addOp(_util.OPS.beginAnnotations, []); + let form = false, + canvas = false; - for (const opList of opLists) { + for (const { + opList, + separateForm, + separateCanvas + } of opLists) { pageOpList.addOpList(opList); + + if (separateForm) { + form = separateForm; + } + + if (separateCanvas) { + canvas = separateCanvas; + } } - pageOpList.addOp(_util.OPS.endAnnotations, []); - pageOpList.flush(true); + pageOpList.flush(true, { + form, + canvas + }); return { length: pageOpList.totalLength }; @@ -3257,12 +4141,12 @@ class Page { extractTextContent({ handler, task, - normalizeWhitespace, + includeMarkedContent, sink, combineTextItems }) { - const contentStreamPromise = this.pdfManager.ensure(this, "getContentStream"); - const resourcesPromise = this.loadResources(["ExtGState", "XObject", "Font"]); + const contentStreamPromise = this.getContentStream(handler); + const resourcesPromise = this.loadResources(["ExtGState", "Font", "Properties", "XObject"]); const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); return dataPromises.then(([contentStream]) => { const partialEvaluator = new _evaluator.PartialEvaluator({ @@ -3272,6 +4156,7 @@ class Page { idFactory: this._localIdFactory, fontCache: this.fontCache, builtInCMapCache: this.builtInCMapCache, + standardFontDataCache: this.standardFontDataCache, globalImageCache: this.globalImageCache, options: this.evaluatorOptions }); @@ -3279,29 +4164,81 @@ class Page { stream: contentStream, task, resources: this.resources, - normalizeWhitespace, + includeMarkedContent, combineTextItems, - sink + sink, + viewBox: this.view }); }); } - getAnnotationsData(intent) { - return this._parsedAnnotations.then(function (annotations) { - const annotationsData = []; + async getStructTree() { + const structTreeRoot = await this.pdfManager.ensureCatalog("structTreeRoot"); - for (let i = 0, ii = annotations.length; i < ii; i++) { - if (!intent || isAnnotationRenderable(annotations[i], intent)) { - annotationsData.push(annotations[i].data); - } + if (!structTreeRoot) { + return null; + } + + const structTree = await this.pdfManager.ensure(this, "_parseStructTree", [structTreeRoot]); + return structTree.serializable; + } + + _parseStructTree(structTreeRoot) { + const tree = new _struct_tree.StructTreePage(structTreeRoot, this.pageDict); + tree.parse(); + return tree; + } + + async getAnnotationsData(handler, task, intent) { + const annotations = await this._parsedAnnotations; + + if (annotations.length === 0) { + return []; + } + + const textContentPromises = []; + const annotationsData = []; + let partialEvaluator; + const intentAny = !!(intent & _util.RenderingIntentFlag.ANY), + intentDisplay = !!(intent & _util.RenderingIntentFlag.DISPLAY), + intentPrint = !!(intent & _util.RenderingIntentFlag.PRINT); + + for (const annotation of annotations) { + const isVisible = intentAny || intentDisplay && annotation.viewable; + + if (isVisible || intentPrint && annotation.printable) { + annotationsData.push(annotation.data); } - return annotationsData; - }); + if (annotation.hasTextContent && isVisible) { + if (!partialEvaluator) { + partialEvaluator = new _evaluator.PartialEvaluator({ + xref: this.xref, + handler, + pageIndex: this.pageIndex, + idFactory: this._localIdFactory, + fontCache: this.fontCache, + builtInCMapCache: this.builtInCMapCache, + standardFontDataCache: this.standardFontDataCache, + globalImageCache: this.globalImageCache, + options: this.evaluatorOptions + }); + } + + textContentPromises.push(annotation.extractTextContent(partialEvaluator, task, this.view).catch(function (reason) { + (0, _util.warn)(`getAnnotationsData - ignoring textContent during "${task.name}" task: "${reason}".`); + })); + } + } + + await Promise.all(textContentPromises); + return annotationsData; } get annotations() { - return (0, _util.shadow)(this, "annotations", this._getInheritableProperty("Annots") || []); + const annots = this._getInheritableProperty("Annots"); + + return (0, _util.shadow)(this, "annotations", Array.isArray(annots) ? annots : []); } get _parsedAnnotations() { @@ -3309,19 +4246,52 @@ class Page { const annotationPromises = []; for (const annotationRef of this.annotations) { - annotationPromises.push(_annotation.AnnotationFactory.create(this.xref, annotationRef, this.pdfManager, this._localIdFactory).catch(function (reason) { + annotationPromises.push(_annotation.AnnotationFactory.create(this.xref, annotationRef, this.pdfManager, this._localIdFactory, false).catch(function (reason) { (0, _util.warn)(`_parsedAnnotations: "${reason}".`); return null; })); } return Promise.all(annotationPromises).then(function (annotations) { - return annotations.filter(annotation => !!annotation); + if (annotations.length === 0) { + return annotations; + } + + const sortedAnnotations = []; + let popupAnnotations; + + for (const annotation of annotations) { + if (!annotation) { + continue; + } + + if (annotation instanceof _annotation.PopupAnnotation) { + if (!popupAnnotations) { + popupAnnotations = []; + } + + popupAnnotations.push(annotation); + continue; + } + + sortedAnnotations.push(annotation); + } + + if (popupAnnotations) { + sortedAnnotations.push(...popupAnnotations); + } + + return sortedAnnotations; }); }); return (0, _util.shadow)(this, "_parsedAnnotations", parsedAnnotations); } + get jsActions() { + const actions = (0, _core_utils.collectActions)(this.xref, this.pageDict, _util.PageActionEventType); + return (0, _util.shadow)(this, "jsActions", actions); + } + } exports.Page = Page; @@ -3330,7 +4300,7 @@ const STARTXREF_SIGNATURE = new Uint8Array([0x73, 0x74, 0x61, 0x72, 0x74, 0x78, const ENDOBJ_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64, 0x6f, 0x62, 0x6a]); const FINGERPRINT_FIRST_BYTES = 1024; const EMPTY_FINGERPRINT = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; -const PDF_HEADER_VERSION_REGEXP = /^[1-9]\.[0-9]$/; +const PDF_HEADER_VERSION_REGEXP = /^[1-9]\.\d$/; function find(stream, signature, limit = 1024, backwards = false) { const signatureLength = signature.length; @@ -3382,25 +4352,15 @@ function find(stream, signature, limit = 1024, backwards = false) { } class PDFDocument { - constructor(pdfManager, arg) { - let stream; - - if ((0, _primitives.isStream)(arg)) { - stream = arg; - } else if ((0, _util.isArrayBuffer)(arg)) { - stream = new _stream.Stream(arg); - } else { - throw new Error("PDFDocument: Unknown argument type"); - } - + constructor(pdfManager, stream) { if (stream.length <= 0) { throw new _util.InvalidPDFException("The PDF file is empty, i.e. its size is zero bytes."); } this.pdfManager = pdfManager; this.stream = stream; - this.xref = new _obj.XRef(stream, pdfManager); - this._pagePromises = []; + this.xref = new _xref.XRef(stream, pdfManager); + this._pagePromises = new Map(); this._version = null; const idCounters = { font: 0 @@ -3418,12 +4378,16 @@ class PDFDocument { (0, _util.unreachable)("Abstract method `createObjId` called."); } + static getPageObjId() { + (0, _util.unreachable)("Abstract method `getPageObjId` called."); + } + }; } parse(recoveryMode) { this.xref.parse(recoveryMode); - this.catalog = new _obj.Catalog(this.pdfManager, this.xref); + this.catalog = new _catalog.Catalog(this.pdfManager, this.xref); if (this.catalog.version) { this._version = this.catalog.version; @@ -3530,16 +4494,35 @@ class PDFDocument { } get numPages() { - const linearization = this.linearization; - const num = linearization ? linearization.numPages : this.catalog.numPages; + let num = 0; + + if (this.catalog.hasActualNumPages) { + num = this.catalog.numPages; + } else if (this.xfaFactory) { + num = this.xfaFactory.getNumPages(); + } else if (this.linearization) { + num = this.linearization.numPages; + } else { + num = this.catalog.numPages; + } + return (0, _util.shadow)(this, "numPages", num); } _hasOnlyDocumentSignatures(fields, recursionDepth = 0) { const RECURSION_LIMIT = 10; + + if (!Array.isArray(fields)) { + return false; + } + return fields.every(field => { field = this.xref.fetchIfRef(field); + if (!(field instanceof _primitives.Dict)) { + return false; + } + if (field.has("Kids")) { if (++recursionDepth > RECURSION_LIMIT) { (0, _util.warn)("_hasOnlyDocumentSignatures: maximum recursion depth reached"); @@ -3556,10 +4539,309 @@ class PDFDocument { }); } + get _xfaStreams() { + const acroForm = this.catalog.acroForm; + + if (!acroForm) { + return null; + } + + const xfa = acroForm.get("XFA"); + const entries = { + "xdp:xdp": "", + template: "", + datasets: "", + config: "", + connectionSet: "", + localeSet: "", + stylesheet: "", + "/xdp:xdp": "" + }; + + if (xfa instanceof _base_stream.BaseStream && !xfa.isEmpty) { + entries["xdp:xdp"] = xfa; + return entries; + } + + if (!Array.isArray(xfa) || xfa.length === 0) { + return null; + } + + for (let i = 0, ii = xfa.length; i < ii; i += 2) { + let name; + + if (i === 0) { + name = "xdp:xdp"; + } else if (i === ii - 2) { + name = "/xdp:xdp"; + } else { + name = xfa[i]; + } + + if (!entries.hasOwnProperty(name)) { + continue; + } + + const data = this.xref.fetchIfRef(xfa[i + 1]); + + if (!(data instanceof _base_stream.BaseStream) || data.isEmpty) { + continue; + } + + entries[name] = data; + } + + return entries; + } + + get xfaDatasets() { + const streams = this._xfaStreams; + + if (!streams) { + return (0, _util.shadow)(this, "xfaDatasets", null); + } + + for (const key of ["datasets", "xdp:xdp"]) { + const stream = streams[key]; + + if (!stream) { + continue; + } + + try { + const str = (0, _util.stringToUTF8String)(stream.getString()); + const data = { + [key]: str + }; + return (0, _util.shadow)(this, "xfaDatasets", new _dataset_reader.DatasetReader(data)); + } catch (_) { + (0, _util.warn)("XFA - Invalid utf-8 string."); + break; + } + } + + return (0, _util.shadow)(this, "xfaDatasets", null); + } + + get xfaData() { + const streams = this._xfaStreams; + + if (!streams) { + return null; + } + + const data = Object.create(null); + + for (const [key, stream] of Object.entries(streams)) { + if (!stream) { + continue; + } + + try { + data[key] = (0, _util.stringToUTF8String)(stream.getString()); + } catch (_) { + (0, _util.warn)("XFA - Invalid utf-8 string."); + return null; + } + } + + return data; + } + + get xfaFactory() { + let data; + + if (this.pdfManager.enableXfa && this.catalog.needsRendering && this.formInfo.hasXfa && !this.formInfo.hasAcroForm) { + data = this.xfaData; + } + + return (0, _util.shadow)(this, "xfaFactory", data ? new _factory.XFAFactory(data) : null); + } + + get isPureXfa() { + return this.xfaFactory ? this.xfaFactory.isValid() : false; + } + + get htmlForXfa() { + return this.xfaFactory ? this.xfaFactory.getPages() : null; + } + + async loadXfaImages() { + const xfaImagesDict = await this.pdfManager.ensureCatalog("xfaImages"); + + if (!xfaImagesDict) { + return; + } + + const keys = xfaImagesDict.getKeys(); + const objectLoader = new _object_loader.ObjectLoader(xfaImagesDict, keys, this.xref); + await objectLoader.load(); + const xfaImages = new Map(); + + for (const key of keys) { + const stream = xfaImagesDict.get(key); + + if (stream instanceof _base_stream.BaseStream) { + xfaImages.set(key, stream.getBytes()); + } + } + + this.xfaFactory.setImages(xfaImages); + } + + async loadXfaFonts(handler, task) { + const acroForm = await this.pdfManager.ensureCatalog("acroForm"); + + if (!acroForm) { + return; + } + + const resources = await acroForm.getAsync("DR"); + + if (!(resources instanceof _primitives.Dict)) { + return; + } + + const objectLoader = new _object_loader.ObjectLoader(resources, ["Font"], this.xref); + await objectLoader.load(); + const fontRes = resources.get("Font"); + + if (!(fontRes instanceof _primitives.Dict)) { + return; + } + + const options = Object.assign(Object.create(null), this.pdfManager.evaluatorOptions); + options.useSystemFonts = false; + const partialEvaluator = new _evaluator.PartialEvaluator({ + xref: this.xref, + handler, + pageIndex: -1, + idFactory: this._globalIdFactory, + fontCache: this.catalog.fontCache, + builtInCMapCache: this.catalog.builtInCMapCache, + standardFontDataCache: this.catalog.standardFontDataCache, + options + }); + const operatorList = new _operator_list.OperatorList(); + const pdfFonts = []; + const initialState = { + get font() { + return pdfFonts.at(-1); + }, + + set font(font) { + pdfFonts.push(font); + }, + + clone() { + return this; + } + + }; + const fonts = new Map(); + fontRes.forEach((fontName, font) => { + fonts.set(fontName, font); + }); + const promises = []; + + for (const [fontName, font] of fonts) { + const descriptor = font.get("FontDescriptor"); + + if (!(descriptor instanceof _primitives.Dict)) { + continue; + } + + let fontFamily = descriptor.get("FontFamily"); + fontFamily = fontFamily.replace(/[ ]+(\d)/g, "$1"); + const fontWeight = descriptor.get("FontWeight"); + const italicAngle = -descriptor.get("ItalicAngle"); + const cssFontInfo = { + fontFamily, + fontWeight, + italicAngle + }; + + if (!(0, _core_utils.validateCSSFont)(cssFontInfo)) { + continue; + } + + promises.push(partialEvaluator.handleSetFont(resources, [_primitives.Name.get(fontName), 1], null, operatorList, task, initialState, null, cssFontInfo).catch(function (reason) { + (0, _util.warn)(`loadXfaFonts: "${reason}".`); + return null; + })); + } + + await Promise.all(promises); + const missingFonts = this.xfaFactory.setFonts(pdfFonts); + + if (!missingFonts) { + return; + } + + options.ignoreErrors = true; + promises.length = 0; + pdfFonts.length = 0; + const reallyMissingFonts = new Set(); + + for (const missing of missingFonts) { + if (!(0, _xfa_fonts.getXfaFontName)(`${missing}-Regular`)) { + reallyMissingFonts.add(missing); + } + } + + if (reallyMissingFonts.size) { + missingFonts.push("PdfJS-Fallback"); + } + + for (const missing of missingFonts) { + if (reallyMissingFonts.has(missing)) { + continue; + } + + for (const fontInfo of [{ + name: "Regular", + fontWeight: 400, + italicAngle: 0 + }, { + name: "Bold", + fontWeight: 700, + italicAngle: 0 + }, { + name: "Italic", + fontWeight: 400, + italicAngle: 12 + }, { + name: "BoldItalic", + fontWeight: 700, + italicAngle: 12 + }]) { + const name = `${missing}-${fontInfo.name}`; + const dict = (0, _xfa_fonts.getXfaFontDict)(name); + promises.push(partialEvaluator.handleSetFont(resources, [_primitives.Name.get(name), 1], null, operatorList, task, initialState, dict, { + fontFamily: missing, + fontWeight: fontInfo.fontWeight, + italicAngle: fontInfo.italicAngle + }).catch(function (reason) { + (0, _util.warn)(`loadXfaFonts: "${reason}".`); + return null; + })); + } + } + + await Promise.all(promises); + this.xfaFactory.appendFonts(pdfFonts, reallyMissingFonts); + } + + async serializeXfaData(annotationStorage) { + return this.xfaFactory ? this.xfaFactory.serializeData(annotationStorage) : null; + } + get formInfo() { const formInfo = { + hasFields: false, hasAcroForm: false, - hasXfa: false + hasXfa: false, + hasSignatures: false }; const acroForm = this.catalog.acroForm; @@ -3568,39 +4850,30 @@ class PDFDocument { } try { - const xfa = acroForm.get("XFA"); - const hasXfa = Array.isArray(xfa) && xfa.length > 0 || (0, _primitives.isStream)(xfa) && !xfa.isEmpty; - formInfo.hasXfa = hasXfa; const fields = acroForm.get("Fields"); const hasFields = Array.isArray(fields) && fields.length > 0; + formInfo.hasFields = hasFields; + const xfa = acroForm.get("XFA"); + formInfo.hasXfa = Array.isArray(xfa) && xfa.length > 0 || xfa instanceof _base_stream.BaseStream && !xfa.isEmpty; const sigFlags = acroForm.get("SigFlags"); + const hasSignatures = !!(sigFlags & 0x1); - const hasOnlyDocumentSignatures = !!(sigFlags & 0x1) && this._hasOnlyDocumentSignatures(fields); + const hasOnlyDocumentSignatures = hasSignatures && this._hasOnlyDocumentSignatures(fields); formInfo.hasAcroForm = hasFields && !hasOnlyDocumentSignatures; + formInfo.hasSignatures = hasSignatures; } catch (ex) { if (ex instanceof _core_utils.MissingDataException) { throw ex; } - (0, _util.info)("Cannot fetch form information."); + (0, _util.warn)(`Cannot fetch form information: "${ex}".`); } return (0, _util.shadow)(this, "formInfo", formInfo); } get documentInfo() { - const DocumentInfoValidators = { - Title: _util.isString, - Author: _util.isString, - Subject: _util.isString, - Keywords: _util.isString, - Creator: _util.isString, - Producer: _util.isString, - CreationDate: _util.isString, - ModDate: _util.isString, - Trapped: _primitives.isName - }; let version = this._version; if (typeof version !== "string" || !PDF_HEADER_VERSION_REGEXP.test(version)) { @@ -3610,10 +4883,13 @@ class PDFDocument { const docInfo = { PDFFormatVersion: version, + Language: this.catalog.lang, + EncryptFilterName: this.xref.encrypt ? this.xref.encrypt.filterName : null, IsLinearized: !!this.linearization, IsAcroFormPresent: this.formInfo.hasAcroForm, IsXFAPresent: this.formInfo.hasXfa, - IsCollectionPresent: !!this.catalog.collection + IsCollectionPresent: !!this.catalog.collection, + IsSignaturesPresent: this.formInfo.hasSignatures }; let infoDict; @@ -3627,25 +4903,60 @@ class PDFDocument { (0, _util.info)("The document information dictionary is invalid."); } - if ((0, _primitives.isDict)(infoDict)) { - for (const key of infoDict.getKeys()) { - const value = infoDict.get(key); + if (!(infoDict instanceof _primitives.Dict)) { + return (0, _util.shadow)(this, "documentInfo", docInfo); + } - if (DocumentInfoValidators[key]) { - if (DocumentInfoValidators[key](value)) { - docInfo[key] = typeof value !== "string" ? value : (0, _util.stringToPDFString)(value); - } else { - (0, _util.info)(`Bad value in document info for "${key}".`); + for (const key of infoDict.getKeys()) { + const value = infoDict.get(key); + + switch (key) { + case "Title": + case "Author": + case "Subject": + case "Keywords": + case "Creator": + case "Producer": + case "CreationDate": + case "ModDate": + if (typeof value === "string") { + docInfo[key] = (0, _util.stringToPDFString)(value); + continue; } - } else if (typeof key === "string") { + + break; + + case "Trapped": + if (value instanceof _primitives.Name) { + docInfo[key] = value; + continue; + } + + break; + + default: let customValue; - if ((0, _util.isString)(value)) { - customValue = (0, _util.stringToPDFString)(value); - } else if ((0, _primitives.isName)(value) || (0, _util.isNum)(value) || (0, _util.isBool)(value)) { - customValue = value; - } else { - (0, _util.info)(`Unsupported value in document info for (custom) "${key}".`); + switch (typeof value) { + case "string": + customValue = (0, _util.stringToPDFString)(value); + break; + + case "number": + case "boolean": + customValue = value; + break; + + default: + if (value instanceof _primitives.Name) { + customValue = value; + } + + break; + } + + if (customValue === undefined) { + (0, _util.warn)(`Bad value, for custom key "${key}", in Info: ${value}.`); continue; } @@ -3654,68 +4965,109 @@ class PDFDocument { } docInfo.Custom[key] = customValue; - } + continue; } + + (0, _util.warn)(`Bad value, for key "${key}", in Info: ${value}.`); } return (0, _util.shadow)(this, "documentInfo", docInfo); } - get fingerprint() { - let hash; + get fingerprints() { + function validate(data) { + return typeof data === "string" && data.length > 0 && data !== EMPTY_FINGERPRINT; + } + + function hexString(hash) { + const buf = []; + + for (let i = 0, ii = hash.length; i < ii; i++) { + const hex = hash[i].toString(16); + buf.push(hex.padStart(2, "0")); + } + + return buf.join(""); + } + const idArray = this.xref.trailer.get("ID"); + let hashOriginal, hashModified; - if (Array.isArray(idArray) && idArray[0] && (0, _util.isString)(idArray[0]) && idArray[0] !== EMPTY_FINGERPRINT) { - hash = (0, _util.stringToBytes)(idArray[0]); + if (Array.isArray(idArray) && validate(idArray[0])) { + hashOriginal = (0, _util.stringToBytes)(idArray[0]); + + if (idArray[1] !== idArray[0] && validate(idArray[1])) { + hashModified = (0, _util.stringToBytes)(idArray[1]); + } } else { - hash = (0, _crypto.calculateMD5)(this.stream.getByteRange(0, FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES); + hashOriginal = (0, _crypto.calculateMD5)(this.stream.getByteRange(0, FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES); } - const fingerprintBuf = []; - - for (let i = 0, ii = hash.length; i < ii; i++) { - const hex = hash[i].toString(16); - fingerprintBuf.push(hex.padStart(2, "0")); - } - - return (0, _util.shadow)(this, "fingerprint", fingerprintBuf.join("")); + return (0, _util.shadow)(this, "fingerprints", [hexString(hashOriginal), hashModified ? hexString(hashModified) : null]); } - _getLinearizationPage(pageIndex) { + async _getLinearizationPage(pageIndex) { const { catalog, - linearization + linearization, + xref } = this; const ref = _primitives.Ref.get(linearization.objectNumberFirst, 0); - return this.xref.fetchAsync(ref).then(obj => { - if ((0, _primitives.isDict)(obj, "Page") || (0, _primitives.isDict)(obj) && !obj.has("Type") && obj.has("Contents")) { - if (ref && !catalog.pageKidsCountCache.has(ref)) { - catalog.pageKidsCountCache.put(ref, 1); + try { + const obj = await xref.fetchAsync(ref); + + if (obj instanceof _primitives.Dict) { + let type = obj.getRaw("Type"); + + if (type instanceof _primitives.Ref) { + type = await xref.fetchAsync(type); } - return [obj, ref]; + if ((0, _primitives.isName)(type, "Page") || !obj.has("Type") && !obj.has("Kids")) { + if (!catalog.pageKidsCountCache.has(ref)) { + catalog.pageKidsCountCache.put(ref, 1); + } + + if (!catalog.pageIndexCache.has(ref)) { + catalog.pageIndexCache.put(ref, 0); + } + + return [obj, ref]; + } } - throw new _util.FormatError("The Linearization dictionary doesn't point " + "to a valid Page dictionary."); - }).catch(reason => { - (0, _util.info)(reason); + throw new _util.FormatError("The Linearization dictionary doesn't point to a valid Page dictionary."); + } catch (reason) { + (0, _util.warn)(`_getLinearizationPage: "${reason.message}".`); return catalog.getPageDict(pageIndex); - }); + } } getPage(pageIndex) { - if (this._pagePromises[pageIndex] !== undefined) { - return this._pagePromises[pageIndex]; + const cachedPromise = this._pagePromises.get(pageIndex); + + if (cachedPromise) { + return cachedPromise; } const { catalog, - linearization + linearization, + xfaFactory } = this; - const promise = linearization && linearization.pageFirst === pageIndex ? this._getLinearizationPage(pageIndex) : catalog.getPageDict(pageIndex); - return this._pagePromises[pageIndex] = promise.then(([pageDict, ref]) => { + let promise; + + if (xfaFactory) { + promise = Promise.resolve([_primitives.Dict.empty, null]); + } else if (linearization && linearization.pageFirst === pageIndex) { + promise = this._getLinearizationPage(pageIndex); + } else { + promise = catalog.getPageDict(pageIndex); + } + + promise = promise.then(([pageDict, ref]) => { return new Page({ pdfManager: this.pdfManager, xref: this.xref, @@ -3725,19 +5077,112 @@ class PDFDocument { globalIdFactory: this._globalIdFactory, fontCache: catalog.fontCache, builtInCMapCache: catalog.builtInCMapCache, - globalImageCache: catalog.globalImageCache + standardFontDataCache: catalog.standardFontDataCache, + globalImageCache: catalog.globalImageCache, + nonBlendModesSet: catalog.nonBlendModesSet, + xfaFactory }); }); + + this._pagePromises.set(pageIndex, promise); + + return promise; } - checkFirstPage() { - return this.getPage(0).catch(async reason => { + async checkFirstPage(recoveryMode = false) { + if (recoveryMode) { + return; + } + + try { + await this.getPage(0); + } catch (reason) { if (reason instanceof _core_utils.XRefEntryException) { - this._pagePromises.length = 0; + this._pagePromises.delete(0); + await this.cleanup(); throw new _core_utils.XRefParseException(); } - }); + } + } + + async checkLastPage(recoveryMode = false) { + const { + catalog, + pdfManager + } = this; + catalog.setActualNumPages(); + let numPages; + + try { + await Promise.all([pdfManager.ensureDoc("xfaFactory"), pdfManager.ensureDoc("linearization"), pdfManager.ensureCatalog("numPages")]); + + if (this.xfaFactory) { + return; + } else if (this.linearization) { + numPages = this.linearization.numPages; + } else { + numPages = catalog.numPages; + } + + if (!Number.isInteger(numPages)) { + throw new _util.FormatError("Page count is not an integer."); + } else if (numPages <= 1) { + return; + } + + await this.getPage(numPages - 1); + } catch (reason) { + this._pagePromises.delete(numPages - 1); + + await this.cleanup(); + + if (reason instanceof _core_utils.XRefEntryException && !recoveryMode) { + throw new _core_utils.XRefParseException(); + } + + (0, _util.warn)(`checkLastPage - invalid /Pages tree /Count: ${numPages}.`); + let pagesTree; + + try { + pagesTree = await catalog.getAllPageDicts(recoveryMode); + } catch (reasonAll) { + if (reasonAll instanceof _core_utils.XRefEntryException && !recoveryMode) { + throw new _core_utils.XRefParseException(); + } + + catalog.setActualNumPages(1); + return; + } + + for (const [pageIndex, [pageDict, ref]] of pagesTree) { + let promise; + + if (pageDict instanceof Error) { + promise = Promise.reject(pageDict); + promise.catch(() => {}); + } else { + promise = Promise.resolve(new Page({ + pdfManager, + xref: this.xref, + pageIndex, + pageDict, + ref, + globalIdFactory: this._globalIdFactory, + fontCache: catalog.fontCache, + builtInCMapCache: catalog.builtInCMapCache, + standardFontDataCache: catalog.standardFontDataCache, + globalImageCache: catalog.globalImageCache, + nonBlendModesSet: catalog.nonBlendModesSet, + xfaFactory: null + })); + } + + this._pagePromises.set(pageIndex, promise); + } + + catalog.setActualNumPages(pagesTree.size); + } } fontFallback(id, handler) { @@ -3745,7 +5190,112 @@ class PDFDocument { } async cleanup(manuallyTriggered = false) { - return this.catalog ? this.catalog.cleanup(manuallyTriggered) : (0, _primitives.clearPrimitiveCaches)(); + return this.catalog ? this.catalog.cleanup(manuallyTriggered) : (0, _cleanup_helper.clearGlobalCaches)(); + } + + _collectFieldObjects(name, fieldRef, promises) { + const field = this.xref.fetchIfRef(fieldRef); + + if (field.has("T")) { + const partName = (0, _util.stringToPDFString)(field.get("T")); + + if (name === "") { + name = partName; + } else { + name = `${name}.${partName}`; + } + } + + if (!promises.has(name)) { + promises.set(name, []); + } + + promises.get(name).push(_annotation.AnnotationFactory.create(this.xref, fieldRef, this.pdfManager, this._localIdFactory, true).then(annotation => annotation && annotation.getFieldObject()).catch(function (reason) { + (0, _util.warn)(`_collectFieldObjects: "${reason}".`); + return null; + })); + + if (field.has("Kids")) { + const kids = field.get("Kids"); + + for (const kid of kids) { + this._collectFieldObjects(name, kid, promises); + } + } + } + + get fieldObjects() { + if (!this.formInfo.hasFields) { + return (0, _util.shadow)(this, "fieldObjects", Promise.resolve(null)); + } + + const allFields = Object.create(null); + const fieldPromises = new Map(); + + for (const fieldRef of this.catalog.acroForm.get("Fields")) { + this._collectFieldObjects("", fieldRef, fieldPromises); + } + + const allPromises = []; + + for (const [name, promises] of fieldPromises) { + allPromises.push(Promise.all(promises).then(fields => { + fields = fields.filter(field => !!field); + + if (fields.length > 0) { + allFields[name] = fields; + } + })); + } + + return (0, _util.shadow)(this, "fieldObjects", Promise.all(allPromises).then(() => allFields)); + } + + get hasJSActions() { + const promise = this.pdfManager.ensureDoc("_parseHasJSActions"); + return (0, _util.shadow)(this, "hasJSActions", promise); + } + + async _parseHasJSActions() { + const [catalogJsActions, fieldObjects] = await Promise.all([this.pdfManager.ensureCatalog("jsActions"), this.pdfManager.ensureDoc("fieldObjects")]); + + if (catalogJsActions) { + return true; + } + + if (fieldObjects) { + return Object.values(fieldObjects).some(fieldObject => fieldObject.some(object => object.actions !== null)); + } + + return false; + } + + get calculationOrderIds() { + const acroForm = this.catalog.acroForm; + + if (!acroForm || !acroForm.has("CO")) { + return (0, _util.shadow)(this, "calculationOrderIds", null); + } + + const calculationOrder = acroForm.get("CO"); + + if (!Array.isArray(calculationOrder) || calculationOrder.length === 0) { + return (0, _util.shadow)(this, "calculationOrderIds", null); + } + + const ids = []; + + for (const id of calculationOrder) { + if (id instanceof _primitives.Ref) { + ids.push(id.toString()); + } + } + + if (ids.length === 0) { + return (0, _util.shadow)(this, "calculationOrderIds", null); + } + + return (0, _util.shadow)(this, "calculationOrderIds", ids); } } @@ -3753,13968 +5303,3494 @@ class PDFDocument { exports.PDFDocument = PDFDocument; /***/ }), -/* 10 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 12 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.FileSpec = exports.XRef = exports.ObjectLoader = exports.Catalog = void 0; +})); +exports.PopupAnnotation = exports.MarkupAnnotation = exports.AnnotationFactory = exports.AnnotationBorderStyle = exports.Annotation = void 0; +exports.getQuadPoints = getQuadPoints; var _util = __w_pdfjs_require__(2); +var _core_utils = __w_pdfjs_require__(6); + +var _default_appearance = __w_pdfjs_require__(13); + var _primitives = __w_pdfjs_require__(5); -var _parser = __w_pdfjs_require__(11); +var _writer = __w_pdfjs_require__(65); -var _core_utils = __w_pdfjs_require__(8); +var _base_stream = __w_pdfjs_require__(7); -var _crypto = __w_pdfjs_require__(22); +var _bidi = __w_pdfjs_require__(60); -var _colorspace = __w_pdfjs_require__(23); +var _catalog = __w_pdfjs_require__(69); -var _image_utils = __w_pdfjs_require__(24); +var _colorspace = __w_pdfjs_require__(14); -function fetchDestination(dest) { - return (0, _primitives.isDict)(dest) ? dest.get("D") : dest; -} +var _file_spec = __w_pdfjs_require__(72); -class Catalog { - constructor(pdfManager, xref) { - this.pdfManager = pdfManager; - this.xref = xref; - this._catDict = xref.getCatalogObj(); +var _object_loader = __w_pdfjs_require__(75); - if (!(0, _primitives.isDict)(this._catDict)) { - throw new _util.FormatError("Catalog object is not a dictionary."); - } +var _operator_list = __w_pdfjs_require__(62); - this.fontCache = new _primitives.RefSetCache(); - this.builtInCMapCache = new Map(); - this.globalImageCache = new _image_utils.GlobalImageCache(); - this.pageKidsCountCache = new _primitives.RefSetCache(); +var _stream = __w_pdfjs_require__(10); + +var _factory = __w_pdfjs_require__(76); + +class AnnotationFactory { + static create(xref, ref, pdfManager, idFactory, collectFields) { + return Promise.all([pdfManager.ensureCatalog("acroForm"), pdfManager.ensureCatalog("baseUrl"), pdfManager.ensureDoc("xfaDatasets"), collectFields ? this._getPageIndex(xref, ref, pdfManager) : -1]).then(([acroForm, baseUrl, xfaDatasets, pageIndex]) => pdfManager.ensure(this, "_create", [xref, ref, pdfManager, idFactory, acroForm, xfaDatasets, collectFields, pageIndex])); } - get version() { - const version = this._catDict.get("Version"); + static _create(xref, ref, pdfManager, idFactory, acroForm, xfaDatasets, collectFields, pageIndex = -1) { + const dict = xref.fetchIfRef(ref); - if (!(0, _primitives.isName)(version)) { - return (0, _util.shadow)(this, "version", null); - } - - return (0, _util.shadow)(this, "version", version.name); - } - - get collection() { - let collection = null; - - try { - const obj = this._catDict.get("Collection"); - - if ((0, _primitives.isDict)(obj) && obj.size > 0) { - collection = obj; - } - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.info)("Cannot fetch Collection entry; assuming no collection is present."); - } - - return (0, _util.shadow)(this, "collection", collection); - } - - get acroForm() { - let acroForm = null; - - try { - const obj = this._catDict.get("AcroForm"); - - if ((0, _primitives.isDict)(obj) && obj.size > 0) { - acroForm = obj; - } - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.info)("Cannot fetch AcroForm entry; assuming no forms are present."); - } - - return (0, _util.shadow)(this, "acroForm", acroForm); - } - - get metadata() { - const streamRef = this._catDict.getRaw("Metadata"); - - if (!(0, _primitives.isRef)(streamRef)) { - return (0, _util.shadow)(this, "metadata", null); - } - - const suppressEncryption = !(this.xref.encrypt && this.xref.encrypt.encryptMetadata); - const stream = this.xref.fetch(streamRef, suppressEncryption); - let metadata; - - if (stream && (0, _primitives.isDict)(stream.dict)) { - const type = stream.dict.get("Type"); - const subtype = stream.dict.get("Subtype"); - - if ((0, _primitives.isName)(type, "Metadata") && (0, _primitives.isName)(subtype, "XML")) { - try { - metadata = (0, _util.stringToUTF8String)((0, _util.bytesToString)(stream.getBytes())); - } catch (e) { - if (e instanceof _core_utils.MissingDataException) { - throw e; - } - - (0, _util.info)("Skipping invalid metadata."); - } - } - } - - return (0, _util.shadow)(this, "metadata", metadata); - } - - get toplevelPagesDict() { - const pagesObj = this._catDict.get("Pages"); - - if (!(0, _primitives.isDict)(pagesObj)) { - throw new _util.FormatError("Invalid top-level pages dictionary."); - } - - return (0, _util.shadow)(this, "toplevelPagesDict", pagesObj); - } - - get documentOutline() { - let obj = null; - - try { - obj = this._readDocumentOutline(); - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.warn)("Unable to read document outline."); - } - - return (0, _util.shadow)(this, "documentOutline", obj); - } - - _readDocumentOutline() { - let obj = this._catDict.get("Outlines"); - - if (!(0, _primitives.isDict)(obj)) { - return null; - } - - obj = obj.getRaw("First"); - - if (!(0, _primitives.isRef)(obj)) { - return null; - } - - const root = { - items: [] - }; - const queue = [{ - obj, - parent: root - }]; - const processed = new _primitives.RefSet(); - processed.put(obj); - const xref = this.xref, - blackColor = new Uint8ClampedArray(3); - - while (queue.length > 0) { - const i = queue.shift(); - const outlineDict = xref.fetchIfRef(i.obj); - - if (outlineDict === null) { - continue; - } - - if (!outlineDict.has("Title")) { - throw new _util.FormatError("Invalid outline item encountered."); - } - - const data = { - url: null, - dest: null - }; - Catalog.parseDestDictionary({ - destDict: outlineDict, - resultObj: data, - docBaseUrl: this.pdfManager.docBaseUrl - }); - const title = outlineDict.get("Title"); - const flags = outlineDict.get("F") || 0; - const color = outlineDict.getArray("C"); - const count = outlineDict.get("Count"); - let rgbColor = blackColor; - - if (Array.isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) { - rgbColor = _colorspace.ColorSpace.singletons.rgb.getRgb(color, 0); - } - - const outlineItem = { - dest: data.dest, - url: data.url, - unsafeUrl: data.unsafeUrl, - newWindow: data.newWindow, - title: (0, _util.stringToPDFString)(title), - color: rgbColor, - count: Number.isInteger(count) ? count : undefined, - bold: !!(flags & 2), - italic: !!(flags & 1), - items: [] - }; - i.parent.items.push(outlineItem); - obj = outlineDict.getRaw("First"); - - if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { - queue.push({ - obj, - parent: outlineItem - }); - processed.put(obj); - } - - obj = outlineDict.getRaw("Next"); - - if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { - queue.push({ - obj, - parent: i.parent - }); - processed.put(obj); - } - } - - return root.items.length > 0 ? root.items : null; - } - - get permissions() { - let permissions = null; - - try { - permissions = this._readPermissions(); - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.warn)("Unable to read permissions."); - } - - return (0, _util.shadow)(this, "permissions", permissions); - } - - _readPermissions() { - const encrypt = this.xref.trailer.get("Encrypt"); - - if (!(0, _primitives.isDict)(encrypt)) { - return null; - } - - let flags = encrypt.get("P"); - - if (!(0, _util.isNum)(flags)) { - return null; - } - - flags += 2 ** 32; - const permissions = []; - - for (const key in _util.PermissionFlag) { - const value = _util.PermissionFlag[key]; - - if (flags & value) { - permissions.push(value); - } - } - - return permissions; - } - - get optionalContentConfig() { - let config = null; - - try { - const properties = this._catDict.get("OCProperties"); - - if (!properties) { - return (0, _util.shadow)(this, "optionalContentConfig", null); - } - - const defaultConfig = properties.get("D"); - - if (!defaultConfig) { - return (0, _util.shadow)(this, "optionalContentConfig", null); - } - - const groupsData = properties.get("OCGs"); - - if (!Array.isArray(groupsData)) { - return (0, _util.shadow)(this, "optionalContentConfig", null); - } - - const groups = []; - const groupRefs = []; - - for (const groupRef of groupsData) { - if (!(0, _primitives.isRef)(groupRef)) { - continue; - } - - groupRefs.push(groupRef); - const group = this.xref.fetchIfRef(groupRef); - groups.push({ - id: groupRef.toString(), - name: (0, _util.isString)(group.get("Name")) ? (0, _util.stringToPDFString)(group.get("Name")) : null, - intent: (0, _util.isString)(group.get("Intent")) ? (0, _util.stringToPDFString)(group.get("Intent")) : null - }); - } - - config = this._readOptionalContentConfig(defaultConfig, groupRefs); - config.groups = groups; - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.warn)(`Unable to read optional content config: ${ex}`); - } - - return (0, _util.shadow)(this, "optionalContentConfig", config); - } - - _readOptionalContentConfig(config, contentGroupRefs) { - function parseOnOff(refs) { - const onParsed = []; - - if (Array.isArray(refs)) { - for (const value of refs) { - if (!(0, _primitives.isRef)(value)) { - continue; - } - - if (contentGroupRefs.includes(value)) { - onParsed.push(value.toString()); - } - } - } - - return onParsed; - } - - function parseOrder(refs, nestedLevels = 0) { - if (!Array.isArray(refs)) { - return null; - } - - const order = []; - - for (const value of refs) { - if ((0, _primitives.isRef)(value) && contentGroupRefs.includes(value)) { - parsedOrderRefs.put(value); - order.push(value.toString()); - continue; - } - - const nestedOrder = parseNestedOrder(value, nestedLevels); - - if (nestedOrder) { - order.push(nestedOrder); - } - } - - if (nestedLevels > 0) { - return order; - } - - const hiddenGroups = []; - - for (const groupRef of contentGroupRefs) { - if (parsedOrderRefs.has(groupRef)) { - continue; - } - - hiddenGroups.push(groupRef.toString()); - } - - if (hiddenGroups.length) { - order.push({ - name: null, - order: hiddenGroups - }); - } - - return order; - } - - function parseNestedOrder(ref, nestedLevels) { - if (++nestedLevels > MAX_NESTED_LEVELS) { - (0, _util.warn)("parseNestedOrder - reached MAX_NESTED_LEVELS."); - return null; - } - - const value = xref.fetchIfRef(ref); - - if (!Array.isArray(value)) { - return null; - } - - const nestedName = xref.fetchIfRef(value[0]); - - if (typeof nestedName !== "string") { - return null; - } - - const nestedOrder = parseOrder(value.slice(1), nestedLevels); - - if (!nestedOrder || !nestedOrder.length) { - return null; - } - - return { - name: (0, _util.stringToPDFString)(nestedName), - order: nestedOrder - }; - } - - const xref = this.xref, - parsedOrderRefs = new _primitives.RefSet(), - MAX_NESTED_LEVELS = 10; - return { - name: (0, _util.isString)(config.get("Name")) ? (0, _util.stringToPDFString)(config.get("Name")) : null, - creator: (0, _util.isString)(config.get("Creator")) ? (0, _util.stringToPDFString)(config.get("Creator")) : null, - baseState: (0, _primitives.isName)(config.get("BaseState")) ? config.get("BaseState").name : null, - on: parseOnOff(config.get("ON")), - off: parseOnOff(config.get("OFF")), - order: parseOrder(config.get("Order")), - groups: null - }; - } - - get numPages() { - const obj = this.toplevelPagesDict.get("Count"); - - if (!Number.isInteger(obj)) { - throw new _util.FormatError("Page count in top-level pages dictionary is not an integer."); - } - - return (0, _util.shadow)(this, "numPages", obj); - } - - get destinations() { - const obj = this._readDests(), - dests = Object.create(null); - - if (obj instanceof NameTree) { - const names = obj.getAll(); - - for (const name in names) { - dests[name] = fetchDestination(names[name]); - } - } else if (obj instanceof _primitives.Dict) { - obj.forEach(function (key, value) { - if (value) { - dests[key] = fetchDestination(value); - } - }); - } - - return (0, _util.shadow)(this, "destinations", dests); - } - - getDestination(destinationId) { - const obj = this._readDests(); - - if (obj instanceof NameTree || obj instanceof _primitives.Dict) { - return fetchDestination(obj.get(destinationId) || null); - } - - return null; - } - - _readDests() { - const obj = this._catDict.get("Names"); - - if (obj && obj.has("Dests")) { - return new NameTree(obj.getRaw("Dests"), this.xref); - } else if (this._catDict.has("Dests")) { - return this._catDict.get("Dests"); - } - - return undefined; - } - - get pageLabels() { - let obj = null; - - try { - obj = this._readPageLabels(); - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.warn)("Unable to read page labels."); - } - - return (0, _util.shadow)(this, "pageLabels", obj); - } - - _readPageLabels() { - const obj = this._catDict.getRaw("PageLabels"); - - if (!obj) { - return null; - } - - const pageLabels = new Array(this.numPages); - let style = null, - prefix = ""; - const numberTree = new NumberTree(obj, this.xref); - const nums = numberTree.getAll(); - let currentLabel = "", - currentIndex = 1; - - for (let i = 0, ii = this.numPages; i < ii; i++) { - if (i in nums) { - const labelDict = nums[i]; - - if (!(0, _primitives.isDict)(labelDict)) { - throw new _util.FormatError("PageLabel is not a dictionary."); - } - - if (labelDict.has("Type") && !(0, _primitives.isName)(labelDict.get("Type"), "PageLabel")) { - throw new _util.FormatError("Invalid type in PageLabel dictionary."); - } - - if (labelDict.has("S")) { - const s = labelDict.get("S"); - - if (!(0, _primitives.isName)(s)) { - throw new _util.FormatError("Invalid style in PageLabel dictionary."); - } - - style = s.name; - } else { - style = null; - } - - if (labelDict.has("P")) { - const p = labelDict.get("P"); - - if (!(0, _util.isString)(p)) { - throw new _util.FormatError("Invalid prefix in PageLabel dictionary."); - } - - prefix = (0, _util.stringToPDFString)(p); - } else { - prefix = ""; - } - - if (labelDict.has("St")) { - const st = labelDict.get("St"); - - if (!(Number.isInteger(st) && st >= 1)) { - throw new _util.FormatError("Invalid start in PageLabel dictionary."); - } - - currentIndex = st; - } else { - currentIndex = 1; - } - } - - switch (style) { - case "D": - currentLabel = currentIndex; - break; - - case "R": - case "r": - currentLabel = (0, _core_utils.toRomanNumerals)(currentIndex, style === "r"); - break; - - case "A": - case "a": - const LIMIT = 26; - const A_UPPER_CASE = 0x41, - A_LOWER_CASE = 0x61; - const baseCharCode = style === "a" ? A_LOWER_CASE : A_UPPER_CASE; - const letterIndex = currentIndex - 1; - const character = String.fromCharCode(baseCharCode + letterIndex % LIMIT); - const charBuf = []; - - for (let j = 0, jj = letterIndex / LIMIT | 0; j <= jj; j++) { - charBuf.push(character); - } - - currentLabel = charBuf.join(""); - break; - - default: - if (style) { - throw new _util.FormatError(`Invalid style "${style}" in PageLabel dictionary.`); - } - - currentLabel = ""; - } - - pageLabels[i] = prefix + currentLabel; - currentIndex++; - } - - return pageLabels; - } - - get pageLayout() { - const obj = this._catDict.get("PageLayout"); - - let pageLayout = ""; - - if ((0, _primitives.isName)(obj)) { - switch (obj.name) { - case "SinglePage": - case "OneColumn": - case "TwoColumnLeft": - case "TwoColumnRight": - case "TwoPageLeft": - case "TwoPageRight": - pageLayout = obj.name; - } - } - - return (0, _util.shadow)(this, "pageLayout", pageLayout); - } - - get pageMode() { - const obj = this._catDict.get("PageMode"); - - let pageMode = "UseNone"; - - if ((0, _primitives.isName)(obj)) { - switch (obj.name) { - case "UseNone": - case "UseOutlines": - case "UseThumbs": - case "FullScreen": - case "UseOC": - case "UseAttachments": - pageMode = obj.name; - } - } - - return (0, _util.shadow)(this, "pageMode", pageMode); - } - - get viewerPreferences() { - const ViewerPreferencesValidators = { - HideToolbar: _util.isBool, - HideMenubar: _util.isBool, - HideWindowUI: _util.isBool, - FitWindow: _util.isBool, - CenterWindow: _util.isBool, - DisplayDocTitle: _util.isBool, - NonFullScreenPageMode: _primitives.isName, - Direction: _primitives.isName, - ViewArea: _primitives.isName, - ViewClip: _primitives.isName, - PrintArea: _primitives.isName, - PrintClip: _primitives.isName, - PrintScaling: _primitives.isName, - Duplex: _primitives.isName, - PickTrayByPDFSize: _util.isBool, - PrintPageRange: Array.isArray, - NumCopies: Number.isInteger - }; - - const obj = this._catDict.get("ViewerPreferences"); - - let prefs = null; - - if ((0, _primitives.isDict)(obj)) { - for (const key in ViewerPreferencesValidators) { - if (!obj.has(key)) { - continue; - } - - const value = obj.get(key); - - if (!ViewerPreferencesValidators[key](value)) { - (0, _util.info)(`Bad value in ViewerPreferences for "${key}".`); - continue; - } - - let prefValue; - - switch (key) { - case "NonFullScreenPageMode": - switch (value.name) { - case "UseNone": - case "UseOutlines": - case "UseThumbs": - case "UseOC": - prefValue = value.name; - break; - - default: - prefValue = "UseNone"; - } - - break; - - case "Direction": - switch (value.name) { - case "L2R": - case "R2L": - prefValue = value.name; - break; - - default: - prefValue = "L2R"; - } - - break; - - case "ViewArea": - case "ViewClip": - case "PrintArea": - case "PrintClip": - switch (value.name) { - case "MediaBox": - case "CropBox": - case "BleedBox": - case "TrimBox": - case "ArtBox": - prefValue = value.name; - break; - - default: - prefValue = "CropBox"; - } - - break; - - case "PrintScaling": - switch (value.name) { - case "None": - case "AppDefault": - prefValue = value.name; - break; - - default: - prefValue = "AppDefault"; - } - - break; - - case "Duplex": - switch (value.name) { - case "Simplex": - case "DuplexFlipShortEdge": - case "DuplexFlipLongEdge": - prefValue = value.name; - break; - - default: - prefValue = "None"; - } - - break; - - case "PrintPageRange": - const length = value.length; - - if (length % 2 !== 0) { - break; - } - - const isValid = value.every((page, i, arr) => { - return Number.isInteger(page) && page > 0 && (i === 0 || page >= arr[i - 1]) && page <= this.numPages; - }); - - if (isValid) { - prefValue = value; - } - - break; - - case "NumCopies": - if (value > 0) { - prefValue = value; - } - - break; - - default: - if (typeof value !== "boolean") { - throw new _util.FormatError(`viewerPreferences - expected a boolean value for: ${key}`); - } - - prefValue = value; - } - - if (prefValue !== undefined) { - if (!prefs) { - prefs = Object.create(null); - } - - prefs[key] = prefValue; - } else { - (0, _util.info)(`Bad value in ViewerPreferences for "${key}".`); - } - } - } - - return (0, _util.shadow)(this, "viewerPreferences", prefs); - } - - get openAction() { - const obj = this._catDict.get("OpenAction"); - - let openAction = null; - - if ((0, _primitives.isDict)(obj)) { - const destDict = new _primitives.Dict(this.xref); - destDict.set("A", obj); - const resultObj = { - url: null, - dest: null, - action: null - }; - Catalog.parseDestDictionary({ - destDict, - resultObj - }); - - if (Array.isArray(resultObj.dest)) { - if (!openAction) { - openAction = Object.create(null); - } - - openAction.dest = resultObj.dest; - } else if (resultObj.action) { - if (!openAction) { - openAction = Object.create(null); - } - - openAction.action = resultObj.action; - } - } else if (Array.isArray(obj)) { - if (!openAction) { - openAction = Object.create(null); - } - - openAction.dest = obj; - } - - return (0, _util.shadow)(this, "openAction", openAction); - } - - get attachments() { - const obj = this._catDict.get("Names"); - - let attachments = null; - - if (obj && obj.has("EmbeddedFiles")) { - const nameTree = new NameTree(obj.getRaw("EmbeddedFiles"), this.xref); - const names = nameTree.getAll(); - - for (const name in names) { - const fs = new FileSpec(names[name], this.xref); - - if (!attachments) { - attachments = Object.create(null); - } - - attachments[(0, _util.stringToPDFString)(name)] = fs.serializable; - } - } - - return (0, _util.shadow)(this, "attachments", attachments); - } - - get javaScript() { - const obj = this._catDict.get("Names"); - - let javaScript = null; - - function appendIfJavaScriptDict(jsDict) { - const type = jsDict.get("S"); - - if (!(0, _primitives.isName)(type, "JavaScript")) { - return; - } - - let js = jsDict.get("JS"); - - if ((0, _primitives.isStream)(js)) { - js = (0, _util.bytesToString)(js.getBytes()); - } else if (!(0, _util.isString)(js)) { - return; - } - - if (!javaScript) { - javaScript = []; - } - - javaScript.push((0, _util.stringToPDFString)(js)); - } - - if (obj && obj.has("JavaScript")) { - const nameTree = new NameTree(obj.getRaw("JavaScript"), this.xref); - const names = nameTree.getAll(); - - for (const name in names) { - const jsDict = names[name]; - - if ((0, _primitives.isDict)(jsDict)) { - appendIfJavaScriptDict(jsDict); - } - } - } - - const openAction = this._catDict.get("OpenAction"); - - if ((0, _primitives.isDict)(openAction) && (0, _primitives.isName)(openAction.get("S"), "JavaScript")) { - appendIfJavaScriptDict(openAction); - } - - return (0, _util.shadow)(this, "javaScript", javaScript); - } - - fontFallback(id, handler) { - const promises = []; - this.fontCache.forEach(function (promise) { - promises.push(promise); - }); - return Promise.all(promises).then(translatedFonts => { - for (const translatedFont of translatedFonts) { - if (translatedFont.loadedName === id) { - translatedFont.fallback(handler); - return; - } - } - }); - } - - cleanup(manuallyTriggered = false) { - (0, _primitives.clearPrimitiveCaches)(); - this.globalImageCache.clear(manuallyTriggered); - this.pageKidsCountCache.clear(); - const promises = []; - this.fontCache.forEach(function (promise) { - promises.push(promise); - }); - return Promise.all(promises).then(translatedFonts => { - for (const { - dict - } of translatedFonts) { - delete dict.translated; - } - - this.fontCache.clear(); - this.builtInCMapCache.clear(); - }); - } - - getPageDict(pageIndex) { - const capability = (0, _util.createPromiseCapability)(); - const nodesToVisit = [this._catDict.getRaw("Pages")]; - const visitedNodes = new _primitives.RefSet(); - const xref = this.xref, - pageKidsCountCache = this.pageKidsCountCache; - let count, - currentPageIndex = 0; - - function next() { - while (nodesToVisit.length) { - const currentNode = nodesToVisit.pop(); - - if ((0, _primitives.isRef)(currentNode)) { - count = pageKidsCountCache.get(currentNode); - - if (count > 0 && currentPageIndex + count < pageIndex) { - currentPageIndex += count; - continue; - } - - if (visitedNodes.has(currentNode)) { - capability.reject(new _util.FormatError("Pages tree contains circular reference.")); - return; - } - - visitedNodes.put(currentNode); - xref.fetchAsync(currentNode).then(function (obj) { - if ((0, _primitives.isDict)(obj, "Page") || (0, _primitives.isDict)(obj) && !obj.has("Kids")) { - if (pageIndex === currentPageIndex) { - if (currentNode && !pageKidsCountCache.has(currentNode)) { - pageKidsCountCache.put(currentNode, 1); - } - - capability.resolve([obj, currentNode]); - } else { - currentPageIndex++; - next(); - } - - return; - } - - nodesToVisit.push(obj); - next(); - }, capability.reject); - return; - } - - if (!(0, _primitives.isDict)(currentNode)) { - capability.reject(new _util.FormatError("Page dictionary kid reference points to wrong type of object.")); - return; - } - - count = currentNode.get("Count"); - - if (Number.isInteger(count) && count >= 0) { - const objId = currentNode.objId; - - if (objId && !pageKidsCountCache.has(objId)) { - pageKidsCountCache.put(objId, count); - } - - if (currentPageIndex + count <= pageIndex) { - currentPageIndex += count; - continue; - } - } - - const kids = currentNode.get("Kids"); - - if (!Array.isArray(kids)) { - if ((0, _primitives.isName)(currentNode.get("Type"), "Page") || !currentNode.has("Type") && currentNode.has("Contents")) { - if (currentPageIndex === pageIndex) { - capability.resolve([currentNode, null]); - return; - } - - currentPageIndex++; - continue; - } - - capability.reject(new _util.FormatError("Page dictionary kids object is not an array.")); - return; - } - - for (let last = kids.length - 1; last >= 0; last--) { - nodesToVisit.push(kids[last]); - } - } - - capability.reject(new Error(`Page index ${pageIndex} not found.`)); - } - - next(); - return capability.promise; - } - - getPageIndex(pageRef) { - const xref = this.xref; - - function pagesBeforeRef(kidRef) { - let total = 0, - parentRef; - return xref.fetchAsync(kidRef).then(function (node) { - if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, "Page") && !((0, _primitives.isDict)(node) && !node.has("Type") && node.has("Contents"))) { - throw new _util.FormatError("The reference does not point to a /Page dictionary."); - } - - if (!node) { - return null; - } - - if (!(0, _primitives.isDict)(node)) { - throw new _util.FormatError("Node must be a dictionary."); - } - - parentRef = node.getRaw("Parent"); - return node.getAsync("Parent"); - }).then(function (parent) { - if (!parent) { - return null; - } - - if (!(0, _primitives.isDict)(parent)) { - throw new _util.FormatError("Parent must be a dictionary."); - } - - return parent.getAsync("Kids"); - }).then(function (kids) { - if (!kids) { - return null; - } - - const kidPromises = []; - let found = false; - - for (let i = 0, ii = kids.length; i < ii; i++) { - const kid = kids[i]; - - if (!(0, _primitives.isRef)(kid)) { - throw new _util.FormatError("Kid must be a reference."); - } - - if ((0, _primitives.isRefsEqual)(kid, kidRef)) { - found = true; - break; - } - - kidPromises.push(xref.fetchAsync(kid).then(function (obj) { - if (!(0, _primitives.isDict)(obj)) { - throw new _util.FormatError("Kid node must be a dictionary."); - } - - if (obj.has("Count")) { - total += obj.get("Count"); - } else { - total++; - } - })); - } - - if (!found) { - throw new _util.FormatError("Kid reference not found in parent's kids."); - } - - return Promise.all(kidPromises).then(function () { - return [total, parentRef]; - }); - }); - } - - let total = 0; - - function next(ref) { - return pagesBeforeRef(ref).then(function (args) { - if (!args) { - return total; - } - - const [count, parentRef] = args; - total += count; - return next(parentRef); - }); - } - - return next(pageRef); - } - - static parseDestDictionary(params) { - function addDefaultProtocolToUrl(url) { - return url.startsWith("www.") ? `http://${url}` : url; - } - - function tryConvertUrlEncoding(url) { - try { - return (0, _util.stringToUTF8String)(url); - } catch (e) { - return url; - } - } - - const destDict = params.destDict; - - if (!(0, _primitives.isDict)(destDict)) { - (0, _util.warn)("parseDestDictionary: `destDict` must be a dictionary."); - return; - } - - const resultObj = params.resultObj; - - if (typeof resultObj !== "object") { - (0, _util.warn)("parseDestDictionary: `resultObj` must be an object."); - return; - } - - const docBaseUrl = params.docBaseUrl || null; - let action = destDict.get("A"), - url, - dest; - - if (!(0, _primitives.isDict)(action) && destDict.has("Dest")) { - action = destDict.get("Dest"); - } - - if ((0, _primitives.isDict)(action)) { - const actionType = action.get("S"); - - if (!(0, _primitives.isName)(actionType)) { - (0, _util.warn)("parseDestDictionary: Invalid type in Action dictionary."); - return; - } - - const actionName = actionType.name; - - switch (actionName) { - case "URI": - url = action.get("URI"); - - if ((0, _primitives.isName)(url)) { - url = "/" + url.name; - } else if ((0, _util.isString)(url)) { - url = addDefaultProtocolToUrl(url); - } - - break; - - case "GoTo": - dest = action.get("D"); - break; - - case "Launch": - case "GoToR": - const urlDict = action.get("F"); - - if ((0, _primitives.isDict)(urlDict)) { - url = urlDict.get("F") || null; - } else if ((0, _util.isString)(urlDict)) { - url = urlDict; - } - - let remoteDest = action.get("D"); - - if (remoteDest) { - if ((0, _primitives.isName)(remoteDest)) { - remoteDest = remoteDest.name; - } - - if ((0, _util.isString)(url)) { - const baseUrl = url.split("#")[0]; - - if ((0, _util.isString)(remoteDest)) { - url = baseUrl + "#" + remoteDest; - } else if (Array.isArray(remoteDest)) { - url = baseUrl + "#" + JSON.stringify(remoteDest); - } - } - } - - const newWindow = action.get("NewWindow"); - - if ((0, _util.isBool)(newWindow)) { - resultObj.newWindow = newWindow; - } - - break; - - case "Named": - const namedAction = action.get("N"); - - if ((0, _primitives.isName)(namedAction)) { - resultObj.action = namedAction.name; - } - - break; - - case "JavaScript": - const jsAction = action.get("JS"); - let js; - - if ((0, _primitives.isStream)(jsAction)) { - js = (0, _util.bytesToString)(jsAction.getBytes()); - } else if ((0, _util.isString)(jsAction)) { - js = jsAction; - } - - if (js) { - const URL_OPEN_METHODS = ["app.launchURL", "window.open"]; - const regex = new RegExp("^\\s*(" + URL_OPEN_METHODS.join("|").split(".").join("\\.") + ")\\((?:'|\")([^'\"]*)(?:'|\")(?:,\\s*(\\w+)\\)|\\))", "i"); - const jsUrl = regex.exec((0, _util.stringToPDFString)(js)); - - if (jsUrl && jsUrl[2]) { - url = jsUrl[2]; - - if (jsUrl[3] === "true" && jsUrl[1] === "app.launchURL") { - resultObj.newWindow = true; - } - - break; - } - } - - default: - (0, _util.warn)(`parseDestDictionary: unsupported action type "${actionName}".`); - break; - } - } else if (destDict.has("Dest")) { - dest = destDict.get("Dest"); - } - - if ((0, _util.isString)(url)) { - url = tryConvertUrlEncoding(url); - const absoluteUrl = (0, _util.createValidAbsoluteUrl)(url, docBaseUrl); - - if (absoluteUrl) { - resultObj.url = absoluteUrl.href; - } - - resultObj.unsafeUrl = url; - } - - if (dest) { - if ((0, _primitives.isName)(dest)) { - dest = dest.name; - } - - if ((0, _util.isString)(dest) || Array.isArray(dest)) { - resultObj.dest = dest; - } - } - } - -} - -exports.Catalog = Catalog; - -var XRef = function XRefClosure() { - function XRef(stream, pdfManager) { - this.stream = stream; - this.pdfManager = pdfManager; - this.entries = []; - this.xrefstms = Object.create(null); - this._cacheMap = new Map(); - this.stats = { - streamTypes: Object.create(null), - fontTypes: Object.create(null) - }; - this._newRefNum = null; - } - - XRef.prototype = { - getNewRef: function XRef_getNewRef() { - if (this._newRefNum === null) { - this._newRefNum = this.entries.length; - } - - return _primitives.Ref.get(this._newRefNum++, 0); - }, - resetNewRef: function XRef_resetNewRef() { - this._newRefNum = null; - }, - setStartXRef: function XRef_setStartXRef(startXRef) { - this.startXRefQueue = [startXRef]; - }, - parse: function XRef_parse(recoveryMode) { - var trailerDict; - - if (!recoveryMode) { - trailerDict = this.readXRef(); - } else { - (0, _util.warn)("Indexing all PDF objects"); - trailerDict = this.indexObjects(); - } - - trailerDict.assignXref(this); - this.trailer = trailerDict; - let encrypt; - - try { - encrypt = trailerDict.get("Encrypt"); - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.warn)(`XRef.parse - Invalid "Encrypt" reference: "${ex}".`); - } - - if ((0, _primitives.isDict)(encrypt)) { - var ids = trailerDict.get("ID"); - var fileId = ids && ids.length ? ids[0] : ""; - encrypt.suppressEncryption = true; - this.encrypt = new _crypto.CipherTransformFactory(encrypt, fileId, this.pdfManager.password); - } - - let root; - - try { - root = trailerDict.get("Root"); - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.warn)(`XRef.parse - Invalid "Root" reference: "${ex}".`); - } - - if ((0, _primitives.isDict)(root) && root.has("Pages")) { - this.root = root; - } else { - if (!recoveryMode) { - throw new _core_utils.XRefParseException(); - } - - throw new _util.FormatError("Invalid root reference"); - } - }, - processXRefTable: function XRef_processXRefTable(parser) { - if (!("tableState" in this)) { - this.tableState = { - entryNum: 0, - streamPos: parser.lexer.stream.pos, - parserBuf1: parser.buf1, - parserBuf2: parser.buf2 - }; - } - - var obj = this.readXRefTable(parser); - - if (!(0, _primitives.isCmd)(obj, "trailer")) { - throw new _util.FormatError("Invalid XRef table: could not find trailer dictionary"); - } - - var dict = parser.getObj(); - - if (!(0, _primitives.isDict)(dict) && dict.dict) { - dict = dict.dict; - } - - if (!(0, _primitives.isDict)(dict)) { - throw new _util.FormatError("Invalid XRef table: could not parse trailer dictionary"); - } - - delete this.tableState; - return dict; - }, - readXRefTable: function XRef_readXRefTable(parser) { - var stream = parser.lexer.stream; - var tableState = this.tableState; - stream.pos = tableState.streamPos; - parser.buf1 = tableState.parserBuf1; - parser.buf2 = tableState.parserBuf2; - var obj; - - while (true) { - if (!("firstEntryNum" in tableState) || !("entryCount" in tableState)) { - if ((0, _primitives.isCmd)(obj = parser.getObj(), "trailer")) { - break; - } - - tableState.firstEntryNum = obj; - tableState.entryCount = parser.getObj(); - } - - var first = tableState.firstEntryNum; - var count = tableState.entryCount; - - if (!Number.isInteger(first) || !Number.isInteger(count)) { - throw new _util.FormatError("Invalid XRef table: wrong types in subsection header"); - } - - for (var i = tableState.entryNum; i < count; i++) { - tableState.streamPos = stream.pos; - tableState.entryNum = i; - tableState.parserBuf1 = parser.buf1; - tableState.parserBuf2 = parser.buf2; - var entry = {}; - entry.offset = parser.getObj(); - entry.gen = parser.getObj(); - var type = parser.getObj(); - - if (type instanceof _primitives.Cmd) { - switch (type.cmd) { - case "f": - entry.free = true; - break; - - case "n": - entry.uncompressed = true; - break; - } - } - - if (!Number.isInteger(entry.offset) || !Number.isInteger(entry.gen) || !(entry.free || entry.uncompressed)) { - throw new _util.FormatError(`Invalid entry in XRef subsection: ${first}, ${count}`); - } - - if (i === 0 && entry.free && first === 1) { - first = 0; - } - - if (!this.entries[i + first]) { - this.entries[i + first] = entry; - } - } - - tableState.entryNum = 0; - tableState.streamPos = stream.pos; - tableState.parserBuf1 = parser.buf1; - tableState.parserBuf2 = parser.buf2; - delete tableState.firstEntryNum; - delete tableState.entryCount; - } - - if (this.entries[0] && !this.entries[0].free) { - throw new _util.FormatError("Invalid XRef table: unexpected first object"); - } - - return obj; - }, - processXRefStream: function XRef_processXRefStream(stream) { - if (!("streamState" in this)) { - var streamParameters = stream.dict; - var byteWidths = streamParameters.get("W"); - var range = streamParameters.get("Index"); - - if (!range) { - range = [0, streamParameters.get("Size")]; - } - - this.streamState = { - entryRanges: range, - byteWidths, - entryNum: 0, - streamPos: stream.pos - }; - } - - this.readXRefStream(stream); - delete this.streamState; - return stream.dict; - }, - readXRefStream: function XRef_readXRefStream(stream) { - var i, j; - var streamState = this.streamState; - stream.pos = streamState.streamPos; - var byteWidths = streamState.byteWidths; - var typeFieldWidth = byteWidths[0]; - var offsetFieldWidth = byteWidths[1]; - var generationFieldWidth = byteWidths[2]; - var entryRanges = streamState.entryRanges; - - while (entryRanges.length > 0) { - var first = entryRanges[0]; - var n = entryRanges[1]; - - if (!Number.isInteger(first) || !Number.isInteger(n)) { - throw new _util.FormatError(`Invalid XRef range fields: ${first}, ${n}`); - } - - if (!Number.isInteger(typeFieldWidth) || !Number.isInteger(offsetFieldWidth) || !Number.isInteger(generationFieldWidth)) { - throw new _util.FormatError(`Invalid XRef entry fields length: ${first}, ${n}`); - } - - for (i = streamState.entryNum; i < n; ++i) { - streamState.entryNum = i; - streamState.streamPos = stream.pos; - var type = 0, - offset = 0, - generation = 0; - - for (j = 0; j < typeFieldWidth; ++j) { - type = type << 8 | stream.getByte(); - } - - if (typeFieldWidth === 0) { - type = 1; - } - - for (j = 0; j < offsetFieldWidth; ++j) { - offset = offset << 8 | stream.getByte(); - } - - for (j = 0; j < generationFieldWidth; ++j) { - generation = generation << 8 | stream.getByte(); - } - - var entry = {}; - entry.offset = offset; - entry.gen = generation; - - switch (type) { - case 0: - entry.free = true; - break; - - case 1: - entry.uncompressed = true; - break; - - case 2: - break; - - default: - throw new _util.FormatError(`Invalid XRef entry type: ${type}`); - } - - if (!this.entries[first + i]) { - this.entries[first + i] = entry; - } - } - - streamState.entryNum = 0; - streamState.streamPos = stream.pos; - entryRanges.splice(0, 2); - } - }, - indexObjects: function XRef_indexObjects() { - var TAB = 0x9, - LF = 0xa, - CR = 0xd, - SPACE = 0x20; - var PERCENT = 0x25, - LT = 0x3c; - - function readToken(data, offset) { - var token = "", - ch = data[offset]; - - while (ch !== LF && ch !== CR && ch !== LT) { - if (++offset >= data.length) { - break; - } - - token += String.fromCharCode(ch); - ch = data[offset]; - } - - return token; - } - - function skipUntil(data, offset, what) { - var length = what.length, - dataLength = data.length; - var skipped = 0; - - while (offset < dataLength) { - var i = 0; - - while (i < length && data[offset + i] === what[i]) { - ++i; - } - - if (i >= length) { - break; - } - - offset++; - skipped++; - } - - return skipped; - } - - var objRegExp = /^(\d+)\s+(\d+)\s+obj\b/; - const endobjRegExp = /\bendobj[\b\s]$/; - const nestedObjRegExp = /\s+(\d+\s+\d+\s+obj[\b\s<])$/; - const CHECK_CONTENT_LENGTH = 25; - var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]); - var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114, 101, 102]); - const objBytes = new Uint8Array([111, 98, 106]); - var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]); - this.entries.length = 0; - var stream = this.stream; - stream.pos = 0; - var buffer = stream.getBytes(); - var position = stream.start, - length = buffer.length; - var trailers = [], - xrefStms = []; - - while (position < length) { - var ch = buffer[position]; - - if (ch === TAB || ch === LF || ch === CR || ch === SPACE) { - ++position; - continue; - } - - if (ch === PERCENT) { - do { - ++position; - - if (position >= length) { - break; - } - - ch = buffer[position]; - } while (ch !== LF && ch !== CR); - - continue; - } - - var token = readToken(buffer, position); - var m; - - if (token.startsWith("xref") && (token.length === 4 || /\s/.test(token[4]))) { - position += skipUntil(buffer, position, trailerBytes); - trailers.push(position); - position += skipUntil(buffer, position, startxrefBytes); - } else if (m = objRegExp.exec(token)) { - const num = m[1] | 0, - gen = m[2] | 0; - - if (!this.entries[num] || this.entries[num].gen === gen) { - this.entries[num] = { - offset: position - stream.start, - gen, - uncompressed: true - }; - } - - let contentLength, - startPos = position + token.length; - - while (startPos < buffer.length) { - const endPos = startPos + skipUntil(buffer, startPos, objBytes) + 4; - contentLength = endPos - position; - const checkPos = Math.max(endPos - CHECK_CONTENT_LENGTH, startPos); - const tokenStr = (0, _util.bytesToString)(buffer.subarray(checkPos, endPos)); - - if (endobjRegExp.test(tokenStr)) { - break; - } else { - const objToken = nestedObjRegExp.exec(tokenStr); - - if (objToken && objToken[1]) { - (0, _util.warn)('indexObjects: Found new "obj" inside of another "obj", ' + 'caused by missing "endobj" -- trying to recover.'); - contentLength -= objToken[1].length; - break; - } - } - - startPos = endPos; - } - - const content = buffer.subarray(position, position + contentLength); - var xrefTagOffset = skipUntil(content, 0, xrefBytes); - - if (xrefTagOffset < contentLength && content[xrefTagOffset + 5] < 64) { - xrefStms.push(position - stream.start); - this.xrefstms[position - stream.start] = 1; - } - - position += contentLength; - } else if (token.startsWith("trailer") && (token.length === 7 || /\s/.test(token[7]))) { - trailers.push(position); - position += skipUntil(buffer, position, startxrefBytes); - } else { - position += token.length + 1; - } - } - - var i, ii; - - for (i = 0, ii = xrefStms.length; i < ii; ++i) { - this.startXRefQueue.push(xrefStms[i]); - this.readXRef(true); - } - - let trailerDict; - - for (i = 0, ii = trailers.length; i < ii; ++i) { - stream.pos = trailers[i]; - const parser = new _parser.Parser({ - lexer: new _parser.Lexer(stream), - xref: this, - allowStreams: true, - recoveryMode: true - }); - var obj = parser.getObj(); - - if (!(0, _primitives.isCmd)(obj, "trailer")) { - continue; - } - - const dict = parser.getObj(); - - if (!(0, _primitives.isDict)(dict)) { - continue; - } - - let rootDict; - - try { - rootDict = dict.get("Root"); - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - continue; - } - - if (!(0, _primitives.isDict)(rootDict) || !rootDict.has("Pages")) { - continue; - } - - if (dict.has("ID")) { - return dict; - } - - trailerDict = dict; - } - - if (trailerDict) { - return trailerDict; - } - - throw new _util.InvalidPDFException("Invalid PDF structure."); - }, - readXRef: function XRef_readXRef(recoveryMode) { - var stream = this.stream; - const startXRefParsedCache = Object.create(null); - - try { - while (this.startXRefQueue.length) { - var startXRef = this.startXRefQueue[0]; - - if (startXRefParsedCache[startXRef]) { - (0, _util.warn)("readXRef - skipping XRef table since it was already parsed."); - this.startXRefQueue.shift(); - continue; - } - - startXRefParsedCache[startXRef] = true; - stream.pos = startXRef + stream.start; - const parser = new _parser.Parser({ - lexer: new _parser.Lexer(stream), - xref: this, - allowStreams: true - }); - var obj = parser.getObj(); - var dict; - - if ((0, _primitives.isCmd)(obj, "xref")) { - dict = this.processXRefTable(parser); - - if (!this.topDict) { - this.topDict = dict; - } - - obj = dict.get("XRefStm"); - - if (Number.isInteger(obj)) { - var pos = obj; - - if (!(pos in this.xrefstms)) { - this.xrefstms[pos] = 1; - this.startXRefQueue.push(pos); - } - } - } else if (Number.isInteger(obj)) { - if (!Number.isInteger(parser.getObj()) || !(0, _primitives.isCmd)(parser.getObj(), "obj") || !(0, _primitives.isStream)(obj = parser.getObj())) { - throw new _util.FormatError("Invalid XRef stream"); - } - - dict = this.processXRefStream(obj); - - if (!this.topDict) { - this.topDict = dict; - } - - if (!dict) { - throw new _util.FormatError("Failed to read XRef stream"); - } - } else { - throw new _util.FormatError("Invalid XRef stream header"); - } - - obj = dict.get("Prev"); - - if (Number.isInteger(obj)) { - this.startXRefQueue.push(obj); - } else if ((0, _primitives.isRef)(obj)) { - this.startXRefQueue.push(obj.num); - } - - this.startXRefQueue.shift(); - } - - return this.topDict; - } catch (e) { - if (e instanceof _core_utils.MissingDataException) { - throw e; - } - - (0, _util.info)("(while reading XRef): " + e); - } - - if (recoveryMode) { - return undefined; - } - - throw new _core_utils.XRefParseException(); - }, - getEntry: function XRef_getEntry(i) { - var xrefEntry = this.entries[i]; - - if (xrefEntry && !xrefEntry.free && xrefEntry.offset) { - return xrefEntry; - } - - return null; - }, - fetchIfRef: function XRef_fetchIfRef(obj, suppressEncryption) { - if (obj instanceof _primitives.Ref) { - return this.fetch(obj, suppressEncryption); - } - - return obj; - }, - fetch: function XRef_fetch(ref, suppressEncryption) { - if (!(ref instanceof _primitives.Ref)) { - throw new Error("ref object is not a reference"); - } - - const num = ref.num; - - const cacheEntry = this._cacheMap.get(num); - - if (cacheEntry !== undefined) { - if (cacheEntry instanceof _primitives.Dict && !cacheEntry.objId) { - cacheEntry.objId = ref.toString(); - } - - return cacheEntry; - } - - let xrefEntry = this.getEntry(num); - - if (xrefEntry === null) { - this._cacheMap.set(num, xrefEntry); - - return xrefEntry; - } - - if (xrefEntry.uncompressed) { - xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption); - } else { - xrefEntry = this.fetchCompressed(ref, xrefEntry, suppressEncryption); - } - - if ((0, _primitives.isDict)(xrefEntry)) { - xrefEntry.objId = ref.toString(); - } else if ((0, _primitives.isStream)(xrefEntry)) { - xrefEntry.dict.objId = ref.toString(); - } - - return xrefEntry; - }, - - fetchUncompressed(ref, xrefEntry, suppressEncryption = false) { - var gen = ref.gen; - var num = ref.num; - - if (xrefEntry.gen !== gen) { - throw new _core_utils.XRefEntryException(`Inconsistent generation in XRef: ${ref}`); - } - - var stream = this.stream.makeSubStream(xrefEntry.offset + this.stream.start); - const parser = new _parser.Parser({ - lexer: new _parser.Lexer(stream), - xref: this, - allowStreams: true - }); - var obj1 = parser.getObj(); - var obj2 = parser.getObj(); - var obj3 = parser.getObj(); - - if (obj1 !== num || obj2 !== gen || !(obj3 instanceof _primitives.Cmd)) { - throw new _core_utils.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`); - } - - if (obj3.cmd !== "obj") { - if (obj3.cmd.startsWith("obj")) { - num = parseInt(obj3.cmd.substring(3), 10); - - if (!Number.isNaN(num)) { - return num; - } - } - - throw new _core_utils.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`); - } - - if (this.encrypt && !suppressEncryption) { - xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen)); - } else { - xrefEntry = parser.getObj(); - } - - if (!(0, _primitives.isStream)(xrefEntry)) { - this._cacheMap.set(num, xrefEntry); - } - - return xrefEntry; - }, - - fetchCompressed(ref, xrefEntry, suppressEncryption = false) { - const tableOffset = xrefEntry.offset; - const stream = this.fetch(_primitives.Ref.get(tableOffset, 0)); - - if (!(0, _primitives.isStream)(stream)) { - throw new _util.FormatError("bad ObjStm stream"); - } - - const first = stream.dict.get("First"); - const n = stream.dict.get("N"); - - if (!Number.isInteger(first) || !Number.isInteger(n)) { - throw new _util.FormatError("invalid first and n parameters for ObjStm stream"); - } - - const parser = new _parser.Parser({ - lexer: new _parser.Lexer(stream), - xref: this, - allowStreams: true - }); - const nums = new Array(n); - - for (let i = 0; i < n; ++i) { - const num = parser.getObj(); - - if (!Number.isInteger(num)) { - throw new _util.FormatError(`invalid object number in the ObjStm stream: ${num}`); - } - - const offset = parser.getObj(); - - if (!Number.isInteger(offset)) { - throw new _util.FormatError(`invalid object offset in the ObjStm stream: ${offset}`); - } - - nums[i] = num; - } - - const entries = new Array(n); - - for (let i = 0; i < n; ++i) { - const obj = parser.getObj(); - entries[i] = obj; - - if (parser.buf1 instanceof _primitives.Cmd && parser.buf1.cmd === "endobj") { - parser.shift(); - } - - if ((0, _primitives.isStream)(obj)) { - continue; - } - - const num = nums[i], - entry = this.entries[num]; - - if (entry && entry.offset === tableOffset && entry.gen === i) { - this._cacheMap.set(num, obj); - } - } - - xrefEntry = entries[xrefEntry.gen]; - - if (xrefEntry === undefined) { - throw new _core_utils.XRefEntryException(`Bad (compressed) XRef entry: ${ref}`); - } - - return xrefEntry; - }, - - async fetchIfRefAsync(obj, suppressEncryption) { - if (obj instanceof _primitives.Ref) { - return this.fetchAsync(obj, suppressEncryption); - } - - return obj; - }, - - async fetchAsync(ref, suppressEncryption) { - try { - return this.fetch(ref, suppressEncryption); - } catch (ex) { - if (!(ex instanceof _core_utils.MissingDataException)) { - throw ex; - } - - await this.pdfManager.requestRange(ex.begin, ex.end); - return this.fetchAsync(ref, suppressEncryption); - } - }, - - getCatalogObj: function XRef_getCatalogObj() { - return this.root; - } - }; - return XRef; -}(); - -exports.XRef = XRef; - -class NameOrNumberTree { - constructor(root, xref, type) { - if (this.constructor === NameOrNumberTree) { - (0, _util.unreachable)("Cannot initialize NameOrNumberTree."); - } - - this.root = root; - this.xref = xref; - this._type = type; - } - - getAll() { - const dict = Object.create(null); - - if (!this.root) { - return dict; - } - - const xref = this.xref; - const processed = new _primitives.RefSet(); - processed.put(this.root); - const queue = [this.root]; - - while (queue.length > 0) { - const obj = xref.fetchIfRef(queue.shift()); - - if (!(0, _primitives.isDict)(obj)) { - continue; - } - - if (obj.has("Kids")) { - const kids = obj.get("Kids"); - - for (let i = 0, ii = kids.length; i < ii; i++) { - const kid = kids[i]; - - if (processed.has(kid)) { - throw new _util.FormatError(`Duplicate entry in "${this._type}" tree.`); - } - - queue.push(kid); - processed.put(kid); - } - - continue; - } - - const entries = obj.get(this._type); - - if (Array.isArray(entries)) { - for (let i = 0, ii = entries.length; i < ii; i += 2) { - dict[xref.fetchIfRef(entries[i])] = xref.fetchIfRef(entries[i + 1]); - } - } - } - - return dict; - } - - get(key) { - if (!this.root) { - return null; - } - - const xref = this.xref; - let kidsOrEntries = xref.fetchIfRef(this.root); - let loopCount = 0; - const MAX_LEVELS = 10; - - while (kidsOrEntries.has("Kids")) { - if (++loopCount > MAX_LEVELS) { - (0, _util.warn)(`Search depth limit reached for "${this._type}" tree.`); - return null; - } - - const kids = kidsOrEntries.get("Kids"); - - if (!Array.isArray(kids)) { - return null; - } - - let l = 0, - r = kids.length - 1; - - while (l <= r) { - const m = l + r >> 1; - const kid = xref.fetchIfRef(kids[m]); - const limits = kid.get("Limits"); - - if (key < xref.fetchIfRef(limits[0])) { - r = m - 1; - } else if (key > xref.fetchIfRef(limits[1])) { - l = m + 1; - } else { - kidsOrEntries = xref.fetchIfRef(kids[m]); - break; - } - } - - if (l > r) { - return null; - } - } - - const entries = kidsOrEntries.get(this._type); - - if (Array.isArray(entries)) { - let l = 0, - r = entries.length - 2; - - while (l <= r) { - const tmp = l + r >> 1, - m = tmp + (tmp & 1); - const currentKey = xref.fetchIfRef(entries[m]); - - if (key < currentKey) { - r = m - 2; - } else if (key > currentKey) { - l = m + 2; - } else { - return xref.fetchIfRef(entries[m + 1]); - } - } - - (0, _util.info)(`Falling back to an exhaustive search, for key "${key}", ` + `in "${this._type}" tree.`); - - for (let m = 0, mm = entries.length; m < mm; m += 2) { - const currentKey = xref.fetchIfRef(entries[m]); - - if (currentKey === key) { - (0, _util.warn)(`The "${key}" key was found at an incorrect, ` + `i.e. out-of-order, position in "${this._type}" tree.`); - return xref.fetchIfRef(entries[m + 1]); - } - } - } - - return null; - } - -} - -class NameTree extends NameOrNumberTree { - constructor(root, xref) { - super(root, xref, "Names"); - } - -} - -class NumberTree extends NameOrNumberTree { - constructor(root, xref) { - super(root, xref, "Nums"); - } - -} - -var FileSpec = function FileSpecClosure() { - function FileSpec(root, xref) { - if (!root || !(0, _primitives.isDict)(root)) { - return; - } - - this.xref = xref; - this.root = root; - - if (root.has("FS")) { - this.fs = root.get("FS"); - } - - this.description = root.has("Desc") ? (0, _util.stringToPDFString)(root.get("Desc")) : ""; - - if (root.has("RF")) { - (0, _util.warn)("Related file specifications are not supported"); - } - - this.contentAvailable = true; - - if (!root.has("EF")) { - this.contentAvailable = false; - (0, _util.warn)("Non-embedded file specifications are not supported"); - } - } - - function pickPlatformItem(dict) { - if (dict.has("UF")) { - return dict.get("UF"); - } else if (dict.has("F")) { - return dict.get("F"); - } else if (dict.has("Unix")) { - return dict.get("Unix"); - } else if (dict.has("Mac")) { - return dict.get("Mac"); - } else if (dict.has("DOS")) { - return dict.get("DOS"); - } - - return null; - } - - FileSpec.prototype = { - get filename() { - if (!this._filename && this.root) { - var filename = pickPlatformItem(this.root) || "unnamed"; - this._filename = (0, _util.stringToPDFString)(filename).replace(/\\\\/g, "\\").replace(/\\\//g, "/").replace(/\\/g, "/"); - } - - return this._filename; - }, - - get content() { - if (!this.contentAvailable) { - return null; - } - - if (!this.contentRef && this.root) { - this.contentRef = pickPlatformItem(this.root.get("EF")); - } - - var content = null; - - if (this.contentRef) { - var xref = this.xref; - var fileObj = xref.fetchIfRef(this.contentRef); - - if (fileObj && (0, _primitives.isStream)(fileObj)) { - content = fileObj.getBytes(); - } else { - (0, _util.warn)("Embedded file specification points to non-existing/invalid " + "content"); - } - } else { - (0, _util.warn)("Embedded file specification does not have a content"); - } - - return content; - }, - - get serializable() { - return { - filename: this.filename, - content: this.content - }; - } - - }; - return FileSpec; -}(); - -exports.FileSpec = FileSpec; - -const ObjectLoader = function () { - function mayHaveChildren(value) { - return value instanceof _primitives.Ref || value instanceof _primitives.Dict || Array.isArray(value) || (0, _primitives.isStream)(value); - } - - function addChildren(node, nodesToVisit) { - if (node instanceof _primitives.Dict) { - node = node.getRawValues(); - } else if ((0, _primitives.isStream)(node)) { - node = node.dict.getRawValues(); - } else if (!Array.isArray(node)) { - return; - } - - for (const rawValue of node) { - if (mayHaveChildren(rawValue)) { - nodesToVisit.push(rawValue); - } - } - } - - function ObjectLoader(dict, keys, xref) { - this.dict = dict; - this.keys = keys; - this.xref = xref; - this.refSet = null; - } - - ObjectLoader.prototype = { - async load() { - if (!this.xref.stream.allChunksLoaded || this.xref.stream.allChunksLoaded()) { - return undefined; - } - - const { - keys, - dict - } = this; - this.refSet = new _primitives.RefSet(); - const nodesToVisit = []; - - for (let i = 0, ii = keys.length; i < ii; i++) { - const rawValue = dict.getRaw(keys[i]); - - if (rawValue !== undefined) { - nodesToVisit.push(rawValue); - } - } - - return this._walk(nodesToVisit); - }, - - async _walk(nodesToVisit) { - const nodesToRevisit = []; - const pendingRequests = []; - - while (nodesToVisit.length) { - let currentNode = nodesToVisit.pop(); - - if (currentNode instanceof _primitives.Ref) { - if (this.refSet.has(currentNode)) { - continue; - } - - try { - this.refSet.put(currentNode); - currentNode = this.xref.fetch(currentNode); - } catch (ex) { - if (!(ex instanceof _core_utils.MissingDataException)) { - throw ex; - } - - nodesToRevisit.push(currentNode); - pendingRequests.push({ - begin: ex.begin, - end: ex.end - }); - } - } - - if (currentNode && currentNode.getBaseStreams) { - const baseStreams = currentNode.getBaseStreams(); - let foundMissingData = false; - - for (let i = 0, ii = baseStreams.length; i < ii; i++) { - const stream = baseStreams[i]; - - if (stream.allChunksLoaded && !stream.allChunksLoaded()) { - foundMissingData = true; - pendingRequests.push({ - begin: stream.start, - end: stream.end - }); - } - } - - if (foundMissingData) { - nodesToRevisit.push(currentNode); - } - } - - addChildren(currentNode, nodesToVisit); - } - - if (pendingRequests.length) { - await this.xref.stream.manager.requestRanges(pendingRequests); - - for (let i = 0, ii = nodesToRevisit.length; i < ii; i++) { - const node = nodesToRevisit[i]; - - if (node instanceof _primitives.Ref) { - this.refSet.remove(node); - } - } - - return this._walk(nodesToRevisit); - } - - this.refSet = null; + if (!(dict instanceof _primitives.Dict)) { return undefined; } - }; - return ObjectLoader; -}(); + const id = ref instanceof _primitives.Ref ? ref.toString() : `annot_${idFactory.createObjId()}`; + let subtype = dict.get("Subtype"); + subtype = subtype instanceof _primitives.Name ? subtype.name : null; + const parameters = { + xref, + ref, + dict, + subtype, + id, + pdfManager, + acroForm: acroForm instanceof _primitives.Dict ? acroForm : _primitives.Dict.empty, + xfaDatasets, + collectFields, + pageIndex + }; -exports.ObjectLoader = ObjectLoader; + switch (subtype) { + case "Link": + return new LinkAnnotation(parameters); -/***/ }), -/* 11 */ -/***/ (function(module, exports, __w_pdfjs_require__) { + case "Text": + return new TextAnnotation(parameters); -"use strict"; + case "Widget": + let fieldType = (0, _core_utils.getInheritableProperty)({ + dict, + key: "FT" + }); + fieldType = fieldType instanceof _primitives.Name ? fieldType.name : null; + switch (fieldType) { + case "Tx": + return new TextWidgetAnnotation(parameters); -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.Parser = exports.Linearization = exports.Lexer = void 0; + case "Btn": + return new ButtonWidgetAnnotation(parameters); -var _stream = __w_pdfjs_require__(12); + case "Ch": + return new ChoiceWidgetAnnotation(parameters); -var _util = __w_pdfjs_require__(2); + case "Sig": + return new SignatureWidgetAnnotation(parameters); + } -var _primitives = __w_pdfjs_require__(5); + (0, _util.warn)(`Unimplemented widget field type "${fieldType}", ` + "falling back to base field type."); + return new WidgetAnnotation(parameters); -var _core_utils = __w_pdfjs_require__(8); + case "Popup": + return new PopupAnnotation(parameters); -var _ccitt_stream = __w_pdfjs_require__(13); + case "FreeText": + return new FreeTextAnnotation(parameters); -var _jbig2_stream = __w_pdfjs_require__(15); + case "Line": + return new LineAnnotation(parameters); -var _jpeg_stream = __w_pdfjs_require__(18); + case "Square": + return new SquareAnnotation(parameters); -var _jpx_stream = __w_pdfjs_require__(20); + case "Circle": + return new CircleAnnotation(parameters); -const MAX_LENGTH_TO_CACHE = 1000; -const MAX_ADLER32_LENGTH = 5552; + case "PolyLine": + return new PolylineAnnotation(parameters); -function computeAdler32(bytes) { - const bytesLength = bytes.length; - let a = 1, - b = 0; + case "Polygon": + return new PolygonAnnotation(parameters); - for (let i = 0; i < bytesLength; ++i) { - a += bytes[i] & 0xff; - b += a; - } + case "Caret": + return new CaretAnnotation(parameters); - return b % 65521 << 16 | a % 65521; -} + case "Ink": + return new InkAnnotation(parameters); -class Parser { - constructor({ - lexer, - xref, - allowStreams = false, - recoveryMode = false - }) { - this.lexer = lexer; - this.xref = xref; - this.allowStreams = allowStreams; - this.recoveryMode = recoveryMode; - this.imageCache = Object.create(null); - this.refill(); - } + case "Highlight": + return new HighlightAnnotation(parameters); - refill() { - this.buf1 = this.lexer.getObj(); - this.buf2 = this.lexer.getObj(); - } + case "Underline": + return new UnderlineAnnotation(parameters); - shift() { - if (this.buf2 instanceof _primitives.Cmd && this.buf2.cmd === "ID") { - this.buf1 = this.buf2; - this.buf2 = null; - } else { - this.buf1 = this.buf2; - this.buf2 = this.lexer.getObj(); - } - } + case "Squiggly": + return new SquigglyAnnotation(parameters); - tryShift() { - try { - this.shift(); - return true; - } catch (e) { - if (e instanceof _core_utils.MissingDataException) { - throw e; - } + case "StrikeOut": + return new StrikeOutAnnotation(parameters); - return false; - } - } + case "Stamp": + return new StampAnnotation(parameters); - getObj(cipherTransform = null) { - const buf1 = this.buf1; - this.shift(); + case "FileAttachment": + return new FileAttachmentAnnotation(parameters); - if (buf1 instanceof _primitives.Cmd) { - switch (buf1.cmd) { - case "BI": - return this.makeInlineImage(cipherTransform); - - case "[": - const array = []; - - while (!(0, _primitives.isCmd)(this.buf1, "]") && !(0, _primitives.isEOF)(this.buf1)) { - array.push(this.getObj(cipherTransform)); - } - - if ((0, _primitives.isEOF)(this.buf1)) { - if (!this.recoveryMode) { - throw new _util.FormatError("End of file inside array"); - } - - return array; - } - - this.shift(); - return array; - - case "<<": - const dict = new _primitives.Dict(this.xref); - - while (!(0, _primitives.isCmd)(this.buf1, ">>") && !(0, _primitives.isEOF)(this.buf1)) { - if (!(0, _primitives.isName)(this.buf1)) { - (0, _util.info)("Malformed dictionary: key must be a name object"); - this.shift(); - continue; - } - - const key = this.buf1.name; - this.shift(); - - if ((0, _primitives.isEOF)(this.buf1)) { - break; - } - - dict.set(key, this.getObj(cipherTransform)); - } - - if ((0, _primitives.isEOF)(this.buf1)) { - if (!this.recoveryMode) { - throw new _util.FormatError("End of file inside dictionary"); - } - - return dict; - } - - if ((0, _primitives.isCmd)(this.buf2, "stream")) { - return this.allowStreams ? this.makeStream(dict, cipherTransform) : dict; - } - - this.shift(); - return dict; - - default: - return buf1; - } - } - - if (Number.isInteger(buf1)) { - if (Number.isInteger(this.buf1) && (0, _primitives.isCmd)(this.buf2, "R")) { - const ref = _primitives.Ref.get(buf1, this.buf1); - - this.shift(); - this.shift(); - return ref; - } - - return buf1; - } - - if (typeof buf1 === "string") { - if (cipherTransform) { - return cipherTransform.decryptString(buf1); - } - - return buf1; - } - - return buf1; - } - - findDefaultInlineStreamEnd(stream) { - const E = 0x45, - I = 0x49, - SPACE = 0x20, - LF = 0xa, - CR = 0xd, - NUL = 0x0; - const lexer = this.lexer, - startPos = stream.pos, - n = 10; - let state = 0, - ch, - maybeEIPos; - - while ((ch = stream.getByte()) !== -1) { - if (state === 0) { - state = ch === E ? 1 : 0; - } else if (state === 1) { - state = ch === I ? 2 : 0; - } else { - (0, _util.assert)(state === 2, "findDefaultInlineStreamEnd - invalid state."); - - if (ch === SPACE || ch === LF || ch === CR) { - maybeEIPos = stream.pos; - const followingBytes = stream.peekBytes(n); - - for (let i = 0, ii = followingBytes.length; i < ii; i++) { - ch = followingBytes[i]; - - if (ch === NUL && followingBytes[i + 1] !== NUL) { - continue; - } - - if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7f)) { - state = 0; - break; - } - } - - if (state !== 2) { - continue; - } - - if (lexer.knownCommands) { - const nextObj = lexer.peekObj(); - - if (nextObj instanceof _primitives.Cmd && !lexer.knownCommands[nextObj.cmd]) { - state = 0; - } + default: + if (!collectFields) { + if (!subtype) { + (0, _util.warn)("Annotation is missing the required /Subtype."); } else { - (0, _util.warn)("findDefaultInlineStreamEnd - `lexer.knownCommands` is undefined."); - } - - if (state === 2) { - break; - } - } else { - state = 0; - } - } - } - - if (ch === -1) { - (0, _util.warn)("findDefaultInlineStreamEnd: " + "Reached the end of the stream without finding a valid EI marker"); - - if (maybeEIPos) { - (0, _util.warn)('... trying to recover by using the last "EI" occurrence.'); - stream.skip(-(stream.pos - maybeEIPos)); - } - } - - let endOffset = 4; - stream.skip(-endOffset); - ch = stream.peekByte(); - stream.skip(endOffset); - - if (!(0, _core_utils.isWhiteSpace)(ch)) { - endOffset--; - } - - return stream.pos - endOffset - startPos; - } - - findDCTDecodeInlineStreamEnd(stream) { - const startPos = stream.pos; - let foundEOI = false, - b, - markerLength; - - while ((b = stream.getByte()) !== -1) { - if (b !== 0xff) { - continue; - } - - switch (stream.getByte()) { - case 0x00: - break; - - case 0xff: - stream.skip(-1); - break; - - case 0xd9: - foundEOI = true; - break; - - case 0xc0: - case 0xc1: - case 0xc2: - case 0xc3: - case 0xc5: - case 0xc6: - case 0xc7: - case 0xc9: - case 0xca: - case 0xcb: - case 0xcd: - case 0xce: - case 0xcf: - case 0xc4: - case 0xcc: - case 0xda: - case 0xdb: - case 0xdc: - case 0xdd: - case 0xde: - case 0xdf: - case 0xe0: - case 0xe1: - case 0xe2: - case 0xe3: - case 0xe4: - case 0xe5: - case 0xe6: - case 0xe7: - case 0xe8: - case 0xe9: - case 0xea: - case 0xeb: - case 0xec: - case 0xed: - case 0xee: - case 0xef: - case 0xfe: - markerLength = stream.getUint16(); - - if (markerLength > 2) { - stream.skip(markerLength - 2); - } else { - stream.skip(-2); - } - - break; - } - - if (foundEOI) { - break; - } - } - - const length = stream.pos - startPos; - - if (b === -1) { - (0, _util.warn)("Inline DCTDecode image stream: " + "EOI marker not found, searching for /EI/ instead."); - stream.skip(-length); - return this.findDefaultInlineStreamEnd(stream); - } - - this.inlineStreamSkipEI(stream); - return length; - } - - findASCII85DecodeInlineStreamEnd(stream) { - const TILDE = 0x7e, - GT = 0x3e; - const startPos = stream.pos; - let ch; - - while ((ch = stream.getByte()) !== -1) { - if (ch === TILDE) { - const tildePos = stream.pos; - ch = stream.peekByte(); - - while ((0, _core_utils.isWhiteSpace)(ch)) { - stream.skip(); - ch = stream.peekByte(); - } - - if (ch === GT) { - stream.skip(); - break; - } - - if (stream.pos > tildePos) { - const maybeEI = stream.peekBytes(2); - - if (maybeEI[0] === 0x45 && maybeEI[1] === 0x49) { - break; - } - } - } - } - - const length = stream.pos - startPos; - - if (ch === -1) { - (0, _util.warn)("Inline ASCII85Decode image stream: " + "EOD marker not found, searching for /EI/ instead."); - stream.skip(-length); - return this.findDefaultInlineStreamEnd(stream); - } - - this.inlineStreamSkipEI(stream); - return length; - } - - findASCIIHexDecodeInlineStreamEnd(stream) { - const GT = 0x3e; - const startPos = stream.pos; - let ch; - - while ((ch = stream.getByte()) !== -1) { - if (ch === GT) { - break; - } - } - - const length = stream.pos - startPos; - - if (ch === -1) { - (0, _util.warn)("Inline ASCIIHexDecode image stream: " + "EOD marker not found, searching for /EI/ instead."); - stream.skip(-length); - return this.findDefaultInlineStreamEnd(stream); - } - - this.inlineStreamSkipEI(stream); - return length; - } - - inlineStreamSkipEI(stream) { - const E = 0x45, - I = 0x49; - let state = 0, - ch; - - while ((ch = stream.getByte()) !== -1) { - if (state === 0) { - state = ch === E ? 1 : 0; - } else if (state === 1) { - state = ch === I ? 2 : 0; - } else if (state === 2) { - break; - } - } - } - - makeInlineImage(cipherTransform) { - const lexer = this.lexer; - const stream = lexer.stream; - const dict = new _primitives.Dict(this.xref); - let dictLength; - - while (!(0, _primitives.isCmd)(this.buf1, "ID") && !(0, _primitives.isEOF)(this.buf1)) { - if (!(0, _primitives.isName)(this.buf1)) { - throw new _util.FormatError("Dictionary key must be a name object"); - } - - const key = this.buf1.name; - this.shift(); - - if ((0, _primitives.isEOF)(this.buf1)) { - break; - } - - dict.set(key, this.getObj(cipherTransform)); - } - - if (lexer.beginInlineImagePos !== -1) { - dictLength = stream.pos - lexer.beginInlineImagePos; - } - - const filter = dict.get("Filter", "F"); - let filterName; - - if ((0, _primitives.isName)(filter)) { - filterName = filter.name; - } else if (Array.isArray(filter)) { - const filterZero = this.xref.fetchIfRef(filter[0]); - - if ((0, _primitives.isName)(filterZero)) { - filterName = filterZero.name; - } - } - - const startPos = stream.pos; - let length; - - if (filterName === "DCTDecode" || filterName === "DCT") { - length = this.findDCTDecodeInlineStreamEnd(stream); - } else if (filterName === "ASCII85Decode" || filterName === "A85") { - length = this.findASCII85DecodeInlineStreamEnd(stream); - } else if (filterName === "ASCIIHexDecode" || filterName === "AHx") { - length = this.findASCIIHexDecodeInlineStreamEnd(stream); - } else { - length = this.findDefaultInlineStreamEnd(stream); - } - - let imageStream = stream.makeSubStream(startPos, length, dict); - let cacheKey; - - if (length < MAX_LENGTH_TO_CACHE && dictLength < MAX_ADLER32_LENGTH) { - const imageBytes = imageStream.getBytes(); - imageStream.reset(); - const initialStreamPos = stream.pos; - stream.pos = lexer.beginInlineImagePos; - const dictBytes = stream.getBytes(dictLength); - stream.pos = initialStreamPos; - cacheKey = computeAdler32(imageBytes) + "_" + computeAdler32(dictBytes); - const cacheEntry = this.imageCache[cacheKey]; - - if (cacheEntry !== undefined) { - this.buf2 = _primitives.Cmd.get("EI"); - this.shift(); - cacheEntry.reset(); - return cacheEntry; - } - } - - if (cipherTransform) { - imageStream = cipherTransform.createStream(imageStream, length); - } - - imageStream = this.filter(imageStream, dict, length); - imageStream.dict = dict; - - if (cacheKey !== undefined) { - imageStream.cacheKey = `inline_${length}_${cacheKey}`; - this.imageCache[cacheKey] = imageStream; - } - - this.buf2 = _primitives.Cmd.get("EI"); - this.shift(); - return imageStream; - } - - _findStreamLength(startPos, signature) { - const { - stream - } = this.lexer; - stream.pos = startPos; - const SCAN_BLOCK_LENGTH = 2048; - const signatureLength = signature.length; - - while (stream.pos < stream.end) { - const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH); - const scanLength = scanBytes.length - signatureLength; - - if (scanLength <= 0) { - break; - } - - let pos = 0; - - while (pos < scanLength) { - let j = 0; - - while (j < signatureLength && scanBytes[pos + j] === signature[j]) { - j++; - } - - if (j >= signatureLength) { - stream.pos += pos; - return stream.pos - startPos; - } - - pos++; - } - - stream.pos += scanLength; - } - - return -1; - } - - makeStream(dict, cipherTransform) { - const lexer = this.lexer; - let stream = lexer.stream; - lexer.skipToNextLine(); - const startPos = stream.pos - 1; - let length = dict.get("Length"); - - if (!Number.isInteger(length)) { - (0, _util.info)(`Bad length "${length}" in stream`); - length = 0; - } - - stream.pos = startPos + length; - lexer.nextChar(); - - if (this.tryShift() && (0, _primitives.isCmd)(this.buf2, "endstream")) { - this.shift(); - } else { - const ENDSTREAM_SIGNATURE = new Uint8Array([0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6D]); - - let actualLength = this._findStreamLength(startPos, ENDSTREAM_SIGNATURE); - - if (actualLength < 0) { - const MAX_TRUNCATION = 1; - - for (let i = 1; i <= MAX_TRUNCATION; i++) { - const end = ENDSTREAM_SIGNATURE.length - i; - const TRUNCATED_SIGNATURE = ENDSTREAM_SIGNATURE.slice(0, end); - - const maybeLength = this._findStreamLength(startPos, TRUNCATED_SIGNATURE); - - if (maybeLength >= 0) { - const lastByte = stream.peekBytes(end + 1)[end]; - - if (!(0, _core_utils.isWhiteSpace)(lastByte)) { - break; - } - - (0, _util.info)(`Found "${(0, _util.bytesToString)(TRUNCATED_SIGNATURE)}" when ` + "searching for endstream command."); - actualLength = maybeLength; - break; + (0, _util.warn)(`Unimplemented annotation type "${subtype}", ` + "falling back to base annotation."); } } - if (actualLength < 0) { - throw new _util.FormatError("Missing endstream command."); - } - } - - length = actualLength; - lexer.nextChar(); - this.shift(); - this.shift(); + return new Annotation(parameters); } - - this.shift(); - stream = stream.makeSubStream(startPos, length, dict); - - if (cipherTransform) { - stream = cipherTransform.createStream(stream, length); - } - - stream = this.filter(stream, dict, length); - stream.dict = dict; - return stream; } - filter(stream, dict, length) { - let filter = dict.get("Filter", "F"); - let params = dict.get("DecodeParms", "DP"); - - if ((0, _primitives.isName)(filter)) { - if (Array.isArray(params)) { - (0, _util.warn)("/DecodeParms should not contain an Array, " + "when /Filter contains a Name."); - } - - return this.makeFilter(stream, filter.name, length, params); - } - - let maybeLength = length; - - if (Array.isArray(filter)) { - const filterArray = filter; - const paramsArray = params; - - for (let i = 0, ii = filterArray.length; i < ii; ++i) { - filter = this.xref.fetchIfRef(filterArray[i]); - - if (!(0, _primitives.isName)(filter)) { - throw new _util.FormatError(`Bad filter name "${filter}"`); - } - - params = null; - - if (Array.isArray(paramsArray) && i in paramsArray) { - params = this.xref.fetchIfRef(paramsArray[i]); - } - - stream = this.makeFilter(stream, filter.name, maybeLength, params); - maybeLength = null; - } - } - - return stream; - } - - makeFilter(stream, name, maybeLength, params) { - if (maybeLength === 0) { - (0, _util.warn)(`Empty "${name}" stream.`); - return new _stream.NullStream(); - } - + static async _getPageIndex(xref, ref, pdfManager) { try { - const xrefStreamStats = this.xref.stats.streamTypes; + const annotDict = await xref.fetchIfRefAsync(ref); - if (name === "FlateDecode" || name === "Fl") { - xrefStreamStats[_util.StreamType.FLATE] = true; - - if (params) { - return new _stream.PredictorStream(new _stream.FlateStream(stream, maybeLength), maybeLength, params); - } - - return new _stream.FlateStream(stream, maybeLength); + if (!(annotDict instanceof _primitives.Dict)) { + return -1; } - if (name === "LZWDecode" || name === "LZW") { - xrefStreamStats[_util.StreamType.LZW] = true; - let earlyChange = 1; + const pageRef = annotDict.getRaw("P"); - if (params) { - if (params.has("EarlyChange")) { - earlyChange = params.get("EarlyChange"); - } - - return new _stream.PredictorStream(new _stream.LZWStream(stream, maybeLength, earlyChange), maybeLength, params); - } - - return new _stream.LZWStream(stream, maybeLength, earlyChange); + if (!(pageRef instanceof _primitives.Ref)) { + return -1; } - if (name === "DCTDecode" || name === "DCT") { - xrefStreamStats[_util.StreamType.DCT] = true; - return new _jpeg_stream.JpegStream(stream, maybeLength, stream.dict, params); - } - - if (name === "JPXDecode" || name === "JPX") { - xrefStreamStats[_util.StreamType.JPX] = true; - return new _jpx_stream.JpxStream(stream, maybeLength, stream.dict, params); - } - - if (name === "ASCII85Decode" || name === "A85") { - xrefStreamStats[_util.StreamType.A85] = true; - return new _stream.Ascii85Stream(stream, maybeLength); - } - - if (name === "ASCIIHexDecode" || name === "AHx") { - xrefStreamStats[_util.StreamType.AHX] = true; - return new _stream.AsciiHexStream(stream, maybeLength); - } - - if (name === "CCITTFaxDecode" || name === "CCF") { - xrefStreamStats[_util.StreamType.CCF] = true; - return new _ccitt_stream.CCITTFaxStream(stream, maybeLength, params); - } - - if (name === "RunLengthDecode" || name === "RL") { - xrefStreamStats[_util.StreamType.RLX] = true; - return new _stream.RunLengthStream(stream, maybeLength); - } - - if (name === "JBIG2Decode") { - xrefStreamStats[_util.StreamType.JBIG] = true; - return new _jbig2_stream.Jbig2Stream(stream, maybeLength, stream.dict, params); - } - - (0, _util.warn)(`Filter "${name}" is not supported.`); - return stream; + const pageIndex = await pdfManager.ensureCatalog("getPageIndex", [pageRef]); + return pageIndex; } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.warn)(`Invalid stream: "${ex}"`); - return new _stream.NullStream(); + (0, _util.warn)(`_getPageIndex: "${ex}".`); + return -1; } } -} + static async saveNewAnnotations(evaluator, task, annotations) { + const xref = evaluator.xref; + let baseFontRef; + const dependencies = []; + const promises = []; -exports.Parser = Parser; -const specialChars = [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - -function toHexDigit(ch) { - if (ch >= 0x30 && ch <= 0x39) { - return ch & 0x0f; - } - - if (ch >= 0x41 && ch <= 0x46 || ch >= 0x61 && ch <= 0x66) { - return (ch & 0x0f) + 9; - } - - return -1; -} - -class Lexer { - constructor(stream, knownCommands = null) { - this.stream = stream; - this.nextChar(); - this.strBuf = []; - this.knownCommands = knownCommands; - this._hexStringNumWarn = 0; - this.beginInlineImagePos = -1; - } - - nextChar() { - return this.currentChar = this.stream.getByte(); - } - - peekChar() { - return this.stream.peekByte(); - } - - getNumber() { - let ch = this.currentChar; - let eNotation = false; - let divideBy = 0; - let sign = 0; - - if (ch === 0x2d) { - sign = -1; - ch = this.nextChar(); - - if (ch === 0x2d) { - ch = this.nextChar(); - } - } else if (ch === 0x2b) { - sign = 1; - ch = this.nextChar(); - } - - if (ch === 0x0a || ch === 0x0d) { - do { - ch = this.nextChar(); - } while (ch === 0x0a || ch === 0x0d); - } - - if (ch === 0x2e) { - divideBy = 10; - ch = this.nextChar(); - } - - if (ch < 0x30 || ch > 0x39) { - if (divideBy === 10 && sign === 0 && ((0, _core_utils.isWhiteSpace)(ch) || ch === -1)) { - (0, _util.warn)("Lexer.getNumber - treating a single decimal point as zero."); - return 0; - } - - throw new _util.FormatError(`Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`); - } - - sign = sign || 1; - let baseValue = ch - 0x30; - let powerValue = 0; - let powerValueSign = 1; - - while ((ch = this.nextChar()) >= 0) { - if (ch >= 0x30 && ch <= 0x39) { - const currentDigit = ch - 0x30; - - if (eNotation) { - powerValue = powerValue * 10 + currentDigit; - } else { - if (divideBy !== 0) { - divideBy *= 10; + for (const annotation of annotations) { + switch (annotation.annotationType) { + case _util.AnnotationEditorType.FREETEXT: + if (!baseFontRef) { + const baseFont = new _primitives.Dict(xref); + baseFont.set("BaseFont", _primitives.Name.get("Helvetica")); + baseFont.set("Type", _primitives.Name.get("Font")); + baseFont.set("Subtype", _primitives.Name.get("Type1")); + baseFont.set("Encoding", _primitives.Name.get("WinAnsiEncoding")); + const buffer = []; + baseFontRef = xref.getNewRef(); + (0, _writer.writeObject)(baseFontRef, baseFont, buffer, null); + dependencies.push({ + ref: baseFontRef, + data: buffer.join("") + }); } - baseValue = baseValue * 10 + currentDigit; - } - } else if (ch === 0x2e) { - if (divideBy === 0) { - divideBy = 1; - } else { - break; - } - } else if (ch === 0x2d) { - (0, _util.warn)("Badly formatted number: minus sign in the middle"); - } else if (ch === 0x45 || ch === 0x65) { - ch = this.peekChar(); - - if (ch === 0x2b || ch === 0x2d) { - powerValueSign = ch === 0x2d ? -1 : 1; - this.nextChar(); - } else if (ch < 0x30 || ch > 0x39) { - break; - } - - eNotation = true; - } else { - break; - } - } - - if (divideBy !== 0) { - baseValue /= divideBy; - } - - if (eNotation) { - baseValue *= 10 ** (powerValueSign * powerValue); - } - - return sign * baseValue; - } - - getString() { - let numParen = 1; - let done = false; - const strBuf = this.strBuf; - strBuf.length = 0; - let ch = this.nextChar(); - - while (true) { - let charBuffered = false; - - switch (ch | 0) { - case -1: - (0, _util.warn)("Unterminated string"); - done = true; + promises.push(FreeTextAnnotation.createNewAnnotation(xref, annotation, dependencies, { + evaluator, + task, + baseFontRef + })); break; - case 0x28: - ++numParen; - strBuf.push("("); - break; - - case 0x29: - if (--numParen === 0) { - this.nextChar(); - done = true; - } else { - strBuf.push(")"); - } - - break; - - case 0x5c: - ch = this.nextChar(); - - switch (ch) { - case -1: - (0, _util.warn)("Unterminated string"); - done = true; - break; - - case 0x6e: - strBuf.push("\n"); - break; - - case 0x72: - strBuf.push("\r"); - break; - - case 0x74: - strBuf.push("\t"); - break; - - case 0x62: - strBuf.push("\b"); - break; - - case 0x66: - strBuf.push("\f"); - break; - - case 0x5c: - case 0x28: - case 0x29: - strBuf.push(String.fromCharCode(ch)); - break; - - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - let x = ch & 0x0f; - ch = this.nextChar(); - charBuffered = true; - - if (ch >= 0x30 && ch <= 0x37) { - x = (x << 3) + (ch & 0x0f); - ch = this.nextChar(); - - if (ch >= 0x30 && ch <= 0x37) { - charBuffered = false; - x = (x << 3) + (ch & 0x0f); - } - } - - strBuf.push(String.fromCharCode(x)); - break; - - case 0x0d: - if (this.peekChar() === 0x0a) { - this.nextChar(); - } - - break; - - case 0x0a: - break; - - default: - strBuf.push(String.fromCharCode(ch)); - break; - } - - break; - - default: - strBuf.push(String.fromCharCode(ch)); - break; + case _util.AnnotationEditorType.INK: + promises.push(InkAnnotation.createNewAnnotation(xref, annotation, dependencies)); } - - if (done) { - break; - } - - if (!charBuffered) { - ch = this.nextChar(); - } - } - - return strBuf.join(""); - } - - getName() { - let ch, previousCh; - const strBuf = this.strBuf; - strBuf.length = 0; - - while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { - if (ch === 0x23) { - ch = this.nextChar(); - - if (specialChars[ch]) { - (0, _util.warn)("Lexer_getName: " + "NUMBER SIGN (#) should be followed by a hexadecimal number."); - strBuf.push("#"); - break; - } - - const x = toHexDigit(ch); - - if (x !== -1) { - previousCh = ch; - ch = this.nextChar(); - const x2 = toHexDigit(ch); - - if (x2 === -1) { - (0, _util.warn)(`Lexer_getName: Illegal digit (${String.fromCharCode(ch)}) ` + "in hexadecimal number."); - strBuf.push("#", String.fromCharCode(previousCh)); - - if (specialChars[ch]) { - break; - } - - strBuf.push(String.fromCharCode(ch)); - continue; - } - - strBuf.push(String.fromCharCode(x << 4 | x2)); - } else { - strBuf.push("#", String.fromCharCode(ch)); - } - } else { - strBuf.push(String.fromCharCode(ch)); - } - } - - if (strBuf.length > 127) { - (0, _util.warn)(`Name token is longer than allowed by the spec: ${strBuf.length}`); - } - - return _primitives.Name.get(strBuf.join("")); - } - - _hexStringWarn(ch) { - const MAX_HEX_STRING_NUM_WARN = 5; - - if (this._hexStringNumWarn++ === MAX_HEX_STRING_NUM_WARN) { - (0, _util.warn)("getHexString - ignoring additional invalid characters."); - return; - } - - if (this._hexStringNumWarn > MAX_HEX_STRING_NUM_WARN) { - return; - } - - (0, _util.warn)(`getHexString - ignoring invalid character: ${ch}`); - } - - getHexString() { - const strBuf = this.strBuf; - strBuf.length = 0; - let ch = this.currentChar; - let isFirstHex = true; - let firstDigit, secondDigit; - this._hexStringNumWarn = 0; - - while (true) { - if (ch < 0) { - (0, _util.warn)("Unterminated hex string"); - break; - } else if (ch === 0x3e) { - this.nextChar(); - break; - } else if (specialChars[ch] === 1) { - ch = this.nextChar(); - continue; - } else { - if (isFirstHex) { - firstDigit = toHexDigit(ch); - - if (firstDigit === -1) { - this._hexStringWarn(ch); - - ch = this.nextChar(); - continue; - } - } else { - secondDigit = toHexDigit(ch); - - if (secondDigit === -1) { - this._hexStringWarn(ch); - - ch = this.nextChar(); - continue; - } - - strBuf.push(String.fromCharCode(firstDigit << 4 | secondDigit)); - } - - isFirstHex = !isFirstHex; - ch = this.nextChar(); - } - } - - return strBuf.join(""); - } - - getObj() { - let comment = false; - let ch = this.currentChar; - - while (true) { - if (ch < 0) { - return _primitives.EOF; - } - - if (comment) { - if (ch === 0x0a || ch === 0x0d) { - comment = false; - } - } else if (ch === 0x25) { - comment = true; - } else if (specialChars[ch] !== 1) { - break; - } - - ch = this.nextChar(); - } - - switch (ch | 0) { - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x2b: - case 0x2d: - case 0x2e: - return this.getNumber(); - - case 0x28: - return this.getString(); - - case 0x2f: - return this.getName(); - - case 0x5b: - this.nextChar(); - return _primitives.Cmd.get("["); - - case 0x5d: - this.nextChar(); - return _primitives.Cmd.get("]"); - - case 0x3c: - ch = this.nextChar(); - - if (ch === 0x3c) { - this.nextChar(); - return _primitives.Cmd.get("<<"); - } - - return this.getHexString(); - - case 0x3e: - ch = this.nextChar(); - - if (ch === 0x3e) { - this.nextChar(); - return _primitives.Cmd.get(">>"); - } - - return _primitives.Cmd.get(">"); - - case 0x7b: - this.nextChar(); - return _primitives.Cmd.get("{"); - - case 0x7d: - this.nextChar(); - return _primitives.Cmd.get("}"); - - case 0x29: - this.nextChar(); - throw new _util.FormatError(`Illegal character: ${ch}`); - } - - let str = String.fromCharCode(ch); - const knownCommands = this.knownCommands; - let knownCommandFound = knownCommands && knownCommands[str] !== undefined; - - while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { - const possibleCommand = str + String.fromCharCode(ch); - - if (knownCommandFound && knownCommands[possibleCommand] === undefined) { - break; - } - - if (str.length === 128) { - throw new _util.FormatError(`Command token too long: ${str.length}`); - } - - str = possibleCommand; - knownCommandFound = knownCommands && knownCommands[str] !== undefined; - } - - if (str === "true") { - return true; - } - - if (str === "false") { - return false; - } - - if (str === "null") { - return null; - } - - if (str === "BI") { - this.beginInlineImagePos = this.stream.pos; - } - - return _primitives.Cmd.get(str); - } - - peekObj() { - const streamPos = this.stream.pos, - currentChar = this.currentChar, - beginInlineImagePos = this.beginInlineImagePos; - let nextObj; - - try { - nextObj = this.getObj(); - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - (0, _util.warn)(`peekObj: ${ex}`); - } - - this.stream.pos = streamPos; - this.currentChar = currentChar; - this.beginInlineImagePos = beginInlineImagePos; - return nextObj; - } - - skipToNextLine() { - let ch = this.currentChar; - - while (ch >= 0) { - if (ch === 0x0d) { - ch = this.nextChar(); - - if (ch === 0x0a) { - this.nextChar(); - } - - break; - } else if (ch === 0x0a) { - this.nextChar(); - break; - } - - ch = this.nextChar(); - } - } - -} - -exports.Lexer = Lexer; - -class Linearization { - static create(stream) { - function getInt(linDict, name, allowZeroValue = false) { - const obj = linDict.get(name); - - if (Number.isInteger(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) { - return obj; - } - - throw new Error(`The "${name}" parameter in the linearization ` + "dictionary is invalid."); - } - - function getHints(linDict) { - const hints = linDict.get("H"); - let hintsLength; - - if (Array.isArray(hints) && ((hintsLength = hints.length) === 2 || hintsLength === 4)) { - for (let index = 0; index < hintsLength; index++) { - const hint = hints[index]; - - if (!(Number.isInteger(hint) && hint > 0)) { - throw new Error(`Hint (${index}) in the linearization dictionary is invalid.`); - } - } - - return hints; - } - - throw new Error("Hint array in the linearization dictionary is invalid."); - } - - const parser = new Parser({ - lexer: new Lexer(stream), - xref: null - }); - const obj1 = parser.getObj(); - const obj2 = parser.getObj(); - const obj3 = parser.getObj(); - const linDict = parser.getObj(); - let obj, length; - - if (!(Number.isInteger(obj1) && Number.isInteger(obj2) && (0, _primitives.isCmd)(obj3, "obj") && (0, _primitives.isDict)(linDict) && (0, _util.isNum)(obj = linDict.get("Linearized")) && obj > 0)) { - return null; - } else if ((length = getInt(linDict, "L")) !== stream.length) { - throw new Error('The "L" parameter in the linearization dictionary ' + "does not equal the stream length."); } return { - length, - hints: getHints(linDict), - objectNumberFirst: getInt(linDict, "O"), - endFirst: getInt(linDict, "E"), - numPages: getInt(linDict, "N"), - mainXRefEntriesOffset: getInt(linDict, "T"), - pageFirst: linDict.has("P") ? getInt(linDict, "P", true) : 0 + annotations: await Promise.all(promises), + dependencies + }; + } + + static async printNewAnnotations(evaluator, task, annotations) { + if (!annotations) { + return null; + } + + const xref = evaluator.xref; + const promises = []; + + for (const annotation of annotations) { + switch (annotation.annotationType) { + case _util.AnnotationEditorType.FREETEXT: + promises.push(FreeTextAnnotation.createNewPrintAnnotation(xref, annotation, { + evaluator, + task + })); + break; + + case _util.AnnotationEditorType.INK: + promises.push(InkAnnotation.createNewPrintAnnotation(xref, annotation)); + break; + } + } + + return Promise.all(promises); + } + +} + +exports.AnnotationFactory = AnnotationFactory; + +function getRgbColor(color, defaultColor = new Uint8ClampedArray(3)) { + if (!Array.isArray(color)) { + return defaultColor; + } + + const rgbColor = defaultColor || new Uint8ClampedArray(3); + + switch (color.length) { + case 0: + return null; + + case 1: + _colorspace.ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0); + + return rgbColor; + + case 3: + _colorspace.ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0); + + return rgbColor; + + case 4: + _colorspace.ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0); + + return rgbColor; + + default: + return defaultColor; + } +} + +function getQuadPoints(dict, rect) { + if (!dict.has("QuadPoints")) { + return null; + } + + const quadPoints = dict.getArray("QuadPoints"); + + if (!Array.isArray(quadPoints) || quadPoints.length === 0 || quadPoints.length % 8 > 0) { + return null; + } + + const quadPointsLists = []; + + for (let i = 0, ii = quadPoints.length / 8; i < ii; i++) { + quadPointsLists.push([]); + + for (let j = i * 8, jj = i * 8 + 8; j < jj; j += 2) { + const x = quadPoints[j]; + const y = quadPoints[j + 1]; + + if (rect !== null && (x < rect[0] || x > rect[2] || y < rect[1] || y > rect[3])) { + return null; + } + + quadPointsLists[i].push({ + x, + y + }); + } + } + + return quadPointsLists.map(quadPointsList => { + const [minX, maxX, minY, maxY] = quadPointsList.reduce(([mX, MX, mY, MY], quadPoint) => [Math.min(mX, quadPoint.x), Math.max(MX, quadPoint.x), Math.min(mY, quadPoint.y), Math.max(MY, quadPoint.y)], [Number.MAX_VALUE, Number.MIN_VALUE, Number.MAX_VALUE, Number.MIN_VALUE]); + return [{ + x: minX, + y: maxY + }, { + x: maxX, + y: maxY + }, { + x: minX, + y: minY + }, { + x: maxX, + y: minY + }]; + }); +} + +function getTransformMatrix(rect, bbox, matrix) { + const [minX, minY, maxX, maxY] = _util.Util.getAxialAlignedBoundingBox(bbox, matrix); + + if (minX === maxX || minY === maxY) { + return [1, 0, 0, 1, rect[0], rect[1]]; + } + + const xRatio = (rect[2] - rect[0]) / (maxX - minX); + const yRatio = (rect[3] - rect[1]) / (maxY - minY); + return [xRatio, 0, 0, yRatio, rect[0] - minX * xRatio, rect[1] - minY * yRatio]; +} + +class Annotation { + constructor(params) { + const dict = params.dict; + this.setTitle(dict.get("T")); + this.setContents(dict.get("Contents")); + this.setModificationDate(dict.get("M")); + this.setFlags(dict.get("F")); + this.setRectangle(dict.getArray("Rect")); + this.setColor(dict.getArray("C")); + this.setBorderStyle(dict); + this.setAppearance(dict); + this.setOptionalContent(dict); + const MK = dict.get("MK"); + this.setBorderAndBackgroundColors(MK); + this.setRotation(MK); + this._streams = []; + + if (this.appearance) { + this._streams.push(this.appearance); + } + + this.data = { + annotationFlags: this.flags, + borderStyle: this.borderStyle, + color: this.color, + backgroundColor: this.backgroundColor, + borderColor: this.borderColor, + rotation: this.rotation, + contentsObj: this._contents, + hasAppearance: !!this.appearance, + id: params.id, + modificationDate: this.modificationDate, + rect: this.rectangle, + subtype: params.subtype, + hasOwnCanvas: false + }; + + if (params.collectFields) { + const kids = dict.get("Kids"); + + if (Array.isArray(kids)) { + const kidIds = []; + + for (const kid of kids) { + if (kid instanceof _primitives.Ref) { + kidIds.push(kid.toString()); + } + } + + if (kidIds.length !== 0) { + this.data.kidIds = kidIds; + } + } + + this.data.actions = (0, _core_utils.collectActions)(params.xref, dict, _util.AnnotationActionEventType); + this.data.fieldName = this._constructFieldName(dict); + this.data.pageIndex = params.pageIndex; + } + + this._fallbackFontDict = null; + } + + _hasFlag(flags, flag) { + return !!(flags & flag); + } + + _isViewable(flags) { + return !this._hasFlag(flags, _util.AnnotationFlag.INVISIBLE) && !this._hasFlag(flags, _util.AnnotationFlag.NOVIEW); + } + + _isPrintable(flags) { + return this._hasFlag(flags, _util.AnnotationFlag.PRINT) && !this._hasFlag(flags, _util.AnnotationFlag.INVISIBLE); + } + + mustBeViewed(annotationStorage) { + const storageEntry = annotationStorage && annotationStorage.get(this.data.id); + + if (storageEntry && storageEntry.hidden !== undefined) { + return !storageEntry.hidden; + } + + return this.viewable && !this._hasFlag(this.flags, _util.AnnotationFlag.HIDDEN); + } + + mustBePrinted(annotationStorage) { + const storageEntry = annotationStorage && annotationStorage.get(this.data.id); + + if (storageEntry && storageEntry.print !== undefined) { + return storageEntry.print; + } + + return this.printable; + } + + get viewable() { + if (this.data.quadPoints === null) { + return false; + } + + if (this.flags === 0) { + return true; + } + + return this._isViewable(this.flags); + } + + get printable() { + if (this.data.quadPoints === null) { + return false; + } + + if (this.flags === 0) { + return false; + } + + return this._isPrintable(this.flags); + } + + _parseStringHelper(data) { + const str = typeof data === "string" ? (0, _util.stringToPDFString)(data) : ""; + const dir = str && (0, _bidi.bidi)(str).dir === "rtl" ? "rtl" : "ltr"; + return { + str, + dir + }; + } + + setTitle(title) { + this._title = this._parseStringHelper(title); + } + + setContents(contents) { + this._contents = this._parseStringHelper(contents); + } + + setModificationDate(modificationDate) { + this.modificationDate = typeof modificationDate === "string" ? modificationDate : null; + } + + setFlags(flags) { + this.flags = Number.isInteger(flags) && flags > 0 ? flags : 0; + } + + hasFlag(flag) { + return this._hasFlag(this.flags, flag); + } + + setRectangle(rectangle) { + if (Array.isArray(rectangle) && rectangle.length === 4) { + this.rectangle = _util.Util.normalizeRect(rectangle); + } else { + this.rectangle = [0, 0, 0, 0]; + } + } + + setColor(color) { + this.color = getRgbColor(color); + } + + setLineEndings(lineEndings) { + this.lineEndings = ["None", "None"]; + + if (Array.isArray(lineEndings) && lineEndings.length === 2) { + for (let i = 0; i < 2; i++) { + const obj = lineEndings[i]; + + if (obj instanceof _primitives.Name) { + switch (obj.name) { + case "None": + continue; + + case "Square": + case "Circle": + case "Diamond": + case "OpenArrow": + case "ClosedArrow": + case "Butt": + case "ROpenArrow": + case "RClosedArrow": + case "Slash": + this.lineEndings[i] = obj.name; + continue; + } + } + + (0, _util.warn)(`Ignoring invalid lineEnding: ${obj}`); + } + } + } + + setRotation(mk) { + this.rotation = 0; + + if (mk instanceof _primitives.Dict) { + let angle = mk.get("R") || 0; + + if (Number.isInteger(angle) && angle !== 0) { + angle %= 360; + + if (angle < 0) { + angle += 360; + } + + if (angle % 90 === 0) { + this.rotation = angle; + } + } + } + } + + setBorderAndBackgroundColors(mk) { + if (mk instanceof _primitives.Dict) { + this.borderColor = getRgbColor(mk.getArray("BC"), null); + this.backgroundColor = getRgbColor(mk.getArray("BG"), null); + } else { + this.borderColor = this.backgroundColor = null; + } + } + + setBorderStyle(borderStyle) { + this.borderStyle = new AnnotationBorderStyle(); + + if (!(borderStyle instanceof _primitives.Dict)) { + return; + } + + if (borderStyle.has("BS")) { + const dict = borderStyle.get("BS"); + const dictType = dict.get("Type"); + + if (!dictType || (0, _primitives.isName)(dictType, "Border")) { + this.borderStyle.setWidth(dict.get("W"), this.rectangle); + this.borderStyle.setStyle(dict.get("S")); + this.borderStyle.setDashArray(dict.getArray("D")); + } + } else if (borderStyle.has("Border")) { + const array = borderStyle.getArray("Border"); + + if (Array.isArray(array) && array.length >= 3) { + this.borderStyle.setHorizontalCornerRadius(array[0]); + this.borderStyle.setVerticalCornerRadius(array[1]); + this.borderStyle.setWidth(array[2], this.rectangle); + + if (array.length === 4) { + this.borderStyle.setDashArray(array[3], true); + } + } + } else { + this.borderStyle.setWidth(0); + } + } + + setAppearance(dict) { + this.appearance = null; + const appearanceStates = dict.get("AP"); + + if (!(appearanceStates instanceof _primitives.Dict)) { + return; + } + + const normalAppearanceState = appearanceStates.get("N"); + + if (normalAppearanceState instanceof _base_stream.BaseStream) { + this.appearance = normalAppearanceState; + return; + } + + if (!(normalAppearanceState instanceof _primitives.Dict)) { + return; + } + + const as = dict.get("AS"); + + if (!(as instanceof _primitives.Name) || !normalAppearanceState.has(as.name)) { + return; + } + + this.appearance = normalAppearanceState.get(as.name); + } + + setOptionalContent(dict) { + this.oc = null; + const oc = dict.get("OC"); + + if (oc instanceof _primitives.Name) { + (0, _util.warn)("setOptionalContent: Support for /Name-entry is not implemented."); + } else if (oc instanceof _primitives.Dict) { + this.oc = oc; + } + } + + loadResources(keys, appearance) { + return appearance.dict.getAsync("Resources").then(resources => { + if (!resources) { + return undefined; + } + + const objectLoader = new _object_loader.ObjectLoader(resources, keys, resources.xref); + return objectLoader.load().then(function () { + return resources; + }); + }); + } + + async getOperatorList(evaluator, task, intent, renderForms, annotationStorage) { + const data = this.data; + let appearance = this.appearance; + const isUsingOwnCanvas = !!(this.data.hasOwnCanvas && intent & _util.RenderingIntentFlag.DISPLAY); + + if (!appearance) { + if (!isUsingOwnCanvas) { + return { + opList: new _operator_list.OperatorList(), + separateForm: false, + separateCanvas: false + }; + } + + appearance = new _stream.StringStream(""); + appearance.dict = new _primitives.Dict(); + } + + const appearanceDict = appearance.dict; + const resources = await this.loadResources(["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"], appearance); + const bbox = appearanceDict.getArray("BBox") || [0, 0, 1, 1]; + const matrix = appearanceDict.getArray("Matrix") || [1, 0, 0, 1, 0, 0]; + const transform = getTransformMatrix(data.rect, bbox, matrix); + const opList = new _operator_list.OperatorList(); + let optionalContent; + + if (this.oc) { + optionalContent = await evaluator.parseMarkedContentProps(this.oc, null); + } + + if (optionalContent !== undefined) { + opList.addOp(_util.OPS.beginMarkedContentProps, ["OC", optionalContent]); + } + + opList.addOp(_util.OPS.beginAnnotation, [data.id, data.rect, transform, matrix, isUsingOwnCanvas]); + await evaluator.getOperatorList({ + stream: appearance, + task, + resources, + operatorList: opList, + fallbackFontDict: this._fallbackFontDict + }); + opList.addOp(_util.OPS.endAnnotation, []); + + if (optionalContent !== undefined) { + opList.addOp(_util.OPS.endMarkedContent, []); + } + + this.reset(); + return { + opList, + separateForm: false, + separateCanvas: isUsingOwnCanvas + }; + } + + async save(evaluator, task, annotationStorage) { + return null; + } + + get hasTextContent() { + return false; + } + + async extractTextContent(evaluator, task, viewBox) { + if (!this.appearance) { + return; + } + + const resources = await this.loadResources(["ExtGState", "Font", "Properties", "XObject"], this.appearance); + const text = []; + const buffer = []; + const sink = { + desiredSize: Math.Infinity, + ready: true, + + enqueue(chunk, size) { + for (const item of chunk.items) { + buffer.push(item.str); + + if (item.hasEOL) { + text.push(buffer.join("")); + buffer.length = 0; + } + } + } + + }; + await evaluator.getTextContent({ + stream: this.appearance, + task, + resources, + includeMarkedContent: true, + combineTextItems: true, + sink, + viewBox + }); + this.reset(); + + if (buffer.length) { + text.push(buffer.join("")); + } + + if (text.length > 0) { + this.data.textContent = text; + } + } + + getFieldObject() { + if (this.data.kidIds) { + return { + id: this.data.id, + actions: this.data.actions, + name: this.data.fieldName, + strokeColor: this.data.borderColor, + fillColor: this.data.backgroundColor, + type: "", + kidIds: this.data.kidIds, + page: this.data.pageIndex, + rotation: this.rotation + }; + } + + return null; + } + + reset() { + for (const stream of this._streams) { + stream.reset(); + } + } + + _constructFieldName(dict) { + if (!dict.has("T") && !dict.has("Parent")) { + (0, _util.warn)("Unknown field name, falling back to empty field name."); + return ""; + } + + if (!dict.has("Parent")) { + return (0, _util.stringToPDFString)(dict.get("T")); + } + + const fieldName = []; + + if (dict.has("T")) { + fieldName.unshift((0, _util.stringToPDFString)(dict.get("T"))); + } + + let loopDict = dict; + const visited = new _primitives.RefSet(); + + if (dict.objId) { + visited.put(dict.objId); + } + + while (loopDict.has("Parent")) { + loopDict = loopDict.get("Parent"); + + if (!(loopDict instanceof _primitives.Dict) || loopDict.objId && visited.has(loopDict.objId)) { + break; + } + + if (loopDict.objId) { + visited.put(loopDict.objId); + } + + if (loopDict.has("T")) { + fieldName.unshift((0, _util.stringToPDFString)(loopDict.get("T"))); + } + } + + return fieldName.join("."); + } + +} + +exports.Annotation = Annotation; + +class AnnotationBorderStyle { + constructor() { + this.width = 1; + this.style = _util.AnnotationBorderStyleType.SOLID; + this.dashArray = [3]; + this.horizontalCornerRadius = 0; + this.verticalCornerRadius = 0; + } + + setWidth(width, rect = [0, 0, 0, 0]) { + if (width instanceof _primitives.Name) { + this.width = 0; + return; + } + + if (typeof width === "number") { + if (width > 0) { + const maxWidth = (rect[2] - rect[0]) / 2; + const maxHeight = (rect[3] - rect[1]) / 2; + + if (maxWidth > 0 && maxHeight > 0 && (width > maxWidth || width > maxHeight)) { + (0, _util.warn)(`AnnotationBorderStyle.setWidth - ignoring width: ${width}`); + width = 1; + } + } + + this.width = width; + } + } + + setStyle(style) { + if (!(style instanceof _primitives.Name)) { + return; + } + + switch (style.name) { + case "S": + this.style = _util.AnnotationBorderStyleType.SOLID; + break; + + case "D": + this.style = _util.AnnotationBorderStyleType.DASHED; + break; + + case "B": + this.style = _util.AnnotationBorderStyleType.BEVELED; + break; + + case "I": + this.style = _util.AnnotationBorderStyleType.INSET; + break; + + case "U": + this.style = _util.AnnotationBorderStyleType.UNDERLINE; + break; + + default: + break; + } + } + + setDashArray(dashArray, forceStyle = false) { + if (Array.isArray(dashArray) && dashArray.length > 0) { + let isValid = true; + let allZeros = true; + + for (const element of dashArray) { + const validNumber = +element >= 0; + + if (!validNumber) { + isValid = false; + break; + } else if (element > 0) { + allZeros = false; + } + } + + if (isValid && !allZeros) { + this.dashArray = dashArray; + + if (forceStyle) { + this.setStyle(_primitives.Name.get("D")); + } + } else { + this.width = 0; + } + } else if (dashArray) { + this.width = 0; + } + } + + setHorizontalCornerRadius(radius) { + if (Number.isInteger(radius)) { + this.horizontalCornerRadius = radius; + } + } + + setVerticalCornerRadius(radius) { + if (Number.isInteger(radius)) { + this.verticalCornerRadius = radius; + } + } + +} + +exports.AnnotationBorderStyle = AnnotationBorderStyle; + +class MarkupAnnotation extends Annotation { + constructor(parameters) { + super(parameters); + const dict = parameters.dict; + + if (dict.has("IRT")) { + const rawIRT = dict.getRaw("IRT"); + this.data.inReplyTo = rawIRT instanceof _primitives.Ref ? rawIRT.toString() : null; + const rt = dict.get("RT"); + this.data.replyType = rt instanceof _primitives.Name ? rt.name : _util.AnnotationReplyType.REPLY; + } + + if (this.data.replyType === _util.AnnotationReplyType.GROUP) { + const parent = dict.get("IRT"); + this.setTitle(parent.get("T")); + this.data.titleObj = this._title; + this.setContents(parent.get("Contents")); + this.data.contentsObj = this._contents; + + if (!parent.has("CreationDate")) { + this.data.creationDate = null; + } else { + this.setCreationDate(parent.get("CreationDate")); + this.data.creationDate = this.creationDate; + } + + if (!parent.has("M")) { + this.data.modificationDate = null; + } else { + this.setModificationDate(parent.get("M")); + this.data.modificationDate = this.modificationDate; + } + + this.data.hasPopup = parent.has("Popup"); + + if (!parent.has("C")) { + this.data.color = null; + } else { + this.setColor(parent.getArray("C")); + this.data.color = this.color; + } + } else { + this.data.titleObj = this._title; + this.setCreationDate(dict.get("CreationDate")); + this.data.creationDate = this.creationDate; + this.data.hasPopup = dict.has("Popup"); + + if (!dict.has("C")) { + this.data.color = null; + } + } + + if (dict.has("RC")) { + this.data.richText = _factory.XFAFactory.getRichTextAsHtml(dict.get("RC")); + } + } + + setCreationDate(creationDate) { + this.creationDate = typeof creationDate === "string" ? creationDate : null; + } + + _setDefaultAppearance({ + xref, + extra, + strokeColor, + fillColor, + blendMode, + strokeAlpha, + fillAlpha, + pointsCallback + }) { + let minX = Number.MAX_VALUE; + let minY = Number.MAX_VALUE; + let maxX = Number.MIN_VALUE; + let maxY = Number.MIN_VALUE; + const buffer = ["q"]; + + if (extra) { + buffer.push(extra); + } + + if (strokeColor) { + buffer.push(`${strokeColor[0]} ${strokeColor[1]} ${strokeColor[2]} RG`); + } + + if (fillColor) { + buffer.push(`${fillColor[0]} ${fillColor[1]} ${fillColor[2]} rg`); + } + + let pointsArray = this.data.quadPoints; + + if (!pointsArray) { + pointsArray = [[{ + x: this.rectangle[0], + y: this.rectangle[3] + }, { + x: this.rectangle[2], + y: this.rectangle[3] + }, { + x: this.rectangle[0], + y: this.rectangle[1] + }, { + x: this.rectangle[2], + y: this.rectangle[1] + }]]; + } + + for (const points of pointsArray) { + const [mX, MX, mY, MY] = pointsCallback(buffer, points); + minX = Math.min(minX, mX); + maxX = Math.max(maxX, MX); + minY = Math.min(minY, mY); + maxY = Math.max(maxY, MY); + } + + buffer.push("Q"); + const formDict = new _primitives.Dict(xref); + const appearanceStreamDict = new _primitives.Dict(xref); + appearanceStreamDict.set("Subtype", _primitives.Name.get("Form")); + const appearanceStream = new _stream.StringStream(buffer.join(" ")); + appearanceStream.dict = appearanceStreamDict; + formDict.set("Fm0", appearanceStream); + const gsDict = new _primitives.Dict(xref); + + if (blendMode) { + gsDict.set("BM", _primitives.Name.get(blendMode)); + } + + if (typeof strokeAlpha === "number") { + gsDict.set("CA", strokeAlpha); + } + + if (typeof fillAlpha === "number") { + gsDict.set("ca", fillAlpha); + } + + const stateDict = new _primitives.Dict(xref); + stateDict.set("GS0", gsDict); + const resources = new _primitives.Dict(xref); + resources.set("ExtGState", stateDict); + resources.set("XObject", formDict); + const appearanceDict = new _primitives.Dict(xref); + appearanceDict.set("Resources", resources); + const bbox = this.data.rect = [minX, minY, maxX, maxY]; + appearanceDict.set("BBox", bbox); + this.appearance = new _stream.StringStream("/GS0 gs /Fm0 Do"); + this.appearance.dict = appearanceDict; + + this._streams.push(this.appearance, appearanceStream); + } + + static async createNewAnnotation(xref, annotation, dependencies, params) { + const annotationRef = xref.getNewRef(); + const apRef = xref.getNewRef(); + const annotationDict = this.createNewDict(annotation, xref, { + apRef + }); + const ap = await this.createNewAppearanceStream(annotation, xref, params); + const buffer = []; + let transform = xref.encrypt ? xref.encrypt.createCipherTransform(apRef.num, apRef.gen) : null; + (0, _writer.writeObject)(apRef, ap, buffer, transform); + dependencies.push({ + ref: apRef, + data: buffer.join("") + }); + buffer.length = 0; + transform = xref.encrypt ? xref.encrypt.createCipherTransform(annotationRef.num, annotationRef.gen) : null; + (0, _writer.writeObject)(annotationRef, annotationDict, buffer, transform); + return { + ref: annotationRef, + data: buffer.join("") + }; + } + + static async createNewPrintAnnotation(xref, annotation, params) { + const ap = await this.createNewAppearanceStream(annotation, xref, params); + const annotationDict = this.createNewDict(annotation, xref, { + ap + }); + return new this.prototype.constructor({ + dict: annotationDict, + xref + }); + } + +} + +exports.MarkupAnnotation = MarkupAnnotation; + +class WidgetAnnotation extends Annotation { + constructor(params) { + super(params); + const dict = params.dict; + const data = this.data; + this.ref = params.ref; + data.annotationType = _util.AnnotationType.WIDGET; + + if (data.fieldName === undefined) { + data.fieldName = this._constructFieldName(dict); + } + + if (data.actions === undefined) { + data.actions = (0, _core_utils.collectActions)(params.xref, dict, _util.AnnotationActionEventType); + } + + let fieldValue = (0, _core_utils.getInheritableProperty)({ + dict, + key: "V", + getArray: true + }); + data.fieldValue = this._decodeFormValue(fieldValue); + const defaultFieldValue = (0, _core_utils.getInheritableProperty)({ + dict, + key: "DV", + getArray: true + }); + data.defaultFieldValue = this._decodeFormValue(defaultFieldValue); + + if (fieldValue === undefined && params.xfaDatasets) { + const path = this._title.str; + + if (path) { + this._hasValueFromXFA = true; + data.fieldValue = fieldValue = params.xfaDatasets.getValue(path); + } + } + + if (fieldValue === undefined && data.defaultFieldValue !== null) { + data.fieldValue = data.defaultFieldValue; + } + + data.alternativeText = (0, _util.stringToPDFString)(dict.get("TU") || ""); + const defaultAppearance = (0, _core_utils.getInheritableProperty)({ + dict, + key: "DA" + }) || params.acroForm.get("DA"); + this._defaultAppearance = typeof defaultAppearance === "string" ? defaultAppearance : ""; + data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(this._defaultAppearance); + const fieldType = (0, _core_utils.getInheritableProperty)({ + dict, + key: "FT" + }); + data.fieldType = fieldType instanceof _primitives.Name ? fieldType.name : null; + const localResources = (0, _core_utils.getInheritableProperty)({ + dict, + key: "DR" + }); + const acroFormResources = params.acroForm.get("DR"); + const appearanceResources = this.appearance && this.appearance.dict.get("Resources"); + this._fieldResources = { + localResources, + acroFormResources, + appearanceResources, + mergedResources: _primitives.Dict.merge({ + xref: params.xref, + dictArray: [localResources, appearanceResources, acroFormResources], + mergeSubDicts: true + }) + }; + data.fieldFlags = (0, _core_utils.getInheritableProperty)({ + dict, + key: "Ff" + }); + + if (!Number.isInteger(data.fieldFlags) || data.fieldFlags < 0) { + data.fieldFlags = 0; + } + + data.readOnly = this.hasFieldFlag(_util.AnnotationFieldFlag.READONLY); + data.required = this.hasFieldFlag(_util.AnnotationFieldFlag.REQUIRED); + data.hidden = this._hasFlag(data.annotationFlags, _util.AnnotationFlag.HIDDEN); + } + + _decodeFormValue(formValue) { + if (Array.isArray(formValue)) { + return formValue.filter(item => typeof item === "string").map(item => (0, _util.stringToPDFString)(item)); + } else if (formValue instanceof _primitives.Name) { + return (0, _util.stringToPDFString)(formValue.name); + } else if (typeof formValue === "string") { + return (0, _util.stringToPDFString)(formValue); + } + + return null; + } + + hasFieldFlag(flag) { + return !!(this.data.fieldFlags & flag); + } + + static _getRotationMatrix(rotation, width, height) { + switch (rotation) { + case 90: + return [0, 1, -1, 0, width, 0]; + + case 180: + return [-1, 0, 0, -1, width, height]; + + case 270: + return [0, -1, 1, 0, 0, height]; + + default: + throw new Error("Invalid rotation"); + } + } + + getRotationMatrix(annotationStorage) { + const storageEntry = annotationStorage ? annotationStorage.get(this.data.id) : undefined; + let rotation = storageEntry && storageEntry.rotation; + + if (rotation === undefined) { + rotation = this.rotation; + } + + if (rotation === 0) { + return _util.IDENTITY_MATRIX; + } + + const width = this.data.rect[2] - this.data.rect[0]; + const height = this.data.rect[3] - this.data.rect[1]; + return WidgetAnnotation._getRotationMatrix(rotation, width, height); + } + + getBorderAndBackgroundAppearances(annotationStorage) { + const storageEntry = annotationStorage ? annotationStorage.get(this.data.id) : undefined; + let rotation = storageEntry && storageEntry.rotation; + + if (rotation === undefined) { + rotation = this.rotation; + } + + if (!this.backgroundColor && !this.borderColor) { + return ""; + } + + const width = this.data.rect[2] - this.data.rect[0]; + const height = this.data.rect[3] - this.data.rect[1]; + const rect = rotation === 0 || rotation === 180 ? `0 0 ${width} ${height} re` : `0 0 ${height} ${width} re`; + let str = ""; + + if (this.backgroundColor) { + str = `${(0, _default_appearance.getPdfColor)(this.backgroundColor, true)} ${rect} f `; + } + + if (this.borderColor) { + const borderWidth = this.borderStyle.width || 1; + str += `${borderWidth} w ${(0, _default_appearance.getPdfColor)(this.borderColor, false)} ${rect} S `; + } + + return str; + } + + async getOperatorList(evaluator, task, intent, renderForms, annotationStorage) { + if (renderForms && !(this instanceof SignatureWidgetAnnotation)) { + return { + opList: new _operator_list.OperatorList(), + separateForm: true, + separateCanvas: false + }; + } + + if (!this._hasText) { + return super.getOperatorList(evaluator, task, intent, renderForms, annotationStorage); + } + + const content = await this._getAppearance(evaluator, task, annotationStorage); + + if (this.appearance && content === null) { + return super.getOperatorList(evaluator, task, intent, renderForms, annotationStorage); + } + + const opList = new _operator_list.OperatorList(); + + if (!this._defaultAppearance || content === null) { + return { + opList, + separateForm: false, + separateCanvas: false + }; + } + + const matrix = [1, 0, 0, 1, 0, 0]; + const bbox = [0, 0, this.data.rect[2] - this.data.rect[0], this.data.rect[3] - this.data.rect[1]]; + const transform = getTransformMatrix(this.data.rect, bbox, matrix); + let optionalContent; + + if (this.oc) { + optionalContent = await evaluator.parseMarkedContentProps(this.oc, null); + } + + if (optionalContent !== undefined) { + opList.addOp(_util.OPS.beginMarkedContentProps, ["OC", optionalContent]); + } + + opList.addOp(_util.OPS.beginAnnotation, [this.data.id, this.data.rect, transform, this.getRotationMatrix(annotationStorage), false]); + const stream = new _stream.StringStream(content); + await evaluator.getOperatorList({ + stream, + task, + resources: this._fieldResources.mergedResources, + operatorList: opList + }); + opList.addOp(_util.OPS.endAnnotation, []); + + if (optionalContent !== undefined) { + opList.addOp(_util.OPS.endMarkedContent, []); + } + + return { + opList, + separateForm: false, + separateCanvas: false + }; + } + + _getMKDict(rotation) { + const mk = new _primitives.Dict(null); + + if (rotation) { + mk.set("R", rotation); + } + + if (this.borderColor) { + mk.set("BC", Array.from(this.borderColor).map(c => c / 255)); + } + + if (this.backgroundColor) { + mk.set("BG", Array.from(this.backgroundColor).map(c => c / 255)); + } + + return mk.size > 0 ? mk : null; + } + + async save(evaluator, task, annotationStorage) { + const storageEntry = annotationStorage ? annotationStorage.get(this.data.id) : undefined; + let value = storageEntry && storageEntry.value; + let rotation = storageEntry && storageEntry.rotation; + + if (value === this.data.fieldValue || value === undefined) { + if (!this._hasValueFromXFA && rotation === undefined) { + return null; + } + + value = value || this.data.fieldValue; + } + + if (rotation === undefined && !this._hasValueFromXFA && Array.isArray(value) && Array.isArray(this.data.fieldValue) && value.length === this.data.fieldValue.length && value.every((x, i) => x === this.data.fieldValue[i])) { + return null; + } + + if (rotation === undefined) { + rotation = this.rotation; + } + + let appearance = await this._getAppearance(evaluator, task, annotationStorage); + + if (appearance === null) { + return null; + } + + const { + xref + } = evaluator; + const dict = xref.fetchIfRef(this.ref); + + if (!(dict instanceof _primitives.Dict)) { + return null; + } + + const bbox = [0, 0, this.data.rect[2] - this.data.rect[0], this.data.rect[3] - this.data.rect[1]]; + const xfa = { + path: (0, _util.stringToPDFString)(dict.get("T") || ""), + value + }; + const newRef = xref.getNewRef(); + const AP = new _primitives.Dict(xref); + AP.set("N", newRef); + const encrypt = xref.encrypt; + let originalTransform = null; + let newTransform = null; + + if (encrypt) { + originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen); + newTransform = encrypt.createCipherTransform(newRef.num, newRef.gen); + appearance = newTransform.encryptString(appearance); + } + + const encoder = val => (0, _util.isAscii)(val) ? val : (0, _util.stringToUTF16BEString)(val); + + dict.set("V", Array.isArray(value) ? value.map(encoder) : encoder(value)); + dict.set("AP", AP); + dict.set("M", `D:${(0, _util.getModificationDate)()}`); + + const maybeMK = this._getMKDict(rotation); + + if (maybeMK) { + dict.set("MK", maybeMK); + } + + const appearanceDict = new _primitives.Dict(xref); + appearanceDict.set("Length", appearance.length); + appearanceDict.set("Subtype", _primitives.Name.get("Form")); + appearanceDict.set("Resources", this._getSaveFieldResources(xref)); + appearanceDict.set("BBox", bbox); + const rotationMatrix = this.getRotationMatrix(annotationStorage); + + if (rotationMatrix !== _util.IDENTITY_MATRIX) { + appearanceDict.set("Matrix", rotationMatrix); + } + + const bufferOriginal = [`${this.ref.num} ${this.ref.gen} obj\n`]; + (0, _writer.writeDict)(dict, bufferOriginal, originalTransform); + bufferOriginal.push("\nendobj\n"); + const bufferNew = [`${newRef.num} ${newRef.gen} obj\n`]; + (0, _writer.writeDict)(appearanceDict, bufferNew, newTransform); + bufferNew.push(" stream\n", appearance, "\nendstream\nendobj\n"); + return [{ + ref: this.ref, + data: bufferOriginal.join(""), + xfa + }, { + ref: newRef, + data: bufferNew.join(""), + xfa: null + }]; + } + + async _getAppearance(evaluator, task, annotationStorage) { + const isPassword = this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD); + + if (isPassword) { + return null; + } + + const storageEntry = annotationStorage ? annotationStorage.get(this.data.id) : undefined; + let value, rotation; + + if (storageEntry) { + value = storageEntry.formattedValue || storageEntry.value; + rotation = storageEntry.rotation; + } + + if (rotation === undefined && value === undefined) { + if (!this._hasValueFromXFA || this.appearance) { + return null; + } + } + + if (value === undefined) { + value = this.data.fieldValue; + + if (!value) { + return ""; + } + } + + if (Array.isArray(value) && value.length === 1) { + value = value[0]; + } + + (0, _util.assert)(typeof value === "string", "Expected `value` to be a string."); + value = value.trim(); + + if (value === "") { + return ""; + } + + if (rotation === undefined) { + rotation = this.rotation; + } + + let lineCount = -1; + + if (this.data.multiLine) { + lineCount = value.split(/\r\n|\r|\n/).length; + } + + const defaultPadding = 2; + const hPadding = defaultPadding; + let totalHeight = this.data.rect[3] - this.data.rect[1]; + let totalWidth = this.data.rect[2] - this.data.rect[0]; + + if (rotation === 90 || rotation === 270) { + [totalWidth, totalHeight] = [totalHeight, totalWidth]; + } + + if (!this._defaultAppearance) { + this.data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(this._defaultAppearance = "/Helvetica 0 Tf 0 g"); + } + + const font = await WidgetAnnotation._getFontData(evaluator, task, this.data.defaultAppearanceData, this._fieldResources.mergedResources); + + const [defaultAppearance, fontSize] = this._computeFontSize(totalHeight - defaultPadding, totalWidth - 2 * hPadding, value, font, lineCount); + + let descent = font.descent; + + if (isNaN(descent)) { + descent = 0; + } + + const defaultVPadding = Math.min(Math.floor((totalHeight - fontSize) / 2), defaultPadding); + const vPadding = defaultVPadding + Math.abs(descent) * fontSize; + const alignment = this.data.textAlignment; + + if (this.data.multiLine) { + return this._getMultilineAppearance(defaultAppearance, value, font, fontSize, totalWidth, totalHeight, alignment, hPadding, vPadding, annotationStorage); + } + + const encodedString = font.encodeString(value).join(""); + + if (this.data.comb) { + return this._getCombAppearance(defaultAppearance, font, encodedString, totalWidth, hPadding, vPadding, annotationStorage); + } + + const colors = this.getBorderAndBackgroundAppearances(annotationStorage); + + if (alignment === 0 || alignment > 2) { + return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 ${hPadding} ${vPadding} Tm (${(0, _util.escapeString)(encodedString)}) Tj` + " ET Q EMC"; + } + + const renderedText = this._renderText(encodedString, font, fontSize, totalWidth, alignment, hPadding, vPadding); + + return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 0 0 Tm ${renderedText}` + " ET Q EMC"; + } + + static async _getFontData(evaluator, task, appearanceData, resources) { + const operatorList = new _operator_list.OperatorList(); + const initialState = { + font: null, + + clone() { + return this; + } + + }; + const { + fontName, + fontSize + } = appearanceData; + await evaluator.handleSetFont(resources, [fontName && _primitives.Name.get(fontName), fontSize], null, operatorList, task, initialState, null); + return initialState.font; + } + + _getTextWidth(text, font) { + return font.charsToGlyphs(text).reduce((width, glyph) => width + glyph.width, 0) / 1000; + } + + _computeFontSize(height, width, text, font, lineCount) { + let { + fontSize + } = this.data.defaultAppearanceData; + + if (!fontSize) { + const roundWithTwoDigits = x => Math.floor(x * 100) / 100; + + if (lineCount === -1) { + const textWidth = this._getTextWidth(text, font); + + fontSize = roundWithTwoDigits(Math.min(height / _util.LINE_FACTOR, width / textWidth)); + } else { + const lines = text.split(/\r\n?|\n/); + const cachedLines = []; + + for (const line of lines) { + const encoded = font.encodeString(line).join(""); + const glyphs = font.charsToGlyphs(encoded); + const positions = font.getCharPositions(encoded); + cachedLines.push({ + line: encoded, + glyphs, + positions + }); + } + + const isTooBig = fsize => { + let totalHeight = 0; + + for (const cache of cachedLines) { + const chunks = this._splitLine(null, font, fsize, width, cache); + + totalHeight += chunks.length * fsize; + + if (totalHeight > height) { + return true; + } + } + + return false; + }; + + fontSize = 12; + let lineHeight = fontSize * _util.LINE_FACTOR; + let numberOfLines = Math.round(height / lineHeight); + numberOfLines = Math.max(numberOfLines, lineCount); + + while (true) { + lineHeight = height / numberOfLines; + fontSize = roundWithTwoDigits(lineHeight / _util.LINE_FACTOR); + + if (isTooBig(fontSize)) { + numberOfLines++; + continue; + } + + break; + } + } + + const { + fontName, + fontColor + } = this.data.defaultAppearanceData; + this._defaultAppearance = (0, _default_appearance.createDefaultAppearance)({ + fontSize, + fontName, + fontColor + }); + } + + return [this._defaultAppearance, fontSize]; + } + + _renderText(text, font, fontSize, totalWidth, alignment, hPadding, vPadding) { + let shift; + + if (alignment === 1) { + const width = this._getTextWidth(text, font) * fontSize; + shift = (totalWidth - width) / 2; + } else if (alignment === 2) { + const width = this._getTextWidth(text, font) * fontSize; + shift = totalWidth - width - hPadding; + } else { + shift = hPadding; + } + + shift = (0, _core_utils.numberToString)(shift); + vPadding = (0, _core_utils.numberToString)(vPadding); + return `${shift} ${vPadding} Td (${(0, _util.escapeString)(text)}) Tj`; + } + + _getSaveFieldResources(xref) { + const { + localResources, + appearanceResources, + acroFormResources + } = this._fieldResources; + const fontName = this.data.defaultAppearanceData && this.data.defaultAppearanceData.fontName; + + if (!fontName) { + return localResources || _primitives.Dict.empty; + } + + for (const resources of [localResources, appearanceResources]) { + if (resources instanceof _primitives.Dict) { + const localFont = resources.get("Font"); + + if (localFont instanceof _primitives.Dict && localFont.has(fontName)) { + return resources; + } + } + } + + if (acroFormResources instanceof _primitives.Dict) { + const acroFormFont = acroFormResources.get("Font"); + + if (acroFormFont instanceof _primitives.Dict && acroFormFont.has(fontName)) { + const subFontDict = new _primitives.Dict(xref); + subFontDict.set(fontName, acroFormFont.getRaw(fontName)); + const subResourcesDict = new _primitives.Dict(xref); + subResourcesDict.set("Font", subFontDict); + return _primitives.Dict.merge({ + xref, + dictArray: [subResourcesDict, localResources], + mergeSubDicts: true + }); + } + } + + return localResources || _primitives.Dict.empty; + } + + getFieldObject() { + return null; + } + +} + +class TextWidgetAnnotation extends WidgetAnnotation { + constructor(params) { + super(params); + this._hasText = true; + const dict = params.dict; + + if (typeof this.data.fieldValue !== "string") { + this.data.fieldValue = ""; + } + + let alignment = (0, _core_utils.getInheritableProperty)({ + dict, + key: "Q" + }); + + if (!Number.isInteger(alignment) || alignment < 0 || alignment > 2) { + alignment = null; + } + + this.data.textAlignment = alignment; + let maximumLength = (0, _core_utils.getInheritableProperty)({ + dict, + key: "MaxLen" + }); + + if (!Number.isInteger(maximumLength) || maximumLength < 0) { + maximumLength = 0; + } + + this.data.maxLen = maximumLength; + this.data.multiLine = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTILINE); + this.data.comb = this.hasFieldFlag(_util.AnnotationFieldFlag.COMB) && !this.hasFieldFlag(_util.AnnotationFieldFlag.MULTILINE) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD) && !this.hasFieldFlag(_util.AnnotationFieldFlag.FILESELECT) && this.data.maxLen !== 0; + this.data.doNotScroll = this.hasFieldFlag(_util.AnnotationFieldFlag.DONOTSCROLL); + } + + _getCombAppearance(defaultAppearance, font, text, width, hPadding, vPadding, annotationStorage) { + const combWidth = (0, _core_utils.numberToString)(width / this.data.maxLen); + const buf = []; + const positions = font.getCharPositions(text); + + for (const [start, end] of positions) { + buf.push(`(${(0, _util.escapeString)(text.substring(start, end))}) Tj`); + } + + const colors = this.getBorderAndBackgroundAppearances(annotationStorage); + const renderedComb = buf.join(` ${combWidth} 0 Td `); + return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 ${hPadding} ${vPadding} Tm ${renderedComb}` + " ET Q EMC"; + } + + _getMultilineAppearance(defaultAppearance, text, font, fontSize, width, height, alignment, hPadding, vPadding, annotationStorage) { + const lines = text.split(/\r\n?|\n/); + const buf = []; + const totalWidth = width - 2 * hPadding; + + for (const line of lines) { + const chunks = this._splitLine(line, font, fontSize, totalWidth); + + for (const chunk of chunks) { + const padding = buf.length === 0 ? hPadding : 0; + buf.push(this._renderText(chunk, font, fontSize, width, alignment, padding, -fontSize)); + } + } + + const renderedText = buf.join("\n"); + const colors = this.getBorderAndBackgroundAppearances(annotationStorage); + return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 0 ${height} Tm ${renderedText}` + " ET Q EMC"; + } + + _splitLine(line, font, fontSize, width, cache = {}) { + line = cache.line || font.encodeString(line).join(""); + const glyphs = cache.glyphs || font.charsToGlyphs(line); + + if (glyphs.length <= 1) { + return [line]; + } + + const positions = cache.positions || font.getCharPositions(line); + const scale = fontSize / 1000; + const chunks = []; + let lastSpacePosInStringStart = -1, + lastSpacePosInStringEnd = -1, + lastSpacePos = -1, + startChunk = 0, + currentWidth = 0; + + for (let i = 0, ii = glyphs.length; i < ii; i++) { + const [start, end] = positions[i]; + const glyph = glyphs[i]; + const glyphWidth = glyph.width * scale; + + if (glyph.unicode === " ") { + if (currentWidth + glyphWidth > width) { + chunks.push(line.substring(startChunk, start)); + startChunk = start; + currentWidth = glyphWidth; + lastSpacePosInStringStart = -1; + lastSpacePos = -1; + } else { + currentWidth += glyphWidth; + lastSpacePosInStringStart = start; + lastSpacePosInStringEnd = end; + lastSpacePos = i; + } + } else { + if (currentWidth + glyphWidth > width) { + if (lastSpacePosInStringStart !== -1) { + chunks.push(line.substring(startChunk, lastSpacePosInStringEnd)); + startChunk = lastSpacePosInStringEnd; + i = lastSpacePos + 1; + lastSpacePosInStringStart = -1; + currentWidth = 0; + } else { + chunks.push(line.substring(startChunk, start)); + startChunk = start; + currentWidth = glyphWidth; + } + } else { + currentWidth += glyphWidth; + } + } + } + + if (startChunk < line.length) { + chunks.push(line.substring(startChunk, line.length)); + } + + return chunks; + } + + getFieldObject() { + return { + id: this.data.id, + value: this.data.fieldValue, + defaultValue: this.data.defaultFieldValue || "", + multiline: this.data.multiLine, + password: this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD), + charLimit: this.data.maxLen, + comb: this.data.comb, + editable: !this.data.readOnly, + hidden: this.data.hidden, + name: this.data.fieldName, + rect: this.data.rect, + actions: this.data.actions, + page: this.data.pageIndex, + strokeColor: this.data.borderColor, + fillColor: this.data.backgroundColor, + rotation: this.rotation, + type: "text" }; } } -exports.Linearization = Linearization; +class ButtonWidgetAnnotation extends WidgetAnnotation { + constructor(params) { + super(params); + this.checkedAppearance = null; + this.uncheckedAppearance = null; + this.data.checkBox = !this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON); + this.data.radioButton = this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON); + this.data.pushButton = this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON); + this.data.isTooltipOnly = false; -/***/ }), -/* 12 */ -/***/ (function(module, exports, __w_pdfjs_require__) { + if (this.data.checkBox) { + this._processCheckBox(params); + } else if (this.data.radioButton) { + this._processRadioButton(params); + } else if (this.data.pushButton) { + this.data.hasOwnCanvas = true; -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.LZWStream = exports.StringStream = exports.StreamsSequenceStream = exports.Stream = exports.RunLengthStream = exports.PredictorStream = exports.NullStream = exports.FlateStream = exports.DecodeStream = exports.DecryptStream = exports.AsciiHexStream = exports.Ascii85Stream = void 0; - -var _util = __w_pdfjs_require__(2); - -var _primitives = __w_pdfjs_require__(5); - -var _core_utils = __w_pdfjs_require__(8); - -var Stream = function StreamClosure() { - function Stream(arrayBuffer, start, length, dict) { - this.bytes = arrayBuffer instanceof Uint8Array ? arrayBuffer : new Uint8Array(arrayBuffer); - this.start = start || 0; - this.pos = this.start; - this.end = start + length || this.bytes.length; - this.dict = dict; - } - - Stream.prototype = { - get length() { - return this.end - this.start; - }, - - get isEmpty() { - return this.length === 0; - }, - - getByte: function Stream_getByte() { - if (this.pos >= this.end) { - return -1; - } - - return this.bytes[this.pos++]; - }, - getUint16: function Stream_getUint16() { - var b0 = this.getByte(); - var b1 = this.getByte(); - - if (b0 === -1 || b1 === -1) { - return -1; - } - - return (b0 << 8) + b1; - }, - getInt32: function Stream_getInt32() { - var b0 = this.getByte(); - var b1 = this.getByte(); - var b2 = this.getByte(); - var b3 = this.getByte(); - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - }, - - getBytes(length, forceClamped = false) { - var bytes = this.bytes; - var pos = this.pos; - var strEnd = this.end; - - if (!length) { - const subarray = bytes.subarray(pos, strEnd); - return forceClamped ? new Uint8ClampedArray(subarray) : subarray; - } - - var end = pos + length; - - if (end > strEnd) { - end = strEnd; - } - - this.pos = end; - const subarray = bytes.subarray(pos, end); - return forceClamped ? new Uint8ClampedArray(subarray) : subarray; - }, - - peekByte: function Stream_peekByte() { - var peekedByte = this.getByte(); - - if (peekedByte !== -1) { - this.pos--; - } - - return peekedByte; - }, - - peekBytes(length, forceClamped = false) { - var bytes = this.getBytes(length, forceClamped); - this.pos -= bytes.length; - return bytes; - }, - - getByteRange(begin, end) { - if (begin < 0) { - begin = 0; - } - - if (end > this.end) { - end = this.end; - } - - return this.bytes.subarray(begin, end); - }, - - skip: function Stream_skip(n) { - if (!n) { - n = 1; - } - - this.pos += n; - }, - reset: function Stream_reset() { - this.pos = this.start; - }, - moveStart: function Stream_moveStart() { - this.start = this.pos; - }, - makeSubStream: function Stream_makeSubStream(start, length, dict) { - return new Stream(this.bytes.buffer, start, length, dict); - } - }; - return Stream; -}(); - -exports.Stream = Stream; - -var StringStream = function StringStreamClosure() { - function StringStream(str) { - const bytes = (0, _util.stringToBytes)(str); - Stream.call(this, bytes); - } - - StringStream.prototype = Stream.prototype; - return StringStream; -}(); - -exports.StringStream = StringStream; - -var DecodeStream = function DecodeStreamClosure() { - var emptyBuffer = new Uint8Array(0); - - function DecodeStream(maybeMinBufferLength) { - this._rawMinBufferLength = maybeMinBufferLength || 0; - this.pos = 0; - this.bufferLength = 0; - this.eof = false; - this.buffer = emptyBuffer; - this.minBufferLength = 512; - - if (maybeMinBufferLength) { - while (this.minBufferLength < maybeMinBufferLength) { - this.minBufferLength *= 2; - } + this._processPushButton(params); + } else { + (0, _util.warn)("Invalid field flags for button widget annotation"); } } - DecodeStream.prototype = { - get isEmpty() { - while (!this.eof && this.bufferLength === 0) { - this.readBlock(); - } + async getOperatorList(evaluator, task, intent, renderForms, annotationStorage) { + if (this.data.pushButton) { + return super.getOperatorList(evaluator, task, intent, false, annotationStorage); + } - return this.bufferLength === 0; - }, + let value = null; + let rotation = null; - ensureBuffer: function DecodeStream_ensureBuffer(requested) { - var buffer = this.buffer; + if (annotationStorage) { + const storageEntry = annotationStorage.get(this.data.id); + value = storageEntry ? storageEntry.value : null; + rotation = storageEntry ? storageEntry.rotation : null; + } - if (requested <= buffer.byteLength) { - return buffer; - } + if (value === null && this.appearance) { + return super.getOperatorList(evaluator, task, intent, renderForms, annotationStorage); + } - var size = this.minBufferLength; - - while (size < requested) { - size *= 2; - } - - var buffer2 = new Uint8Array(size); - buffer2.set(buffer); - return this.buffer = buffer2; - }, - getByte: function DecodeStream_getByte() { - var pos = this.pos; - - while (this.bufferLength <= pos) { - if (this.eof) { - return -1; - } - - this.readBlock(); - } - - return this.buffer[this.pos++]; - }, - getUint16: function DecodeStream_getUint16() { - var b0 = this.getByte(); - var b1 = this.getByte(); - - if (b0 === -1 || b1 === -1) { - return -1; - } - - return (b0 << 8) + b1; - }, - getInt32: function DecodeStream_getInt32() { - var b0 = this.getByte(); - var b1 = this.getByte(); - var b2 = this.getByte(); - var b3 = this.getByte(); - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - }, - - getBytes(length, forceClamped = false) { - var end, - pos = this.pos; - - if (length) { - this.ensureBuffer(pos + length); - end = pos + length; - - while (!this.eof && this.bufferLength < end) { - this.readBlock(); - } - - var bufEnd = this.bufferLength; - - if (end > bufEnd) { - end = bufEnd; - } + if (value === null || value === undefined) { + if (this.data.checkBox) { + value = this.data.fieldValue === this.data.exportValue; } else { - while (!this.eof) { - this.readBlock(); - } - - end = this.bufferLength; - } - - this.pos = end; - const subarray = this.buffer.subarray(pos, end); - return forceClamped && !(subarray instanceof Uint8ClampedArray) ? new Uint8ClampedArray(subarray) : subarray; - }, - - peekByte: function DecodeStream_peekByte() { - var peekedByte = this.getByte(); - - if (peekedByte !== -1) { - this.pos--; - } - - return peekedByte; - }, - - peekBytes(length, forceClamped = false) { - var bytes = this.getBytes(length, forceClamped); - this.pos -= bytes.length; - return bytes; - }, - - makeSubStream: function DecodeStream_makeSubStream(start, length, dict) { - var end = start + length; - - while (this.bufferLength <= end && !this.eof) { - this.readBlock(); - } - - return new Stream(this.buffer, start, length, dict); - }, - - getByteRange(begin, end) { - (0, _util.unreachable)("Should not call DecodeStream.getByteRange"); - }, - - skip: function DecodeStream_skip(n) { - if (!n) { - n = 1; - } - - this.pos += n; - }, - reset: function DecodeStream_reset() { - this.pos = 0; - }, - getBaseStreams: function DecodeStream_getBaseStreams() { - if (this.str && this.str.getBaseStreams) { - return this.str.getBaseStreams(); - } - - return []; - } - }; - return DecodeStream; -}(); - -exports.DecodeStream = DecodeStream; - -var StreamsSequenceStream = function StreamsSequenceStreamClosure() { - function StreamsSequenceStream(streams) { - this.streams = streams; - let maybeLength = 0; - - for (let i = 0, ii = streams.length; i < ii; i++) { - const stream = streams[i]; - - if (stream instanceof DecodeStream) { - maybeLength += stream._rawMinBufferLength; - } else { - maybeLength += stream.length; + value = this.data.fieldValue === this.data.buttonValue; } } - DecodeStream.call(this, maybeLength); - } + const appearance = value ? this.checkedAppearance : this.uncheckedAppearance; - StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype); + if (appearance) { + const savedAppearance = this.appearance; - StreamsSequenceStream.prototype.readBlock = function streamSequenceStreamReadBlock() { - var streams = this.streams; + const savedMatrix = appearance.dict.getArray("Matrix") || _util.IDENTITY_MATRIX; - if (streams.length === 0) { - this.eof = true; - return; - } - - var stream = streams.shift(); - var chunk = stream.getBytes(); - var bufferLength = this.bufferLength; - var newLength = bufferLength + chunk.length; - var buffer = this.ensureBuffer(newLength); - buffer.set(chunk, bufferLength); - this.bufferLength = newLength; - }; - - StreamsSequenceStream.prototype.getBaseStreams = function StreamsSequenceStream_getBaseStreams() { - var baseStreams = []; - - for (var i = 0, ii = this.streams.length; i < ii; i++) { - var stream = this.streams[i]; - - if (stream.getBaseStreams) { - baseStreams.push(...stream.getBaseStreams()); - } - } - - return baseStreams; - }; - - return StreamsSequenceStream; -}(); - -exports.StreamsSequenceStream = StreamsSequenceStream; - -var FlateStream = function FlateStreamClosure() { - var codeLenCodeMap = new Int32Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); - var lengthDecode = new Int32Array([0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102]); - var distDecode = new Int32Array([0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001]); - var fixedLitCodeTab = [new Int32Array([0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7, 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff]), 9]; - var fixedDistCodeTab = [new Int32Array([0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000]), 5]; - - function FlateStream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - var cmf = str.getByte(); - var flg = str.getByte(); - - if (cmf === -1 || flg === -1) { - throw new _util.FormatError(`Invalid header in flate stream: ${cmf}, ${flg}`); - } - - if ((cmf & 0x0f) !== 0x08) { - throw new _util.FormatError(`Unknown compression method in flate stream: ${cmf}, ${flg}`); - } - - if (((cmf << 8) + flg) % 31 !== 0) { - throw new _util.FormatError(`Bad FCHECK in flate stream: ${cmf}, ${flg}`); - } - - if (flg & 0x20) { - throw new _util.FormatError(`FDICT bit set in flate stream: ${cmf}, ${flg}`); - } - - this.codeSize = 0; - this.codeBuf = 0; - DecodeStream.call(this, maybeLength); - } - - FlateStream.prototype = Object.create(DecodeStream.prototype); - - FlateStream.prototype.getBits = function FlateStream_getBits(bits) { - var str = this.str; - var codeSize = this.codeSize; - var codeBuf = this.codeBuf; - var b; - - while (codeSize < bits) { - if ((b = str.getByte()) === -1) { - throw new _util.FormatError("Bad encoding in flate stream"); + if (rotation) { + appearance.dict.set("Matrix", this.getRotationMatrix(annotationStorage)); } - codeBuf |= b << codeSize; - codeSize += 8; + this.appearance = appearance; + const operatorList = super.getOperatorList(evaluator, task, intent, renderForms, annotationStorage); + this.appearance = savedAppearance; + appearance.dict.set("Matrix", savedMatrix); + return operatorList; } - b = codeBuf & (1 << bits) - 1; - this.codeBuf = codeBuf >> bits; - this.codeSize = codeSize -= bits; - return b; - }; - - FlateStream.prototype.getCode = function FlateStream_getCode(table) { - var str = this.str; - var codes = table[0]; - var maxLen = table[1]; - var codeSize = this.codeSize; - var codeBuf = this.codeBuf; - var b; - - while (codeSize < maxLen) { - if ((b = str.getByte()) === -1) { - break; - } - - codeBuf |= b << codeSize; - codeSize += 8; - } - - var code = codes[codeBuf & (1 << maxLen) - 1]; - var codeLen = code >> 16; - var codeVal = code & 0xffff; - - if (codeLen < 1 || codeSize < codeLen) { - throw new _util.FormatError("Bad encoding in flate stream"); - } - - this.codeBuf = codeBuf >> codeLen; - this.codeSize = codeSize - codeLen; - return codeVal; - }; - - FlateStream.prototype.generateHuffmanTable = function flateStreamGenerateHuffmanTable(lengths) { - var n = lengths.length; - var maxLen = 0; - var i; - - for (i = 0; i < n; ++i) { - if (lengths[i] > maxLen) { - maxLen = lengths[i]; - } - } - - var size = 1 << maxLen; - var codes = new Int32Array(size); - - for (var len = 1, code = 0, skip = 2; len <= maxLen; ++len, code <<= 1, skip <<= 1) { - for (var val = 0; val < n; ++val) { - if (lengths[val] === len) { - var code2 = 0; - var t = code; - - for (i = 0; i < len; ++i) { - code2 = code2 << 1 | t & 1; - t >>= 1; - } - - for (i = code2; i < size; i += skip) { - codes[i] = len << 16 | val; - } - - ++code; - } - } - } - - return [codes, maxLen]; - }; - - FlateStream.prototype.readBlock = function FlateStream_readBlock() { - var buffer, len; - var str = this.str; - var hdr = this.getBits(3); - - if (hdr & 1) { - this.eof = true; - } - - hdr >>= 1; - - if (hdr === 0) { - var b; - - if ((b = str.getByte()) === -1) { - throw new _util.FormatError("Bad block header in flate stream"); - } - - var blockLen = b; - - if ((b = str.getByte()) === -1) { - throw new _util.FormatError("Bad block header in flate stream"); - } - - blockLen |= b << 8; - - if ((b = str.getByte()) === -1) { - throw new _util.FormatError("Bad block header in flate stream"); - } - - var check = b; - - if ((b = str.getByte()) === -1) { - throw new _util.FormatError("Bad block header in flate stream"); - } - - check |= b << 8; - - if (check !== (~blockLen & 0xffff) && (blockLen !== 0 || check !== 0)) { - throw new _util.FormatError("Bad uncompressed block length in flate stream"); - } - - this.codeBuf = 0; - this.codeSize = 0; - const bufferLength = this.bufferLength, - end = bufferLength + blockLen; - buffer = this.ensureBuffer(end); - this.bufferLength = end; - - if (blockLen === 0) { - if (str.peekByte() === -1) { - this.eof = true; - } - } else { - const block = str.getBytes(blockLen); - buffer.set(block, bufferLength); - - if (block.length < blockLen) { - this.eof = true; - } - } - - return; - } - - var litCodeTable; - var distCodeTable; - - if (hdr === 1) { - litCodeTable = fixedLitCodeTab; - distCodeTable = fixedDistCodeTab; - } else if (hdr === 2) { - var numLitCodes = this.getBits(5) + 257; - var numDistCodes = this.getBits(5) + 1; - var numCodeLenCodes = this.getBits(4) + 4; - var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length); - var i; - - for (i = 0; i < numCodeLenCodes; ++i) { - codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3); - } - - var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); - len = 0; - i = 0; - var codes = numLitCodes + numDistCodes; - var codeLengths = new Uint8Array(codes); - var bitsLength, bitsOffset, what; - - while (i < codes) { - var code = this.getCode(codeLenCodeTab); - - if (code === 16) { - bitsLength = 2; - bitsOffset = 3; - what = len; - } else if (code === 17) { - bitsLength = 3; - bitsOffset = 3; - what = len = 0; - } else if (code === 18) { - bitsLength = 7; - bitsOffset = 11; - what = len = 0; - } else { - codeLengths[i++] = len = code; - continue; - } - - var repeatLength = this.getBits(bitsLength) + bitsOffset; - - while (repeatLength-- > 0) { - codeLengths[i++] = what; - } - } - - litCodeTable = this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes)); - distCodeTable = this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes)); - } else { - throw new _util.FormatError("Unknown block type in flate stream"); - } - - buffer = this.buffer; - var limit = buffer ? buffer.length : 0; - var pos = this.bufferLength; - - while (true) { - var code1 = this.getCode(litCodeTable); - - if (code1 < 256) { - if (pos + 1 >= limit) { - buffer = this.ensureBuffer(pos + 1); - limit = buffer.length; - } - - buffer[pos++] = code1; - continue; - } - - if (code1 === 256) { - this.bufferLength = pos; - return; - } - - code1 -= 257; - code1 = lengthDecode[code1]; - var code2 = code1 >> 16; - - if (code2 > 0) { - code2 = this.getBits(code2); - } - - len = (code1 & 0xffff) + code2; - code1 = this.getCode(distCodeTable); - code1 = distDecode[code1]; - code2 = code1 >> 16; - - if (code2 > 0) { - code2 = this.getBits(code2); - } - - var dist = (code1 & 0xffff) + code2; - - if (pos + len >= limit) { - buffer = this.ensureBuffer(pos + len); - limit = buffer.length; - } - - for (var k = 0; k < len; ++k, ++pos) { - buffer[pos] = buffer[pos - dist]; - } - } - }; - - return FlateStream; -}(); - -exports.FlateStream = FlateStream; - -var PredictorStream = function PredictorStreamClosure() { - function PredictorStream(str, maybeLength, params) { - if (!(0, _primitives.isDict)(params)) { - return str; - } - - var predictor = this.predictor = params.get("Predictor") || 1; - - if (predictor <= 1) { - return str; - } - - if (predictor !== 2 && (predictor < 10 || predictor > 15)) { - throw new _util.FormatError(`Unsupported predictor: ${predictor}`); - } - - if (predictor === 2) { - this.readBlock = this.readBlockTiff; - } else { - this.readBlock = this.readBlockPng; - } - - this.str = str; - this.dict = str.dict; - var colors = this.colors = params.get("Colors") || 1; - var bits = this.bits = params.get("BitsPerComponent") || 8; - var columns = this.columns = params.get("Columns") || 1; - this.pixBytes = colors * bits + 7 >> 3; - this.rowBytes = columns * colors * bits + 7 >> 3; - DecodeStream.call(this, maybeLength); - return this; - } - - PredictorStream.prototype = Object.create(DecodeStream.prototype); - - PredictorStream.prototype.readBlockTiff = function predictorStreamReadBlockTiff() { - var rowBytes = this.rowBytes; - var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + rowBytes); - var bits = this.bits; - var colors = this.colors; - var rawBytes = this.str.getBytes(rowBytes); - this.eof = !rawBytes.length; - - if (this.eof) { - return; - } - - var inbuf = 0, - outbuf = 0; - var inbits = 0, - outbits = 0; - var pos = bufferLength; - var i; - - if (bits === 1 && colors === 1) { - for (i = 0; i < rowBytes; ++i) { - var c = rawBytes[i] ^ inbuf; - c ^= c >> 1; - c ^= c >> 2; - c ^= c >> 4; - inbuf = (c & 1) << 7; - buffer[pos++] = c; - } - } else if (bits === 8) { - for (i = 0; i < colors; ++i) { - buffer[pos++] = rawBytes[i]; - } - - for (; i < rowBytes; ++i) { - buffer[pos] = buffer[pos - colors] + rawBytes[i]; - pos++; - } - } else if (bits === 16) { - var bytesPerPixel = colors * 2; - - for (i = 0; i < bytesPerPixel; ++i) { - buffer[pos++] = rawBytes[i]; - } - - for (; i < rowBytes; i += 2) { - var sum = ((rawBytes[i] & 0xff) << 8) + (rawBytes[i + 1] & 0xff) + ((buffer[pos - bytesPerPixel] & 0xff) << 8) + (buffer[pos - bytesPerPixel + 1] & 0xff); - buffer[pos++] = sum >> 8 & 0xff; - buffer[pos++] = sum & 0xff; - } - } else { - var compArray = new Uint8Array(colors + 1); - var bitMask = (1 << bits) - 1; - var j = 0, - k = bufferLength; - var columns = this.columns; - - for (i = 0; i < columns; ++i) { - for (var kk = 0; kk < colors; ++kk) { - if (inbits < bits) { - inbuf = inbuf << 8 | rawBytes[j++] & 0xff; - inbits += 8; - } - - compArray[kk] = compArray[kk] + (inbuf >> inbits - bits) & bitMask; - inbits -= bits; - outbuf = outbuf << bits | compArray[kk]; - outbits += bits; - - if (outbits >= 8) { - buffer[k++] = outbuf >> outbits - 8 & 0xff; - outbits -= 8; - } - } - } - - if (outbits > 0) { - buffer[k++] = (outbuf << 8 - outbits) + (inbuf & (1 << 8 - outbits) - 1); - } - } - - this.bufferLength += rowBytes; - }; - - PredictorStream.prototype.readBlockPng = function predictorStreamReadBlockPng() { - var rowBytes = this.rowBytes; - var pixBytes = this.pixBytes; - var predictor = this.str.getByte(); - var rawBytes = this.str.getBytes(rowBytes); - this.eof = !rawBytes.length; - - if (this.eof) { - return; - } - - var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + rowBytes); - var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); - - if (prevRow.length === 0) { - prevRow = new Uint8Array(rowBytes); - } - - var i, - j = bufferLength, - up, - c; - - switch (predictor) { - case 0: - for (i = 0; i < rowBytes; ++i) { - buffer[j++] = rawBytes[i]; - } - - break; - - case 1: - for (i = 0; i < pixBytes; ++i) { - buffer[j++] = rawBytes[i]; - } - - for (; i < rowBytes; ++i) { - buffer[j] = buffer[j - pixBytes] + rawBytes[i] & 0xff; - j++; - } - - break; - - case 2: - for (i = 0; i < rowBytes; ++i) { - buffer[j++] = prevRow[i] + rawBytes[i] & 0xff; - } - - break; - - case 3: - for (i = 0; i < pixBytes; ++i) { - buffer[j++] = (prevRow[i] >> 1) + rawBytes[i]; - } - - for (; i < rowBytes; ++i) { - buffer[j] = (prevRow[i] + buffer[j - pixBytes] >> 1) + rawBytes[i] & 0xff; - j++; - } - - break; - - case 4: - for (i = 0; i < pixBytes; ++i) { - up = prevRow[i]; - c = rawBytes[i]; - buffer[j++] = up + c; - } - - for (; i < rowBytes; ++i) { - up = prevRow[i]; - var upLeft = prevRow[i - pixBytes]; - var left = buffer[j - pixBytes]; - var p = left + up - upLeft; - var pa = p - left; - - if (pa < 0) { - pa = -pa; - } - - var pb = p - up; - - if (pb < 0) { - pb = -pb; - } - - var pc = p - upLeft; - - if (pc < 0) { - pc = -pc; - } - - c = rawBytes[i]; - - if (pa <= pb && pa <= pc) { - buffer[j++] = left + c; - } else if (pb <= pc) { - buffer[j++] = up + c; - } else { - buffer[j++] = upLeft + c; - } - } - - break; - - default: - throw new _util.FormatError(`Unsupported predictor: ${predictor}`); - } - - this.bufferLength += rowBytes; - }; - - return PredictorStream; -}(); - -exports.PredictorStream = PredictorStream; - -var DecryptStream = function DecryptStreamClosure() { - function DecryptStream(str, maybeLength, decrypt) { - this.str = str; - this.dict = str.dict; - this.decrypt = decrypt; - this.nextChunk = null; - this.initialized = false; - DecodeStream.call(this, maybeLength); - } - - var chunkSize = 512; - DecryptStream.prototype = Object.create(DecodeStream.prototype); - - DecryptStream.prototype.readBlock = function DecryptStream_readBlock() { - var chunk; - - if (this.initialized) { - chunk = this.nextChunk; - } else { - chunk = this.str.getBytes(chunkSize); - this.initialized = true; - } - - if (!chunk || chunk.length === 0) { - this.eof = true; - return; - } - - this.nextChunk = this.str.getBytes(chunkSize); - var hasMoreData = this.nextChunk && this.nextChunk.length > 0; - var decrypt = this.decrypt; - chunk = decrypt(chunk, !hasMoreData); - var bufferLength = this.bufferLength; - var i, - n = chunk.length; - var buffer = this.ensureBuffer(bufferLength + n); - - for (i = 0; i < n; i++) { - buffer[bufferLength++] = chunk[i]; - } - - this.bufferLength = bufferLength; - }; - - return DecryptStream; -}(); - -exports.DecryptStream = DecryptStream; - -var Ascii85Stream = function Ascii85StreamClosure() { - function Ascii85Stream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - this.input = new Uint8Array(5); - - if (maybeLength) { - maybeLength = 0.8 * maybeLength; - } - - DecodeStream.call(this, maybeLength); - } - - Ascii85Stream.prototype = Object.create(DecodeStream.prototype); - - Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() { - var TILDA_CHAR = 0x7e; - var Z_LOWER_CHAR = 0x7a; - var EOF = -1; - var str = this.str; - var c = str.getByte(); - - while ((0, _core_utils.isWhiteSpace)(c)) { - c = str.getByte(); - } - - if (c === EOF || c === TILDA_CHAR) { - this.eof = true; - return; - } - - var bufferLength = this.bufferLength, - buffer; - var i; - - if (c === Z_LOWER_CHAR) { - buffer = this.ensureBuffer(bufferLength + 4); - - for (i = 0; i < 4; ++i) { - buffer[bufferLength + i] = 0; - } - - this.bufferLength += 4; - } else { - var input = this.input; - input[0] = c; - - for (i = 1; i < 5; ++i) { - c = str.getByte(); - - while ((0, _core_utils.isWhiteSpace)(c)) { - c = str.getByte(); - } - - input[i] = c; - - if (c === EOF || c === TILDA_CHAR) { - break; - } - } - - buffer = this.ensureBuffer(bufferLength + i - 1); - this.bufferLength += i - 1; - - if (i < 5) { - for (; i < 5; ++i) { - input[i] = 0x21 + 84; - } - - this.eof = true; - } - - var t = 0; - - for (i = 0; i < 5; ++i) { - t = t * 85 + (input[i] - 0x21); - } - - for (i = 3; i >= 0; --i) { - buffer[bufferLength + i] = t & 0xff; - t >>= 8; - } - } - }; - - return Ascii85Stream; -}(); - -exports.Ascii85Stream = Ascii85Stream; - -var AsciiHexStream = function AsciiHexStreamClosure() { - function AsciiHexStream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - this.firstDigit = -1; - - if (maybeLength) { - maybeLength = 0.5 * maybeLength; - } - - DecodeStream.call(this, maybeLength); - } - - AsciiHexStream.prototype = Object.create(DecodeStream.prototype); - - AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() { - var UPSTREAM_BLOCK_SIZE = 8000; - var bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE); - - if (!bytes.length) { - this.eof = true; - return; - } - - var maxDecodeLength = bytes.length + 1 >> 1; - var buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength); - var bufferLength = this.bufferLength; - var firstDigit = this.firstDigit; - - for (var i = 0, ii = bytes.length; i < ii; i++) { - var ch = bytes[i], - digit; - - if (ch >= 0x30 && ch <= 0x39) { - digit = ch & 0x0f; - } else if (ch >= 0x41 && ch <= 0x46 || ch >= 0x61 && ch <= 0x66) { - digit = (ch & 0x0f) + 9; - } else if (ch === 0x3e) { - this.eof = true; - break; - } else { - continue; - } - - if (firstDigit < 0) { - firstDigit = digit; - } else { - buffer[bufferLength++] = firstDigit << 4 | digit; - firstDigit = -1; - } - } - - if (firstDigit >= 0 && this.eof) { - buffer[bufferLength++] = firstDigit << 4; - firstDigit = -1; - } - - this.firstDigit = firstDigit; - this.bufferLength = bufferLength; - }; - - return AsciiHexStream; -}(); - -exports.AsciiHexStream = AsciiHexStream; - -var RunLengthStream = function RunLengthStreamClosure() { - function RunLengthStream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - DecodeStream.call(this, maybeLength); - } - - RunLengthStream.prototype = Object.create(DecodeStream.prototype); - - RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() { - var repeatHeader = this.str.getBytes(2); - - if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] === 128) { - this.eof = true; - return; - } - - var buffer; - var bufferLength = this.bufferLength; - var n = repeatHeader[0]; - - if (n < 128) { - buffer = this.ensureBuffer(bufferLength + n + 1); - buffer[bufferLength++] = repeatHeader[1]; - - if (n > 0) { - var source = this.str.getBytes(n); - buffer.set(source, bufferLength); - bufferLength += n; - } - } else { - n = 257 - n; - var b = repeatHeader[1]; - buffer = this.ensureBuffer(bufferLength + n + 1); - - for (var i = 0; i < n; i++) { - buffer[bufferLength++] = b; - } - } - - this.bufferLength = bufferLength; - }; - - return RunLengthStream; -}(); - -exports.RunLengthStream = RunLengthStream; - -var LZWStream = function LZWStreamClosure() { - function LZWStream(str, maybeLength, earlyChange) { - this.str = str; - this.dict = str.dict; - this.cachedData = 0; - this.bitsCached = 0; - var maxLzwDictionarySize = 4096; - var lzwState = { - earlyChange, - codeLength: 9, - nextCode: 258, - dictionaryValues: new Uint8Array(maxLzwDictionarySize), - dictionaryLengths: new Uint16Array(maxLzwDictionarySize), - dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize), - currentSequence: new Uint8Array(maxLzwDictionarySize), - currentSequenceLength: 0 + return { + opList: new _operator_list.OperatorList(), + separateForm: false, + separateCanvas: false }; - - for (var i = 0; i < 256; ++i) { - lzwState.dictionaryValues[i] = i; - lzwState.dictionaryLengths[i] = 1; - } - - this.lzwState = lzwState; - DecodeStream.call(this, maybeLength); } - LZWStream.prototype = Object.create(DecodeStream.prototype); + async save(evaluator, task, annotationStorage) { + if (this.data.checkBox) { + return this._saveCheckbox(evaluator, task, annotationStorage); + } - LZWStream.prototype.readBits = function LZWStream_readBits(n) { - var bitsCached = this.bitsCached; - var cachedData = this.cachedData; + if (this.data.radioButton) { + return this._saveRadioButton(evaluator, task, annotationStorage); + } - while (bitsCached < n) { - var c = this.str.getByte(); + return null; + } - if (c === -1) { - this.eof = true; + async _saveCheckbox(evaluator, task, annotationStorage) { + if (!annotationStorage) { + return null; + } + + const storageEntry = annotationStorage.get(this.data.id); + let rotation = storageEntry && storageEntry.rotation; + let value = storageEntry && storageEntry.value; + + if (rotation === undefined) { + if (value === undefined) { return null; } - cachedData = cachedData << 8 | c; - bitsCached += 8; + const defaultValue = this.data.fieldValue === this.data.exportValue; + + if (defaultValue === value) { + return null; + } } - this.bitsCached = bitsCached -= n; - this.cachedData = cachedData; - this.lastCode = null; - return cachedData >>> bitsCached & (1 << n) - 1; - }; + const dict = evaluator.xref.fetchIfRef(this.ref); - LZWStream.prototype.readBlock = function LZWStream_readBlock() { - var blockSize = 512; - var estimatedDecodedSize = blockSize * 2, - decodedSizeDelta = blockSize; - var i, j, q; - var lzwState = this.lzwState; + if (!(dict instanceof _primitives.Dict)) { + return null; + } - if (!lzwState) { + if (rotation === undefined) { + rotation = this.rotation; + } + + if (value === undefined) { + value = this.data.fieldValue === this.data.exportValue; + } + + const xfa = { + path: (0, _util.stringToPDFString)(dict.get("T") || ""), + value: value ? this.data.exportValue : "" + }; + + const name = _primitives.Name.get(value ? this.data.exportValue : "Off"); + + dict.set("V", name); + dict.set("AS", name); + dict.set("M", `D:${(0, _util.getModificationDate)()}`); + + const maybeMK = this._getMKDict(rotation); + + if (maybeMK) { + dict.set("MK", maybeMK); + } + + const encrypt = evaluator.xref.encrypt; + let originalTransform = null; + + if (encrypt) { + originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen); + } + + const buffer = [`${this.ref.num} ${this.ref.gen} obj\n`]; + (0, _writer.writeDict)(dict, buffer, originalTransform); + buffer.push("\nendobj\n"); + return [{ + ref: this.ref, + data: buffer.join(""), + xfa + }]; + } + + async _saveRadioButton(evaluator, task, annotationStorage) { + if (!annotationStorage) { + return null; + } + + const storageEntry = annotationStorage.get(this.data.id); + let rotation = storageEntry && storageEntry.rotation; + let value = storageEntry && storageEntry.value; + + if (rotation === undefined) { + if (value === undefined) { + return null; + } + + const defaultValue = this.data.fieldValue === this.data.buttonValue; + + if (defaultValue === value) { + return null; + } + } + + const dict = evaluator.xref.fetchIfRef(this.ref); + + if (!(dict instanceof _primitives.Dict)) { + return null; + } + + if (value === undefined) { + value = this.data.fieldValue === this.data.buttonValue; + } + + if (rotation === undefined) { + rotation = this.rotation; + } + + const xfa = { + path: (0, _util.stringToPDFString)(dict.get("T") || ""), + value: value ? this.data.buttonValue : "" + }; + + const name = _primitives.Name.get(value ? this.data.buttonValue : "Off"); + + let parentBuffer = null; + const encrypt = evaluator.xref.encrypt; + + if (value) { + if (this.parent instanceof _primitives.Ref) { + const parent = evaluator.xref.fetch(this.parent); + let parentTransform = null; + + if (encrypt) { + parentTransform = encrypt.createCipherTransform(this.parent.num, this.parent.gen); + } + + parent.set("V", name); + parentBuffer = [`${this.parent.num} ${this.parent.gen} obj\n`]; + (0, _writer.writeDict)(parent, parentBuffer, parentTransform); + parentBuffer.push("\nendobj\n"); + } else if (this.parent instanceof _primitives.Dict) { + this.parent.set("V", name); + } + } + + dict.set("AS", name); + dict.set("M", `D:${(0, _util.getModificationDate)()}`); + + const maybeMK = this._getMKDict(rotation); + + if (maybeMK) { + dict.set("MK", maybeMK); + } + + let originalTransform = null; + + if (encrypt) { + originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen); + } + + const buffer = [`${this.ref.num} ${this.ref.gen} obj\n`]; + (0, _writer.writeDict)(dict, buffer, originalTransform); + buffer.push("\nendobj\n"); + const newRefs = [{ + ref: this.ref, + data: buffer.join(""), + xfa + }]; + + if (parentBuffer !== null) { + newRefs.push({ + ref: this.parent, + data: parentBuffer.join(""), + xfa: null + }); + } + + return newRefs; + } + + _getDefaultCheckedAppearance(params, type) { + const width = this.data.rect[2] - this.data.rect[0]; + const height = this.data.rect[3] - this.data.rect[1]; + const bbox = [0, 0, width, height]; + const FONT_RATIO = 0.8; + const fontSize = Math.min(width, height) * FONT_RATIO; + let metrics, char; + + if (type === "check") { + metrics = { + width: 0.755 * fontSize, + height: 0.705 * fontSize + }; + char = "\x33"; + } else if (type === "disc") { + metrics = { + width: 0.791 * fontSize, + height: 0.705 * fontSize + }; + char = "\x6C"; + } else { + (0, _util.unreachable)(`_getDefaultCheckedAppearance - unsupported type: ${type}`); + } + + const xShift = (0, _core_utils.numberToString)((width - metrics.width) / 2); + const yShift = (0, _core_utils.numberToString)((height - metrics.height) / 2); + const appearance = `q BT /PdfJsZaDb ${fontSize} Tf 0 g ${xShift} ${yShift} Td (${char}) Tj ET Q`; + const appearanceStreamDict = new _primitives.Dict(params.xref); + appearanceStreamDict.set("FormType", 1); + appearanceStreamDict.set("Subtype", _primitives.Name.get("Form")); + appearanceStreamDict.set("Type", _primitives.Name.get("XObject")); + appearanceStreamDict.set("BBox", bbox); + appearanceStreamDict.set("Matrix", [1, 0, 0, 1, 0, 0]); + appearanceStreamDict.set("Length", appearance.length); + const resources = new _primitives.Dict(params.xref); + const font = new _primitives.Dict(params.xref); + font.set("PdfJsZaDb", this.fallbackFontDict); + resources.set("Font", font); + appearanceStreamDict.set("Resources", resources); + this.checkedAppearance = new _stream.StringStream(appearance); + this.checkedAppearance.dict = appearanceStreamDict; + + this._streams.push(this.checkedAppearance); + } + + _processCheckBox(params) { + const customAppearance = params.dict.get("AP"); + + if (!(customAppearance instanceof _primitives.Dict)) { return; } - var earlyChange = lzwState.earlyChange; - var nextCode = lzwState.nextCode; - var dictionaryValues = lzwState.dictionaryValues; - var dictionaryLengths = lzwState.dictionaryLengths; - var dictionaryPrevCodes = lzwState.dictionaryPrevCodes; - var codeLength = lzwState.codeLength; - var prevCode = lzwState.prevCode; - var currentSequence = lzwState.currentSequence; - var currentSequenceLength = lzwState.currentSequenceLength; - var decodedLength = 0; - var currentBufferLength = this.bufferLength; - var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); + const normalAppearance = customAppearance.get("N"); - for (i = 0; i < blockSize; i++) { - var code = this.readBits(codeLength); - var hasPrev = currentSequenceLength > 0; + if (!(normalAppearance instanceof _primitives.Dict)) { + return; + } - if (code < 256) { - currentSequence[0] = code; - currentSequenceLength = 1; - } else if (code >= 258) { - if (code < nextCode) { - currentSequenceLength = dictionaryLengths[code]; + const asValue = this._decodeFormValue(params.dict.get("AS")); - for (j = currentSequenceLength - 1, q = code; j >= 0; j--) { - currentSequence[j] = dictionaryValues[q]; - q = dictionaryPrevCodes[q]; - } - } else { - currentSequence[currentSequenceLength++] = currentSequence[0]; - } - } else if (code === 256) { - codeLength = 9; - nextCode = 258; - currentSequenceLength = 0; - continue; + if (typeof asValue === "string") { + this.data.fieldValue = asValue; + } + + const yes = this.data.fieldValue !== null && this.data.fieldValue !== "Off" ? this.data.fieldValue : "Yes"; + const exportValues = normalAppearance.getKeys(); + + if (exportValues.length === 0) { + exportValues.push("Off", yes); + } else if (exportValues.length === 1) { + if (exportValues[0] === "Off") { + exportValues.push(yes); } else { - this.eof = true; - delete this.lzwState; - break; + exportValues.unshift("Off"); } + } else if (exportValues.includes(yes)) { + exportValues.length = 0; + exportValues.push("Off", yes); + } else { + const otherYes = exportValues.find(v => v !== "Off"); + exportValues.length = 0; + exportValues.push("Off", otherYes); + } - if (hasPrev) { - dictionaryPrevCodes[nextCode] = prevCode; - dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1; - dictionaryValues[nextCode] = currentSequence[0]; - nextCode++; - codeLength = nextCode + earlyChange & nextCode + earlyChange - 1 ? codeLength : Math.min(Math.log(nextCode + earlyChange) / 0.6931471805599453 + 1, 12) | 0; - } + if (!exportValues.includes(this.data.fieldValue)) { + this.data.fieldValue = "Off"; + } - prevCode = code; - decodedLength += currentSequenceLength; + this.data.exportValue = exportValues[1]; + this.checkedAppearance = normalAppearance.get(this.data.exportValue) || null; + this.uncheckedAppearance = normalAppearance.get("Off") || null; - if (estimatedDecodedSize < decodedLength) { - do { - estimatedDecodedSize += decodedSizeDelta; - } while (estimatedDecodedSize < decodedLength); + if (this.checkedAppearance) { + this._streams.push(this.checkedAppearance); + } else { + this._getDefaultCheckedAppearance(params, "check"); + } - buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); - } + if (this.uncheckedAppearance) { + this._streams.push(this.uncheckedAppearance); + } - for (j = 0; j < currentSequenceLength; j++) { - buffer[currentBufferLength++] = currentSequence[j]; + this._fallbackFontDict = this.fallbackFontDict; + } + + _processRadioButton(params) { + this.data.fieldValue = this.data.buttonValue = null; + const fieldParent = params.dict.get("Parent"); + + if (fieldParent instanceof _primitives.Dict) { + this.parent = params.dict.getRaw("Parent"); + const fieldParentValue = fieldParent.get("V"); + + if (fieldParentValue instanceof _primitives.Name) { + this.data.fieldValue = this._decodeFormValue(fieldParentValue); } } - lzwState.nextCode = nextCode; - lzwState.codeLength = codeLength; - lzwState.prevCode = prevCode; - lzwState.currentSequenceLength = currentSequenceLength; - this.bufferLength = currentBufferLength; - }; + const appearanceStates = params.dict.get("AP"); - return LZWStream; -}(); + if (!(appearanceStates instanceof _primitives.Dict)) { + return; + } -exports.LZWStream = LZWStream; + const normalAppearance = appearanceStates.get("N"); -var NullStream = function NullStreamClosure() { - function NullStream() { - Stream.call(this, new Uint8Array(0)); + if (!(normalAppearance instanceof _primitives.Dict)) { + return; + } + + for (const key of normalAppearance.getKeys()) { + if (key !== "Off") { + this.data.buttonValue = this._decodeFormValue(key); + break; + } + } + + this.checkedAppearance = normalAppearance.get(this.data.buttonValue) || null; + this.uncheckedAppearance = normalAppearance.get("Off") || null; + + if (this.checkedAppearance) { + this._streams.push(this.checkedAppearance); + } else { + this._getDefaultCheckedAppearance(params, "disc"); + } + + if (this.uncheckedAppearance) { + this._streams.push(this.uncheckedAppearance); + } + + this._fallbackFontDict = this.fallbackFontDict; } - NullStream.prototype = Stream.prototype; - return NullStream; -}(); + _processPushButton(params) { + if (!params.dict.has("A") && !params.dict.has("AA") && !this.data.alternativeText) { + (0, _util.warn)("Push buttons without action dictionaries are not supported"); + return; + } -exports.NullStream = NullStream; + this.data.isTooltipOnly = !params.dict.has("A") && !params.dict.has("AA"); + + _catalog.Catalog.parseDestDictionary({ + destDict: params.dict, + resultObj: this.data, + docBaseUrl: params.pdfManager.docBaseUrl + }); + } + + getFieldObject() { + let type = "button"; + let exportValues; + + if (this.data.checkBox) { + type = "checkbox"; + exportValues = this.data.exportValue; + } else if (this.data.radioButton) { + type = "radiobutton"; + exportValues = this.data.buttonValue; + } + + return { + id: this.data.id, + value: this.data.fieldValue || "Off", + defaultValue: this.data.defaultFieldValue, + exportValues, + editable: !this.data.readOnly, + name: this.data.fieldName, + rect: this.data.rect, + hidden: this.data.hidden, + actions: this.data.actions, + page: this.data.pageIndex, + strokeColor: this.data.borderColor, + fillColor: this.data.backgroundColor, + rotation: this.rotation, + type + }; + } + + get fallbackFontDict() { + const dict = new _primitives.Dict(); + dict.set("BaseFont", _primitives.Name.get("ZapfDingbats")); + dict.set("Type", _primitives.Name.get("FallbackType")); + dict.set("Subtype", _primitives.Name.get("FallbackType")); + dict.set("Encoding", _primitives.Name.get("ZapfDingbatsEncoding")); + return (0, _util.shadow)(this, "fallbackFontDict", dict); + } + +} + +class ChoiceWidgetAnnotation extends WidgetAnnotation { + constructor(params) { + super(params); + this.data.options = []; + const options = (0, _core_utils.getInheritableProperty)({ + dict: params.dict, + key: "Opt" + }); + + if (Array.isArray(options)) { + const xref = params.xref; + + for (let i = 0, ii = options.length; i < ii; i++) { + const option = xref.fetchIfRef(options[i]); + const isOptionArray = Array.isArray(option); + this.data.options[i] = { + exportValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[0]) : option), + displayValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[1]) : option) + }; + } + } + + if (typeof this.data.fieldValue === "string") { + this.data.fieldValue = [this.data.fieldValue]; + } else if (!this.data.fieldValue) { + this.data.fieldValue = []; + } + + this.data.combo = this.hasFieldFlag(_util.AnnotationFieldFlag.COMBO); + this.data.multiSelect = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTISELECT); + this._hasText = true; + } + + getFieldObject() { + const type = this.data.combo ? "combobox" : "listbox"; + const value = this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : null; + return { + id: this.data.id, + value, + defaultValue: this.data.defaultFieldValue, + editable: !this.data.readOnly, + name: this.data.fieldName, + rect: this.data.rect, + numItems: this.data.fieldValue.length, + multipleSelection: this.data.multiSelect, + hidden: this.data.hidden, + actions: this.data.actions, + items: this.data.options, + page: this.data.pageIndex, + strokeColor: this.data.borderColor, + fillColor: this.data.backgroundColor, + rotation: this.rotation, + type + }; + } + + async _getAppearance(evaluator, task, annotationStorage) { + if (this.data.combo) { + return super._getAppearance(evaluator, task, annotationStorage); + } + + if (!annotationStorage) { + return null; + } + + const storageEntry = annotationStorage.get(this.data.id); + + if (!storageEntry) { + return null; + } + + const rotation = storageEntry.rotation; + let exportedValue = storageEntry.value; + + if (rotation === undefined && exportedValue === undefined) { + return null; + } + + if (exportedValue === undefined) { + exportedValue = this.data.fieldValue; + } else if (!Array.isArray(exportedValue)) { + exportedValue = [exportedValue]; + } + + const defaultPadding = 2; + const hPadding = defaultPadding; + let totalHeight = this.data.rect[3] - this.data.rect[1]; + let totalWidth = this.data.rect[2] - this.data.rect[0]; + + if (rotation === 90 || rotation === 270) { + [totalWidth, totalHeight] = [totalHeight, totalWidth]; + } + + const lineCount = this.data.options.length; + const valueIndices = []; + + for (let i = 0; i < lineCount; i++) { + const { + exportValue + } = this.data.options[i]; + + if (exportedValue.includes(exportValue)) { + valueIndices.push(i); + } + } + + if (!this._defaultAppearance) { + this.data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(this._defaultAppearance = "/Helvetica 0 Tf 0 g"); + } + + const font = await WidgetAnnotation._getFontData(evaluator, task, this.data.defaultAppearanceData, this._fieldResources.mergedResources); + let defaultAppearance; + let { + fontSize + } = this.data.defaultAppearanceData; + + if (!fontSize) { + const lineHeight = (totalHeight - defaultPadding) / lineCount; + let lineWidth = -1; + let value; + + for (const { + displayValue + } of this.data.options) { + const width = this._getTextWidth(displayValue, font); + + if (width > lineWidth) { + lineWidth = width; + value = displayValue; + } + } + + [defaultAppearance, fontSize] = this._computeFontSize(lineHeight, totalWidth - 2 * hPadding, value, font, -1); + } else { + defaultAppearance = this._defaultAppearance; + } + + const lineHeight = fontSize * _util.LINE_FACTOR; + const vPadding = (lineHeight - fontSize) / 2; + const numberOfVisibleLines = Math.floor(totalHeight / lineHeight); + let firstIndex; + + if (valueIndices.length === 1) { + const valuePosition = valueIndices[0]; + const indexInPage = valuePosition % numberOfVisibleLines; + firstIndex = valuePosition - indexInPage; + } else { + firstIndex = valueIndices.length ? valueIndices[0] : 0; + } + + const end = Math.min(firstIndex + numberOfVisibleLines + 1, lineCount); + const buf = ["/Tx BMC q", `1 1 ${totalWidth} ${totalHeight} re W n`]; + + if (valueIndices.length) { + buf.push("0.600006 0.756866 0.854904 rg"); + + for (const index of valueIndices) { + if (firstIndex <= index && index < end) { + buf.push(`1 ${totalHeight - (index - firstIndex + 1) * lineHeight} ${totalWidth} ${lineHeight} re f`); + } + } + } + + buf.push("BT", defaultAppearance, `1 0 0 1 0 ${totalHeight} Tm`); + + for (let i = firstIndex; i < end; i++) { + const { + displayValue + } = this.data.options[i]; + const hpadding = i === firstIndex ? hPadding : 0; + const vpadding = i === firstIndex ? vPadding : 0; + buf.push(this._renderText(displayValue, font, fontSize, totalWidth, 0, hpadding, -lineHeight + vpadding)); + } + + buf.push("ET Q EMC"); + return buf.join("\n"); + } + +} + +class SignatureWidgetAnnotation extends WidgetAnnotation { + constructor(params) { + super(params); + this.data.fieldValue = null; + } + + getFieldObject() { + return { + id: this.data.id, + value: null, + page: this.data.pageIndex, + type: "signature" + }; + } + +} + +class TextAnnotation extends MarkupAnnotation { + constructor(parameters) { + const DEFAULT_ICON_SIZE = 22; + super(parameters); + const dict = parameters.dict; + this.data.annotationType = _util.AnnotationType.TEXT; + + if (this.data.hasAppearance) { + this.data.name = "NoIcon"; + } else { + this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE; + this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE; + this.data.name = dict.has("Name") ? dict.get("Name").name : "Note"; + } + + if (dict.has("State")) { + this.data.state = dict.get("State") || null; + this.data.stateModel = dict.get("StateModel") || null; + } else { + this.data.state = null; + this.data.stateModel = null; + } + } + +} + +class LinkAnnotation extends Annotation { + constructor(params) { + super(params); + this.data.annotationType = _util.AnnotationType.LINK; + const quadPoints = getQuadPoints(params.dict, this.rectangle); + + if (quadPoints) { + this.data.quadPoints = quadPoints; + } + + this.data.borderColor = this.data.borderColor || this.data.color; + + _catalog.Catalog.parseDestDictionary({ + destDict: params.dict, + resultObj: this.data, + docBaseUrl: params.pdfManager.docBaseUrl + }); + } + +} + +class PopupAnnotation extends Annotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.POPUP; + let parentItem = parameters.dict.get("Parent"); + + if (!parentItem) { + (0, _util.warn)("Popup annotation has a missing or invalid parent annotation."); + return; + } + + const parentSubtype = parentItem.get("Subtype"); + this.data.parentType = parentSubtype instanceof _primitives.Name ? parentSubtype.name : null; + const rawParent = parameters.dict.getRaw("Parent"); + this.data.parentId = rawParent instanceof _primitives.Ref ? rawParent.toString() : null; + const parentRect = parentItem.getArray("Rect"); + + if (Array.isArray(parentRect) && parentRect.length === 4) { + this.data.parentRect = _util.Util.normalizeRect(parentRect); + } else { + this.data.parentRect = [0, 0, 0, 0]; + } + + const rt = parentItem.get("RT"); + + if ((0, _primitives.isName)(rt, _util.AnnotationReplyType.GROUP)) { + parentItem = parentItem.get("IRT"); + } + + if (!parentItem.has("M")) { + this.data.modificationDate = null; + } else { + this.setModificationDate(parentItem.get("M")); + this.data.modificationDate = this.modificationDate; + } + + if (!parentItem.has("C")) { + this.data.color = null; + } else { + this.setColor(parentItem.getArray("C")); + this.data.color = this.color; + } + + if (!this.viewable) { + const parentFlags = parentItem.get("F"); + + if (this._isViewable(parentFlags)) { + this.setFlags(parentFlags); + } + } + + this.setTitle(parentItem.get("T")); + this.data.titleObj = this._title; + this.setContents(parentItem.get("Contents")); + this.data.contentsObj = this._contents; + + if (parentItem.has("RC")) { + this.data.richText = _factory.XFAFactory.getRichTextAsHtml(parentItem.get("RC")); + } + } + +} + +exports.PopupAnnotation = PopupAnnotation; + +class FreeTextAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.FREETEXT; + } + + get hasTextContent() { + return !!this.appearance; + } + + static createNewDict(annotation, xref, { + apRef, + ap + }) { + const { + color, + fontSize, + rect, + rotation, + user, + value + } = annotation; + const freetext = new _primitives.Dict(xref); + freetext.set("Type", _primitives.Name.get("Annot")); + freetext.set("Subtype", _primitives.Name.get("FreeText")); + freetext.set("CreationDate", `D:${(0, _util.getModificationDate)()}`); + freetext.set("Rect", rect); + const da = `/Helv ${fontSize} Tf ${(0, _default_appearance.getPdfColor)(color, true)}`; + freetext.set("DA", da); + freetext.set("Contents", value); + freetext.set("F", 4); + freetext.set("Border", [0, 0, 0]); + freetext.set("Rotate", rotation); + + if (user) { + freetext.set("T", (0, _util.stringToUTF8String)(user)); + } + + const n = new _primitives.Dict(xref); + freetext.set("AP", n); + + if (apRef) { + n.set("N", apRef); + } else { + n.set("N", ap); + } + + return freetext; + } + + static async createNewAppearanceStream(annotation, xref, params) { + const { + baseFontRef, + evaluator, + task + } = params; + const { + color, + fontSize, + rect, + rotation, + value + } = annotation; + const resources = new _primitives.Dict(xref); + const font = new _primitives.Dict(xref); + + if (baseFontRef) { + font.set("Helv", baseFontRef); + } else { + const baseFont = new _primitives.Dict(xref); + baseFont.set("BaseFont", _primitives.Name.get("Helvetica")); + baseFont.set("Type", _primitives.Name.get("Font")); + baseFont.set("Subtype", _primitives.Name.get("Type1")); + baseFont.set("Encoding", _primitives.Name.get("WinAnsiEncoding")); + font.set("Helv", baseFont); + } + + resources.set("Font", font); + const helv = await WidgetAnnotation._getFontData(evaluator, task, { + fontName: "Helvetica", + fontSize + }, resources); + const [x1, y1, x2, y2] = rect; + let w = x2 - x1; + let h = y2 - y1; + + if (rotation % 180 !== 0) { + [w, h] = [h, w]; + } + + const lines = value.split("\n"); + const scale = fontSize / 1000; + let totalWidth = -Infinity; + const encodedLines = []; + + for (let line of lines) { + line = helv.encodeString(line).join(""); + encodedLines.push(line); + let lineWidth = 0; + const glyphs = helv.charsToGlyphs(line); + + for (const glyph of glyphs) { + lineWidth += glyph.width * scale; + } + + totalWidth = Math.max(totalWidth, lineWidth); + } + + let hscale = 1; + + if (totalWidth > w) { + hscale = w / totalWidth; + } + + let vscale = 1; + const lineHeight = _util.LINE_FACTOR * fontSize; + const lineDescent = _util.LINE_DESCENT_FACTOR * fontSize; + const totalHeight = lineHeight * lines.length; + + if (totalHeight > h) { + vscale = h / totalHeight; + } + + const fscale = Math.min(hscale, vscale); + const newFontSize = fontSize * fscale; + const buffer = ["q", `0 0 ${(0, _core_utils.numberToString)(w)} ${(0, _core_utils.numberToString)(h)} re W n`, `BT`, `1 0 0 1 0 ${(0, _core_utils.numberToString)(h + lineDescent)} Tm 0 Tc ${(0, _default_appearance.getPdfColor)(color, true)}`, `/Helv ${(0, _core_utils.numberToString)(newFontSize)} Tf`]; + const vShift = (0, _core_utils.numberToString)(lineHeight); + + for (const line of encodedLines) { + buffer.push(`0 -${vShift} Td (${(0, _util.escapeString)(line)}) Tj`); + } + + buffer.push("ET", "Q"); + const appearance = buffer.join("\n"); + const appearanceStreamDict = new _primitives.Dict(xref); + appearanceStreamDict.set("FormType", 1); + appearanceStreamDict.set("Subtype", _primitives.Name.get("Form")); + appearanceStreamDict.set("Type", _primitives.Name.get("XObject")); + appearanceStreamDict.set("BBox", [0, 0, w, h]); + appearanceStreamDict.set("Length", appearance.length); + appearanceStreamDict.set("Resources", resources); + + if (rotation) { + const matrix = WidgetAnnotation._getRotationMatrix(rotation, w, h); + + appearanceStreamDict.set("Matrix", matrix); + } + + const ap = new _stream.StringStream(appearance); + ap.dict = appearanceStreamDict; + return ap; + } + +} + +class LineAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + const { + dict + } = parameters; + this.data.annotationType = _util.AnnotationType.LINE; + const lineCoordinates = dict.getArray("L"); + this.data.lineCoordinates = _util.Util.normalizeRect(lineCoordinates); + this.setLineEndings(dict.getArray("LE")); + this.data.lineEndings = this.lineEndings; + + if (!this.appearance) { + const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0]; + const strokeAlpha = dict.get("CA"); + let fillColor = null, + interiorColor = dict.getArray("IC"); + + if (interiorColor) { + interiorColor = getRgbColor(interiorColor, null); + fillColor = interiorColor ? Array.from(interiorColor).map(c => c / 255) : null; + } + + const fillAlpha = fillColor ? strokeAlpha : null; + const borderWidth = this.borderStyle.width || 1, + borderAdjust = 2 * borderWidth; + const bbox = [this.data.lineCoordinates[0] - borderAdjust, this.data.lineCoordinates[1] - borderAdjust, this.data.lineCoordinates[2] + borderAdjust, this.data.lineCoordinates[3] + borderAdjust]; + + if (!_util.Util.intersect(this.rectangle, bbox)) { + this.rectangle = bbox; + } + + this._setDefaultAppearance({ + xref: parameters.xref, + extra: `${borderWidth} w`, + strokeColor, + fillColor, + strokeAlpha, + fillAlpha, + pointsCallback: (buffer, points) => { + buffer.push(`${lineCoordinates[0]} ${lineCoordinates[1]} m`, `${lineCoordinates[2]} ${lineCoordinates[3]} l`, "S"); + return [points[0].x - borderWidth, points[1].x + borderWidth, points[3].y - borderWidth, points[1].y + borderWidth]; + } + }); + } + } + +} + +class SquareAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.SQUARE; + + if (!this.appearance) { + const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0]; + const strokeAlpha = parameters.dict.get("CA"); + let fillColor = null, + interiorColor = parameters.dict.getArray("IC"); + + if (interiorColor) { + interiorColor = getRgbColor(interiorColor, null); + fillColor = interiorColor ? Array.from(interiorColor).map(c => c / 255) : null; + } + + const fillAlpha = fillColor ? strokeAlpha : null; + + if (this.borderStyle.width === 0 && !fillColor) { + return; + } + + this._setDefaultAppearance({ + xref: parameters.xref, + extra: `${this.borderStyle.width} w`, + strokeColor, + fillColor, + strokeAlpha, + fillAlpha, + pointsCallback: (buffer, points) => { + const x = points[2].x + this.borderStyle.width / 2; + const y = points[2].y + this.borderStyle.width / 2; + const width = points[3].x - points[2].x - this.borderStyle.width; + const height = points[1].y - points[3].y - this.borderStyle.width; + buffer.push(`${x} ${y} ${width} ${height} re`); + + if (fillColor) { + buffer.push("B"); + } else { + buffer.push("S"); + } + + return [points[0].x, points[1].x, points[3].y, points[1].y]; + } + }); + } + } + +} + +class CircleAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.CIRCLE; + + if (!this.appearance) { + const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0]; + const strokeAlpha = parameters.dict.get("CA"); + let fillColor = null; + let interiorColor = parameters.dict.getArray("IC"); + + if (interiorColor) { + interiorColor = getRgbColor(interiorColor, null); + fillColor = interiorColor ? Array.from(interiorColor).map(c => c / 255) : null; + } + + const fillAlpha = fillColor ? strokeAlpha : null; + + if (this.borderStyle.width === 0 && !fillColor) { + return; + } + + const controlPointsDistance = 4 / 3 * Math.tan(Math.PI / (2 * 4)); + + this._setDefaultAppearance({ + xref: parameters.xref, + extra: `${this.borderStyle.width} w`, + strokeColor, + fillColor, + strokeAlpha, + fillAlpha, + pointsCallback: (buffer, points) => { + const x0 = points[0].x + this.borderStyle.width / 2; + const y0 = points[0].y - this.borderStyle.width / 2; + const x1 = points[3].x - this.borderStyle.width / 2; + const y1 = points[3].y + this.borderStyle.width / 2; + const xMid = x0 + (x1 - x0) / 2; + const yMid = y0 + (y1 - y0) / 2; + const xOffset = (x1 - x0) / 2 * controlPointsDistance; + const yOffset = (y1 - y0) / 2 * controlPointsDistance; + buffer.push(`${xMid} ${y1} m`, `${xMid + xOffset} ${y1} ${x1} ${yMid + yOffset} ${x1} ${yMid} c`, `${x1} ${yMid - yOffset} ${xMid + xOffset} ${y0} ${xMid} ${y0} c`, `${xMid - xOffset} ${y0} ${x0} ${yMid - yOffset} ${x0} ${yMid} c`, `${x0} ${yMid + yOffset} ${xMid - xOffset} ${y1} ${xMid} ${y1} c`, "h"); + + if (fillColor) { + buffer.push("B"); + } else { + buffer.push("S"); + } + + return [points[0].x, points[1].x, points[3].y, points[1].y]; + } + }); + } + } + +} + +class PolylineAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + const { + dict + } = parameters; + this.data.annotationType = _util.AnnotationType.POLYLINE; + this.data.vertices = []; + + if (!(this instanceof PolygonAnnotation)) { + this.setLineEndings(dict.getArray("LE")); + this.data.lineEndings = this.lineEndings; + } + + const rawVertices = dict.getArray("Vertices"); + + if (!Array.isArray(rawVertices)) { + return; + } + + for (let i = 0, ii = rawVertices.length; i < ii; i += 2) { + this.data.vertices.push({ + x: rawVertices[i], + y: rawVertices[i + 1] + }); + } + + if (!this.appearance) { + const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0]; + const strokeAlpha = dict.get("CA"); + const borderWidth = this.borderStyle.width || 1, + borderAdjust = 2 * borderWidth; + const bbox = [Infinity, Infinity, -Infinity, -Infinity]; + + for (const vertex of this.data.vertices) { + bbox[0] = Math.min(bbox[0], vertex.x - borderAdjust); + bbox[1] = Math.min(bbox[1], vertex.y - borderAdjust); + bbox[2] = Math.max(bbox[2], vertex.x + borderAdjust); + bbox[3] = Math.max(bbox[3], vertex.y + borderAdjust); + } + + if (!_util.Util.intersect(this.rectangle, bbox)) { + this.rectangle = bbox; + } + + this._setDefaultAppearance({ + xref: parameters.xref, + extra: `${borderWidth} w`, + strokeColor, + strokeAlpha, + pointsCallback: (buffer, points) => { + const vertices = this.data.vertices; + + for (let i = 0, ii = vertices.length; i < ii; i++) { + buffer.push(`${vertices[i].x} ${vertices[i].y} ${i === 0 ? "m" : "l"}`); + } + + buffer.push("S"); + return [points[0].x, points[1].x, points[3].y, points[1].y]; + } + }); + } + } + +} + +class PolygonAnnotation extends PolylineAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.POLYGON; + } + +} + +class CaretAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.CARET; + } + +} + +class InkAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.INK; + this.data.inkLists = []; + const rawInkLists = parameters.dict.getArray("InkList"); + + if (!Array.isArray(rawInkLists)) { + return; + } + + const xref = parameters.xref; + + for (let i = 0, ii = rawInkLists.length; i < ii; ++i) { + this.data.inkLists.push([]); + + for (let j = 0, jj = rawInkLists[i].length; j < jj; j += 2) { + this.data.inkLists[i].push({ + x: xref.fetchIfRef(rawInkLists[i][j]), + y: xref.fetchIfRef(rawInkLists[i][j + 1]) + }); + } + } + + if (!this.appearance) { + const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0]; + const strokeAlpha = parameters.dict.get("CA"); + const borderWidth = this.borderStyle.width || 1, + borderAdjust = 2 * borderWidth; + const bbox = [Infinity, Infinity, -Infinity, -Infinity]; + + for (const inkLists of this.data.inkLists) { + for (const vertex of inkLists) { + bbox[0] = Math.min(bbox[0], vertex.x - borderAdjust); + bbox[1] = Math.min(bbox[1], vertex.y - borderAdjust); + bbox[2] = Math.max(bbox[2], vertex.x + borderAdjust); + bbox[3] = Math.max(bbox[3], vertex.y + borderAdjust); + } + } + + if (!_util.Util.intersect(this.rectangle, bbox)) { + this.rectangle = bbox; + } + + this._setDefaultAppearance({ + xref: parameters.xref, + extra: `${borderWidth} w`, + strokeColor, + strokeAlpha, + pointsCallback: (buffer, points) => { + for (const inkList of this.data.inkLists) { + for (let i = 0, ii = inkList.length; i < ii; i++) { + buffer.push(`${inkList[i].x} ${inkList[i].y} ${i === 0 ? "m" : "l"}`); + } + + buffer.push("S"); + } + + return [points[0].x, points[1].x, points[3].y, points[1].y]; + } + }); + } + } + + static createNewDict(annotation, xref, { + apRef, + ap + }) { + const { + paths, + rect, + rotation + } = annotation; + const ink = new _primitives.Dict(xref); + ink.set("Type", _primitives.Name.get("Annot")); + ink.set("Subtype", _primitives.Name.get("Ink")); + ink.set("CreationDate", `D:${(0, _util.getModificationDate)()}`); + ink.set("Rect", rect); + ink.set("InkList", paths.map(p => p.points)); + ink.set("F", 4); + ink.set("Border", [0, 0, 0]); + ink.set("Rotate", rotation); + const n = new _primitives.Dict(xref); + ink.set("AP", n); + + if (apRef) { + n.set("N", apRef); + } else { + n.set("N", ap); + } + + return ink; + } + + static async createNewAppearanceStream(annotation, xref, params) { + const { + color, + rect, + rotation, + paths, + thickness, + opacity + } = annotation; + const [x1, y1, x2, y2] = rect; + let w = x2 - x1; + let h = y2 - y1; + + if (rotation % 180 !== 0) { + [w, h] = [h, w]; + } + + const appearanceBuffer = [`${thickness} w 1 J 1 j`, `${(0, _default_appearance.getPdfColor)(color, false)}`]; + + if (opacity !== 1) { + appearanceBuffer.push("/R0 gs"); + } + + const buffer = []; + + for (const { + bezier + } of paths) { + buffer.length = 0; + buffer.push(`${(0, _core_utils.numberToString)(bezier[0])} ${(0, _core_utils.numberToString)(bezier[1])} m`); + + for (let i = 2, ii = bezier.length; i < ii; i += 6) { + const curve = bezier.slice(i, i + 6).map(_core_utils.numberToString).join(" "); + buffer.push(`${curve} c`); + } + + buffer.push("S"); + appearanceBuffer.push(buffer.join("\n")); + } + + const appearance = appearanceBuffer.join("\n"); + const appearanceStreamDict = new _primitives.Dict(xref); + appearanceStreamDict.set("FormType", 1); + appearanceStreamDict.set("Subtype", _primitives.Name.get("Form")); + appearanceStreamDict.set("Type", _primitives.Name.get("XObject")); + appearanceStreamDict.set("BBox", [0, 0, w, h]); + appearanceStreamDict.set("Length", appearance.length); + + if (rotation) { + const matrix = WidgetAnnotation._getRotationMatrix(rotation, w, h); + + appearanceStreamDict.set("Matrix", matrix); + } + + if (opacity !== 1) { + const resources = new _primitives.Dict(xref); + const extGState = new _primitives.Dict(xref); + const r0 = new _primitives.Dict(xref); + r0.set("CA", opacity); + r0.set("Type", _primitives.Name.get("ExtGState")); + extGState.set("R0", r0); + resources.set("ExtGState", extGState); + appearanceStreamDict.set("Resources", resources); + } + + const ap = new _stream.StringStream(appearance); + ap.dict = appearanceStreamDict; + return ap; + } + +} + +class HighlightAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.HIGHLIGHT; + const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null); + + if (quadPoints) { + const resources = this.appearance && this.appearance.dict.get("Resources"); + + if (!this.appearance || !(resources && resources.has("ExtGState"))) { + if (this.appearance) { + (0, _util.warn)("HighlightAnnotation - ignoring built-in appearance stream."); + } + + const fillColor = this.color ? Array.from(this.color).map(c => c / 255) : [1, 1, 0]; + const fillAlpha = parameters.dict.get("CA"); + + this._setDefaultAppearance({ + xref: parameters.xref, + fillColor, + blendMode: "Multiply", + fillAlpha, + pointsCallback: (buffer, points) => { + buffer.push(`${points[0].x} ${points[0].y} m`, `${points[1].x} ${points[1].y} l`, `${points[3].x} ${points[3].y} l`, `${points[2].x} ${points[2].y} l`, "f"); + return [points[0].x, points[1].x, points[3].y, points[1].y]; + } + }); + } + } else { + this.data.hasPopup = false; + } + } + +} + +class UnderlineAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.UNDERLINE; + const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null); + + if (quadPoints) { + if (!this.appearance) { + const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0]; + const strokeAlpha = parameters.dict.get("CA"); + + this._setDefaultAppearance({ + xref: parameters.xref, + extra: "[] 0 d 1 w", + strokeColor, + strokeAlpha, + pointsCallback: (buffer, points) => { + buffer.push(`${points[2].x} ${points[2].y} m`, `${points[3].x} ${points[3].y} l`, "S"); + return [points[0].x, points[1].x, points[3].y, points[1].y]; + } + }); + } + } else { + this.data.hasPopup = false; + } + } + +} + +class SquigglyAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.SQUIGGLY; + const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null); + + if (quadPoints) { + if (!this.appearance) { + const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0]; + const strokeAlpha = parameters.dict.get("CA"); + + this._setDefaultAppearance({ + xref: parameters.xref, + extra: "[] 0 d 1 w", + strokeColor, + strokeAlpha, + pointsCallback: (buffer, points) => { + const dy = (points[0].y - points[2].y) / 6; + let shift = dy; + let x = points[2].x; + const y = points[2].y; + const xEnd = points[3].x; + buffer.push(`${x} ${y + shift} m`); + + do { + x += 2; + shift = shift === 0 ? dy : 0; + buffer.push(`${x} ${y + shift} l`); + } while (x < xEnd); + + buffer.push("S"); + return [points[2].x, xEnd, y - 2 * dy, y + 2 * dy]; + } + }); + } + } else { + this.data.hasPopup = false; + } + } + +} + +class StrikeOutAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.STRIKEOUT; + const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null); + + if (quadPoints) { + if (!this.appearance) { + const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0]; + const strokeAlpha = parameters.dict.get("CA"); + + this._setDefaultAppearance({ + xref: parameters.xref, + extra: "[] 0 d 1 w", + strokeColor, + strokeAlpha, + pointsCallback: (buffer, points) => { + buffer.push(`${(points[0].x + points[2].x) / 2} ` + `${(points[0].y + points[2].y) / 2} m`, `${(points[1].x + points[3].x) / 2} ` + `${(points[1].y + points[3].y) / 2} l`, "S"); + return [points[0].x, points[1].x, points[3].y, points[1].y]; + } + }); + } + } else { + this.data.hasPopup = false; + } + } + +} + +class StampAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + this.data.annotationType = _util.AnnotationType.STAMP; + } + +} + +class FileAttachmentAnnotation extends MarkupAnnotation { + constructor(parameters) { + super(parameters); + const file = new _file_spec.FileSpec(parameters.dict.get("FS"), parameters.xref); + this.data.annotationType = _util.AnnotationType.FILEATTACHMENT; + this.data.file = file.serializable; + } + +} /***/ }), /* 13 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.CCITTFaxStream = void 0; +})); +exports.createDefaultAppearance = createDefaultAppearance; +exports.getPdfColor = getPdfColor; +exports.parseDefaultAppearance = parseDefaultAppearance; + +var _core_utils = __w_pdfjs_require__(6); + +var _util = __w_pdfjs_require__(2); + +var _colorspace = __w_pdfjs_require__(14); + +var _evaluator = __w_pdfjs_require__(15); var _primitives = __w_pdfjs_require__(5); -var _ccitt = __w_pdfjs_require__(14); +var _stream = __w_pdfjs_require__(10); -var _stream = __w_pdfjs_require__(12); - -var CCITTFaxStream = function CCITTFaxStreamClosure() { - function CCITTFaxStream(str, maybeLength, params) { - this.str = str; - this.dict = str.dict; - - if (!(0, _primitives.isDict)(params)) { - params = _primitives.Dict.empty; - } - - const source = { - next() { - return str.getByte(); - } - - }; - this.ccittFaxDecoder = new _ccitt.CCITTFaxDecoder(source, { - K: params.get("K"), - EndOfLine: params.get("EndOfLine"), - EncodedByteAlign: params.get("EncodedByteAlign"), - Columns: params.get("Columns"), - Rows: params.get("Rows"), - EndOfBlock: params.get("EndOfBlock"), - BlackIs1: params.get("BlackIs1") - }); - - _stream.DecodeStream.call(this, maybeLength); +class DefaultAppearanceEvaluator extends _evaluator.EvaluatorPreprocessor { + constructor(str) { + super(new _stream.StringStream(str)); } - CCITTFaxStream.prototype = Object.create(_stream.DecodeStream.prototype); + parse() { + const operation = { + fn: 0, + args: [] + }; + const result = { + fontSize: 0, + fontName: "", + fontColor: new Uint8ClampedArray(3) + }; - CCITTFaxStream.prototype.readBlock = function () { - while (!this.eof) { - const c = this.ccittFaxDecoder.readNextChar(); + try { + while (true) { + operation.args.length = 0; - if (c === -1) { - this.eof = true; - return; + if (!this.read(operation)) { + break; + } + + if (this.savedStatesDepth !== 0) { + continue; + } + + const { + fn, + args + } = operation; + + switch (fn | 0) { + case _util.OPS.setFont: + const [fontName, fontSize] = args; + + if (fontName instanceof _primitives.Name) { + result.fontName = fontName.name; + } + + if (typeof fontSize === "number" && fontSize > 0) { + result.fontSize = fontSize; + } + + break; + + case _util.OPS.setFillRGBColor: + _colorspace.ColorSpace.singletons.rgb.getRgbItem(args, 0, result.fontColor, 0); + + break; + + case _util.OPS.setFillGray: + _colorspace.ColorSpace.singletons.gray.getRgbItem(args, 0, result.fontColor, 0); + + break; + + case _util.OPS.setFillColorSpace: + _colorspace.ColorSpace.singletons.cmyk.getRgbItem(args, 0, result.fontColor, 0); + + break; + } } - - this.ensureBuffer(this.bufferLength + 1); - this.buffer[this.bufferLength++] = c; + } catch (reason) { + (0, _util.warn)(`parseDefaultAppearance - ignoring errors: "${reason}".`); } - }; - return CCITTFaxStream; -}(); + return result; + } -exports.CCITTFaxStream = CCITTFaxStream; +} + +function parseDefaultAppearance(str) { + return new DefaultAppearanceEvaluator(str).parse(); +} + +function getPdfColor(color, isFill) { + if (color[0] === color[1] && color[1] === color[2]) { + const gray = color[0] / 255; + return `${(0, _core_utils.numberToString)(gray)} ${isFill ? "g" : "G"}`; + } + + return Array.from(color).map(c => (0, _core_utils.numberToString)(c / 255)).join(" ") + ` ${isFill ? "rg" : "RG"}`; +} + +function createDefaultAppearance({ + fontSize, + fontName, + fontColor +}) { + return `/${(0, _core_utils.escapePDFName)(fontName)} ${fontSize} Tf ${getPdfColor(fontColor, true)}`; +} /***/ }), /* 14 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.CCITTFaxDecoder = void 0; - -var _util = __w_pdfjs_require__(2); - -const CCITTFaxDecoder = function CCITTFaxDecoder() { - const ccittEOL = -2; - const ccittEOF = -1; - const twoDimPass = 0; - const twoDimHoriz = 1; - const twoDimVert0 = 2; - const twoDimVertR1 = 3; - const twoDimVertL1 = 4; - const twoDimVertR2 = 5; - const twoDimVertL2 = 6; - const twoDimVertR3 = 7; - const twoDimVertL3 = 8; - const twoDimTable = [[-1, -1], [-1, -1], [7, twoDimVertL3], [7, twoDimVertR3], [6, twoDimVertL2], [6, twoDimVertL2], [6, twoDimVertR2], [6, twoDimVertR2], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0]]; - const whiteTable1 = [[-1, -1], [12, ccittEOL], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [11, 1792], [11, 1792], [12, 1984], [12, 2048], [12, 2112], [12, 2176], [12, 2240], [12, 2304], [11, 1856], [11, 1856], [11, 1920], [11, 1920], [12, 2368], [12, 2432], [12, 2496], [12, 2560]]; - const whiteTable2 = [[-1, -1], [-1, -1], [-1, -1], [-1, -1], [8, 29], [8, 29], [8, 30], [8, 30], [8, 45], [8, 45], [8, 46], [8, 46], [7, 22], [7, 22], [7, 22], [7, 22], [7, 23], [7, 23], [7, 23], [7, 23], [8, 47], [8, 47], [8, 48], [8, 48], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [7, 20], [7, 20], [7, 20], [7, 20], [8, 33], [8, 33], [8, 34], [8, 34], [8, 35], [8, 35], [8, 36], [8, 36], [8, 37], [8, 37], [8, 38], [8, 38], [7, 19], [7, 19], [7, 19], [7, 19], [8, 31], [8, 31], [8, 32], [8, 32], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [8, 53], [8, 53], [8, 54], [8, 54], [7, 26], [7, 26], [7, 26], [7, 26], [8, 39], [8, 39], [8, 40], [8, 40], [8, 41], [8, 41], [8, 42], [8, 42], [8, 43], [8, 43], [8, 44], [8, 44], [7, 21], [7, 21], [7, 21], [7, 21], [7, 28], [7, 28], [7, 28], [7, 28], [8, 61], [8, 61], [8, 62], [8, 62], [8, 63], [8, 63], [8, 0], [8, 0], [8, 320], [8, 320], [8, 384], [8, 384], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [7, 27], [7, 27], [7, 27], [7, 27], [8, 59], [8, 59], [8, 60], [8, 60], [9, 1472], [9, 1536], [9, 1600], [9, 1728], [7, 18], [7, 18], [7, 18], [7, 18], [7, 24], [7, 24], [7, 24], [7, 24], [8, 49], [8, 49], [8, 50], [8, 50], [8, 51], [8, 51], [8, 52], [8, 52], [7, 25], [7, 25], [7, 25], [7, 25], [8, 55], [8, 55], [8, 56], [8, 56], [8, 57], [8, 57], [8, 58], [8, 58], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [8, 448], [8, 448], [8, 512], [8, 512], [9, 704], [9, 768], [8, 640], [8, 640], [8, 576], [8, 576], [9, 832], [9, 896], [9, 960], [9, 1024], [9, 1088], [9, 1152], [9, 1216], [9, 1280], [9, 1344], [9, 1408], [7, 256], [7, 256], [7, 256], [7, 256], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7]]; - const blackTable1 = [[-1, -1], [-1, -1], [12, ccittEOL], [12, ccittEOL], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [11, 1792], [11, 1792], [11, 1792], [11, 1792], [12, 1984], [12, 1984], [12, 2048], [12, 2048], [12, 2112], [12, 2112], [12, 2176], [12, 2176], [12, 2240], [12, 2240], [12, 2304], [12, 2304], [11, 1856], [11, 1856], [11, 1856], [11, 1856], [11, 1920], [11, 1920], [11, 1920], [11, 1920], [12, 2368], [12, 2368], [12, 2432], [12, 2432], [12, 2496], [12, 2496], [12, 2560], [12, 2560], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [12, 52], [12, 52], [13, 640], [13, 704], [13, 768], [13, 832], [12, 55], [12, 55], [12, 56], [12, 56], [13, 1280], [13, 1344], [13, 1408], [13, 1472], [12, 59], [12, 59], [12, 60], [12, 60], [13, 1536], [13, 1600], [11, 24], [11, 24], [11, 24], [11, 24], [11, 25], [11, 25], [11, 25], [11, 25], [13, 1664], [13, 1728], [12, 320], [12, 320], [12, 384], [12, 384], [12, 448], [12, 448], [13, 512], [13, 576], [12, 53], [12, 53], [12, 54], [12, 54], [13, 896], [13, 960], [13, 1024], [13, 1088], [13, 1152], [13, 1216], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64]]; - const blackTable2 = [[8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [11, 23], [11, 23], [12, 50], [12, 51], [12, 44], [12, 45], [12, 46], [12, 47], [12, 57], [12, 58], [12, 61], [12, 256], [10, 16], [10, 16], [10, 16], [10, 16], [10, 17], [10, 17], [10, 17], [10, 17], [12, 48], [12, 49], [12, 62], [12, 63], [12, 30], [12, 31], [12, 32], [12, 33], [12, 40], [12, 41], [11, 22], [11, 22], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [12, 128], [12, 192], [12, 26], [12, 27], [12, 28], [12, 29], [11, 19], [11, 19], [11, 20], [11, 20], [12, 34], [12, 35], [12, 36], [12, 37], [12, 38], [12, 39], [11, 21], [11, 21], [12, 42], [12, 43], [10, 0], [10, 0], [10, 0], [10, 0], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12]]; - const blackTable3 = [[-1, -1], [-1, -1], [-1, -1], [-1, -1], [6, 9], [6, 8], [5, 7], [5, 7], [4, 6], [4, 6], [4, 6], [4, 6], [4, 5], [4, 5], [4, 5], [4, 5], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2]]; - - function CCITTFaxDecoder(source, options = {}) { - if (!source || typeof source.next !== "function") { - throw new Error('CCITTFaxDecoder - invalid "source" parameter.'); - } - - this.source = source; - this.eof = false; - this.encoding = options.K || 0; - this.eoline = options.EndOfLine || false; - this.byteAlign = options.EncodedByteAlign || false; - this.columns = options.Columns || 1728; - this.rows = options.Rows || 0; - let eoblock = options.EndOfBlock; - - if (eoblock === null || eoblock === undefined) { - eoblock = true; - } - - this.eoblock = eoblock; - this.black = options.BlackIs1 || false; - this.codingLine = new Uint32Array(this.columns + 1); - this.refLine = new Uint32Array(this.columns + 2); - this.codingLine[0] = this.columns; - this.codingPos = 0; - this.row = 0; - this.nextLine2D = this.encoding < 0; - this.inputBits = 0; - this.inputBuf = 0; - this.outputBits = 0; - this.rowsDone = false; - let code1; - - while ((code1 = this._lookBits(12)) === 0) { - this._eatBits(1); - } - - if (code1 === 1) { - this._eatBits(12); - } - - if (this.encoding > 0) { - this.nextLine2D = !this._lookBits(1); - - this._eatBits(1); - } - } - - CCITTFaxDecoder.prototype = { - readNextChar() { - if (this.eof) { - return -1; - } - - const refLine = this.refLine; - const codingLine = this.codingLine; - const columns = this.columns; - let refPos, blackPixels, bits, i; - - if (this.outputBits === 0) { - if (this.rowsDone) { - this.eof = true; - } - - if (this.eof) { - return -1; - } - - this.err = false; - let code1, code2, code3; - - if (this.nextLine2D) { - for (i = 0; codingLine[i] < columns; ++i) { - refLine[i] = codingLine[i]; - } - - refLine[i++] = columns; - refLine[i] = columns; - codingLine[0] = 0; - this.codingPos = 0; - refPos = 0; - blackPixels = 0; - - while (codingLine[this.codingPos] < columns) { - code1 = this._getTwoDimCode(); - - switch (code1) { - case twoDimPass: - this._addPixels(refLine[refPos + 1], blackPixels); - - if (refLine[refPos + 1] < columns) { - refPos += 2; - } - - break; - - case twoDimHoriz: - code1 = code2 = 0; - - if (blackPixels) { - do { - code1 += code3 = this._getBlackCode(); - } while (code3 >= 64); - - do { - code2 += code3 = this._getWhiteCode(); - } while (code3 >= 64); - } else { - do { - code1 += code3 = this._getWhiteCode(); - } while (code3 >= 64); - - do { - code2 += code3 = this._getBlackCode(); - } while (code3 >= 64); - } - - this._addPixels(codingLine[this.codingPos] + code1, blackPixels); - - if (codingLine[this.codingPos] < columns) { - this._addPixels(codingLine[this.codingPos] + code2, blackPixels ^ 1); - } - - while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { - refPos += 2; - } - - break; - - case twoDimVertR3: - this._addPixels(refLine[refPos] + 3, blackPixels); - - blackPixels ^= 1; - - if (codingLine[this.codingPos] < columns) { - ++refPos; - - while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { - refPos += 2; - } - } - - break; - - case twoDimVertR2: - this._addPixels(refLine[refPos] + 2, blackPixels); - - blackPixels ^= 1; - - if (codingLine[this.codingPos] < columns) { - ++refPos; - - while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { - refPos += 2; - } - } - - break; - - case twoDimVertR1: - this._addPixels(refLine[refPos] + 1, blackPixels); - - blackPixels ^= 1; - - if (codingLine[this.codingPos] < columns) { - ++refPos; - - while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { - refPos += 2; - } - } - - break; - - case twoDimVert0: - this._addPixels(refLine[refPos], blackPixels); - - blackPixels ^= 1; - - if (codingLine[this.codingPos] < columns) { - ++refPos; - - while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { - refPos += 2; - } - } - - break; - - case twoDimVertL3: - this._addPixelsNeg(refLine[refPos] - 3, blackPixels); - - blackPixels ^= 1; - - if (codingLine[this.codingPos] < columns) { - if (refPos > 0) { - --refPos; - } else { - ++refPos; - } - - while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { - refPos += 2; - } - } - - break; - - case twoDimVertL2: - this._addPixelsNeg(refLine[refPos] - 2, blackPixels); - - blackPixels ^= 1; - - if (codingLine[this.codingPos] < columns) { - if (refPos > 0) { - --refPos; - } else { - ++refPos; - } - - while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { - refPos += 2; - } - } - - break; - - case twoDimVertL1: - this._addPixelsNeg(refLine[refPos] - 1, blackPixels); - - blackPixels ^= 1; - - if (codingLine[this.codingPos] < columns) { - if (refPos > 0) { - --refPos; - } else { - ++refPos; - } - - while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { - refPos += 2; - } - } - - break; - - case ccittEOF: - this._addPixels(columns, 0); - - this.eof = true; - break; - - default: - (0, _util.info)("bad 2d code"); - - this._addPixels(columns, 0); - - this.err = true; - } - } - } else { - codingLine[0] = 0; - this.codingPos = 0; - blackPixels = 0; - - while (codingLine[this.codingPos] < columns) { - code1 = 0; - - if (blackPixels) { - do { - code1 += code3 = this._getBlackCode(); - } while (code3 >= 64); - } else { - do { - code1 += code3 = this._getWhiteCode(); - } while (code3 >= 64); - } - - this._addPixels(codingLine[this.codingPos] + code1, blackPixels); - - blackPixels ^= 1; - } - } - - let gotEOL = false; - - if (this.byteAlign) { - this.inputBits &= ~7; - } - - if (!this.eoblock && this.row === this.rows - 1) { - this.rowsDone = true; - } else { - code1 = this._lookBits(12); - - if (this.eoline) { - while (code1 !== ccittEOF && code1 !== 1) { - this._eatBits(1); - - code1 = this._lookBits(12); - } - } else { - while (code1 === 0) { - this._eatBits(1); - - code1 = this._lookBits(12); - } - } - - if (code1 === 1) { - this._eatBits(12); - - gotEOL = true; - } else if (code1 === ccittEOF) { - this.eof = true; - } - } - - if (!this.eof && this.encoding > 0 && !this.rowsDone) { - this.nextLine2D = !this._lookBits(1); - - this._eatBits(1); - } - - if (this.eoblock && gotEOL && this.byteAlign) { - code1 = this._lookBits(12); - - if (code1 === 1) { - this._eatBits(12); - - if (this.encoding > 0) { - this._lookBits(1); - - this._eatBits(1); - } - - if (this.encoding >= 0) { - for (i = 0; i < 4; ++i) { - code1 = this._lookBits(12); - - if (code1 !== 1) { - (0, _util.info)("bad rtc code: " + code1); - } - - this._eatBits(12); - - if (this.encoding > 0) { - this._lookBits(1); - - this._eatBits(1); - } - } - } - - this.eof = true; - } - } else if (this.err && this.eoline) { - while (true) { - code1 = this._lookBits(13); - - if (code1 === ccittEOF) { - this.eof = true; - return -1; - } - - if (code1 >> 1 === 1) { - break; - } - - this._eatBits(1); - } - - this._eatBits(12); - - if (this.encoding > 0) { - this._eatBits(1); - - this.nextLine2D = !(code1 & 1); - } - } - - if (codingLine[0] > 0) { - this.outputBits = codingLine[this.codingPos = 0]; - } else { - this.outputBits = codingLine[this.codingPos = 1]; - } - - this.row++; - } - - let c; - - if (this.outputBits >= 8) { - c = this.codingPos & 1 ? 0 : 0xff; - this.outputBits -= 8; - - if (this.outputBits === 0 && codingLine[this.codingPos] < columns) { - this.codingPos++; - this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; - } - } else { - bits = 8; - c = 0; - - do { - if (this.outputBits > bits) { - c <<= bits; - - if (!(this.codingPos & 1)) { - c |= 0xff >> 8 - bits; - } - - this.outputBits -= bits; - bits = 0; - } else { - c <<= this.outputBits; - - if (!(this.codingPos & 1)) { - c |= 0xff >> 8 - this.outputBits; - } - - bits -= this.outputBits; - this.outputBits = 0; - - if (codingLine[this.codingPos] < columns) { - this.codingPos++; - this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; - } else if (bits > 0) { - c <<= bits; - bits = 0; - } - } - } while (bits); - } - - if (this.black) { - c ^= 0xff; - } - - return c; - }, - - _addPixels(a1, blackPixels) { - const codingLine = this.codingLine; - let codingPos = this.codingPos; - - if (a1 > codingLine[codingPos]) { - if (a1 > this.columns) { - (0, _util.info)("row is wrong length"); - this.err = true; - a1 = this.columns; - } - - if (codingPos & 1 ^ blackPixels) { - ++codingPos; - } - - codingLine[codingPos] = a1; - } - - this.codingPos = codingPos; - }, - - _addPixelsNeg(a1, blackPixels) { - const codingLine = this.codingLine; - let codingPos = this.codingPos; - - if (a1 > codingLine[codingPos]) { - if (a1 > this.columns) { - (0, _util.info)("row is wrong length"); - this.err = true; - a1 = this.columns; - } - - if (codingPos & 1 ^ blackPixels) { - ++codingPos; - } - - codingLine[codingPos] = a1; - } else if (a1 < codingLine[codingPos]) { - if (a1 < 0) { - (0, _util.info)("invalid code"); - this.err = true; - a1 = 0; - } - - while (codingPos > 0 && a1 < codingLine[codingPos - 1]) { - --codingPos; - } - - codingLine[codingPos] = a1; - } - - this.codingPos = codingPos; - }, - - _findTableCode(start, end, table, limit) { - const limitValue = limit || 0; - - for (let i = start; i <= end; ++i) { - let code = this._lookBits(i); - - if (code === ccittEOF) { - return [true, 1, false]; - } - - if (i < end) { - code <<= end - i; - } - - if (!limitValue || code >= limitValue) { - const p = table[code - limitValue]; - - if (p[0] === i) { - this._eatBits(i); - - return [true, p[1], true]; - } - } - } - - return [false, 0, false]; - }, - - _getTwoDimCode() { - let code = 0; - let p; - - if (this.eoblock) { - code = this._lookBits(7); - p = twoDimTable[code]; - - if (p && p[0] > 0) { - this._eatBits(p[0]); - - return p[1]; - } - } else { - const result = this._findTableCode(1, 7, twoDimTable); - - if (result[0] && result[2]) { - return result[1]; - } - } - - (0, _util.info)("Bad two dim code"); - return ccittEOF; - }, - - _getWhiteCode() { - let code = 0; - let p; - - if (this.eoblock) { - code = this._lookBits(12); - - if (code === ccittEOF) { - return 1; - } - - if (code >> 5 === 0) { - p = whiteTable1[code]; - } else { - p = whiteTable2[code >> 3]; - } - - if (p[0] > 0) { - this._eatBits(p[0]); - - return p[1]; - } - } else { - let result = this._findTableCode(1, 9, whiteTable2); - - if (result[0]) { - return result[1]; - } - - result = this._findTableCode(11, 12, whiteTable1); - - if (result[0]) { - return result[1]; - } - } - - (0, _util.info)("bad white code"); - - this._eatBits(1); - - return 1; - }, - - _getBlackCode() { - let code, p; - - if (this.eoblock) { - code = this._lookBits(13); - - if (code === ccittEOF) { - return 1; - } - - if (code >> 7 === 0) { - p = blackTable1[code]; - } else if (code >> 9 === 0 && code >> 7 !== 0) { - p = blackTable2[(code >> 1) - 64]; - } else { - p = blackTable3[code >> 7]; - } - - if (p[0] > 0) { - this._eatBits(p[0]); - - return p[1]; - } - } else { - let result = this._findTableCode(2, 6, blackTable3); - - if (result[0]) { - return result[1]; - } - - result = this._findTableCode(7, 12, blackTable2, 64); - - if (result[0]) { - return result[1]; - } - - result = this._findTableCode(10, 13, blackTable1); - - if (result[0]) { - return result[1]; - } - } - - (0, _util.info)("bad black code"); - - this._eatBits(1); - - return 1; - }, - - _lookBits(n) { - let c; - - while (this.inputBits < n) { - if ((c = this.source.next()) === -1) { - if (this.inputBits === 0) { - return ccittEOF; - } - - return this.inputBuf << n - this.inputBits & 0xffff >> 16 - n; - } - - this.inputBuf = this.inputBuf << 8 | c; - this.inputBits += 8; - } - - return this.inputBuf >> this.inputBits - n & 0xffff >> 16 - n; - }, - - _eatBits(n) { - if ((this.inputBits -= n) < 0) { - this.inputBits = 0; - } - } - - }; - return CCITTFaxDecoder; -}(); - -exports.CCITTFaxDecoder = CCITTFaxDecoder; - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.Jbig2Stream = void 0; - -var _primitives = __w_pdfjs_require__(5); - -var _stream = __w_pdfjs_require__(12); - -var _jbig = __w_pdfjs_require__(16); - -var _util = __w_pdfjs_require__(2); - -const Jbig2Stream = function Jbig2StreamClosure() { - function Jbig2Stream(stream, maybeLength, dict, params) { - this.stream = stream; - this.maybeLength = maybeLength; - this.dict = dict; - this.params = params; - - _stream.DecodeStream.call(this, maybeLength); - } - - Jbig2Stream.prototype = Object.create(_stream.DecodeStream.prototype); - Object.defineProperty(Jbig2Stream.prototype, "bytes", { - get() { - return (0, _util.shadow)(this, "bytes", this.stream.getBytes(this.maybeLength)); - }, - - configurable: true - }); - - Jbig2Stream.prototype.ensureBuffer = function (requested) {}; - - Jbig2Stream.prototype.readBlock = function () { - if (this.eof) { - return; - } - - const jbig2Image = new _jbig.Jbig2Image(); - const chunks = []; - - if ((0, _primitives.isDict)(this.params)) { - const globalsStream = this.params.get("JBIG2Globals"); - - if ((0, _primitives.isStream)(globalsStream)) { - const globals = globalsStream.getBytes(); - chunks.push({ - data: globals, - start: 0, - end: globals.length - }); - } - } - - chunks.push({ - data: this.bytes, - start: 0, - end: this.bytes.length - }); - const data = jbig2Image.parseChunks(chunks); - const dataLength = data.length; - - for (let i = 0; i < dataLength; i++) { - data[i] ^= 0xff; - } - - this.buffer = data; - this.bufferLength = dataLength; - this.eof = true; - }; - - return Jbig2Stream; -}(); - -exports.Jbig2Stream = Jbig2Stream; - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.Jbig2Image = void 0; - -var _util = __w_pdfjs_require__(2); - -var _core_utils = __w_pdfjs_require__(8); - -var _arithmetic_decoder = __w_pdfjs_require__(17); - -var _ccitt = __w_pdfjs_require__(14); - -class Jbig2Error extends _util.BaseException { - constructor(msg) { - super(`JBIG2 error: ${msg}`); - } - -} - -var Jbig2Image = function Jbig2ImageClosure() { - function ContextCache() {} - - ContextCache.prototype = { - getContexts(id) { - if (id in this) { - return this[id]; - } - - return this[id] = new Int8Array(1 << 16); - } - - }; - - function DecodingContext(data, start, end) { - this.data = data; - this.start = start; - this.end = end; - } - - DecodingContext.prototype = { - get decoder() { - var decoder = new _arithmetic_decoder.ArithmeticDecoder(this.data, this.start, this.end); - return (0, _util.shadow)(this, "decoder", decoder); - }, - - get contextCache() { - var cache = new ContextCache(); - return (0, _util.shadow)(this, "contextCache", cache); - } - - }; - - function decodeInteger(contextCache, procedure, decoder) { - var contexts = contextCache.getContexts(procedure); - var prev = 1; - - function readBits(length) { - var v = 0; - - for (var i = 0; i < length; i++) { - var bit = decoder.readBit(contexts, prev); - prev = prev < 256 ? prev << 1 | bit : (prev << 1 | bit) & 511 | 256; - v = v << 1 | bit; - } - - return v >>> 0; - } - - var sign = readBits(1); - var value = readBits(1) ? readBits(1) ? readBits(1) ? readBits(1) ? readBits(1) ? readBits(32) + 4436 : readBits(12) + 340 : readBits(8) + 84 : readBits(6) + 20 : readBits(4) + 4 : readBits(2); - - if (sign === 0) { - return value; - } else if (value > 0) { - return -value; - } - - return null; - } - - function decodeIAID(contextCache, decoder, codeLength) { - var contexts = contextCache.getContexts("IAID"); - var prev = 1; - - for (var i = 0; i < codeLength; i++) { - var bit = decoder.readBit(contexts, prev); - prev = prev << 1 | bit; - } - - if (codeLength < 31) { - return prev & (1 << codeLength) - 1; - } - - return prev & 0x7fffffff; - } - - var SegmentTypes = ["SymbolDictionary", null, null, null, "IntermediateTextRegion", null, "ImmediateTextRegion", "ImmediateLosslessTextRegion", null, null, null, null, null, null, null, null, "PatternDictionary", null, null, null, "IntermediateHalftoneRegion", null, "ImmediateHalftoneRegion", "ImmediateLosslessHalftoneRegion", null, null, null, null, null, null, null, null, null, null, null, null, "IntermediateGenericRegion", null, "ImmediateGenericRegion", "ImmediateLosslessGenericRegion", "IntermediateGenericRefinementRegion", null, "ImmediateGenericRefinementRegion", "ImmediateLosslessGenericRefinementRegion", null, null, null, null, "PageInformation", "EndOfPage", "EndOfStripe", "EndOfFile", "Profiles", "Tables", null, null, null, null, null, null, null, null, "Extension"]; - var CodingTemplates = [[{ - x: -1, - y: -2 - }, { - x: 0, - y: -2 - }, { - x: 1, - y: -2 - }, { - x: -2, - y: -1 - }, { - x: -1, - y: -1 - }, { - x: 0, - y: -1 - }, { - x: 1, - y: -1 - }, { - x: 2, - y: -1 - }, { - x: -4, - y: 0 - }, { - x: -3, - y: 0 - }, { - x: -2, - y: 0 - }, { - x: -1, - y: 0 - }], [{ - x: -1, - y: -2 - }, { - x: 0, - y: -2 - }, { - x: 1, - y: -2 - }, { - x: 2, - y: -2 - }, { - x: -2, - y: -1 - }, { - x: -1, - y: -1 - }, { - x: 0, - y: -1 - }, { - x: 1, - y: -1 - }, { - x: 2, - y: -1 - }, { - x: -3, - y: 0 - }, { - x: -2, - y: 0 - }, { - x: -1, - y: 0 - }], [{ - x: -1, - y: -2 - }, { - x: 0, - y: -2 - }, { - x: 1, - y: -2 - }, { - x: -2, - y: -1 - }, { - x: -1, - y: -1 - }, { - x: 0, - y: -1 - }, { - x: 1, - y: -1 - }, { - x: -2, - y: 0 - }, { - x: -1, - y: 0 - }], [{ - x: -3, - y: -1 - }, { - x: -2, - y: -1 - }, { - x: -1, - y: -1 - }, { - x: 0, - y: -1 - }, { - x: 1, - y: -1 - }, { - x: -4, - y: 0 - }, { - x: -3, - y: 0 - }, { - x: -2, - y: 0 - }, { - x: -1, - y: 0 - }]]; - var RefinementTemplates = [{ - coding: [{ - x: 0, - y: -1 - }, { - x: 1, - y: -1 - }, { - x: -1, - y: 0 - }], - reference: [{ - x: 0, - y: -1 - }, { - x: 1, - y: -1 - }, { - x: -1, - y: 0 - }, { - x: 0, - y: 0 - }, { - x: 1, - y: 0 - }, { - x: -1, - y: 1 - }, { - x: 0, - y: 1 - }, { - x: 1, - y: 1 - }] - }, { - coding: [{ - x: -1, - y: -1 - }, { - x: 0, - y: -1 - }, { - x: 1, - y: -1 - }, { - x: -1, - y: 0 - }], - reference: [{ - x: 0, - y: -1 - }, { - x: -1, - y: 0 - }, { - x: 0, - y: 0 - }, { - x: 1, - y: 0 - }, { - x: 0, - y: 1 - }, { - x: 1, - y: 1 - }] - }]; - var ReusedContexts = [0x9b25, 0x0795, 0x00e5, 0x0195]; - var RefinementReusedContexts = [0x0020, 0x0008]; - - function decodeBitmapTemplate0(width, height, decodingContext) { - var decoder = decodingContext.decoder; - var contexts = decodingContext.contextCache.getContexts("GB"); - var contextLabel, - i, - j, - pixel, - row, - row1, - row2, - bitmap = []; - var OLD_PIXEL_MASK = 0x7bf7; - - for (i = 0; i < height; i++) { - row = bitmap[i] = new Uint8Array(width); - row1 = i < 1 ? row : bitmap[i - 1]; - row2 = i < 2 ? row : bitmap[i - 2]; - contextLabel = row2[0] << 13 | row2[1] << 12 | row2[2] << 11 | row1[0] << 7 | row1[1] << 6 | row1[2] << 5 | row1[3] << 4; - - for (j = 0; j < width; j++) { - row[j] = pixel = decoder.readBit(contexts, contextLabel); - contextLabel = (contextLabel & OLD_PIXEL_MASK) << 1 | (j + 3 < width ? row2[j + 3] << 11 : 0) | (j + 4 < width ? row1[j + 4] << 4 : 0) | pixel; - } - } - - return bitmap; - } - - function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at, decodingContext) { - if (mmr) { - const input = new Reader(decodingContext.data, decodingContext.start, decodingContext.end); - return decodeMMRBitmap(input, width, height, false); - } - - if (templateIndex === 0 && !skip && !prediction && at.length === 4 && at[0].x === 3 && at[0].y === -1 && at[1].x === -3 && at[1].y === -1 && at[2].x === 2 && at[2].y === -2 && at[3].x === -2 && at[3].y === -2) { - return decodeBitmapTemplate0(width, height, decodingContext); - } - - var useskip = !!skip; - var template = CodingTemplates[templateIndex].concat(at); - template.sort(function (a, b) { - return a.y - b.y || a.x - b.x; - }); - var templateLength = template.length; - var templateX = new Int8Array(templateLength); - var templateY = new Int8Array(templateLength); - var changingTemplateEntries = []; - var reuseMask = 0, - minX = 0, - maxX = 0, - minY = 0; - var c, k; - - for (k = 0; k < templateLength; k++) { - templateX[k] = template[k].x; - templateY[k] = template[k].y; - minX = Math.min(minX, template[k].x); - maxX = Math.max(maxX, template[k].x); - minY = Math.min(minY, template[k].y); - - if (k < templateLength - 1 && template[k].y === template[k + 1].y && template[k].x === template[k + 1].x - 1) { - reuseMask |= 1 << templateLength - 1 - k; - } else { - changingTemplateEntries.push(k); - } - } - - var changingEntriesLength = changingTemplateEntries.length; - var changingTemplateX = new Int8Array(changingEntriesLength); - var changingTemplateY = new Int8Array(changingEntriesLength); - var changingTemplateBit = new Uint16Array(changingEntriesLength); - - for (c = 0; c < changingEntriesLength; c++) { - k = changingTemplateEntries[c]; - changingTemplateX[c] = template[k].x; - changingTemplateY[c] = template[k].y; - changingTemplateBit[c] = 1 << templateLength - 1 - k; - } - - var sbb_left = -minX; - var sbb_top = -minY; - var sbb_right = width - maxX; - var pseudoPixelContext = ReusedContexts[templateIndex]; - var row = new Uint8Array(width); - var bitmap = []; - var decoder = decodingContext.decoder; - var contexts = decodingContext.contextCache.getContexts("GB"); - var ltp = 0, - j, - i0, - j0, - contextLabel = 0, - bit, - shift; - - for (var i = 0; i < height; i++) { - if (prediction) { - var sltp = decoder.readBit(contexts, pseudoPixelContext); - ltp ^= sltp; - - if (ltp) { - bitmap.push(row); - continue; - } - } - - row = new Uint8Array(row); - bitmap.push(row); - - for (j = 0; j < width; j++) { - if (useskip && skip[i][j]) { - row[j] = 0; - continue; - } - - if (j >= sbb_left && j < sbb_right && i >= sbb_top) { - contextLabel = contextLabel << 1 & reuseMask; - - for (k = 0; k < changingEntriesLength; k++) { - i0 = i + changingTemplateY[k]; - j0 = j + changingTemplateX[k]; - bit = bitmap[i0][j0]; - - if (bit) { - bit = changingTemplateBit[k]; - contextLabel |= bit; - } - } - } else { - contextLabel = 0; - shift = templateLength - 1; - - for (k = 0; k < templateLength; k++, shift--) { - j0 = j + templateX[k]; - - if (j0 >= 0 && j0 < width) { - i0 = i + templateY[k]; - - if (i0 >= 0) { - bit = bitmap[i0][j0]; - - if (bit) { - contextLabel |= bit << shift; - } - } - } - } - } - - var pixel = decoder.readBit(contexts, contextLabel); - row[j] = pixel; - } - } - - return bitmap; - } - - function decodeRefinement(width, height, templateIndex, referenceBitmap, offsetX, offsetY, prediction, at, decodingContext) { - var codingTemplate = RefinementTemplates[templateIndex].coding; - - if (templateIndex === 0) { - codingTemplate = codingTemplate.concat([at[0]]); - } - - var codingTemplateLength = codingTemplate.length; - var codingTemplateX = new Int32Array(codingTemplateLength); - var codingTemplateY = new Int32Array(codingTemplateLength); - var k; - - for (k = 0; k < codingTemplateLength; k++) { - codingTemplateX[k] = codingTemplate[k].x; - codingTemplateY[k] = codingTemplate[k].y; - } - - var referenceTemplate = RefinementTemplates[templateIndex].reference; - - if (templateIndex === 0) { - referenceTemplate = referenceTemplate.concat([at[1]]); - } - - var referenceTemplateLength = referenceTemplate.length; - var referenceTemplateX = new Int32Array(referenceTemplateLength); - var referenceTemplateY = new Int32Array(referenceTemplateLength); - - for (k = 0; k < referenceTemplateLength; k++) { - referenceTemplateX[k] = referenceTemplate[k].x; - referenceTemplateY[k] = referenceTemplate[k].y; - } - - var referenceWidth = referenceBitmap[0].length; - var referenceHeight = referenceBitmap.length; - var pseudoPixelContext = RefinementReusedContexts[templateIndex]; - var bitmap = []; - var decoder = decodingContext.decoder; - var contexts = decodingContext.contextCache.getContexts("GR"); - var ltp = 0; - - for (var i = 0; i < height; i++) { - if (prediction) { - var sltp = decoder.readBit(contexts, pseudoPixelContext); - ltp ^= sltp; - - if (ltp) { - throw new Jbig2Error("prediction is not supported"); - } - } - - var row = new Uint8Array(width); - bitmap.push(row); - - for (var j = 0; j < width; j++) { - var i0, j0; - var contextLabel = 0; - - for (k = 0; k < codingTemplateLength; k++) { - i0 = i + codingTemplateY[k]; - j0 = j + codingTemplateX[k]; - - if (i0 < 0 || j0 < 0 || j0 >= width) { - contextLabel <<= 1; - } else { - contextLabel = contextLabel << 1 | bitmap[i0][j0]; - } - } - - for (k = 0; k < referenceTemplateLength; k++) { - i0 = i + referenceTemplateY[k] - offsetY; - j0 = j + referenceTemplateX[k] - offsetX; - - if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || j0 >= referenceWidth) { - contextLabel <<= 1; - } else { - contextLabel = contextLabel << 1 | referenceBitmap[i0][j0]; - } - } - - var pixel = decoder.readBit(contexts, contextLabel); - row[j] = pixel; - } - } - - return bitmap; - } - - function decodeSymbolDictionary(huffman, refinement, symbols, numberOfNewSymbols, numberOfExportedSymbols, huffmanTables, templateIndex, at, refinementTemplateIndex, refinementAt, decodingContext, huffmanInput) { - if (huffman && refinement) { - throw new Jbig2Error("symbol refinement with Huffman is not supported"); - } - - var newSymbols = []; - var currentHeight = 0; - var symbolCodeLength = (0, _core_utils.log2)(symbols.length + numberOfNewSymbols); - var decoder = decodingContext.decoder; - var contextCache = decodingContext.contextCache; - let tableB1, symbolWidths; - - if (huffman) { - tableB1 = getStandardTable(1); - symbolWidths = []; - symbolCodeLength = Math.max(symbolCodeLength, 1); - } - - while (newSymbols.length < numberOfNewSymbols) { - var deltaHeight = huffman ? huffmanTables.tableDeltaHeight.decode(huffmanInput) : decodeInteger(contextCache, "IADH", decoder); - currentHeight += deltaHeight; - let currentWidth = 0, - totalWidth = 0; - const firstSymbol = huffman ? symbolWidths.length : 0; - - while (true) { - var deltaWidth = huffman ? huffmanTables.tableDeltaWidth.decode(huffmanInput) : decodeInteger(contextCache, "IADW", decoder); - - if (deltaWidth === null) { - break; - } - - currentWidth += deltaWidth; - totalWidth += currentWidth; - var bitmap; - - if (refinement) { - var numberOfInstances = decodeInteger(contextCache, "IAAI", decoder); - - if (numberOfInstances > 1) { - bitmap = decodeTextRegion(huffman, refinement, currentWidth, currentHeight, 0, numberOfInstances, 1, symbols.concat(newSymbols), symbolCodeLength, 0, 0, 1, 0, huffmanTables, refinementTemplateIndex, refinementAt, decodingContext, 0, huffmanInput); - } else { - var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength); - var rdx = decodeInteger(contextCache, "IARDX", decoder); - var rdy = decodeInteger(contextCache, "IARDY", decoder); - var symbol = symbolId < symbols.length ? symbols[symbolId] : newSymbols[symbolId - symbols.length]; - bitmap = decodeRefinement(currentWidth, currentHeight, refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt, decodingContext); - } - - newSymbols.push(bitmap); - } else if (huffman) { - symbolWidths.push(currentWidth); - } else { - bitmap = decodeBitmap(false, currentWidth, currentHeight, templateIndex, false, null, at, decodingContext); - newSymbols.push(bitmap); - } - } - - if (huffman && !refinement) { - const bitmapSize = huffmanTables.tableBitmapSize.decode(huffmanInput); - huffmanInput.byteAlign(); - let collectiveBitmap; - - if (bitmapSize === 0) { - collectiveBitmap = readUncompressedBitmap(huffmanInput, totalWidth, currentHeight); - } else { - const originalEnd = huffmanInput.end; - const bitmapEnd = huffmanInput.position + bitmapSize; - huffmanInput.end = bitmapEnd; - collectiveBitmap = decodeMMRBitmap(huffmanInput, totalWidth, currentHeight, false); - huffmanInput.end = originalEnd; - huffmanInput.position = bitmapEnd; - } - - const numberOfSymbolsDecoded = symbolWidths.length; - - if (firstSymbol === numberOfSymbolsDecoded - 1) { - newSymbols.push(collectiveBitmap); - } else { - let i, - y, - xMin = 0, - xMax, - bitmapWidth, - symbolBitmap; - - for (i = firstSymbol; i < numberOfSymbolsDecoded; i++) { - bitmapWidth = symbolWidths[i]; - xMax = xMin + bitmapWidth; - symbolBitmap = []; - - for (y = 0; y < currentHeight; y++) { - symbolBitmap.push(collectiveBitmap[y].subarray(xMin, xMax)); - } - - newSymbols.push(symbolBitmap); - xMin = xMax; - } - } - } - } - - var exportedSymbols = []; - var flags = [], - currentFlag = false; - var totalSymbolsLength = symbols.length + numberOfNewSymbols; - - while (flags.length < totalSymbolsLength) { - var runLength = huffman ? tableB1.decode(huffmanInput) : decodeInteger(contextCache, "IAEX", decoder); - - while (runLength--) { - flags.push(currentFlag); - } - - currentFlag = !currentFlag; - } - - for (var i = 0, ii = symbols.length; i < ii; i++) { - if (flags[i]) { - exportedSymbols.push(symbols[i]); - } - } - - for (var j = 0; j < numberOfNewSymbols; i++, j++) { - if (flags[i]) { - exportedSymbols.push(newSymbols[j]); - } - } - - return exportedSymbols; - } - - function decodeTextRegion(huffman, refinement, width, height, defaultPixelValue, numberOfSymbolInstances, stripSize, inputSymbols, symbolCodeLength, transposed, dsOffset, referenceCorner, combinationOperator, huffmanTables, refinementTemplateIndex, refinementAt, decodingContext, logStripSize, huffmanInput) { - if (huffman && refinement) { - throw new Jbig2Error("refinement with Huffman is not supported"); - } - - var bitmap = []; - var i, row; - - for (i = 0; i < height; i++) { - row = new Uint8Array(width); - - if (defaultPixelValue) { - for (var j = 0; j < width; j++) { - row[j] = defaultPixelValue; - } - } - - bitmap.push(row); - } - - var decoder = decodingContext.decoder; - var contextCache = decodingContext.contextCache; - var stripT = huffman ? -huffmanTables.tableDeltaT.decode(huffmanInput) : -decodeInteger(contextCache, "IADT", decoder); - var firstS = 0; - i = 0; - - while (i < numberOfSymbolInstances) { - var deltaT = huffman ? huffmanTables.tableDeltaT.decode(huffmanInput) : decodeInteger(contextCache, "IADT", decoder); - stripT += deltaT; - var deltaFirstS = huffman ? huffmanTables.tableFirstS.decode(huffmanInput) : decodeInteger(contextCache, "IAFS", decoder); - firstS += deltaFirstS; - var currentS = firstS; - - do { - let currentT = 0; - - if (stripSize > 1) { - currentT = huffman ? huffmanInput.readBits(logStripSize) : decodeInteger(contextCache, "IAIT", decoder); - } - - var t = stripSize * stripT + currentT; - var symbolId = huffman ? huffmanTables.symbolIDTable.decode(huffmanInput) : decodeIAID(contextCache, decoder, symbolCodeLength); - var applyRefinement = refinement && (huffman ? huffmanInput.readBit() : decodeInteger(contextCache, "IARI", decoder)); - var symbolBitmap = inputSymbols[symbolId]; - var symbolWidth = symbolBitmap[0].length; - var symbolHeight = symbolBitmap.length; - - if (applyRefinement) { - var rdw = decodeInteger(contextCache, "IARDW", decoder); - var rdh = decodeInteger(contextCache, "IARDH", decoder); - var rdx = decodeInteger(contextCache, "IARDX", decoder); - var rdy = decodeInteger(contextCache, "IARDY", decoder); - symbolWidth += rdw; - symbolHeight += rdh; - symbolBitmap = decodeRefinement(symbolWidth, symbolHeight, refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx, (rdh >> 1) + rdy, false, refinementAt, decodingContext); - } - - var offsetT = t - (referenceCorner & 1 ? 0 : symbolHeight - 1); - var offsetS = currentS - (referenceCorner & 2 ? symbolWidth - 1 : 0); - var s2, t2, symbolRow; - - if (transposed) { - for (s2 = 0; s2 < symbolHeight; s2++) { - row = bitmap[offsetS + s2]; - - if (!row) { - continue; - } - - symbolRow = symbolBitmap[s2]; - var maxWidth = Math.min(width - offsetT, symbolWidth); - - switch (combinationOperator) { - case 0: - for (t2 = 0; t2 < maxWidth; t2++) { - row[offsetT + t2] |= symbolRow[t2]; - } - - break; - - case 2: - for (t2 = 0; t2 < maxWidth; t2++) { - row[offsetT + t2] ^= symbolRow[t2]; - } - - break; - - default: - throw new Jbig2Error(`operator ${combinationOperator} is not supported`); - } - } - - currentS += symbolHeight - 1; - } else { - for (t2 = 0; t2 < symbolHeight; t2++) { - row = bitmap[offsetT + t2]; - - if (!row) { - continue; - } - - symbolRow = symbolBitmap[t2]; - - switch (combinationOperator) { - case 0: - for (s2 = 0; s2 < symbolWidth; s2++) { - row[offsetS + s2] |= symbolRow[s2]; - } - - break; - - case 2: - for (s2 = 0; s2 < symbolWidth; s2++) { - row[offsetS + s2] ^= symbolRow[s2]; - } - - break; - - default: - throw new Jbig2Error(`operator ${combinationOperator} is not supported`); - } - } - - currentS += symbolWidth - 1; - } - - i++; - var deltaS = huffman ? huffmanTables.tableDeltaS.decode(huffmanInput) : decodeInteger(contextCache, "IADS", decoder); - - if (deltaS === null) { - break; - } - - currentS += deltaS + dsOffset; - } while (true); - } - - return bitmap; - } - - function decodePatternDictionary(mmr, patternWidth, patternHeight, maxPatternIndex, template, decodingContext) { - const at = []; - - if (!mmr) { - at.push({ - x: -patternWidth, - y: 0 - }); - - if (template === 0) { - at.push({ - x: -3, - y: -1 - }); - at.push({ - x: 2, - y: -2 - }); - at.push({ - x: -2, - y: -2 - }); - } - } - - const collectiveWidth = (maxPatternIndex + 1) * patternWidth; - const collectiveBitmap = decodeBitmap(mmr, collectiveWidth, patternHeight, template, false, null, at, decodingContext); - const patterns = []; - - for (let i = 0; i <= maxPatternIndex; i++) { - const patternBitmap = []; - const xMin = patternWidth * i; - const xMax = xMin + patternWidth; - - for (let y = 0; y < patternHeight; y++) { - patternBitmap.push(collectiveBitmap[y].subarray(xMin, xMax)); - } - - patterns.push(patternBitmap); - } - - return patterns; - } - - function decodeHalftoneRegion(mmr, patterns, template, regionWidth, regionHeight, defaultPixelValue, enableSkip, combinationOperator, gridWidth, gridHeight, gridOffsetX, gridOffsetY, gridVectorX, gridVectorY, decodingContext) { - const skip = null; - - if (enableSkip) { - throw new Jbig2Error("skip is not supported"); - } - - if (combinationOperator !== 0) { - throw new Jbig2Error("operator " + combinationOperator + " is not supported in halftone region"); - } - - const regionBitmap = []; - let i, j, row; - - for (i = 0; i < regionHeight; i++) { - row = new Uint8Array(regionWidth); - - if (defaultPixelValue) { - for (j = 0; j < regionWidth; j++) { - row[j] = defaultPixelValue; - } - } - - regionBitmap.push(row); - } - - const numberOfPatterns = patterns.length; - const pattern0 = patterns[0]; - const patternWidth = pattern0[0].length, - patternHeight = pattern0.length; - const bitsPerValue = (0, _core_utils.log2)(numberOfPatterns); - const at = []; - - if (!mmr) { - at.push({ - x: template <= 1 ? 3 : 2, - y: -1 - }); - - if (template === 0) { - at.push({ - x: -3, - y: -1 - }); - at.push({ - x: 2, - y: -2 - }); - at.push({ - x: -2, - y: -2 - }); - } - } - - const grayScaleBitPlanes = []; - let mmrInput, bitmap; - - if (mmr) { - mmrInput = new Reader(decodingContext.data, decodingContext.start, decodingContext.end); - } - - for (i = bitsPerValue - 1; i >= 0; i--) { - if (mmr) { - bitmap = decodeMMRBitmap(mmrInput, gridWidth, gridHeight, true); - } else { - bitmap = decodeBitmap(false, gridWidth, gridHeight, template, false, skip, at, decodingContext); - } - - grayScaleBitPlanes[i] = bitmap; - } - - let mg, ng, bit, patternIndex, patternBitmap, x, y, patternRow, regionRow; - - for (mg = 0; mg < gridHeight; mg++) { - for (ng = 0; ng < gridWidth; ng++) { - bit = 0; - patternIndex = 0; - - for (j = bitsPerValue - 1; j >= 0; j--) { - bit = grayScaleBitPlanes[j][mg][ng] ^ bit; - patternIndex |= bit << j; - } - - patternBitmap = patterns[patternIndex]; - x = gridOffsetX + mg * gridVectorY + ng * gridVectorX >> 8; - y = gridOffsetY + mg * gridVectorX - ng * gridVectorY >> 8; - - if (x >= 0 && x + patternWidth <= regionWidth && y >= 0 && y + patternHeight <= regionHeight) { - for (i = 0; i < patternHeight; i++) { - regionRow = regionBitmap[y + i]; - patternRow = patternBitmap[i]; - - for (j = 0; j < patternWidth; j++) { - regionRow[x + j] |= patternRow[j]; - } - } - } else { - let regionX, regionY; - - for (i = 0; i < patternHeight; i++) { - regionY = y + i; - - if (regionY < 0 || regionY >= regionHeight) { - continue; - } - - regionRow = regionBitmap[regionY]; - patternRow = patternBitmap[i]; - - for (j = 0; j < patternWidth; j++) { - regionX = x + j; - - if (regionX >= 0 && regionX < regionWidth) { - regionRow[regionX] |= patternRow[j]; - } - } - } - } - } - } - - return regionBitmap; - } - - function readSegmentHeader(data, start) { - var segmentHeader = {}; - segmentHeader.number = (0, _core_utils.readUint32)(data, start); - var flags = data[start + 4]; - var segmentType = flags & 0x3f; - - if (!SegmentTypes[segmentType]) { - throw new Jbig2Error("invalid segment type: " + segmentType); - } - - segmentHeader.type = segmentType; - segmentHeader.typeName = SegmentTypes[segmentType]; - segmentHeader.deferredNonRetain = !!(flags & 0x80); - var pageAssociationFieldSize = !!(flags & 0x40); - var referredFlags = data[start + 5]; - var referredToCount = referredFlags >> 5 & 7; - var retainBits = [referredFlags & 31]; - var position = start + 6; - - if (referredFlags === 7) { - referredToCount = (0, _core_utils.readUint32)(data, position - 1) & 0x1fffffff; - position += 3; - var bytes = referredToCount + 7 >> 3; - retainBits[0] = data[position++]; - - while (--bytes > 0) { - retainBits.push(data[position++]); - } - } else if (referredFlags === 5 || referredFlags === 6) { - throw new Jbig2Error("invalid referred-to flags"); - } - - segmentHeader.retainBits = retainBits; - let referredToSegmentNumberSize = 4; - - if (segmentHeader.number <= 256) { - referredToSegmentNumberSize = 1; - } else if (segmentHeader.number <= 65536) { - referredToSegmentNumberSize = 2; - } - - var referredTo = []; - var i, ii; - - for (i = 0; i < referredToCount; i++) { - let number; - - if (referredToSegmentNumberSize === 1) { - number = data[position]; - } else if (referredToSegmentNumberSize === 2) { - number = (0, _core_utils.readUint16)(data, position); - } else { - number = (0, _core_utils.readUint32)(data, position); - } - - referredTo.push(number); - position += referredToSegmentNumberSize; - } - - segmentHeader.referredTo = referredTo; - - if (!pageAssociationFieldSize) { - segmentHeader.pageAssociation = data[position++]; - } else { - segmentHeader.pageAssociation = (0, _core_utils.readUint32)(data, position); - position += 4; - } - - segmentHeader.length = (0, _core_utils.readUint32)(data, position); - position += 4; - - if (segmentHeader.length === 0xffffffff) { - if (segmentType === 38) { - var genericRegionInfo = readRegionSegmentInformation(data, position); - var genericRegionSegmentFlags = data[position + RegionSegmentInformationFieldLength]; - var genericRegionMmr = !!(genericRegionSegmentFlags & 1); - var searchPatternLength = 6; - var searchPattern = new Uint8Array(searchPatternLength); - - if (!genericRegionMmr) { - searchPattern[0] = 0xff; - searchPattern[1] = 0xac; - } - - searchPattern[2] = genericRegionInfo.height >>> 24 & 0xff; - searchPattern[3] = genericRegionInfo.height >> 16 & 0xff; - searchPattern[4] = genericRegionInfo.height >> 8 & 0xff; - searchPattern[5] = genericRegionInfo.height & 0xff; - - for (i = position, ii = data.length; i < ii; i++) { - var j = 0; - - while (j < searchPatternLength && searchPattern[j] === data[i + j]) { - j++; - } - - if (j === searchPatternLength) { - segmentHeader.length = i + searchPatternLength; - break; - } - } - - if (segmentHeader.length === 0xffffffff) { - throw new Jbig2Error("segment end was not found"); - } - } else { - throw new Jbig2Error("invalid unknown segment length"); - } - } - - segmentHeader.headerEnd = position; - return segmentHeader; - } - - function readSegments(header, data, start, end) { - var segments = []; - var position = start; - - while (position < end) { - var segmentHeader = readSegmentHeader(data, position); - position = segmentHeader.headerEnd; - var segment = { - header: segmentHeader, - data - }; - - if (!header.randomAccess) { - segment.start = position; - position += segmentHeader.length; - segment.end = position; - } - - segments.push(segment); - - if (segmentHeader.type === 51) { - break; - } - } - - if (header.randomAccess) { - for (var i = 0, ii = segments.length; i < ii; i++) { - segments[i].start = position; - position += segments[i].header.length; - segments[i].end = position; - } - } - - return segments; - } - - function readRegionSegmentInformation(data, start) { - return { - width: (0, _core_utils.readUint32)(data, start), - height: (0, _core_utils.readUint32)(data, start + 4), - x: (0, _core_utils.readUint32)(data, start + 8), - y: (0, _core_utils.readUint32)(data, start + 12), - combinationOperator: data[start + 16] & 7 - }; - } - - var RegionSegmentInformationFieldLength = 17; - - function processSegment(segment, visitor) { - var header = segment.header; - var data = segment.data, - position = segment.start, - end = segment.end; - var args, at, i, atLength; - - switch (header.type) { - case 0: - var dictionary = {}; - var dictionaryFlags = (0, _core_utils.readUint16)(data, position); - dictionary.huffman = !!(dictionaryFlags & 1); - dictionary.refinement = !!(dictionaryFlags & 2); - dictionary.huffmanDHSelector = dictionaryFlags >> 2 & 3; - dictionary.huffmanDWSelector = dictionaryFlags >> 4 & 3; - dictionary.bitmapSizeSelector = dictionaryFlags >> 6 & 1; - dictionary.aggregationInstancesSelector = dictionaryFlags >> 7 & 1; - dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256); - dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512); - dictionary.template = dictionaryFlags >> 10 & 3; - dictionary.refinementTemplate = dictionaryFlags >> 12 & 1; - position += 2; - - if (!dictionary.huffman) { - atLength = dictionary.template === 0 ? 4 : 1; - at = []; - - for (i = 0; i < atLength; i++) { - at.push({ - x: (0, _core_utils.readInt8)(data, position), - y: (0, _core_utils.readInt8)(data, position + 1) - }); - position += 2; - } - - dictionary.at = at; - } - - if (dictionary.refinement && !dictionary.refinementTemplate) { - at = []; - - for (i = 0; i < 2; i++) { - at.push({ - x: (0, _core_utils.readInt8)(data, position), - y: (0, _core_utils.readInt8)(data, position + 1) - }); - position += 2; - } - - dictionary.refinementAt = at; - } - - dictionary.numberOfExportedSymbols = (0, _core_utils.readUint32)(data, position); - position += 4; - dictionary.numberOfNewSymbols = (0, _core_utils.readUint32)(data, position); - position += 4; - args = [dictionary, header.number, header.referredTo, data, position, end]; - break; - - case 6: - case 7: - var textRegion = {}; - textRegion.info = readRegionSegmentInformation(data, position); - position += RegionSegmentInformationFieldLength; - var textRegionSegmentFlags = (0, _core_utils.readUint16)(data, position); - position += 2; - textRegion.huffman = !!(textRegionSegmentFlags & 1); - textRegion.refinement = !!(textRegionSegmentFlags & 2); - textRegion.logStripSize = textRegionSegmentFlags >> 2 & 3; - textRegion.stripSize = 1 << textRegion.logStripSize; - textRegion.referenceCorner = textRegionSegmentFlags >> 4 & 3; - textRegion.transposed = !!(textRegionSegmentFlags & 64); - textRegion.combinationOperator = textRegionSegmentFlags >> 7 & 3; - textRegion.defaultPixelValue = textRegionSegmentFlags >> 9 & 1; - textRegion.dsOffset = textRegionSegmentFlags << 17 >> 27; - textRegion.refinementTemplate = textRegionSegmentFlags >> 15 & 1; - - if (textRegion.huffman) { - var textRegionHuffmanFlags = (0, _core_utils.readUint16)(data, position); - position += 2; - textRegion.huffmanFS = textRegionHuffmanFlags & 3; - textRegion.huffmanDS = textRegionHuffmanFlags >> 2 & 3; - textRegion.huffmanDT = textRegionHuffmanFlags >> 4 & 3; - textRegion.huffmanRefinementDW = textRegionHuffmanFlags >> 6 & 3; - textRegion.huffmanRefinementDH = textRegionHuffmanFlags >> 8 & 3; - textRegion.huffmanRefinementDX = textRegionHuffmanFlags >> 10 & 3; - textRegion.huffmanRefinementDY = textRegionHuffmanFlags >> 12 & 3; - textRegion.huffmanRefinementSizeSelector = !!(textRegionHuffmanFlags & 0x4000); - } - - if (textRegion.refinement && !textRegion.refinementTemplate) { - at = []; - - for (i = 0; i < 2; i++) { - at.push({ - x: (0, _core_utils.readInt8)(data, position), - y: (0, _core_utils.readInt8)(data, position + 1) - }); - position += 2; - } - - textRegion.refinementAt = at; - } - - textRegion.numberOfSymbolInstances = (0, _core_utils.readUint32)(data, position); - position += 4; - args = [textRegion, header.referredTo, data, position, end]; - break; - - case 16: - const patternDictionary = {}; - const patternDictionaryFlags = data[position++]; - patternDictionary.mmr = !!(patternDictionaryFlags & 1); - patternDictionary.template = patternDictionaryFlags >> 1 & 3; - patternDictionary.patternWidth = data[position++]; - patternDictionary.patternHeight = data[position++]; - patternDictionary.maxPatternIndex = (0, _core_utils.readUint32)(data, position); - position += 4; - args = [patternDictionary, header.number, data, position, end]; - break; - - case 22: - case 23: - const halftoneRegion = {}; - halftoneRegion.info = readRegionSegmentInformation(data, position); - position += RegionSegmentInformationFieldLength; - const halftoneRegionFlags = data[position++]; - halftoneRegion.mmr = !!(halftoneRegionFlags & 1); - halftoneRegion.template = halftoneRegionFlags >> 1 & 3; - halftoneRegion.enableSkip = !!(halftoneRegionFlags & 8); - halftoneRegion.combinationOperator = halftoneRegionFlags >> 4 & 7; - halftoneRegion.defaultPixelValue = halftoneRegionFlags >> 7 & 1; - halftoneRegion.gridWidth = (0, _core_utils.readUint32)(data, position); - position += 4; - halftoneRegion.gridHeight = (0, _core_utils.readUint32)(data, position); - position += 4; - halftoneRegion.gridOffsetX = (0, _core_utils.readUint32)(data, position) & 0xffffffff; - position += 4; - halftoneRegion.gridOffsetY = (0, _core_utils.readUint32)(data, position) & 0xffffffff; - position += 4; - halftoneRegion.gridVectorX = (0, _core_utils.readUint16)(data, position); - position += 2; - halftoneRegion.gridVectorY = (0, _core_utils.readUint16)(data, position); - position += 2; - args = [halftoneRegion, header.referredTo, data, position, end]; - break; - - case 38: - case 39: - var genericRegion = {}; - genericRegion.info = readRegionSegmentInformation(data, position); - position += RegionSegmentInformationFieldLength; - var genericRegionSegmentFlags = data[position++]; - genericRegion.mmr = !!(genericRegionSegmentFlags & 1); - genericRegion.template = genericRegionSegmentFlags >> 1 & 3; - genericRegion.prediction = !!(genericRegionSegmentFlags & 8); - - if (!genericRegion.mmr) { - atLength = genericRegion.template === 0 ? 4 : 1; - at = []; - - for (i = 0; i < atLength; i++) { - at.push({ - x: (0, _core_utils.readInt8)(data, position), - y: (0, _core_utils.readInt8)(data, position + 1) - }); - position += 2; - } - - genericRegion.at = at; - } - - args = [genericRegion, data, position, end]; - break; - - case 48: - var pageInfo = { - width: (0, _core_utils.readUint32)(data, position), - height: (0, _core_utils.readUint32)(data, position + 4), - resolutionX: (0, _core_utils.readUint32)(data, position + 8), - resolutionY: (0, _core_utils.readUint32)(data, position + 12) - }; - - if (pageInfo.height === 0xffffffff) { - delete pageInfo.height; - } - - var pageSegmentFlags = data[position + 16]; - (0, _core_utils.readUint16)(data, position + 17); - pageInfo.lossless = !!(pageSegmentFlags & 1); - pageInfo.refinement = !!(pageSegmentFlags & 2); - pageInfo.defaultPixelValue = pageSegmentFlags >> 2 & 1; - pageInfo.combinationOperator = pageSegmentFlags >> 3 & 3; - pageInfo.requiresBuffer = !!(pageSegmentFlags & 32); - pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64); - args = [pageInfo]; - break; - - case 49: - break; - - case 50: - break; - - case 51: - break; - - case 53: - args = [header.number, data, position, end]; - break; - - case 62: - break; - - default: - throw new Jbig2Error(`segment type ${header.typeName}(${header.type})` + " is not implemented"); - } - - var callbackName = "on" + header.typeName; - - if (callbackName in visitor) { - visitor[callbackName].apply(visitor, args); - } - } - - function processSegments(segments, visitor) { - for (var i = 0, ii = segments.length; i < ii; i++) { - processSegment(segments[i], visitor); - } - } - - function parseJbig2Chunks(chunks) { - var visitor = new SimpleSegmentVisitor(); - - for (var i = 0, ii = chunks.length; i < ii; i++) { - var chunk = chunks[i]; - var segments = readSegments({}, chunk.data, chunk.start, chunk.end); - processSegments(segments, visitor); - } - - return visitor.buffer; - } - - function parseJbig2(data) { - const end = data.length; - let position = 0; - - if (data[position] !== 0x97 || data[position + 1] !== 0x4a || data[position + 2] !== 0x42 || data[position + 3] !== 0x32 || data[position + 4] !== 0x0d || data[position + 5] !== 0x0a || data[position + 6] !== 0x1a || data[position + 7] !== 0x0a) { - throw new Jbig2Error("parseJbig2 - invalid header."); - } - - const header = Object.create(null); - position += 8; - const flags = data[position++]; - header.randomAccess = !(flags & 1); - - if (!(flags & 2)) { - header.numberOfPages = (0, _core_utils.readUint32)(data, position); - position += 4; - } - - const segments = readSegments(header, data, position, end); - const visitor = new SimpleSegmentVisitor(); - processSegments(segments, visitor); - const { - width, - height - } = visitor.currentPageInfo; - const bitPacked = visitor.buffer; - const imgData = new Uint8ClampedArray(width * height); - let q = 0, - k = 0; - - for (let i = 0; i < height; i++) { - let mask = 0, - buffer; - - for (let j = 0; j < width; j++) { - if (!mask) { - mask = 128; - buffer = bitPacked[k++]; - } - - imgData[q++] = buffer & mask ? 0 : 255; - mask >>= 1; - } - } - - return { - imgData, - width, - height - }; - } - - function SimpleSegmentVisitor() {} - - SimpleSegmentVisitor.prototype = { - onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) { - this.currentPageInfo = info; - var rowSize = info.width + 7 >> 3; - var buffer = new Uint8ClampedArray(rowSize * info.height); - - if (info.defaultPixelValue) { - for (var i = 0, ii = buffer.length; i < ii; i++) { - buffer[i] = 0xff; - } - } - - this.buffer = buffer; - }, - drawBitmap: function SimpleSegmentVisitor_drawBitmap(regionInfo, bitmap) { - var pageInfo = this.currentPageInfo; - var width = regionInfo.width, - height = regionInfo.height; - var rowSize = pageInfo.width + 7 >> 3; - var combinationOperator = pageInfo.combinationOperatorOverride ? regionInfo.combinationOperator : pageInfo.combinationOperator; - var buffer = this.buffer; - var mask0 = 128 >> (regionInfo.x & 7); - var offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3); - var i, j, mask, offset; - - switch (combinationOperator) { - case 0: - for (i = 0; i < height; i++) { - mask = mask0; - offset = offset0; - - for (j = 0; j < width; j++) { - if (bitmap[i][j]) { - buffer[offset] |= mask; - } - - mask >>= 1; - - if (!mask) { - mask = 128; - offset++; - } - } - - offset0 += rowSize; - } - - break; - - case 2: - for (i = 0; i < height; i++) { - mask = mask0; - offset = offset0; - - for (j = 0; j < width; j++) { - if (bitmap[i][j]) { - buffer[offset] ^= mask; - } - - mask >>= 1; - - if (!mask) { - mask = 128; - offset++; - } - } - - offset0 += rowSize; - } - - break; - - default: - throw new Jbig2Error(`operator ${combinationOperator} is not supported`); - } - }, - onImmediateGenericRegion: function SimpleSegmentVisitor_onImmediateGenericRegion(region, data, start, end) { - var regionInfo = region.info; - var decodingContext = new DecodingContext(data, start, end); - var bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height, region.template, region.prediction, null, region.at, decodingContext); - this.drawBitmap(regionInfo, bitmap); - }, - onImmediateLosslessGenericRegion: function SimpleSegmentVisitor_onImmediateLosslessGenericRegion() { - this.onImmediateGenericRegion.apply(this, arguments); - }, - onSymbolDictionary: function SimpleSegmentVisitor_onSymbolDictionary(dictionary, currentSegment, referredSegments, data, start, end) { - let huffmanTables, huffmanInput; - - if (dictionary.huffman) { - huffmanTables = getSymbolDictionaryHuffmanTables(dictionary, referredSegments, this.customTables); - huffmanInput = new Reader(data, start, end); - } - - var symbols = this.symbols; - - if (!symbols) { - this.symbols = symbols = {}; - } - - var inputSymbols = []; - - for (var i = 0, ii = referredSegments.length; i < ii; i++) { - const referredSymbols = symbols[referredSegments[i]]; - - if (referredSymbols) { - inputSymbols = inputSymbols.concat(referredSymbols); - } - } - - var decodingContext = new DecodingContext(data, start, end); - symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman, dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols, dictionary.numberOfExportedSymbols, huffmanTables, dictionary.template, dictionary.at, dictionary.refinementTemplate, dictionary.refinementAt, decodingContext, huffmanInput); - }, - onImmediateTextRegion: function SimpleSegmentVisitor_onImmediateTextRegion(region, referredSegments, data, start, end) { - var regionInfo = region.info; - let huffmanTables, huffmanInput; - var symbols = this.symbols; - var inputSymbols = []; - - for (var i = 0, ii = referredSegments.length; i < ii; i++) { - const referredSymbols = symbols[referredSegments[i]]; - - if (referredSymbols) { - inputSymbols = inputSymbols.concat(referredSymbols); - } - } - - var symbolCodeLength = (0, _core_utils.log2)(inputSymbols.length); - - if (region.huffman) { - huffmanInput = new Reader(data, start, end); - huffmanTables = getTextRegionHuffmanTables(region, referredSegments, this.customTables, inputSymbols.length, huffmanInput); - } - - var decodingContext = new DecodingContext(data, start, end); - var bitmap = decodeTextRegion(region.huffman, region.refinement, regionInfo.width, regionInfo.height, region.defaultPixelValue, region.numberOfSymbolInstances, region.stripSize, inputSymbols, symbolCodeLength, region.transposed, region.dsOffset, region.referenceCorner, region.combinationOperator, huffmanTables, region.refinementTemplate, region.refinementAt, decodingContext, region.logStripSize, huffmanInput); - this.drawBitmap(regionInfo, bitmap); - }, - onImmediateLosslessTextRegion: function SimpleSegmentVisitor_onImmediateLosslessTextRegion() { - this.onImmediateTextRegion.apply(this, arguments); - }, - - onPatternDictionary(dictionary, currentSegment, data, start, end) { - let patterns = this.patterns; - - if (!patterns) { - this.patterns = patterns = {}; - } - - const decodingContext = new DecodingContext(data, start, end); - patterns[currentSegment] = decodePatternDictionary(dictionary.mmr, dictionary.patternWidth, dictionary.patternHeight, dictionary.maxPatternIndex, dictionary.template, decodingContext); - }, - - onImmediateHalftoneRegion(region, referredSegments, data, start, end) { - const patterns = this.patterns[referredSegments[0]]; - const regionInfo = region.info; - const decodingContext = new DecodingContext(data, start, end); - const bitmap = decodeHalftoneRegion(region.mmr, patterns, region.template, regionInfo.width, regionInfo.height, region.defaultPixelValue, region.enableSkip, region.combinationOperator, region.gridWidth, region.gridHeight, region.gridOffsetX, region.gridOffsetY, region.gridVectorX, region.gridVectorY, decodingContext); - this.drawBitmap(regionInfo, bitmap); - }, - - onImmediateLosslessHalftoneRegion() { - this.onImmediateHalftoneRegion.apply(this, arguments); - }, - - onTables(currentSegment, data, start, end) { - let customTables = this.customTables; - - if (!customTables) { - this.customTables = customTables = {}; - } - - customTables[currentSegment] = decodeTablesSegment(data, start, end); - } - - }; - - function HuffmanLine(lineData) { - if (lineData.length === 2) { - this.isOOB = true; - this.rangeLow = 0; - this.prefixLength = lineData[0]; - this.rangeLength = 0; - this.prefixCode = lineData[1]; - this.isLowerRange = false; - } else { - this.isOOB = false; - this.rangeLow = lineData[0]; - this.prefixLength = lineData[1]; - this.rangeLength = lineData[2]; - this.prefixCode = lineData[3]; - this.isLowerRange = lineData[4] === "lower"; - } - } - - function HuffmanTreeNode(line) { - this.children = []; - - if (line) { - this.isLeaf = true; - this.rangeLength = line.rangeLength; - this.rangeLow = line.rangeLow; - this.isLowerRange = line.isLowerRange; - this.isOOB = line.isOOB; - } else { - this.isLeaf = false; - } - } - - HuffmanTreeNode.prototype = { - buildTree(line, shift) { - const bit = line.prefixCode >> shift & 1; - - if (shift <= 0) { - this.children[bit] = new HuffmanTreeNode(line); - } else { - let node = this.children[bit]; - - if (!node) { - this.children[bit] = node = new HuffmanTreeNode(null); - } - - node.buildTree(line, shift - 1); - } - }, - - decodeNode(reader) { - if (this.isLeaf) { - if (this.isOOB) { - return null; - } - - const htOffset = reader.readBits(this.rangeLength); - return this.rangeLow + (this.isLowerRange ? -htOffset : htOffset); - } - - const node = this.children[reader.readBit()]; - - if (!node) { - throw new Jbig2Error("invalid Huffman data"); - } - - return node.decodeNode(reader); - } - - }; - - function HuffmanTable(lines, prefixCodesDone) { - if (!prefixCodesDone) { - this.assignPrefixCodes(lines); - } - - this.rootNode = new HuffmanTreeNode(null); - - for (let i = 0, ii = lines.length; i < ii; i++) { - const line = lines[i]; - - if (line.prefixLength > 0) { - this.rootNode.buildTree(line, line.prefixLength - 1); - } - } - } - - HuffmanTable.prototype = { - decode(reader) { - return this.rootNode.decodeNode(reader); - }, - - assignPrefixCodes(lines) { - const linesLength = lines.length; - let prefixLengthMax = 0; - - for (let i = 0; i < linesLength; i++) { - prefixLengthMax = Math.max(prefixLengthMax, lines[i].prefixLength); - } - - const histogram = new Uint32Array(prefixLengthMax + 1); - - for (let i = 0; i < linesLength; i++) { - histogram[lines[i].prefixLength]++; - } - - let currentLength = 1, - firstCode = 0, - currentCode, - currentTemp, - line; - histogram[0] = 0; - - while (currentLength <= prefixLengthMax) { - firstCode = firstCode + histogram[currentLength - 1] << 1; - currentCode = firstCode; - currentTemp = 0; - - while (currentTemp < linesLength) { - line = lines[currentTemp]; - - if (line.prefixLength === currentLength) { - line.prefixCode = currentCode; - currentCode++; - } - - currentTemp++; - } - - currentLength++; - } - } - - }; - - function decodeTablesSegment(data, start, end) { - const flags = data[start]; - const lowestValue = (0, _core_utils.readUint32)(data, start + 1) & 0xffffffff; - const highestValue = (0, _core_utils.readUint32)(data, start + 5) & 0xffffffff; - const reader = new Reader(data, start + 9, end); - const prefixSizeBits = (flags >> 1 & 7) + 1; - const rangeSizeBits = (flags >> 4 & 7) + 1; - const lines = []; - let prefixLength, - rangeLength, - currentRangeLow = lowestValue; - - do { - prefixLength = reader.readBits(prefixSizeBits); - rangeLength = reader.readBits(rangeSizeBits); - lines.push(new HuffmanLine([currentRangeLow, prefixLength, rangeLength, 0])); - currentRangeLow += 1 << rangeLength; - } while (currentRangeLow < highestValue); - - prefixLength = reader.readBits(prefixSizeBits); - lines.push(new HuffmanLine([lowestValue - 1, prefixLength, 32, 0, "lower"])); - prefixLength = reader.readBits(prefixSizeBits); - lines.push(new HuffmanLine([highestValue, prefixLength, 32, 0])); - - if (flags & 1) { - prefixLength = reader.readBits(prefixSizeBits); - lines.push(new HuffmanLine([prefixLength, 0])); - } - - return new HuffmanTable(lines, false); - } - - const standardTablesCache = {}; - - function getStandardTable(number) { - let table = standardTablesCache[number]; - - if (table) { - return table; - } - - let lines; - - switch (number) { - case 1: - lines = [[0, 1, 4, 0x0], [16, 2, 8, 0x2], [272, 3, 16, 0x6], [65808, 3, 32, 0x7]]; - break; - - case 2: - lines = [[0, 1, 0, 0x0], [1, 2, 0, 0x2], [2, 3, 0, 0x6], [3, 4, 3, 0xe], [11, 5, 6, 0x1e], [75, 6, 32, 0x3e], [6, 0x3f]]; - break; - - case 3: - lines = [[-256, 8, 8, 0xfe], [0, 1, 0, 0x0], [1, 2, 0, 0x2], [2, 3, 0, 0x6], [3, 4, 3, 0xe], [11, 5, 6, 0x1e], [-257, 8, 32, 0xff, "lower"], [75, 7, 32, 0x7e], [6, 0x3e]]; - break; - - case 4: - lines = [[1, 1, 0, 0x0], [2, 2, 0, 0x2], [3, 3, 0, 0x6], [4, 4, 3, 0xe], [12, 5, 6, 0x1e], [76, 5, 32, 0x1f]]; - break; - - case 5: - lines = [[-255, 7, 8, 0x7e], [1, 1, 0, 0x0], [2, 2, 0, 0x2], [3, 3, 0, 0x6], [4, 4, 3, 0xe], [12, 5, 6, 0x1e], [-256, 7, 32, 0x7f, "lower"], [76, 6, 32, 0x3e]]; - break; - - case 6: - lines = [[-2048, 5, 10, 0x1c], [-1024, 4, 9, 0x8], [-512, 4, 8, 0x9], [-256, 4, 7, 0xa], [-128, 5, 6, 0x1d], [-64, 5, 5, 0x1e], [-32, 4, 5, 0xb], [0, 2, 7, 0x0], [128, 3, 7, 0x2], [256, 3, 8, 0x3], [512, 4, 9, 0xc], [1024, 4, 10, 0xd], [-2049, 6, 32, 0x3e, "lower"], [2048, 6, 32, 0x3f]]; - break; - - case 7: - lines = [[-1024, 4, 9, 0x8], [-512, 3, 8, 0x0], [-256, 4, 7, 0x9], [-128, 5, 6, 0x1a], [-64, 5, 5, 0x1b], [-32, 4, 5, 0xa], [0, 4, 5, 0xb], [32, 5, 5, 0x1c], [64, 5, 6, 0x1d], [128, 4, 7, 0xc], [256, 3, 8, 0x1], [512, 3, 9, 0x2], [1024, 3, 10, 0x3], [-1025, 5, 32, 0x1e, "lower"], [2048, 5, 32, 0x1f]]; - break; - - case 8: - lines = [[-15, 8, 3, 0xfc], [-7, 9, 1, 0x1fc], [-5, 8, 1, 0xfd], [-3, 9, 0, 0x1fd], [-2, 7, 0, 0x7c], [-1, 4, 0, 0xa], [0, 2, 1, 0x0], [2, 5, 0, 0x1a], [3, 6, 0, 0x3a], [4, 3, 4, 0x4], [20, 6, 1, 0x3b], [22, 4, 4, 0xb], [38, 4, 5, 0xc], [70, 5, 6, 0x1b], [134, 5, 7, 0x1c], [262, 6, 7, 0x3c], [390, 7, 8, 0x7d], [646, 6, 10, 0x3d], [-16, 9, 32, 0x1fe, "lower"], [1670, 9, 32, 0x1ff], [2, 0x1]]; - break; - - case 9: - lines = [[-31, 8, 4, 0xfc], [-15, 9, 2, 0x1fc], [-11, 8, 2, 0xfd], [-7, 9, 1, 0x1fd], [-5, 7, 1, 0x7c], [-3, 4, 1, 0xa], [-1, 3, 1, 0x2], [1, 3, 1, 0x3], [3, 5, 1, 0x1a], [5, 6, 1, 0x3a], [7, 3, 5, 0x4], [39, 6, 2, 0x3b], [43, 4, 5, 0xb], [75, 4, 6, 0xc], [139, 5, 7, 0x1b], [267, 5, 8, 0x1c], [523, 6, 8, 0x3c], [779, 7, 9, 0x7d], [1291, 6, 11, 0x3d], [-32, 9, 32, 0x1fe, "lower"], [3339, 9, 32, 0x1ff], [2, 0x0]]; - break; - - case 10: - lines = [[-21, 7, 4, 0x7a], [-5, 8, 0, 0xfc], [-4, 7, 0, 0x7b], [-3, 5, 0, 0x18], [-2, 2, 2, 0x0], [2, 5, 0, 0x19], [3, 6, 0, 0x36], [4, 7, 0, 0x7c], [5, 8, 0, 0xfd], [6, 2, 6, 0x1], [70, 5, 5, 0x1a], [102, 6, 5, 0x37], [134, 6, 6, 0x38], [198, 6, 7, 0x39], [326, 6, 8, 0x3a], [582, 6, 9, 0x3b], [1094, 6, 10, 0x3c], [2118, 7, 11, 0x7d], [-22, 8, 32, 0xfe, "lower"], [4166, 8, 32, 0xff], [2, 0x2]]; - break; - - case 11: - lines = [[1, 1, 0, 0x0], [2, 2, 1, 0x2], [4, 4, 0, 0xc], [5, 4, 1, 0xd], [7, 5, 1, 0x1c], [9, 5, 2, 0x1d], [13, 6, 2, 0x3c], [17, 7, 2, 0x7a], [21, 7, 3, 0x7b], [29, 7, 4, 0x7c], [45, 7, 5, 0x7d], [77, 7, 6, 0x7e], [141, 7, 32, 0x7f]]; - break; - - case 12: - lines = [[1, 1, 0, 0x0], [2, 2, 0, 0x2], [3, 3, 1, 0x6], [5, 5, 0, 0x1c], [6, 5, 1, 0x1d], [8, 6, 1, 0x3c], [10, 7, 0, 0x7a], [11, 7, 1, 0x7b], [13, 7, 2, 0x7c], [17, 7, 3, 0x7d], [25, 7, 4, 0x7e], [41, 8, 5, 0xfe], [73, 8, 32, 0xff]]; - break; - - case 13: - lines = [[1, 1, 0, 0x0], [2, 3, 0, 0x4], [3, 4, 0, 0xc], [4, 5, 0, 0x1c], [5, 4, 1, 0xd], [7, 3, 3, 0x5], [15, 6, 1, 0x3a], [17, 6, 2, 0x3b], [21, 6, 3, 0x3c], [29, 6, 4, 0x3d], [45, 6, 5, 0x3e], [77, 7, 6, 0x7e], [141, 7, 32, 0x7f]]; - break; - - case 14: - lines = [[-2, 3, 0, 0x4], [-1, 3, 0, 0x5], [0, 1, 0, 0x0], [1, 3, 0, 0x6], [2, 3, 0, 0x7]]; - break; - - case 15: - lines = [[-24, 7, 4, 0x7c], [-8, 6, 2, 0x3c], [-4, 5, 1, 0x1c], [-2, 4, 0, 0xc], [-1, 3, 0, 0x4], [0, 1, 0, 0x0], [1, 3, 0, 0x5], [2, 4, 0, 0xd], [3, 5, 1, 0x1d], [5, 6, 2, 0x3d], [9, 7, 4, 0x7d], [-25, 7, 32, 0x7e, "lower"], [25, 7, 32, 0x7f]]; - break; - - default: - throw new Jbig2Error(`standard table B.${number} does not exist`); - } - - for (let i = 0, ii = lines.length; i < ii; i++) { - lines[i] = new HuffmanLine(lines[i]); - } - - table = new HuffmanTable(lines, true); - standardTablesCache[number] = table; - return table; - } - - function Reader(data, start, end) { - this.data = data; - this.start = start; - this.end = end; - this.position = start; - this.shift = -1; - this.currentByte = 0; - } - - Reader.prototype = { - readBit() { - if (this.shift < 0) { - if (this.position >= this.end) { - throw new Jbig2Error("end of data while reading bit"); - } - - this.currentByte = this.data[this.position++]; - this.shift = 7; - } - - const bit = this.currentByte >> this.shift & 1; - this.shift--; - return bit; - }, - - readBits(numBits) { - let result = 0, - i; - - for (i = numBits - 1; i >= 0; i--) { - result |= this.readBit() << i; - } - - return result; - }, - - byteAlign() { - this.shift = -1; - }, - - next() { - if (this.position >= this.end) { - return -1; - } - - return this.data[this.position++]; - } - - }; - - function getCustomHuffmanTable(index, referredTo, customTables) { - let currentIndex = 0; - - for (let i = 0, ii = referredTo.length; i < ii; i++) { - const table = customTables[referredTo[i]]; - - if (table) { - if (index === currentIndex) { - return table; - } - - currentIndex++; - } - } - - throw new Jbig2Error("can't find custom Huffman table"); - } - - function getTextRegionHuffmanTables(textRegion, referredTo, customTables, numberOfSymbols, reader) { - const codes = []; - - for (let i = 0; i <= 34; i++) { - const codeLength = reader.readBits(4); - codes.push(new HuffmanLine([i, codeLength, 0, 0])); - } - - const runCodesTable = new HuffmanTable(codes, false); - codes.length = 0; - - for (let i = 0; i < numberOfSymbols;) { - const codeLength = runCodesTable.decode(reader); - - if (codeLength >= 32) { - let repeatedLength, numberOfRepeats, j; - - switch (codeLength) { - case 32: - if (i === 0) { - throw new Jbig2Error("no previous value in symbol ID table"); - } - - numberOfRepeats = reader.readBits(2) + 3; - repeatedLength = codes[i - 1].prefixLength; - break; - - case 33: - numberOfRepeats = reader.readBits(3) + 3; - repeatedLength = 0; - break; - - case 34: - numberOfRepeats = reader.readBits(7) + 11; - repeatedLength = 0; - break; - - default: - throw new Jbig2Error("invalid code length in symbol ID table"); - } - - for (j = 0; j < numberOfRepeats; j++) { - codes.push(new HuffmanLine([i, repeatedLength, 0, 0])); - i++; - } - } else { - codes.push(new HuffmanLine([i, codeLength, 0, 0])); - i++; - } - } - - reader.byteAlign(); - const symbolIDTable = new HuffmanTable(codes, false); - let customIndex = 0, - tableFirstS, - tableDeltaS, - tableDeltaT; - - switch (textRegion.huffmanFS) { - case 0: - case 1: - tableFirstS = getStandardTable(textRegion.huffmanFS + 6); - break; - - case 3: - tableFirstS = getCustomHuffmanTable(customIndex, referredTo, customTables); - customIndex++; - break; - - default: - throw new Jbig2Error("invalid Huffman FS selector"); - } - - switch (textRegion.huffmanDS) { - case 0: - case 1: - case 2: - tableDeltaS = getStandardTable(textRegion.huffmanDS + 8); - break; - - case 3: - tableDeltaS = getCustomHuffmanTable(customIndex, referredTo, customTables); - customIndex++; - break; - - default: - throw new Jbig2Error("invalid Huffman DS selector"); - } - - switch (textRegion.huffmanDT) { - case 0: - case 1: - case 2: - tableDeltaT = getStandardTable(textRegion.huffmanDT + 11); - break; - - case 3: - tableDeltaT = getCustomHuffmanTable(customIndex, referredTo, customTables); - customIndex++; - break; - - default: - throw new Jbig2Error("invalid Huffman DT selector"); - } - - if (textRegion.refinement) { - throw new Jbig2Error("refinement with Huffman is not supported"); - } - - return { - symbolIDTable, - tableFirstS, - tableDeltaS, - tableDeltaT - }; - } - - function getSymbolDictionaryHuffmanTables(dictionary, referredTo, customTables) { - let customIndex = 0, - tableDeltaHeight, - tableDeltaWidth; - - switch (dictionary.huffmanDHSelector) { - case 0: - case 1: - tableDeltaHeight = getStandardTable(dictionary.huffmanDHSelector + 4); - break; - - case 3: - tableDeltaHeight = getCustomHuffmanTable(customIndex, referredTo, customTables); - customIndex++; - break; - - default: - throw new Jbig2Error("invalid Huffman DH selector"); - } - - switch (dictionary.huffmanDWSelector) { - case 0: - case 1: - tableDeltaWidth = getStandardTable(dictionary.huffmanDWSelector + 2); - break; - - case 3: - tableDeltaWidth = getCustomHuffmanTable(customIndex, referredTo, customTables); - customIndex++; - break; - - default: - throw new Jbig2Error("invalid Huffman DW selector"); - } - - let tableBitmapSize, tableAggregateInstances; - - if (dictionary.bitmapSizeSelector) { - tableBitmapSize = getCustomHuffmanTable(customIndex, referredTo, customTables); - customIndex++; - } else { - tableBitmapSize = getStandardTable(1); - } - - if (dictionary.aggregationInstancesSelector) { - tableAggregateInstances = getCustomHuffmanTable(customIndex, referredTo, customTables); - } else { - tableAggregateInstances = getStandardTable(1); - } - - return { - tableDeltaHeight, - tableDeltaWidth, - tableBitmapSize, - tableAggregateInstances - }; - } - - function readUncompressedBitmap(reader, width, height) { - const bitmap = []; - - for (let y = 0; y < height; y++) { - const row = new Uint8Array(width); - bitmap.push(row); - - for (let x = 0; x < width; x++) { - row[x] = reader.readBit(); - } - - reader.byteAlign(); - } - - return bitmap; - } - - function decodeMMRBitmap(input, width, height, endOfBlock) { - const params = { - K: -1, - Columns: width, - Rows: height, - BlackIs1: true, - EndOfBlock: endOfBlock - }; - const decoder = new _ccitt.CCITTFaxDecoder(input, params); - const bitmap = []; - let currentByte, - eof = false; - - for (let y = 0; y < height; y++) { - const row = new Uint8Array(width); - bitmap.push(row); - let shift = -1; - - for (let x = 0; x < width; x++) { - if (shift < 0) { - currentByte = decoder.readNextChar(); - - if (currentByte === -1) { - currentByte = 0; - eof = true; - } - - shift = 7; - } - - row[x] = currentByte >> shift & 1; - shift--; - } - } - - if (endOfBlock && !eof) { - const lookForEOFLimit = 5; - - for (let i = 0; i < lookForEOFLimit; i++) { - if (decoder.readNextChar() === -1) { - break; - } - } - } - - return bitmap; - } - - function Jbig2Image() {} - - Jbig2Image.prototype = { - parseChunks(chunks) { - return parseJbig2Chunks(chunks); - }, - - parse(data) { - const { - imgData, - width, - height - } = parseJbig2(data); - this.width = width; - this.height = height; - return imgData; - } - - }; - return Jbig2Image; -}(); - -exports.Jbig2Image = Jbig2Image; - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.ArithmeticDecoder = void 0; -const QeTable = [{ - qe: 0x5601, - nmps: 1, - nlps: 1, - switchFlag: 1 -}, { - qe: 0x3401, - nmps: 2, - nlps: 6, - switchFlag: 0 -}, { - qe: 0x1801, - nmps: 3, - nlps: 9, - switchFlag: 0 -}, { - qe: 0x0ac1, - nmps: 4, - nlps: 12, - switchFlag: 0 -}, { - qe: 0x0521, - nmps: 5, - nlps: 29, - switchFlag: 0 -}, { - qe: 0x0221, - nmps: 38, - nlps: 33, - switchFlag: 0 -}, { - qe: 0x5601, - nmps: 7, - nlps: 6, - switchFlag: 1 -}, { - qe: 0x5401, - nmps: 8, - nlps: 14, - switchFlag: 0 -}, { - qe: 0x4801, - nmps: 9, - nlps: 14, - switchFlag: 0 -}, { - qe: 0x3801, - nmps: 10, - nlps: 14, - switchFlag: 0 -}, { - qe: 0x3001, - nmps: 11, - nlps: 17, - switchFlag: 0 -}, { - qe: 0x2401, - nmps: 12, - nlps: 18, - switchFlag: 0 -}, { - qe: 0x1c01, - nmps: 13, - nlps: 20, - switchFlag: 0 -}, { - qe: 0x1601, - nmps: 29, - nlps: 21, - switchFlag: 0 -}, { - qe: 0x5601, - nmps: 15, - nlps: 14, - switchFlag: 1 -}, { - qe: 0x5401, - nmps: 16, - nlps: 14, - switchFlag: 0 -}, { - qe: 0x5101, - nmps: 17, - nlps: 15, - switchFlag: 0 -}, { - qe: 0x4801, - nmps: 18, - nlps: 16, - switchFlag: 0 -}, { - qe: 0x3801, - nmps: 19, - nlps: 17, - switchFlag: 0 -}, { - qe: 0x3401, - nmps: 20, - nlps: 18, - switchFlag: 0 -}, { - qe: 0x3001, - nmps: 21, - nlps: 19, - switchFlag: 0 -}, { - qe: 0x2801, - nmps: 22, - nlps: 19, - switchFlag: 0 -}, { - qe: 0x2401, - nmps: 23, - nlps: 20, - switchFlag: 0 -}, { - qe: 0x2201, - nmps: 24, - nlps: 21, - switchFlag: 0 -}, { - qe: 0x1c01, - nmps: 25, - nlps: 22, - switchFlag: 0 -}, { - qe: 0x1801, - nmps: 26, - nlps: 23, - switchFlag: 0 -}, { - qe: 0x1601, - nmps: 27, - nlps: 24, - switchFlag: 0 -}, { - qe: 0x1401, - nmps: 28, - nlps: 25, - switchFlag: 0 -}, { - qe: 0x1201, - nmps: 29, - nlps: 26, - switchFlag: 0 -}, { - qe: 0x1101, - nmps: 30, - nlps: 27, - switchFlag: 0 -}, { - qe: 0x0ac1, - nmps: 31, - nlps: 28, - switchFlag: 0 -}, { - qe: 0x09c1, - nmps: 32, - nlps: 29, - switchFlag: 0 -}, { - qe: 0x08a1, - nmps: 33, - nlps: 30, - switchFlag: 0 -}, { - qe: 0x0521, - nmps: 34, - nlps: 31, - switchFlag: 0 -}, { - qe: 0x0441, - nmps: 35, - nlps: 32, - switchFlag: 0 -}, { - qe: 0x02a1, - nmps: 36, - nlps: 33, - switchFlag: 0 -}, { - qe: 0x0221, - nmps: 37, - nlps: 34, - switchFlag: 0 -}, { - qe: 0x0141, - nmps: 38, - nlps: 35, - switchFlag: 0 -}, { - qe: 0x0111, - nmps: 39, - nlps: 36, - switchFlag: 0 -}, { - qe: 0x0085, - nmps: 40, - nlps: 37, - switchFlag: 0 -}, { - qe: 0x0049, - nmps: 41, - nlps: 38, - switchFlag: 0 -}, { - qe: 0x0025, - nmps: 42, - nlps: 39, - switchFlag: 0 -}, { - qe: 0x0015, - nmps: 43, - nlps: 40, - switchFlag: 0 -}, { - qe: 0x0009, - nmps: 44, - nlps: 41, - switchFlag: 0 -}, { - qe: 0x0005, - nmps: 45, - nlps: 42, - switchFlag: 0 -}, { - qe: 0x0001, - nmps: 45, - nlps: 43, - switchFlag: 0 -}, { - qe: 0x5601, - nmps: 46, - nlps: 46, - switchFlag: 0 -}]; - -class ArithmeticDecoder { - constructor(data, start, end) { - this.data = data; - this.bp = start; - this.dataEnd = end; - this.chigh = data[start]; - this.clow = 0; - this.byteIn(); - this.chigh = this.chigh << 7 & 0xffff | this.clow >> 9 & 0x7f; - this.clow = this.clow << 7 & 0xffff; - this.ct -= 7; - this.a = 0x8000; - } - - byteIn() { - const data = this.data; - let bp = this.bp; - - if (data[bp] === 0xff) { - if (data[bp + 1] > 0x8f) { - this.clow += 0xff00; - this.ct = 8; - } else { - bp++; - this.clow += data[bp] << 9; - this.ct = 7; - this.bp = bp; - } - } else { - bp++; - this.clow += bp < this.dataEnd ? data[bp] << 8 : 0xff00; - this.ct = 8; - this.bp = bp; - } - - if (this.clow > 0xffff) { - this.chigh += this.clow >> 16; - this.clow &= 0xffff; - } - } - - readBit(contexts, pos) { - let cx_index = contexts[pos] >> 1, - cx_mps = contexts[pos] & 1; - const qeTableIcx = QeTable[cx_index]; - const qeIcx = qeTableIcx.qe; - let d; - let a = this.a - qeIcx; - - if (this.chigh < qeIcx) { - if (a < qeIcx) { - a = qeIcx; - d = cx_mps; - cx_index = qeTableIcx.nmps; - } else { - a = qeIcx; - d = 1 ^ cx_mps; - - if (qeTableIcx.switchFlag === 1) { - cx_mps = d; - } - - cx_index = qeTableIcx.nlps; - } - } else { - this.chigh -= qeIcx; - - if ((a & 0x8000) !== 0) { - this.a = a; - return cx_mps; - } - - if (a < qeIcx) { - d = 1 ^ cx_mps; - - if (qeTableIcx.switchFlag === 1) { - cx_mps = d; - } - - cx_index = qeTableIcx.nlps; - } else { - d = cx_mps; - cx_index = qeTableIcx.nmps; - } - } - - do { - if (this.ct === 0) { - this.byteIn(); - } - - a <<= 1; - this.chigh = this.chigh << 1 & 0xffff | this.clow >> 15 & 1; - this.clow = this.clow << 1 & 0xffff; - this.ct--; - } while ((a & 0x8000) === 0); - - this.a = a; - contexts[pos] = cx_index << 1 | cx_mps; - return d; - } - -} - -exports.ArithmeticDecoder = ArithmeticDecoder; - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.JpegStream = void 0; - -var _stream = __w_pdfjs_require__(12); - -var _primitives = __w_pdfjs_require__(5); - -var _jpg = __w_pdfjs_require__(19); - -var _util = __w_pdfjs_require__(2); - -const JpegStream = function JpegStreamClosure() { - function JpegStream(stream, maybeLength, dict, params) { - let ch; - - while ((ch = stream.getByte()) !== -1) { - if (ch === 0xff) { - stream.skip(-1); - break; - } - } - - this.stream = stream; - this.maybeLength = maybeLength; - this.dict = dict; - this.params = params; - - _stream.DecodeStream.call(this, maybeLength); - } - - JpegStream.prototype = Object.create(_stream.DecodeStream.prototype); - Object.defineProperty(JpegStream.prototype, "bytes", { - get: function JpegStream_bytes() { - return (0, _util.shadow)(this, "bytes", this.stream.getBytes(this.maybeLength)); - }, - configurable: true - }); - - JpegStream.prototype.ensureBuffer = function (requested) {}; - - JpegStream.prototype.readBlock = function () { - if (this.eof) { - return; - } - - const jpegOptions = { - decodeTransform: undefined, - colorTransform: undefined - }; - const decodeArr = this.dict.getArray("Decode", "D"); - - if (this.forceRGB && Array.isArray(decodeArr)) { - const bitsPerComponent = this.dict.get("BitsPerComponent") || 8; - const decodeArrLength = decodeArr.length; - const transform = new Int32Array(decodeArrLength); - let transformNeeded = false; - const maxValue = (1 << bitsPerComponent) - 1; - - for (let i = 0; i < decodeArrLength; i += 2) { - transform[i] = (decodeArr[i + 1] - decodeArr[i]) * 256 | 0; - transform[i + 1] = decodeArr[i] * maxValue | 0; - - if (transform[i] !== 256 || transform[i + 1] !== 0) { - transformNeeded = true; - } - } - - if (transformNeeded) { - jpegOptions.decodeTransform = transform; - } - } - - if ((0, _primitives.isDict)(this.params)) { - const colorTransform = this.params.get("ColorTransform"); - - if (Number.isInteger(colorTransform)) { - jpegOptions.colorTransform = colorTransform; - } - } - - const jpegImage = new _jpg.JpegImage(jpegOptions); - jpegImage.parse(this.bytes); - const data = jpegImage.getData({ - width: this.drawWidth, - height: this.drawHeight, - forceRGB: this.forceRGB, - isSourcePDF: true - }); - this.buffer = data; - this.bufferLength = data.length; - this.eof = true; - }; - - return JpegStream; -}(); - -exports.JpegStream = JpegStream; - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.JpegImage = void 0; - -var _util = __w_pdfjs_require__(2); - -var _core_utils = __w_pdfjs_require__(8); - -class JpegError extends _util.BaseException { - constructor(msg) { - super(`JPEG error: ${msg}`); - } - -} - -class DNLMarkerError extends _util.BaseException { - constructor(message, scanLines) { - super(message); - this.scanLines = scanLines; - } - -} - -class EOIMarkerError extends _util.BaseException {} - -var JpegImage = function JpegImageClosure() { - var dctZigZag = new Uint8Array([0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63]); - var dctCos1 = 4017; - var dctSin1 = 799; - var dctCos3 = 3406; - var dctSin3 = 2276; - var dctCos6 = 1567; - var dctSin6 = 3784; - var dctSqrt2 = 5793; - var dctSqrt1d2 = 2896; - - function JpegImage({ - decodeTransform = null, - colorTransform = -1 - } = {}) { - this._decodeTransform = decodeTransform; - this._colorTransform = colorTransform; - } - - function buildHuffmanTable(codeLengths, values) { - var k = 0, - code = [], - i, - j, - length = 16; - - while (length > 0 && !codeLengths[length - 1]) { - length--; - } - - code.push({ - children: [], - index: 0 - }); - var p = code[0], - q; - - for (i = 0; i < length; i++) { - for (j = 0; j < codeLengths[i]; j++) { - p = code.pop(); - p.children[p.index] = values[k]; - - while (p.index > 0) { - p = code.pop(); - } - - p.index++; - code.push(p); - - while (code.length <= i) { - code.push(q = { - children: [], - index: 0 - }); - p.children[p.index] = q.children; - p = q; - } - - k++; - } - - if (i + 1 < length) { - code.push(q = { - children: [], - index: 0 - }); - p.children[p.index] = q.children; - p = q; - } - } - - return code[0].children; - } - - function getBlockBufferOffset(component, row, col) { - return 64 * ((component.blocksPerLine + 1) * row + col); - } - - function decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successivePrev, successive, parseDNLMarker = false) { - var mcusPerLine = frame.mcusPerLine; - var progressive = frame.progressive; - const startOffset = offset; - let bitsData = 0, - bitsCount = 0; - - function readBit() { - if (bitsCount > 0) { - bitsCount--; - return bitsData >> bitsCount & 1; - } - - bitsData = data[offset++]; - - if (bitsData === 0xff) { - var nextByte = data[offset++]; - - if (nextByte) { - if (nextByte === 0xdc && parseDNLMarker) { - offset += 2; - const scanLines = (0, _core_utils.readUint16)(data, offset); - offset += 2; - - if (scanLines > 0 && scanLines !== frame.scanLines) { - throw new DNLMarkerError("Found DNL marker (0xFFDC) while parsing scan data", scanLines); - } - } else if (nextByte === 0xd9) { - if (parseDNLMarker) { - const maybeScanLines = blockRow * (frame.precision === 8 ? 8 : 0); - - if (maybeScanLines > 0 && Math.round(frame.scanLines / maybeScanLines) >= 10) { - throw new DNLMarkerError("Found EOI marker (0xFFD9) while parsing scan data, " + "possibly caused by incorrect `scanLines` parameter", maybeScanLines); - } - } - - throw new EOIMarkerError("Found EOI marker (0xFFD9) while parsing scan data"); - } - - throw new JpegError(`unexpected marker ${(bitsData << 8 | nextByte).toString(16)}`); - } - } - - bitsCount = 7; - return bitsData >>> 7; - } - - function decodeHuffman(tree) { - var node = tree; - - while (true) { - node = node[readBit()]; - - switch (typeof node) { - case "number": - return node; - - case "object": - continue; - } - - throw new JpegError("invalid huffman sequence"); - } - } - - function receive(length) { - var n = 0; - - while (length > 0) { - n = n << 1 | readBit(); - length--; - } - - return n; - } - - function receiveAndExtend(length) { - if (length === 1) { - return readBit() === 1 ? 1 : -1; - } - - var n = receive(length); - - if (n >= 1 << length - 1) { - return n; - } - - return n + (-1 << length) + 1; - } - - function decodeBaseline(component, blockOffset) { - var t = decodeHuffman(component.huffmanTableDC); - var diff = t === 0 ? 0 : receiveAndExtend(t); - component.blockData[blockOffset] = component.pred += diff; - var k = 1; - - while (k < 64) { - var rs = decodeHuffman(component.huffmanTableAC); - var s = rs & 15, - r = rs >> 4; - - if (s === 0) { - if (r < 15) { - break; - } - - k += 16; - continue; - } - - k += r; - var z = dctZigZag[k]; - component.blockData[blockOffset + z] = receiveAndExtend(s); - k++; - } - } - - function decodeDCFirst(component, blockOffset) { - var t = decodeHuffman(component.huffmanTableDC); - var diff = t === 0 ? 0 : receiveAndExtend(t) << successive; - component.blockData[blockOffset] = component.pred += diff; - } - - function decodeDCSuccessive(component, blockOffset) { - component.blockData[blockOffset] |= readBit() << successive; - } - - var eobrun = 0; - - function decodeACFirst(component, blockOffset) { - if (eobrun > 0) { - eobrun--; - return; - } - - var k = spectralStart, - e = spectralEnd; - - while (k <= e) { - var rs = decodeHuffman(component.huffmanTableAC); - var s = rs & 15, - r = rs >> 4; - - if (s === 0) { - if (r < 15) { - eobrun = receive(r) + (1 << r) - 1; - break; - } - - k += 16; - continue; - } - - k += r; - var z = dctZigZag[k]; - component.blockData[blockOffset + z] = receiveAndExtend(s) * (1 << successive); - k++; - } - } - - var successiveACState = 0, - successiveACNextValue; - - function decodeACSuccessive(component, blockOffset) { - var k = spectralStart; - var e = spectralEnd; - var r = 0; - var s; - var rs; - - while (k <= e) { - const offsetZ = blockOffset + dctZigZag[k]; - const sign = component.blockData[offsetZ] < 0 ? -1 : 1; - - switch (successiveACState) { - case 0: - rs = decodeHuffman(component.huffmanTableAC); - s = rs & 15; - r = rs >> 4; - - if (s === 0) { - if (r < 15) { - eobrun = receive(r) + (1 << r); - successiveACState = 4; - } else { - r = 16; - successiveACState = 1; - } - } else { - if (s !== 1) { - throw new JpegError("invalid ACn encoding"); - } - - successiveACNextValue = receiveAndExtend(s); - successiveACState = r ? 2 : 3; - } - - continue; - - case 1: - case 2: - if (component.blockData[offsetZ]) { - component.blockData[offsetZ] += sign * (readBit() << successive); - } else { - r--; - - if (r === 0) { - successiveACState = successiveACState === 2 ? 3 : 0; - } - } - - break; - - case 3: - if (component.blockData[offsetZ]) { - component.blockData[offsetZ] += sign * (readBit() << successive); - } else { - component.blockData[offsetZ] = successiveACNextValue << successive; - successiveACState = 0; - } - - break; - - case 4: - if (component.blockData[offsetZ]) { - component.blockData[offsetZ] += sign * (readBit() << successive); - } - - break; - } - - k++; - } - - if (successiveACState === 4) { - eobrun--; - - if (eobrun === 0) { - successiveACState = 0; - } - } - } - - let blockRow = 0; - - function decodeMcu(component, decode, mcu, row, col) { - var mcuRow = mcu / mcusPerLine | 0; - var mcuCol = mcu % mcusPerLine; - blockRow = mcuRow * component.v + row; - var blockCol = mcuCol * component.h + col; - const blockOffset = getBlockBufferOffset(component, blockRow, blockCol); - decode(component, blockOffset); - } - - function decodeBlock(component, decode, mcu) { - blockRow = mcu / component.blocksPerLine | 0; - var blockCol = mcu % component.blocksPerLine; - const blockOffset = getBlockBufferOffset(component, blockRow, blockCol); - decode(component, blockOffset); - } - - var componentsLength = components.length; - var component, i, j, k, n; - var decodeFn; - - if (progressive) { - if (spectralStart === 0) { - decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive; - } else { - decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive; - } - } else { - decodeFn = decodeBaseline; - } - - var mcu = 0, - fileMarker; - var mcuExpected; - - if (componentsLength === 1) { - mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn; - } else { - mcuExpected = mcusPerLine * frame.mcusPerColumn; - } - - var h, v; - - while (mcu <= mcuExpected) { - var mcuToRead = resetInterval ? Math.min(mcuExpected - mcu, resetInterval) : mcuExpected; - - if (mcuToRead > 0) { - for (i = 0; i < componentsLength; i++) { - components[i].pred = 0; - } - - eobrun = 0; - - if (componentsLength === 1) { - component = components[0]; - - for (n = 0; n < mcuToRead; n++) { - decodeBlock(component, decodeFn, mcu); - mcu++; - } - } else { - for (n = 0; n < mcuToRead; n++) { - for (i = 0; i < componentsLength; i++) { - component = components[i]; - h = component.h; - v = component.v; - - for (j = 0; j < v; j++) { - for (k = 0; k < h; k++) { - decodeMcu(component, decodeFn, mcu, j, k); - } - } - } - - mcu++; - } - } - } - - bitsCount = 0; - fileMarker = findNextFileMarker(data, offset); - - if (!fileMarker) { - break; - } - - if (fileMarker.invalid) { - const partialMsg = mcuToRead > 0 ? "unexpected" : "excessive"; - (0, _util.warn)(`decodeScan - ${partialMsg} MCU data, current marker is: ${fileMarker.invalid}`); - offset = fileMarker.offset; - } - - if (fileMarker.marker >= 0xffd0 && fileMarker.marker <= 0xffd7) { - offset += 2; - } else { - break; - } - } - - return offset - startOffset; - } - - function quantizeAndInverse(component, blockBufferOffset, p) { - var qt = component.quantizationTable, - blockData = component.blockData; - var v0, v1, v2, v3, v4, v5, v6, v7; - var p0, p1, p2, p3, p4, p5, p6, p7; - var t; - - if (!qt) { - throw new JpegError("missing required Quantization Table."); - } - - for (var row = 0; row < 64; row += 8) { - p0 = blockData[blockBufferOffset + row]; - p1 = blockData[blockBufferOffset + row + 1]; - p2 = blockData[blockBufferOffset + row + 2]; - p3 = blockData[blockBufferOffset + row + 3]; - p4 = blockData[blockBufferOffset + row + 4]; - p5 = blockData[blockBufferOffset + row + 5]; - p6 = blockData[blockBufferOffset + row + 6]; - p7 = blockData[blockBufferOffset + row + 7]; - p0 *= qt[row]; - - if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) { - t = dctSqrt2 * p0 + 512 >> 10; - p[row] = t; - p[row + 1] = t; - p[row + 2] = t; - p[row + 3] = t; - p[row + 4] = t; - p[row + 5] = t; - p[row + 6] = t; - p[row + 7] = t; - continue; - } - - p1 *= qt[row + 1]; - p2 *= qt[row + 2]; - p3 *= qt[row + 3]; - p4 *= qt[row + 4]; - p5 *= qt[row + 5]; - p6 *= qt[row + 6]; - p7 *= qt[row + 7]; - v0 = dctSqrt2 * p0 + 128 >> 8; - v1 = dctSqrt2 * p4 + 128 >> 8; - v2 = p2; - v3 = p6; - v4 = dctSqrt1d2 * (p1 - p7) + 128 >> 8; - v7 = dctSqrt1d2 * (p1 + p7) + 128 >> 8; - v5 = p3 << 4; - v6 = p5 << 4; - v0 = v0 + v1 + 1 >> 1; - v1 = v0 - v1; - t = v2 * dctSin6 + v3 * dctCos6 + 128 >> 8; - v2 = v2 * dctCos6 - v3 * dctSin6 + 128 >> 8; - v3 = t; - v4 = v4 + v6 + 1 >> 1; - v6 = v4 - v6; - v7 = v7 + v5 + 1 >> 1; - v5 = v7 - v5; - v0 = v0 + v3 + 1 >> 1; - v3 = v0 - v3; - v1 = v1 + v2 + 1 >> 1; - v2 = v1 - v2; - t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12; - v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12; - v7 = t; - t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12; - v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12; - v6 = t; - p[row] = v0 + v7; - p[row + 7] = v0 - v7; - p[row + 1] = v1 + v6; - p[row + 6] = v1 - v6; - p[row + 2] = v2 + v5; - p[row + 5] = v2 - v5; - p[row + 3] = v3 + v4; - p[row + 4] = v3 - v4; - } - - for (var col = 0; col < 8; ++col) { - p0 = p[col]; - p1 = p[col + 8]; - p2 = p[col + 16]; - p3 = p[col + 24]; - p4 = p[col + 32]; - p5 = p[col + 40]; - p6 = p[col + 48]; - p7 = p[col + 56]; - - if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) { - t = dctSqrt2 * p0 + 8192 >> 14; - - if (t < -2040) { - t = 0; - } else if (t >= 2024) { - t = 255; - } else { - t = t + 2056 >> 4; - } - - blockData[blockBufferOffset + col] = t; - blockData[blockBufferOffset + col + 8] = t; - blockData[blockBufferOffset + col + 16] = t; - blockData[blockBufferOffset + col + 24] = t; - blockData[blockBufferOffset + col + 32] = t; - blockData[blockBufferOffset + col + 40] = t; - blockData[blockBufferOffset + col + 48] = t; - blockData[blockBufferOffset + col + 56] = t; - continue; - } - - v0 = dctSqrt2 * p0 + 2048 >> 12; - v1 = dctSqrt2 * p4 + 2048 >> 12; - v2 = p2; - v3 = p6; - v4 = dctSqrt1d2 * (p1 - p7) + 2048 >> 12; - v7 = dctSqrt1d2 * (p1 + p7) + 2048 >> 12; - v5 = p3; - v6 = p5; - v0 = (v0 + v1 + 1 >> 1) + 4112; - v1 = v0 - v1; - t = v2 * dctSin6 + v3 * dctCos6 + 2048 >> 12; - v2 = v2 * dctCos6 - v3 * dctSin6 + 2048 >> 12; - v3 = t; - v4 = v4 + v6 + 1 >> 1; - v6 = v4 - v6; - v7 = v7 + v5 + 1 >> 1; - v5 = v7 - v5; - v0 = v0 + v3 + 1 >> 1; - v3 = v0 - v3; - v1 = v1 + v2 + 1 >> 1; - v2 = v1 - v2; - t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12; - v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12; - v7 = t; - t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12; - v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12; - v6 = t; - p0 = v0 + v7; - p7 = v0 - v7; - p1 = v1 + v6; - p6 = v1 - v6; - p2 = v2 + v5; - p5 = v2 - v5; - p3 = v3 + v4; - p4 = v3 - v4; - - if (p0 < 16) { - p0 = 0; - } else if (p0 >= 4080) { - p0 = 255; - } else { - p0 >>= 4; - } - - if (p1 < 16) { - p1 = 0; - } else if (p1 >= 4080) { - p1 = 255; - } else { - p1 >>= 4; - } - - if (p2 < 16) { - p2 = 0; - } else if (p2 >= 4080) { - p2 = 255; - } else { - p2 >>= 4; - } - - if (p3 < 16) { - p3 = 0; - } else if (p3 >= 4080) { - p3 = 255; - } else { - p3 >>= 4; - } - - if (p4 < 16) { - p4 = 0; - } else if (p4 >= 4080) { - p4 = 255; - } else { - p4 >>= 4; - } - - if (p5 < 16) { - p5 = 0; - } else if (p5 >= 4080) { - p5 = 255; - } else { - p5 >>= 4; - } - - if (p6 < 16) { - p6 = 0; - } else if (p6 >= 4080) { - p6 = 255; - } else { - p6 >>= 4; - } - - if (p7 < 16) { - p7 = 0; - } else if (p7 >= 4080) { - p7 = 255; - } else { - p7 >>= 4; - } - - blockData[blockBufferOffset + col] = p0; - blockData[blockBufferOffset + col + 8] = p1; - blockData[blockBufferOffset + col + 16] = p2; - blockData[blockBufferOffset + col + 24] = p3; - blockData[blockBufferOffset + col + 32] = p4; - blockData[blockBufferOffset + col + 40] = p5; - blockData[blockBufferOffset + col + 48] = p6; - blockData[blockBufferOffset + col + 56] = p7; - } - } - - function buildComponentData(frame, component) { - var blocksPerLine = component.blocksPerLine; - var blocksPerColumn = component.blocksPerColumn; - var computationBuffer = new Int16Array(64); - - for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) { - for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) { - var offset = getBlockBufferOffset(component, blockRow, blockCol); - quantizeAndInverse(component, offset, computationBuffer); - } - } - - return component.blockData; - } - - function findNextFileMarker(data, currentPos, startPos = currentPos) { - const maxPos = data.length - 1; - var newPos = startPos < currentPos ? startPos : currentPos; - - if (currentPos >= maxPos) { - return null; - } - - var currentMarker = (0, _core_utils.readUint16)(data, currentPos); - - if (currentMarker >= 0xffc0 && currentMarker <= 0xfffe) { - return { - invalid: null, - marker: currentMarker, - offset: currentPos - }; - } - - var newMarker = (0, _core_utils.readUint16)(data, newPos); - - while (!(newMarker >= 0xffc0 && newMarker <= 0xfffe)) { - if (++newPos >= maxPos) { - return null; - } - - newMarker = (0, _core_utils.readUint16)(data, newPos); - } - - return { - invalid: currentMarker.toString(16), - marker: newMarker, - offset: newPos - }; - } - - JpegImage.prototype = { - parse(data, { - dnlScanLines = null - } = {}) { - function readDataBlock() { - const length = (0, _core_utils.readUint16)(data, offset); - offset += 2; - let endOffset = offset + length - 2; - var fileMarker = findNextFileMarker(data, endOffset, offset); - - if (fileMarker && fileMarker.invalid) { - (0, _util.warn)("readDataBlock - incorrect length, current marker is: " + fileMarker.invalid); - endOffset = fileMarker.offset; - } - - var array = data.subarray(offset, endOffset); - offset += array.length; - return array; - } - - function prepareComponents(frame) { - var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH); - var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV); - - for (var i = 0; i < frame.components.length; i++) { - component = frame.components[i]; - var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / frame.maxH); - var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) * component.v / frame.maxV); - var blocksPerLineForMcu = mcusPerLine * component.h; - var blocksPerColumnForMcu = mcusPerColumn * component.v; - var blocksBufferSize = 64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1); - component.blockData = new Int16Array(blocksBufferSize); - component.blocksPerLine = blocksPerLine; - component.blocksPerColumn = blocksPerColumn; - } - - frame.mcusPerLine = mcusPerLine; - frame.mcusPerColumn = mcusPerColumn; - } - - var offset = 0; - var jfif = null; - var adobe = null; - var frame, resetInterval; - let numSOSMarkers = 0; - var quantizationTables = []; - var huffmanTablesAC = [], - huffmanTablesDC = []; - let fileMarker = (0, _core_utils.readUint16)(data, offset); - offset += 2; - - if (fileMarker !== 0xffd8) { - throw new JpegError("SOI not found"); - } - - fileMarker = (0, _core_utils.readUint16)(data, offset); - offset += 2; - - markerLoop: while (fileMarker !== 0xffd9) { - var i, j, l; - - switch (fileMarker) { - case 0xffe0: - case 0xffe1: - case 0xffe2: - case 0xffe3: - case 0xffe4: - case 0xffe5: - case 0xffe6: - case 0xffe7: - case 0xffe8: - case 0xffe9: - case 0xffea: - case 0xffeb: - case 0xffec: - case 0xffed: - case 0xffee: - case 0xffef: - case 0xfffe: - var appData = readDataBlock(); - - if (fileMarker === 0xffe0) { - if (appData[0] === 0x4a && appData[1] === 0x46 && appData[2] === 0x49 && appData[3] === 0x46 && appData[4] === 0) { - jfif = { - version: { - major: appData[5], - minor: appData[6] - }, - densityUnits: appData[7], - xDensity: appData[8] << 8 | appData[9], - yDensity: appData[10] << 8 | appData[11], - thumbWidth: appData[12], - thumbHeight: appData[13], - thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13]) - }; - } - } - - if (fileMarker === 0xffee) { - if (appData[0] === 0x41 && appData[1] === 0x64 && appData[2] === 0x6f && appData[3] === 0x62 && appData[4] === 0x65) { - adobe = { - version: appData[5] << 8 | appData[6], - flags0: appData[7] << 8 | appData[8], - flags1: appData[9] << 8 | appData[10], - transformCode: appData[11] - }; - } - } - - break; - - case 0xffdb: - const quantizationTablesLength = (0, _core_utils.readUint16)(data, offset); - offset += 2; - var quantizationTablesEnd = quantizationTablesLength + offset - 2; - var z; - - while (offset < quantizationTablesEnd) { - var quantizationTableSpec = data[offset++]; - var tableData = new Uint16Array(64); - - if (quantizationTableSpec >> 4 === 0) { - for (j = 0; j < 64; j++) { - z = dctZigZag[j]; - tableData[z] = data[offset++]; - } - } else if (quantizationTableSpec >> 4 === 1) { - for (j = 0; j < 64; j++) { - z = dctZigZag[j]; - tableData[z] = (0, _core_utils.readUint16)(data, offset); - offset += 2; - } - } else { - throw new JpegError("DQT - invalid table spec"); - } - - quantizationTables[quantizationTableSpec & 15] = tableData; - } - - break; - - case 0xffc0: - case 0xffc1: - case 0xffc2: - if (frame) { - throw new JpegError("Only single frame JPEGs supported"); - } - - offset += 2; - frame = {}; - frame.extended = fileMarker === 0xffc1; - frame.progressive = fileMarker === 0xffc2; - frame.precision = data[offset++]; - const sofScanLines = (0, _core_utils.readUint16)(data, offset); - offset += 2; - frame.scanLines = dnlScanLines || sofScanLines; - frame.samplesPerLine = (0, _core_utils.readUint16)(data, offset); - offset += 2; - frame.components = []; - frame.componentIds = {}; - var componentsCount = data[offset++], - componentId; - var maxH = 0, - maxV = 0; - - for (i = 0; i < componentsCount; i++) { - componentId = data[offset]; - var h = data[offset + 1] >> 4; - var v = data[offset + 1] & 15; - - if (maxH < h) { - maxH = h; - } - - if (maxV < v) { - maxV = v; - } - - var qId = data[offset + 2]; - l = frame.components.push({ - h, - v, - quantizationId: qId, - quantizationTable: null - }); - frame.componentIds[componentId] = l - 1; - offset += 3; - } - - frame.maxH = maxH; - frame.maxV = maxV; - prepareComponents(frame); - break; - - case 0xffc4: - const huffmanLength = (0, _core_utils.readUint16)(data, offset); - offset += 2; - - for (i = 2; i < huffmanLength;) { - var huffmanTableSpec = data[offset++]; - var codeLengths = new Uint8Array(16); - var codeLengthSum = 0; - - for (j = 0; j < 16; j++, offset++) { - codeLengthSum += codeLengths[j] = data[offset]; - } - - var huffmanValues = new Uint8Array(codeLengthSum); - - for (j = 0; j < codeLengthSum; j++, offset++) { - huffmanValues[j] = data[offset]; - } - - i += 17 + codeLengthSum; - (huffmanTableSpec >> 4 === 0 ? huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] = buildHuffmanTable(codeLengths, huffmanValues); - } - - break; - - case 0xffdd: - offset += 2; - resetInterval = (0, _core_utils.readUint16)(data, offset); - offset += 2; - break; - - case 0xffda: - const parseDNLMarker = ++numSOSMarkers === 1 && !dnlScanLines; - offset += 2; - var selectorsCount = data[offset++]; - var components = [], - component; - - for (i = 0; i < selectorsCount; i++) { - const index = data[offset++]; - var componentIndex = frame.componentIds[index]; - component = frame.components[componentIndex]; - component.index = index; - var tableSpec = data[offset++]; - component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4]; - component.huffmanTableAC = huffmanTablesAC[tableSpec & 15]; - components.push(component); - } - - var spectralStart = data[offset++]; - var spectralEnd = data[offset++]; - var successiveApproximation = data[offset++]; - - try { - var processed = decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successiveApproximation >> 4, successiveApproximation & 15, parseDNLMarker); - offset += processed; - } catch (ex) { - if (ex instanceof DNLMarkerError) { - (0, _util.warn)(`${ex.message} -- attempting to re-parse the JPEG image.`); - return this.parse(data, { - dnlScanLines: ex.scanLines - }); - } else if (ex instanceof EOIMarkerError) { - (0, _util.warn)(`${ex.message} -- ignoring the rest of the image data.`); - break markerLoop; - } - - throw ex; - } - - break; - - case 0xffdc: - offset += 4; - break; - - case 0xffff: - if (data[offset] !== 0xff) { - offset--; - } - - break; - - default: - const nextFileMarker = findNextFileMarker(data, offset - 2, offset - 3); - - if (nextFileMarker && nextFileMarker.invalid) { - (0, _util.warn)("JpegImage.parse - unexpected data, current marker is: " + nextFileMarker.invalid); - offset = nextFileMarker.offset; - break; - } - - if (offset >= data.length - 1) { - (0, _util.warn)("JpegImage.parse - reached the end of the image data " + "without finding an EOI marker (0xFFD9)."); - break markerLoop; - } - - throw new JpegError("JpegImage.parse - unknown marker: " + fileMarker.toString(16)); - } - - fileMarker = (0, _core_utils.readUint16)(data, offset); - offset += 2; - } - - this.width = frame.samplesPerLine; - this.height = frame.scanLines; - this.jfif = jfif; - this.adobe = adobe; - this.components = []; - - for (i = 0; i < frame.components.length; i++) { - component = frame.components[i]; - var quantizationTable = quantizationTables[component.quantizationId]; - - if (quantizationTable) { - component.quantizationTable = quantizationTable; - } - - this.components.push({ - index: component.index, - output: buildComponentData(frame, component), - scaleX: component.h / frame.maxH, - scaleY: component.v / frame.maxV, - blocksPerLine: component.blocksPerLine, - blocksPerColumn: component.blocksPerColumn - }); - } - - this.numComponents = this.components.length; - return undefined; - }, - - _getLinearizedBlockData(width, height, isSourcePDF = false) { - var scaleX = this.width / width, - scaleY = this.height / height; - var component, componentScaleX, componentScaleY, blocksPerScanline; - var x, y, i, j, k; - var index; - var offset = 0; - var output; - var numComponents = this.components.length; - var dataLength = width * height * numComponents; - var data = new Uint8ClampedArray(dataLength); - var xScaleBlockOffset = new Uint32Array(width); - var mask3LSB = 0xfffffff8; - let lastComponentScaleX; - - for (i = 0; i < numComponents; i++) { - component = this.components[i]; - componentScaleX = component.scaleX * scaleX; - componentScaleY = component.scaleY * scaleY; - offset = i; - output = component.output; - blocksPerScanline = component.blocksPerLine + 1 << 3; - - if (componentScaleX !== lastComponentScaleX) { - for (x = 0; x < width; x++) { - j = 0 | x * componentScaleX; - xScaleBlockOffset[x] = (j & mask3LSB) << 3 | j & 7; - } - - lastComponentScaleX = componentScaleX; - } - - for (y = 0; y < height; y++) { - j = 0 | y * componentScaleY; - index = blocksPerScanline * (j & mask3LSB) | (j & 7) << 3; - - for (x = 0; x < width; x++) { - data[offset] = output[index + xScaleBlockOffset[x]]; - offset += numComponents; - } - } - } - - let transform = this._decodeTransform; - - if (!isSourcePDF && numComponents === 4 && !transform) { - transform = new Int32Array([-256, 255, -256, 255, -256, 255, -256, 255]); - } - - if (transform) { - for (i = 0; i < dataLength;) { - for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) { - data[i] = (data[i] * transform[k] >> 8) + transform[k + 1]; - } - } - } - - return data; - }, - - get _isColorConversionNeeded() { - if (this.adobe) { - return !!this.adobe.transformCode; - } - - if (this.numComponents === 3) { - if (this._colorTransform === 0) { - return false; - } else if (this.components[0].index === 0x52 && this.components[1].index === 0x47 && this.components[2].index === 0x42) { - return false; - } - - return true; - } - - if (this._colorTransform === 1) { - return true; - } - - return false; - }, - - _convertYccToRgb: function convertYccToRgb(data) { - var Y, Cb, Cr; - - for (var i = 0, length = data.length; i < length; i += 3) { - Y = data[i]; - Cb = data[i + 1]; - Cr = data[i + 2]; - data[i] = Y - 179.456 + 1.402 * Cr; - data[i + 1] = Y + 135.459 - 0.344 * Cb - 0.714 * Cr; - data[i + 2] = Y - 226.816 + 1.772 * Cb; - } - - return data; - }, - _convertYcckToRgb: function convertYcckToRgb(data) { - var Y, Cb, Cr, k; - var offset = 0; - - for (var i = 0, length = data.length; i < length; i += 4) { - Y = data[i]; - Cb = data[i + 1]; - Cr = data[i + 2]; - k = data[i + 3]; - data[offset++] = -122.67195406894 + Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr - 5.4080610064599e-5 * Y + 0.00048449797120281 * k - 0.154362151871126) + Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y - 0.00477271405408747 * k + 1.53380253221734) + Y * (0.000961250184130688 * Y - 0.00266257332283933 * k + 0.48357088451265) + k * (-0.000336197177618394 * k + 0.484791561490776); - data[offset++] = 107.268039397724 + Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr + 0.000659397001245577 * Y + 0.000426105652938837 * k - 0.176491792462875) + Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y + 0.000770482631801132 * k - 0.151051492775562) + Y * (0.00126935368114843 * Y - 0.00265090189010898 * k + 0.25802910206845) + k * (-0.000318913117588328 * k - 0.213742400323665); - data[offset++] = -20.810012546947 + Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr + 0.0020741088115012 * Y - 0.00288260236853442 * k + 0.814272968359295) + Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y + 0.000560833691242812 * k - 0.195152027534049) + Y * (0.00174418132927582 * Y - 0.00255243321439347 * k + 0.116935020465145) + k * (-0.000343531996510555 * k + 0.24165260232407); - } - - return data.subarray(0, offset); - }, - _convertYcckToCmyk: function convertYcckToCmyk(data) { - var Y, Cb, Cr; - - for (var i = 0, length = data.length; i < length; i += 4) { - Y = data[i]; - Cb = data[i + 1]; - Cr = data[i + 2]; - data[i] = 434.456 - Y - 1.402 * Cr; - data[i + 1] = 119.541 - Y + 0.344 * Cb + 0.714 * Cr; - data[i + 2] = 481.816 - Y - 1.772 * Cb; - } - - return data; - }, - _convertCmykToRgb: function convertCmykToRgb(data) { - var c, m, y, k; - var offset = 0; - - for (var i = 0, length = data.length; i < length; i += 4) { - c = data[i]; - m = data[i + 1]; - y = data[i + 2]; - k = data[i + 3]; - data[offset++] = 255 + c * (-0.00006747147073602441 * c + 0.0008379262121013727 * m + 0.0002894718188643294 * y + 0.003264231057537806 * k - 1.1185611867203937) + m * (0.000026374107616089405 * m - 0.00008626949158638572 * y - 0.0002748769067499491 * k - 0.02155688794978967) + y * (-0.00003878099212869363 * y - 0.0003267808279485286 * k + 0.0686742238595345) - k * (0.0003361971776183937 * k + 0.7430659151342254); - data[offset++] = 255 + c * (0.00013596372813588848 * c + 0.000924537132573585 * m + 0.00010567359618683593 * y + 0.0004791864687436512 * k - 0.3109689587515875) + m * (-0.00023545346108370344 * m + 0.0002702845253534714 * y + 0.0020200308977307156 * k - 0.7488052167015494) + y * (0.00006834815998235662 * y + 0.00015168452363460973 * k - 0.09751927774728933) - k * (0.00031891311758832814 * k + 0.7364883807733168); - data[offset++] = 255 + c * (0.000013598650411385307 * c + 0.00012423956175490851 * m + 0.0004751985097583589 * y - 0.0000036729317476630422 * k - 0.05562186980264034) + m * (0.00016141380598724676 * m + 0.0009692239130725186 * y + 0.0007782692450036253 * k - 0.44015232367526463) + y * (5.068882914068769e-7 * y + 0.0017778369011375071 * k - 0.7591454649749609) - k * (0.0003435319965105553 * k + 0.7063770186160144); - } - - return data.subarray(0, offset); - }, - - getData({ - width, - height, - forceRGB = false, - isSourcePDF = false - }) { - if (this.numComponents > 4) { - throw new JpegError("Unsupported color mode"); - } - - var data = this._getLinearizedBlockData(width, height, isSourcePDF); - - if (this.numComponents === 1 && forceRGB) { - var dataLength = data.length; - var rgbData = new Uint8ClampedArray(dataLength * 3); - var offset = 0; - - for (var i = 0; i < dataLength; i++) { - var grayColor = data[i]; - rgbData[offset++] = grayColor; - rgbData[offset++] = grayColor; - rgbData[offset++] = grayColor; - } - - return rgbData; - } else if (this.numComponents === 3 && this._isColorConversionNeeded) { - return this._convertYccToRgb(data); - } else if (this.numComponents === 4) { - if (this._isColorConversionNeeded) { - if (forceRGB) { - return this._convertYcckToRgb(data); - } - - return this._convertYcckToCmyk(data); - } else if (forceRGB) { - return this._convertCmykToRgb(data); - } - } - - return data; - } - - }; - return JpegImage; -}(); - -exports.JpegImage = JpegImage; - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.JpxStream = void 0; - -var _stream = __w_pdfjs_require__(12); - -var _jpx = __w_pdfjs_require__(21); - -var _util = __w_pdfjs_require__(2); - -const JpxStream = function JpxStreamClosure() { - function JpxStream(stream, maybeLength, dict, params) { - this.stream = stream; - this.maybeLength = maybeLength; - this.dict = dict; - this.params = params; - - _stream.DecodeStream.call(this, maybeLength); - } - - JpxStream.prototype = Object.create(_stream.DecodeStream.prototype); - Object.defineProperty(JpxStream.prototype, "bytes", { - get: function JpxStream_bytes() { - return (0, _util.shadow)(this, "bytes", this.stream.getBytes(this.maybeLength)); - }, - configurable: true - }); - - JpxStream.prototype.ensureBuffer = function (requested) {}; - - JpxStream.prototype.readBlock = function () { - if (this.eof) { - return; - } - - const jpxImage = new _jpx.JpxImage(); - jpxImage.parse(this.bytes); - const width = jpxImage.width; - const height = jpxImage.height; - const componentsCount = jpxImage.componentsCount; - const tileCount = jpxImage.tiles.length; - - if (tileCount === 1) { - this.buffer = jpxImage.tiles[0].items; - } else { - const data = new Uint8ClampedArray(width * height * componentsCount); - - for (let k = 0; k < tileCount; k++) { - const tileComponents = jpxImage.tiles[k]; - const tileWidth = tileComponents.width; - const tileHeight = tileComponents.height; - const tileLeft = tileComponents.left; - const tileTop = tileComponents.top; - const src = tileComponents.items; - let srcPosition = 0; - let dataPosition = (width * tileTop + tileLeft) * componentsCount; - const imgRowSize = width * componentsCount; - const tileRowSize = tileWidth * componentsCount; - - for (let j = 0; j < tileHeight; j++) { - const rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize); - data.set(rowBytes, dataPosition); - srcPosition += tileRowSize; - dataPosition += imgRowSize; - } - } - - this.buffer = data; - } - - this.bufferLength = this.buffer.length; - this.eof = true; - }; - - return JpxStream; -}(); - -exports.JpxStream = JpxStream; - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.JpxImage = void 0; - -var _util = __w_pdfjs_require__(2); - -var _core_utils = __w_pdfjs_require__(8); - -var _arithmetic_decoder = __w_pdfjs_require__(17); - -class JpxError extends _util.BaseException { - constructor(msg) { - super(`JPX error: ${msg}`); - } - -} - -var JpxImage = function JpxImageClosure() { - var SubbandsGainLog2 = { - LL: 0, - LH: 1, - HL: 1, - HH: 2 - }; - - function JpxImage() { - this.failOnCorruptedImage = false; - } - - JpxImage.prototype = { - parse: function JpxImage_parse(data) { - var head = (0, _core_utils.readUint16)(data, 0); - - if (head === 0xff4f) { - this.parseCodestream(data, 0, data.length); - return; - } - - var position = 0, - length = data.length; - - while (position < length) { - var headerSize = 8; - var lbox = (0, _core_utils.readUint32)(data, position); - var tbox = (0, _core_utils.readUint32)(data, position + 4); - position += headerSize; - - if (lbox === 1) { - lbox = (0, _core_utils.readUint32)(data, position) * 4294967296 + (0, _core_utils.readUint32)(data, position + 4); - position += 8; - headerSize += 8; - } - - if (lbox === 0) { - lbox = length - position + headerSize; - } - - if (lbox < headerSize) { - throw new JpxError("Invalid box field size"); - } - - var dataLength = lbox - headerSize; - var jumpDataLength = true; - - switch (tbox) { - case 0x6a703268: - jumpDataLength = false; - break; - - case 0x636f6c72: - var method = data[position]; - - if (method === 1) { - var colorspace = (0, _core_utils.readUint32)(data, position + 3); - - switch (colorspace) { - case 16: - case 17: - case 18: - break; - - default: - (0, _util.warn)("Unknown colorspace " + colorspace); - break; - } - } else if (method === 2) { - (0, _util.info)("ICC profile not supported"); - } - - break; - - case 0x6a703263: - this.parseCodestream(data, position, position + dataLength); - break; - - case 0x6a502020: - if ((0, _core_utils.readUint32)(data, position) !== 0x0d0a870a) { - (0, _util.warn)("Invalid JP2 signature"); - } - - break; - - case 0x6a501a1a: - case 0x66747970: - case 0x72726571: - case 0x72657320: - case 0x69686472: - break; - - default: - var headerType = String.fromCharCode(tbox >> 24 & 0xff, tbox >> 16 & 0xff, tbox >> 8 & 0xff, tbox & 0xff); - (0, _util.warn)("Unsupported header type " + tbox + " (" + headerType + ")"); - break; - } - - if (jumpDataLength) { - position += dataLength; - } - } - }, - parseImageProperties: function JpxImage_parseImageProperties(stream) { - var newByte = stream.getByte(); - - while (newByte >= 0) { - var oldByte = newByte; - newByte = stream.getByte(); - var code = oldByte << 8 | newByte; - - if (code === 0xff51) { - stream.skip(4); - var Xsiz = stream.getInt32() >>> 0; - var Ysiz = stream.getInt32() >>> 0; - var XOsiz = stream.getInt32() >>> 0; - var YOsiz = stream.getInt32() >>> 0; - stream.skip(16); - var Csiz = stream.getUint16(); - this.width = Xsiz - XOsiz; - this.height = Ysiz - YOsiz; - this.componentsCount = Csiz; - this.bitsPerComponent = 8; - return; - } - } - - throw new JpxError("No size marker found in JPX stream"); - }, - parseCodestream: function JpxImage_parseCodestream(data, start, end) { - var context = {}; - var doNotRecover = false; - - try { - var position = start; - - while (position + 1 < end) { - var code = (0, _core_utils.readUint16)(data, position); - position += 2; - var length = 0, - j, - sqcd, - spqcds, - spqcdSize, - scalarExpounded, - tile; - - switch (code) { - case 0xff4f: - context.mainHeader = true; - break; - - case 0xffd9: - break; - - case 0xff51: - length = (0, _core_utils.readUint16)(data, position); - var siz = {}; - siz.Xsiz = (0, _core_utils.readUint32)(data, position + 4); - siz.Ysiz = (0, _core_utils.readUint32)(data, position + 8); - siz.XOsiz = (0, _core_utils.readUint32)(data, position + 12); - siz.YOsiz = (0, _core_utils.readUint32)(data, position + 16); - siz.XTsiz = (0, _core_utils.readUint32)(data, position + 20); - siz.YTsiz = (0, _core_utils.readUint32)(data, position + 24); - siz.XTOsiz = (0, _core_utils.readUint32)(data, position + 28); - siz.YTOsiz = (0, _core_utils.readUint32)(data, position + 32); - var componentsCount = (0, _core_utils.readUint16)(data, position + 36); - siz.Csiz = componentsCount; - var components = []; - j = position + 38; - - for (var i = 0; i < componentsCount; i++) { - var component = { - precision: (data[j] & 0x7f) + 1, - isSigned: !!(data[j] & 0x80), - XRsiz: data[j + 1], - YRsiz: data[j + 2] - }; - j += 3; - calculateComponentDimensions(component, siz); - components.push(component); - } - - context.SIZ = siz; - context.components = components; - calculateTileGrids(context, components); - context.QCC = []; - context.COC = []; - break; - - case 0xff5c: - length = (0, _core_utils.readUint16)(data, position); - var qcd = {}; - j = position + 2; - sqcd = data[j++]; - - switch (sqcd & 0x1f) { - case 0: - spqcdSize = 8; - scalarExpounded = true; - break; - - case 1: - spqcdSize = 16; - scalarExpounded = false; - break; - - case 2: - spqcdSize = 16; - scalarExpounded = true; - break; - - default: - throw new Error("Invalid SQcd value " + sqcd); - } - - qcd.noQuantization = spqcdSize === 8; - qcd.scalarExpounded = scalarExpounded; - qcd.guardBits = sqcd >> 5; - spqcds = []; - - while (j < length + position) { - var spqcd = {}; - - if (spqcdSize === 8) { - spqcd.epsilon = data[j++] >> 3; - spqcd.mu = 0; - } else { - spqcd.epsilon = data[j] >> 3; - spqcd.mu = (data[j] & 0x7) << 8 | data[j + 1]; - j += 2; - } - - spqcds.push(spqcd); - } - - qcd.SPqcds = spqcds; - - if (context.mainHeader) { - context.QCD = qcd; - } else { - context.currentTile.QCD = qcd; - context.currentTile.QCC = []; - } - - break; - - case 0xff5d: - length = (0, _core_utils.readUint16)(data, position); - var qcc = {}; - j = position + 2; - var cqcc; - - if (context.SIZ.Csiz < 257) { - cqcc = data[j++]; - } else { - cqcc = (0, _core_utils.readUint16)(data, j); - j += 2; - } - - sqcd = data[j++]; - - switch (sqcd & 0x1f) { - case 0: - spqcdSize = 8; - scalarExpounded = true; - break; - - case 1: - spqcdSize = 16; - scalarExpounded = false; - break; - - case 2: - spqcdSize = 16; - scalarExpounded = true; - break; - - default: - throw new Error("Invalid SQcd value " + sqcd); - } - - qcc.noQuantization = spqcdSize === 8; - qcc.scalarExpounded = scalarExpounded; - qcc.guardBits = sqcd >> 5; - spqcds = []; - - while (j < length + position) { - spqcd = {}; - - if (spqcdSize === 8) { - spqcd.epsilon = data[j++] >> 3; - spqcd.mu = 0; - } else { - spqcd.epsilon = data[j] >> 3; - spqcd.mu = (data[j] & 0x7) << 8 | data[j + 1]; - j += 2; - } - - spqcds.push(spqcd); - } - - qcc.SPqcds = spqcds; - - if (context.mainHeader) { - context.QCC[cqcc] = qcc; - } else { - context.currentTile.QCC[cqcc] = qcc; - } - - break; - - case 0xff52: - length = (0, _core_utils.readUint16)(data, position); - var cod = {}; - j = position + 2; - var scod = data[j++]; - cod.entropyCoderWithCustomPrecincts = !!(scod & 1); - cod.sopMarkerUsed = !!(scod & 2); - cod.ephMarkerUsed = !!(scod & 4); - cod.progressionOrder = data[j++]; - cod.layersCount = (0, _core_utils.readUint16)(data, j); - j += 2; - cod.multipleComponentTransform = data[j++]; - cod.decompositionLevelsCount = data[j++]; - cod.xcb = (data[j++] & 0xf) + 2; - cod.ycb = (data[j++] & 0xf) + 2; - var blockStyle = data[j++]; - cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1); - cod.resetContextProbabilities = !!(blockStyle & 2); - cod.terminationOnEachCodingPass = !!(blockStyle & 4); - cod.verticallyStripe = !!(blockStyle & 8); - cod.predictableTermination = !!(blockStyle & 16); - cod.segmentationSymbolUsed = !!(blockStyle & 32); - cod.reversibleTransformation = data[j++]; - - if (cod.entropyCoderWithCustomPrecincts) { - var precinctsSizes = []; - - while (j < length + position) { - var precinctsSize = data[j++]; - precinctsSizes.push({ - PPx: precinctsSize & 0xf, - PPy: precinctsSize >> 4 - }); - } - - cod.precinctsSizes = precinctsSizes; - } - - var unsupported = []; - - if (cod.selectiveArithmeticCodingBypass) { - unsupported.push("selectiveArithmeticCodingBypass"); - } - - if (cod.resetContextProbabilities) { - unsupported.push("resetContextProbabilities"); - } - - if (cod.terminationOnEachCodingPass) { - unsupported.push("terminationOnEachCodingPass"); - } - - if (cod.verticallyStripe) { - unsupported.push("verticallyStripe"); - } - - if (cod.predictableTermination) { - unsupported.push("predictableTermination"); - } - - if (unsupported.length > 0) { - doNotRecover = true; - throw new Error("Unsupported COD options (" + unsupported.join(", ") + ")"); - } - - if (context.mainHeader) { - context.COD = cod; - } else { - context.currentTile.COD = cod; - context.currentTile.COC = []; - } - - break; - - case 0xff90: - length = (0, _core_utils.readUint16)(data, position); - tile = {}; - tile.index = (0, _core_utils.readUint16)(data, position + 2); - tile.length = (0, _core_utils.readUint32)(data, position + 4); - tile.dataEnd = tile.length + position - 2; - tile.partIndex = data[position + 8]; - tile.partsCount = data[position + 9]; - context.mainHeader = false; - - if (tile.partIndex === 0) { - tile.COD = context.COD; - tile.COC = context.COC.slice(0); - tile.QCD = context.QCD; - tile.QCC = context.QCC.slice(0); - } - - context.currentTile = tile; - break; - - case 0xff93: - tile = context.currentTile; - - if (tile.partIndex === 0) { - initializeTile(context, tile.index); - buildPackets(context); - } - - length = tile.dataEnd - position; - parseTilePackets(context, data, position, length); - break; - - case 0xff55: - case 0xff57: - case 0xff58: - case 0xff64: - length = (0, _core_utils.readUint16)(data, position); - break; - - case 0xff53: - throw new Error("Codestream code 0xFF53 (COC) is not implemented"); - - default: - throw new Error("Unknown codestream code: " + code.toString(16)); - } - - position += length; - } - } catch (e) { - if (doNotRecover || this.failOnCorruptedImage) { - throw new JpxError(e.message); - } else { - (0, _util.warn)("JPX: Trying to recover from: " + e.message); - } - } - - this.tiles = transformComponents(context); - this.width = context.SIZ.Xsiz - context.SIZ.XOsiz; - this.height = context.SIZ.Ysiz - context.SIZ.YOsiz; - this.componentsCount = context.SIZ.Csiz; - } - }; - - function calculateComponentDimensions(component, siz) { - component.x0 = Math.ceil(siz.XOsiz / component.XRsiz); - component.x1 = Math.ceil(siz.Xsiz / component.XRsiz); - component.y0 = Math.ceil(siz.YOsiz / component.YRsiz); - component.y1 = Math.ceil(siz.Ysiz / component.YRsiz); - component.width = component.x1 - component.x0; - component.height = component.y1 - component.y0; - } - - function calculateTileGrids(context, components) { - var siz = context.SIZ; - var tile, - tiles = []; - var numXtiles = Math.ceil((siz.Xsiz - siz.XTOsiz) / siz.XTsiz); - var numYtiles = Math.ceil((siz.Ysiz - siz.YTOsiz) / siz.YTsiz); - - for (var q = 0; q < numYtiles; q++) { - for (var p = 0; p < numXtiles; p++) { - tile = {}; - tile.tx0 = Math.max(siz.XTOsiz + p * siz.XTsiz, siz.XOsiz); - tile.ty0 = Math.max(siz.YTOsiz + q * siz.YTsiz, siz.YOsiz); - tile.tx1 = Math.min(siz.XTOsiz + (p + 1) * siz.XTsiz, siz.Xsiz); - tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz); - tile.width = tile.tx1 - tile.tx0; - tile.height = tile.ty1 - tile.ty0; - tile.components = []; - tiles.push(tile); - } - } - - context.tiles = tiles; - var componentsCount = siz.Csiz; - - for (var i = 0, ii = componentsCount; i < ii; i++) { - var component = components[i]; - - for (var j = 0, jj = tiles.length; j < jj; j++) { - var tileComponent = {}; - tile = tiles[j]; - tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz); - tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz); - tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz); - tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz); - tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0; - tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0; - tile.components[i] = tileComponent; - } - } - } - - function getBlocksDimensions(context, component, r) { - var codOrCoc = component.codingStyleParameters; - var result = {}; - - if (!codOrCoc.entropyCoderWithCustomPrecincts) { - result.PPx = 15; - result.PPy = 15; - } else { - result.PPx = codOrCoc.precinctsSizes[r].PPx; - result.PPy = codOrCoc.precinctsSizes[r].PPy; - } - - result.xcb_ = r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) : Math.min(codOrCoc.xcb, result.PPx); - result.ycb_ = r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) : Math.min(codOrCoc.ycb, result.PPy); - return result; - } - - function buildPrecincts(context, resolution, dimensions) { - var precinctWidth = 1 << dimensions.PPx; - var precinctHeight = 1 << dimensions.PPy; - var isZeroRes = resolution.resLevel === 0; - var precinctWidthInSubband = 1 << dimensions.PPx + (isZeroRes ? 0 : -1); - var precinctHeightInSubband = 1 << dimensions.PPy + (isZeroRes ? 0 : -1); - var numprecinctswide = resolution.trx1 > resolution.trx0 ? Math.ceil(resolution.trx1 / precinctWidth) - Math.floor(resolution.trx0 / precinctWidth) : 0; - var numprecinctshigh = resolution.try1 > resolution.try0 ? Math.ceil(resolution.try1 / precinctHeight) - Math.floor(resolution.try0 / precinctHeight) : 0; - var numprecincts = numprecinctswide * numprecinctshigh; - resolution.precinctParameters = { - precinctWidth, - precinctHeight, - numprecinctswide, - numprecinctshigh, - numprecincts, - precinctWidthInSubband, - precinctHeightInSubband - }; - } - - function buildCodeblocks(context, subband, dimensions) { - var xcb_ = dimensions.xcb_; - var ycb_ = dimensions.ycb_; - var codeblockWidth = 1 << xcb_; - var codeblockHeight = 1 << ycb_; - var cbx0 = subband.tbx0 >> xcb_; - var cby0 = subband.tby0 >> ycb_; - var cbx1 = subband.tbx1 + codeblockWidth - 1 >> xcb_; - var cby1 = subband.tby1 + codeblockHeight - 1 >> ycb_; - var precinctParameters = subband.resolution.precinctParameters; - var codeblocks = []; - var precincts = []; - var i, j, codeblock, precinctNumber; - - for (j = cby0; j < cby1; j++) { - for (i = cbx0; i < cbx1; i++) { - codeblock = { - cbx: i, - cby: j, - tbx0: codeblockWidth * i, - tby0: codeblockHeight * j, - tbx1: codeblockWidth * (i + 1), - tby1: codeblockHeight * (j + 1) - }; - codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0); - codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0); - codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1); - codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1); - var pi = Math.floor((codeblock.tbx0_ - subband.tbx0) / precinctParameters.precinctWidthInSubband); - var pj = Math.floor((codeblock.tby0_ - subband.tby0) / precinctParameters.precinctHeightInSubband); - precinctNumber = pi + pj * precinctParameters.numprecinctswide; - codeblock.precinctNumber = precinctNumber; - codeblock.subbandType = subband.type; - codeblock.Lblock = 3; - - if (codeblock.tbx1_ <= codeblock.tbx0_ || codeblock.tby1_ <= codeblock.tby0_) { - continue; - } - - codeblocks.push(codeblock); - var precinct = precincts[precinctNumber]; - - if (precinct !== undefined) { - if (i < precinct.cbxMin) { - precinct.cbxMin = i; - } else if (i > precinct.cbxMax) { - precinct.cbxMax = i; - } - - if (j < precinct.cbyMin) { - precinct.cbxMin = j; - } else if (j > precinct.cbyMax) { - precinct.cbyMax = j; - } - } else { - precincts[precinctNumber] = precinct = { - cbxMin: i, - cbyMin: j, - cbxMax: i, - cbyMax: j - }; - } - - codeblock.precinct = precinct; - } - } - - subband.codeblockParameters = { - codeblockWidth: xcb_, - codeblockHeight: ycb_, - numcodeblockwide: cbx1 - cbx0 + 1, - numcodeblockhigh: cby1 - cby0 + 1 - }; - subband.codeblocks = codeblocks; - subband.precincts = precincts; - } - - function createPacket(resolution, precinctNumber, layerNumber) { - var precinctCodeblocks = []; - var subbands = resolution.subbands; - - for (var i = 0, ii = subbands.length; i < ii; i++) { - var subband = subbands[i]; - var codeblocks = subband.codeblocks; - - for (var j = 0, jj = codeblocks.length; j < jj; j++) { - var codeblock = codeblocks[j]; - - if (codeblock.precinctNumber !== precinctNumber) { - continue; - } - - precinctCodeblocks.push(codeblock); - } - } - - return { - layerNumber, - codeblocks: precinctCodeblocks - }; - } - - function LayerResolutionComponentPositionIterator(context) { - var siz = context.SIZ; - var tileIndex = context.currentTile.index; - var tile = context.tiles[tileIndex]; - var layersCount = tile.codingStyleDefaultParameters.layersCount; - var componentsCount = siz.Csiz; - var maxDecompositionLevelsCount = 0; - - for (var q = 0; q < componentsCount; q++) { - maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, tile.components[q].codingStyleParameters.decompositionLevelsCount); - } - - var l = 0, - r = 0, - i = 0, - k = 0; - - this.nextPacket = function JpxImage_nextPacket() { - for (; l < layersCount; l++) { - for (; r <= maxDecompositionLevelsCount; r++) { - for (; i < componentsCount; i++) { - var component = tile.components[i]; - - if (r > component.codingStyleParameters.decompositionLevelsCount) { - continue; - } - - var resolution = component.resolutions[r]; - var numprecincts = resolution.precinctParameters.numprecincts; - - for (; k < numprecincts;) { - var packet = createPacket(resolution, k, l); - k++; - return packet; - } - - k = 0; - } - - i = 0; - } - - r = 0; - } - - throw new JpxError("Out of packets"); - }; - } - - function ResolutionLayerComponentPositionIterator(context) { - var siz = context.SIZ; - var tileIndex = context.currentTile.index; - var tile = context.tiles[tileIndex]; - var layersCount = tile.codingStyleDefaultParameters.layersCount; - var componentsCount = siz.Csiz; - var maxDecompositionLevelsCount = 0; - - for (var q = 0; q < componentsCount; q++) { - maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, tile.components[q].codingStyleParameters.decompositionLevelsCount); - } - - var r = 0, - l = 0, - i = 0, - k = 0; - - this.nextPacket = function JpxImage_nextPacket() { - for (; r <= maxDecompositionLevelsCount; r++) { - for (; l < layersCount; l++) { - for (; i < componentsCount; i++) { - var component = tile.components[i]; - - if (r > component.codingStyleParameters.decompositionLevelsCount) { - continue; - } - - var resolution = component.resolutions[r]; - var numprecincts = resolution.precinctParameters.numprecincts; - - for (; k < numprecincts;) { - var packet = createPacket(resolution, k, l); - k++; - return packet; - } - - k = 0; - } - - i = 0; - } - - l = 0; - } - - throw new JpxError("Out of packets"); - }; - } - - function ResolutionPositionComponentLayerIterator(context) { - var siz = context.SIZ; - var tileIndex = context.currentTile.index; - var tile = context.tiles[tileIndex]; - var layersCount = tile.codingStyleDefaultParameters.layersCount; - var componentsCount = siz.Csiz; - var l, r, c, p; - var maxDecompositionLevelsCount = 0; - - for (c = 0; c < componentsCount; c++) { - const component = tile.components[c]; - maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, component.codingStyleParameters.decompositionLevelsCount); - } - - var maxNumPrecinctsInLevel = new Int32Array(maxDecompositionLevelsCount + 1); - - for (r = 0; r <= maxDecompositionLevelsCount; ++r) { - var maxNumPrecincts = 0; - - for (c = 0; c < componentsCount; ++c) { - var resolutions = tile.components[c].resolutions; - - if (r < resolutions.length) { - maxNumPrecincts = Math.max(maxNumPrecincts, resolutions[r].precinctParameters.numprecincts); - } - } - - maxNumPrecinctsInLevel[r] = maxNumPrecincts; - } - - l = 0; - r = 0; - c = 0; - p = 0; - - this.nextPacket = function JpxImage_nextPacket() { - for (; r <= maxDecompositionLevelsCount; r++) { - for (; p < maxNumPrecinctsInLevel[r]; p++) { - for (; c < componentsCount; c++) { - const component = tile.components[c]; - - if (r > component.codingStyleParameters.decompositionLevelsCount) { - continue; - } - - var resolution = component.resolutions[r]; - var numprecincts = resolution.precinctParameters.numprecincts; - - if (p >= numprecincts) { - continue; - } - - for (; l < layersCount;) { - var packet = createPacket(resolution, p, l); - l++; - return packet; - } - - l = 0; - } - - c = 0; - } - - p = 0; - } - - throw new JpxError("Out of packets"); - }; - } - - function PositionComponentResolutionLayerIterator(context) { - var siz = context.SIZ; - var tileIndex = context.currentTile.index; - var tile = context.tiles[tileIndex]; - var layersCount = tile.codingStyleDefaultParameters.layersCount; - var componentsCount = siz.Csiz; - var precinctsSizes = getPrecinctSizesInImageScale(tile); - var precinctsIterationSizes = precinctsSizes; - var l = 0, - r = 0, - c = 0, - px = 0, - py = 0; - - this.nextPacket = function JpxImage_nextPacket() { - for (; py < precinctsIterationSizes.maxNumHigh; py++) { - for (; px < precinctsIterationSizes.maxNumWide; px++) { - for (; c < componentsCount; c++) { - var component = tile.components[c]; - var decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount; - - for (; r <= decompositionLevelsCount; r++) { - var resolution = component.resolutions[r]; - var sizeInImageScale = precinctsSizes.components[c].resolutions[r]; - var k = getPrecinctIndexIfExist(px, py, sizeInImageScale, precinctsIterationSizes, resolution); - - if (k === null) { - continue; - } - - for (; l < layersCount;) { - var packet = createPacket(resolution, k, l); - l++; - return packet; - } - - l = 0; - } - - r = 0; - } - - c = 0; - } - - px = 0; - } - - throw new JpxError("Out of packets"); - }; - } - - function ComponentPositionResolutionLayerIterator(context) { - var siz = context.SIZ; - var tileIndex = context.currentTile.index; - var tile = context.tiles[tileIndex]; - var layersCount = tile.codingStyleDefaultParameters.layersCount; - var componentsCount = siz.Csiz; - var precinctsSizes = getPrecinctSizesInImageScale(tile); - var l = 0, - r = 0, - c = 0, - px = 0, - py = 0; - - this.nextPacket = function JpxImage_nextPacket() { - for (; c < componentsCount; ++c) { - var component = tile.components[c]; - var precinctsIterationSizes = precinctsSizes.components[c]; - var decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount; - - for (; py < precinctsIterationSizes.maxNumHigh; py++) { - for (; px < precinctsIterationSizes.maxNumWide; px++) { - for (; r <= decompositionLevelsCount; r++) { - var resolution = component.resolutions[r]; - var sizeInImageScale = precinctsIterationSizes.resolutions[r]; - var k = getPrecinctIndexIfExist(px, py, sizeInImageScale, precinctsIterationSizes, resolution); - - if (k === null) { - continue; - } - - for (; l < layersCount;) { - var packet = createPacket(resolution, k, l); - l++; - return packet; - } - - l = 0; - } - - r = 0; - } - - px = 0; - } - - py = 0; - } - - throw new JpxError("Out of packets"); - }; - } - - function getPrecinctIndexIfExist(pxIndex, pyIndex, sizeInImageScale, precinctIterationSizes, resolution) { - var posX = pxIndex * precinctIterationSizes.minWidth; - var posY = pyIndex * precinctIterationSizes.minHeight; - - if (posX % sizeInImageScale.width !== 0 || posY % sizeInImageScale.height !== 0) { - return null; - } - - var startPrecinctRowIndex = posY / sizeInImageScale.width * resolution.precinctParameters.numprecinctswide; - return posX / sizeInImageScale.height + startPrecinctRowIndex; - } - - function getPrecinctSizesInImageScale(tile) { - var componentsCount = tile.components.length; - var minWidth = Number.MAX_VALUE; - var minHeight = Number.MAX_VALUE; - var maxNumWide = 0; - var maxNumHigh = 0; - var sizePerComponent = new Array(componentsCount); - - for (var c = 0; c < componentsCount; c++) { - var component = tile.components[c]; - var decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount; - var sizePerResolution = new Array(decompositionLevelsCount + 1); - var minWidthCurrentComponent = Number.MAX_VALUE; - var minHeightCurrentComponent = Number.MAX_VALUE; - var maxNumWideCurrentComponent = 0; - var maxNumHighCurrentComponent = 0; - var scale = 1; - - for (var r = decompositionLevelsCount; r >= 0; --r) { - var resolution = component.resolutions[r]; - var widthCurrentResolution = scale * resolution.precinctParameters.precinctWidth; - var heightCurrentResolution = scale * resolution.precinctParameters.precinctHeight; - minWidthCurrentComponent = Math.min(minWidthCurrentComponent, widthCurrentResolution); - minHeightCurrentComponent = Math.min(minHeightCurrentComponent, heightCurrentResolution); - maxNumWideCurrentComponent = Math.max(maxNumWideCurrentComponent, resolution.precinctParameters.numprecinctswide); - maxNumHighCurrentComponent = Math.max(maxNumHighCurrentComponent, resolution.precinctParameters.numprecinctshigh); - sizePerResolution[r] = { - width: widthCurrentResolution, - height: heightCurrentResolution - }; - scale <<= 1; - } - - minWidth = Math.min(minWidth, minWidthCurrentComponent); - minHeight = Math.min(minHeight, minHeightCurrentComponent); - maxNumWide = Math.max(maxNumWide, maxNumWideCurrentComponent); - maxNumHigh = Math.max(maxNumHigh, maxNumHighCurrentComponent); - sizePerComponent[c] = { - resolutions: sizePerResolution, - minWidth: minWidthCurrentComponent, - minHeight: minHeightCurrentComponent, - maxNumWide: maxNumWideCurrentComponent, - maxNumHigh: maxNumHighCurrentComponent - }; - } - - return { - components: sizePerComponent, - minWidth, - minHeight, - maxNumWide, - maxNumHigh - }; - } - - function buildPackets(context) { - var siz = context.SIZ; - var tileIndex = context.currentTile.index; - var tile = context.tiles[tileIndex]; - var componentsCount = siz.Csiz; - - for (var c = 0; c < componentsCount; c++) { - var component = tile.components[c]; - var decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount; - var resolutions = []; - var subbands = []; - - for (var r = 0; r <= decompositionLevelsCount; r++) { - var blocksDimensions = getBlocksDimensions(context, component, r); - var resolution = {}; - var scale = 1 << decompositionLevelsCount - r; - resolution.trx0 = Math.ceil(component.tcx0 / scale); - resolution.try0 = Math.ceil(component.tcy0 / scale); - resolution.trx1 = Math.ceil(component.tcx1 / scale); - resolution.try1 = Math.ceil(component.tcy1 / scale); - resolution.resLevel = r; - buildPrecincts(context, resolution, blocksDimensions); - resolutions.push(resolution); - var subband; - - if (r === 0) { - subband = {}; - subband.type = "LL"; - subband.tbx0 = Math.ceil(component.tcx0 / scale); - subband.tby0 = Math.ceil(component.tcy0 / scale); - subband.tbx1 = Math.ceil(component.tcx1 / scale); - subband.tby1 = Math.ceil(component.tcy1 / scale); - subband.resolution = resolution; - buildCodeblocks(context, subband, blocksDimensions); - subbands.push(subband); - resolution.subbands = [subband]; - } else { - var bscale = 1 << decompositionLevelsCount - r + 1; - var resolutionSubbands = []; - subband = {}; - subband.type = "HL"; - subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5); - subband.tby0 = Math.ceil(component.tcy0 / bscale); - subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5); - subband.tby1 = Math.ceil(component.tcy1 / bscale); - subband.resolution = resolution; - buildCodeblocks(context, subband, blocksDimensions); - subbands.push(subband); - resolutionSubbands.push(subband); - subband = {}; - subband.type = "LH"; - subband.tbx0 = Math.ceil(component.tcx0 / bscale); - subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5); - subband.tbx1 = Math.ceil(component.tcx1 / bscale); - subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5); - subband.resolution = resolution; - buildCodeblocks(context, subband, blocksDimensions); - subbands.push(subband); - resolutionSubbands.push(subband); - subband = {}; - subband.type = "HH"; - subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5); - subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5); - subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5); - subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5); - subband.resolution = resolution; - buildCodeblocks(context, subband, blocksDimensions); - subbands.push(subband); - resolutionSubbands.push(subband); - resolution.subbands = resolutionSubbands; - } - } - - component.resolutions = resolutions; - component.subbands = subbands; - } - - var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder; - - switch (progressionOrder) { - case 0: - tile.packetsIterator = new LayerResolutionComponentPositionIterator(context); - break; - - case 1: - tile.packetsIterator = new ResolutionLayerComponentPositionIterator(context); - break; - - case 2: - tile.packetsIterator = new ResolutionPositionComponentLayerIterator(context); - break; - - case 3: - tile.packetsIterator = new PositionComponentResolutionLayerIterator(context); - break; - - case 4: - tile.packetsIterator = new ComponentPositionResolutionLayerIterator(context); - break; - - default: - throw new JpxError(`Unsupported progression order ${progressionOrder}`); - } - } - - function parseTilePackets(context, data, offset, dataLength) { - var position = 0; - var buffer, - bufferSize = 0, - skipNextBit = false; - - function readBits(count) { - while (bufferSize < count) { - var b = data[offset + position]; - position++; - - if (skipNextBit) { - buffer = buffer << 7 | b; - bufferSize += 7; - skipNextBit = false; - } else { - buffer = buffer << 8 | b; - bufferSize += 8; - } - - if (b === 0xff) { - skipNextBit = true; - } - } - - bufferSize -= count; - return buffer >>> bufferSize & (1 << count) - 1; - } - - function skipMarkerIfEqual(value) { - if (data[offset + position - 1] === 0xff && data[offset + position] === value) { - skipBytes(1); - return true; - } else if (data[offset + position] === 0xff && data[offset + position + 1] === value) { - skipBytes(2); - return true; - } - - return false; - } - - function skipBytes(count) { - position += count; - } - - function alignToByte() { - bufferSize = 0; - - if (skipNextBit) { - position++; - skipNextBit = false; - } - } - - function readCodingpasses() { - if (readBits(1) === 0) { - return 1; - } - - if (readBits(1) === 0) { - return 2; - } - - var value = readBits(2); - - if (value < 3) { - return value + 3; - } - - value = readBits(5); - - if (value < 31) { - return value + 6; - } - - value = readBits(7); - return value + 37; - } - - var tileIndex = context.currentTile.index; - var tile = context.tiles[tileIndex]; - var sopMarkerUsed = context.COD.sopMarkerUsed; - var ephMarkerUsed = context.COD.ephMarkerUsed; - var packetsIterator = tile.packetsIterator; - - while (position < dataLength) { - alignToByte(); - - if (sopMarkerUsed && skipMarkerIfEqual(0x91)) { - skipBytes(4); - } - - var packet = packetsIterator.nextPacket(); - - if (!readBits(1)) { - continue; - } - - var layerNumber = packet.layerNumber; - var queue = [], - codeblock; - - for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) { - codeblock = packet.codeblocks[i]; - var precinct = codeblock.precinct; - var codeblockColumn = codeblock.cbx - precinct.cbxMin; - var codeblockRow = codeblock.cby - precinct.cbyMin; - var codeblockIncluded = false; - var firstTimeInclusion = false; - var valueReady; - - if (codeblock.included !== undefined) { - codeblockIncluded = !!readBits(1); - } else { - precinct = codeblock.precinct; - var inclusionTree, zeroBitPlanesTree; - - if (precinct.inclusionTree !== undefined) { - inclusionTree = precinct.inclusionTree; - } else { - var width = precinct.cbxMax - precinct.cbxMin + 1; - var height = precinct.cbyMax - precinct.cbyMin + 1; - inclusionTree = new InclusionTree(width, height, layerNumber); - zeroBitPlanesTree = new TagTree(width, height); - precinct.inclusionTree = inclusionTree; - precinct.zeroBitPlanesTree = zeroBitPlanesTree; - } - - if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) { - while (true) { - if (readBits(1)) { - valueReady = !inclusionTree.nextLevel(); - - if (valueReady) { - codeblock.included = true; - codeblockIncluded = firstTimeInclusion = true; - break; - } - } else { - inclusionTree.incrementValue(layerNumber); - break; - } - } - } - } - - if (!codeblockIncluded) { - continue; - } - - if (firstTimeInclusion) { - zeroBitPlanesTree = precinct.zeroBitPlanesTree; - zeroBitPlanesTree.reset(codeblockColumn, codeblockRow); - - while (true) { - if (readBits(1)) { - valueReady = !zeroBitPlanesTree.nextLevel(); - - if (valueReady) { - break; - } - } else { - zeroBitPlanesTree.incrementValue(); - } - } - - codeblock.zeroBitPlanes = zeroBitPlanesTree.value; - } - - var codingpasses = readCodingpasses(); - - while (readBits(1)) { - codeblock.Lblock++; - } - - var codingpassesLog2 = (0, _core_utils.log2)(codingpasses); - var bits = (codingpasses < 1 << codingpassesLog2 ? codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock; - var codedDataLength = readBits(bits); - queue.push({ - codeblock, - codingpasses, - dataLength: codedDataLength - }); - } - - alignToByte(); - - if (ephMarkerUsed) { - skipMarkerIfEqual(0x92); - } - - while (queue.length > 0) { - var packetItem = queue.shift(); - codeblock = packetItem.codeblock; - - if (codeblock.data === undefined) { - codeblock.data = []; - } - - codeblock.data.push({ - data, - start: offset + position, - end: offset + position + packetItem.dataLength, - codingpasses: packetItem.codingpasses - }); - position += packetItem.dataLength; - } - } - - return position; - } - - function copyCoefficients(coefficients, levelWidth, levelHeight, subband, delta, mb, reversible, segmentationSymbolUsed) { - var x0 = subband.tbx0; - var y0 = subband.tby0; - var width = subband.tbx1 - subband.tbx0; - var codeblocks = subband.codeblocks; - var right = subband.type.charAt(0) === "H" ? 1 : 0; - var bottom = subband.type.charAt(1) === "H" ? levelWidth : 0; - - for (var i = 0, ii = codeblocks.length; i < ii; ++i) { - var codeblock = codeblocks[i]; - var blockWidth = codeblock.tbx1_ - codeblock.tbx0_; - var blockHeight = codeblock.tby1_ - codeblock.tby0_; - - if (blockWidth === 0 || blockHeight === 0) { - continue; - } - - if (codeblock.data === undefined) { - continue; - } - - var bitModel, currentCodingpassType; - bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType, codeblock.zeroBitPlanes, mb); - currentCodingpassType = 2; - var data = codeblock.data, - totalLength = 0, - codingpasses = 0; - var j, jj, dataItem; - - for (j = 0, jj = data.length; j < jj; j++) { - dataItem = data[j]; - totalLength += dataItem.end - dataItem.start; - codingpasses += dataItem.codingpasses; - } - - var encodedData = new Uint8Array(totalLength); - var position = 0; - - for (j = 0, jj = data.length; j < jj; j++) { - dataItem = data[j]; - var chunk = dataItem.data.subarray(dataItem.start, dataItem.end); - encodedData.set(chunk, position); - position += chunk.length; - } - - var decoder = new _arithmetic_decoder.ArithmeticDecoder(encodedData, 0, totalLength); - bitModel.setDecoder(decoder); - - for (j = 0; j < codingpasses; j++) { - switch (currentCodingpassType) { - case 0: - bitModel.runSignificancePropagationPass(); - break; - - case 1: - bitModel.runMagnitudeRefinementPass(); - break; - - case 2: - bitModel.runCleanupPass(); - - if (segmentationSymbolUsed) { - bitModel.checkSegmentationSymbol(); - } - - break; - } - - currentCodingpassType = (currentCodingpassType + 1) % 3; - } - - var offset = codeblock.tbx0_ - x0 + (codeblock.tby0_ - y0) * width; - var sign = bitModel.coefficentsSign; - var magnitude = bitModel.coefficentsMagnitude; - var bitsDecoded = bitModel.bitsDecoded; - var magnitudeCorrection = reversible ? 0 : 0.5; - var k, n, nb; - position = 0; - var interleave = subband.type !== "LL"; - - for (j = 0; j < blockHeight; j++) { - var row = offset / width | 0; - var levelOffset = 2 * row * (levelWidth - width) + right + bottom; - - for (k = 0; k < blockWidth; k++) { - n = magnitude[position]; - - if (n !== 0) { - n = (n + magnitudeCorrection) * delta; - - if (sign[position] !== 0) { - n = -n; - } - - nb = bitsDecoded[position]; - var pos = interleave ? levelOffset + (offset << 1) : offset; - - if (reversible && nb >= mb) { - coefficients[pos] = n; - } else { - coefficients[pos] = n * (1 << mb - nb); - } - } - - offset++; - position++; - } - - offset += width - blockWidth; - } - } - } - - function transformTile(context, tile, c) { - var component = tile.components[c]; - var codingStyleParameters = component.codingStyleParameters; - var quantizationParameters = component.quantizationParameters; - var decompositionLevelsCount = codingStyleParameters.decompositionLevelsCount; - var spqcds = quantizationParameters.SPqcds; - var scalarExpounded = quantizationParameters.scalarExpounded; - var guardBits = quantizationParameters.guardBits; - var segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed; - var precision = context.components[c].precision; - var reversible = codingStyleParameters.reversibleTransformation; - var transform = reversible ? new ReversibleTransform() : new IrreversibleTransform(); - var subbandCoefficients = []; - var b = 0; - - for (var i = 0; i <= decompositionLevelsCount; i++) { - var resolution = component.resolutions[i]; - var width = resolution.trx1 - resolution.trx0; - var height = resolution.try1 - resolution.try0; - var coefficients = new Float32Array(width * height); - - for (var j = 0, jj = resolution.subbands.length; j < jj; j++) { - var mu, epsilon; - - if (!scalarExpounded) { - mu = spqcds[0].mu; - epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0); - } else { - mu = spqcds[b].mu; - epsilon = spqcds[b].epsilon; - b++; - } - - var subband = resolution.subbands[j]; - var gainLog2 = SubbandsGainLog2[subband.type]; - var delta = reversible ? 1 : 2 ** (precision + gainLog2 - epsilon) * (1 + mu / 2048); - var mb = guardBits + epsilon - 1; - copyCoefficients(coefficients, width, height, subband, delta, mb, reversible, segmentationSymbolUsed); - } - - subbandCoefficients.push({ - width, - height, - items: coefficients - }); - } - - var result = transform.calculate(subbandCoefficients, component.tcx0, component.tcy0); - return { - left: component.tcx0, - top: component.tcy0, - width: result.width, - height: result.height, - items: result.items - }; - } - - function transformComponents(context) { - var siz = context.SIZ; - var components = context.components; - var componentsCount = siz.Csiz; - var resultImages = []; - - for (var i = 0, ii = context.tiles.length; i < ii; i++) { - var tile = context.tiles[i]; - var transformedTiles = []; - var c; - - for (c = 0; c < componentsCount; c++) { - transformedTiles[c] = transformTile(context, tile, c); - } - - var tile0 = transformedTiles[0]; - var out = new Uint8ClampedArray(tile0.items.length * componentsCount); - var result = { - left: tile0.left, - top: tile0.top, - width: tile0.width, - height: tile0.height, - items: out - }; - var shift, offset; - var pos = 0, - j, - jj, - y0, - y1, - y2; - - if (tile.codingStyleDefaultParameters.multipleComponentTransform) { - var fourComponents = componentsCount === 4; - var y0items = transformedTiles[0].items; - var y1items = transformedTiles[1].items; - var y2items = transformedTiles[2].items; - var y3items = fourComponents ? transformedTiles[3].items : null; - shift = components[0].precision - 8; - offset = (128 << shift) + 0.5; - var component0 = tile.components[0]; - var alpha01 = componentsCount - 3; - jj = y0items.length; - - if (!component0.codingStyleParameters.reversibleTransformation) { - for (j = 0; j < jj; j++, pos += alpha01) { - y0 = y0items[j] + offset; - y1 = y1items[j]; - y2 = y2items[j]; - out[pos++] = y0 + 1.402 * y2 >> shift; - out[pos++] = y0 - 0.34413 * y1 - 0.71414 * y2 >> shift; - out[pos++] = y0 + 1.772 * y1 >> shift; - } - } else { - for (j = 0; j < jj; j++, pos += alpha01) { - y0 = y0items[j] + offset; - y1 = y1items[j]; - y2 = y2items[j]; - const g = y0 - (y2 + y1 >> 2); - out[pos++] = g + y2 >> shift; - out[pos++] = g >> shift; - out[pos++] = g + y1 >> shift; - } - } - - if (fourComponents) { - for (j = 0, pos = 3; j < jj; j++, pos += 4) { - out[pos] = y3items[j] + offset >> shift; - } - } - } else { - for (c = 0; c < componentsCount; c++) { - var items = transformedTiles[c].items; - shift = components[c].precision - 8; - offset = (128 << shift) + 0.5; - - for (pos = c, j = 0, jj = items.length; j < jj; j++) { - out[pos] = items[j] + offset >> shift; - pos += componentsCount; - } - } - } - - resultImages.push(result); - } - - return resultImages; - } - - function initializeTile(context, tileIndex) { - var siz = context.SIZ; - var componentsCount = siz.Csiz; - var tile = context.tiles[tileIndex]; - - for (var c = 0; c < componentsCount; c++) { - var component = tile.components[c]; - var qcdOrQcc = context.currentTile.QCC[c] !== undefined ? context.currentTile.QCC[c] : context.currentTile.QCD; - component.quantizationParameters = qcdOrQcc; - var codOrCoc = context.currentTile.COC[c] !== undefined ? context.currentTile.COC[c] : context.currentTile.COD; - component.codingStyleParameters = codOrCoc; - } - - tile.codingStyleDefaultParameters = context.currentTile.COD; - } - - var TagTree = function TagTreeClosure() { - function TagTree(width, height) { - var levelsLength = (0, _core_utils.log2)(Math.max(width, height)) + 1; - this.levels = []; - - for (var i = 0; i < levelsLength; i++) { - var level = { - width, - height, - items: [] - }; - this.levels.push(level); - width = Math.ceil(width / 2); - height = Math.ceil(height / 2); - } - } - - TagTree.prototype = { - reset: function TagTree_reset(i, j) { - var currentLevel = 0, - value = 0, - level; - - while (currentLevel < this.levels.length) { - level = this.levels[currentLevel]; - var index = i + j * level.width; - - if (level.items[index] !== undefined) { - value = level.items[index]; - break; - } - - level.index = index; - i >>= 1; - j >>= 1; - currentLevel++; - } - - currentLevel--; - level = this.levels[currentLevel]; - level.items[level.index] = value; - this.currentLevel = currentLevel; - delete this.value; - }, - incrementValue: function TagTree_incrementValue() { - var level = this.levels[this.currentLevel]; - level.items[level.index]++; - }, - nextLevel: function TagTree_nextLevel() { - var currentLevel = this.currentLevel; - var level = this.levels[currentLevel]; - var value = level.items[level.index]; - currentLevel--; - - if (currentLevel < 0) { - this.value = value; - return false; - } - - this.currentLevel = currentLevel; - level = this.levels[currentLevel]; - level.items[level.index] = value; - return true; - } - }; - return TagTree; - }(); - - var InclusionTree = function InclusionTreeClosure() { - function InclusionTree(width, height, defaultValue) { - var levelsLength = (0, _core_utils.log2)(Math.max(width, height)) + 1; - this.levels = []; - - for (var i = 0; i < levelsLength; i++) { - var items = new Uint8Array(width * height); - - for (var j = 0, jj = items.length; j < jj; j++) { - items[j] = defaultValue; - } - - var level = { - width, - height, - items - }; - this.levels.push(level); - width = Math.ceil(width / 2); - height = Math.ceil(height / 2); - } - } - - InclusionTree.prototype = { - reset: function InclusionTree_reset(i, j, stopValue) { - var currentLevel = 0; - - while (currentLevel < this.levels.length) { - var level = this.levels[currentLevel]; - var index = i + j * level.width; - level.index = index; - var value = level.items[index]; - - if (value === 0xff) { - break; - } - - if (value > stopValue) { - this.currentLevel = currentLevel; - this.propagateValues(); - return false; - } - - i >>= 1; - j >>= 1; - currentLevel++; - } - - this.currentLevel = currentLevel - 1; - return true; - }, - incrementValue: function InclusionTree_incrementValue(stopValue) { - var level = this.levels[this.currentLevel]; - level.items[level.index] = stopValue + 1; - this.propagateValues(); - }, - propagateValues: function InclusionTree_propagateValues() { - var levelIndex = this.currentLevel; - var level = this.levels[levelIndex]; - var currentValue = level.items[level.index]; - - while (--levelIndex >= 0) { - level = this.levels[levelIndex]; - level.items[level.index] = currentValue; - } - }, - nextLevel: function InclusionTree_nextLevel() { - var currentLevel = this.currentLevel; - var level = this.levels[currentLevel]; - var value = level.items[level.index]; - level.items[level.index] = 0xff; - currentLevel--; - - if (currentLevel < 0) { - return false; - } - - this.currentLevel = currentLevel; - level = this.levels[currentLevel]; - level.items[level.index] = value; - return true; - } - }; - return InclusionTree; - }(); - - var BitModel = function BitModelClosure() { - var UNIFORM_CONTEXT = 17; - var RUNLENGTH_CONTEXT = 18; - var LLAndLHContextsLabel = new Uint8Array([0, 5, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 1, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8]); - var HLContextLabel = new Uint8Array([0, 3, 4, 0, 5, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8]); - var HHContextLabel = new Uint8Array([0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8]); - - function BitModel(width, height, subband, zeroBitPlanes, mb) { - this.width = width; - this.height = height; - let contextLabelTable; - - if (subband === "HH") { - contextLabelTable = HHContextLabel; - } else if (subband === "HL") { - contextLabelTable = HLContextLabel; - } else { - contextLabelTable = LLAndLHContextsLabel; - } - - this.contextLabelTable = contextLabelTable; - var coefficientCount = width * height; - this.neighborsSignificance = new Uint8Array(coefficientCount); - this.coefficentsSign = new Uint8Array(coefficientCount); - let coefficentsMagnitude; - - if (mb > 14) { - coefficentsMagnitude = new Uint32Array(coefficientCount); - } else if (mb > 6) { - coefficentsMagnitude = new Uint16Array(coefficientCount); - } else { - coefficentsMagnitude = new Uint8Array(coefficientCount); - } - - this.coefficentsMagnitude = coefficentsMagnitude; - this.processingFlags = new Uint8Array(coefficientCount); - var bitsDecoded = new Uint8Array(coefficientCount); - - if (zeroBitPlanes !== 0) { - for (var i = 0; i < coefficientCount; i++) { - bitsDecoded[i] = zeroBitPlanes; - } - } - - this.bitsDecoded = bitsDecoded; - this.reset(); - } - - BitModel.prototype = { - setDecoder: function BitModel_setDecoder(decoder) { - this.decoder = decoder; - }, - reset: function BitModel_reset() { - this.contexts = new Int8Array(19); - this.contexts[0] = 4 << 1 | 0; - this.contexts[UNIFORM_CONTEXT] = 46 << 1 | 0; - this.contexts[RUNLENGTH_CONTEXT] = 3 << 1 | 0; - }, - setNeighborsSignificance: function BitModel_setNeighborsSignificance(row, column, index) { - var neighborsSignificance = this.neighborsSignificance; - var width = this.width, - height = this.height; - var left = column > 0; - var right = column + 1 < width; - var i; - - if (row > 0) { - i = index - width; - - if (left) { - neighborsSignificance[i - 1] += 0x10; - } - - if (right) { - neighborsSignificance[i + 1] += 0x10; - } - - neighborsSignificance[i] += 0x04; - } - - if (row + 1 < height) { - i = index + width; - - if (left) { - neighborsSignificance[i - 1] += 0x10; - } - - if (right) { - neighborsSignificance[i + 1] += 0x10; - } - - neighborsSignificance[i] += 0x04; - } - - if (left) { - neighborsSignificance[index - 1] += 0x01; - } - - if (right) { - neighborsSignificance[index + 1] += 0x01; - } - - neighborsSignificance[index] |= 0x80; - }, - runSignificancePropagationPass: function BitModel_runSignificancePropagationPass() { - var decoder = this.decoder; - var width = this.width, - height = this.height; - var coefficentsMagnitude = this.coefficentsMagnitude; - var coefficentsSign = this.coefficentsSign; - var neighborsSignificance = this.neighborsSignificance; - var processingFlags = this.processingFlags; - var contexts = this.contexts; - var labels = this.contextLabelTable; - var bitsDecoded = this.bitsDecoded; - var processedInverseMask = ~1; - var processedMask = 1; - var firstMagnitudeBitMask = 2; - - for (var i0 = 0; i0 < height; i0 += 4) { - for (var j = 0; j < width; j++) { - var index = i0 * width + j; - - for (var i1 = 0; i1 < 4; i1++, index += width) { - var i = i0 + i1; - - if (i >= height) { - break; - } - - processingFlags[index] &= processedInverseMask; - - if (coefficentsMagnitude[index] || !neighborsSignificance[index]) { - continue; - } - - var contextLabel = labels[neighborsSignificance[index]]; - var decision = decoder.readBit(contexts, contextLabel); - - if (decision) { - var sign = this.decodeSignBit(i, j, index); - coefficentsSign[index] = sign; - coefficentsMagnitude[index] = 1; - this.setNeighborsSignificance(i, j, index); - processingFlags[index] |= firstMagnitudeBitMask; - } - - bitsDecoded[index]++; - processingFlags[index] |= processedMask; - } - } - } - }, - decodeSignBit: function BitModel_decodeSignBit(row, column, index) { - var width = this.width, - height = this.height; - var coefficentsMagnitude = this.coefficentsMagnitude; - var coefficentsSign = this.coefficentsSign; - var contribution, sign0, sign1, significance1; - var contextLabel, decoded; - significance1 = column > 0 && coefficentsMagnitude[index - 1] !== 0; - - if (column + 1 < width && coefficentsMagnitude[index + 1] !== 0) { - sign1 = coefficentsSign[index + 1]; - - if (significance1) { - sign0 = coefficentsSign[index - 1]; - contribution = 1 - sign1 - sign0; - } else { - contribution = 1 - sign1 - sign1; - } - } else if (significance1) { - sign0 = coefficentsSign[index - 1]; - contribution = 1 - sign0 - sign0; - } else { - contribution = 0; - } - - var horizontalContribution = 3 * contribution; - significance1 = row > 0 && coefficentsMagnitude[index - width] !== 0; - - if (row + 1 < height && coefficentsMagnitude[index + width] !== 0) { - sign1 = coefficentsSign[index + width]; - - if (significance1) { - sign0 = coefficentsSign[index - width]; - contribution = 1 - sign1 - sign0 + horizontalContribution; - } else { - contribution = 1 - sign1 - sign1 + horizontalContribution; - } - } else if (significance1) { - sign0 = coefficentsSign[index - width]; - contribution = 1 - sign0 - sign0 + horizontalContribution; - } else { - contribution = horizontalContribution; - } - - if (contribution >= 0) { - contextLabel = 9 + contribution; - decoded = this.decoder.readBit(this.contexts, contextLabel); - } else { - contextLabel = 9 - contribution; - decoded = this.decoder.readBit(this.contexts, contextLabel) ^ 1; - } - - return decoded; - }, - runMagnitudeRefinementPass: function BitModel_runMagnitudeRefinementPass() { - var decoder = this.decoder; - var width = this.width, - height = this.height; - var coefficentsMagnitude = this.coefficentsMagnitude; - var neighborsSignificance = this.neighborsSignificance; - var contexts = this.contexts; - var bitsDecoded = this.bitsDecoded; - var processingFlags = this.processingFlags; - var processedMask = 1; - var firstMagnitudeBitMask = 2; - var length = width * height; - var width4 = width * 4; - - for (var index0 = 0, indexNext; index0 < length; index0 = indexNext) { - indexNext = Math.min(length, index0 + width4); - - for (var j = 0; j < width; j++) { - for (var index = index0 + j; index < indexNext; index += width) { - if (!coefficentsMagnitude[index] || (processingFlags[index] & processedMask) !== 0) { - continue; - } - - var contextLabel = 16; - - if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) { - processingFlags[index] ^= firstMagnitudeBitMask; - var significance = neighborsSignificance[index] & 127; - contextLabel = significance === 0 ? 15 : 14; - } - - var bit = decoder.readBit(contexts, contextLabel); - coefficentsMagnitude[index] = coefficentsMagnitude[index] << 1 | bit; - bitsDecoded[index]++; - processingFlags[index] |= processedMask; - } - } - } - }, - runCleanupPass: function BitModel_runCleanupPass() { - var decoder = this.decoder; - var width = this.width, - height = this.height; - var neighborsSignificance = this.neighborsSignificance; - var coefficentsMagnitude = this.coefficentsMagnitude; - var coefficentsSign = this.coefficentsSign; - var contexts = this.contexts; - var labels = this.contextLabelTable; - var bitsDecoded = this.bitsDecoded; - var processingFlags = this.processingFlags; - var processedMask = 1; - var firstMagnitudeBitMask = 2; - var oneRowDown = width; - var twoRowsDown = width * 2; - var threeRowsDown = width * 3; - var iNext; - - for (var i0 = 0; i0 < height; i0 = iNext) { - iNext = Math.min(i0 + 4, height); - var indexBase = i0 * width; - var checkAllEmpty = i0 + 3 < height; - - for (var j = 0; j < width; j++) { - var index0 = indexBase + j; - var allEmpty = checkAllEmpty && processingFlags[index0] === 0 && processingFlags[index0 + oneRowDown] === 0 && processingFlags[index0 + twoRowsDown] === 0 && processingFlags[index0 + threeRowsDown] === 0 && neighborsSignificance[index0] === 0 && neighborsSignificance[index0 + oneRowDown] === 0 && neighborsSignificance[index0 + twoRowsDown] === 0 && neighborsSignificance[index0 + threeRowsDown] === 0; - var i1 = 0, - index = index0; - var i = i0, - sign; - - if (allEmpty) { - var hasSignificantCoefficent = decoder.readBit(contexts, RUNLENGTH_CONTEXT); - - if (!hasSignificantCoefficent) { - bitsDecoded[index0]++; - bitsDecoded[index0 + oneRowDown]++; - bitsDecoded[index0 + twoRowsDown]++; - bitsDecoded[index0 + threeRowsDown]++; - continue; - } - - i1 = decoder.readBit(contexts, UNIFORM_CONTEXT) << 1 | decoder.readBit(contexts, UNIFORM_CONTEXT); - - if (i1 !== 0) { - i = i0 + i1; - index += i1 * width; - } - - sign = this.decodeSignBit(i, j, index); - coefficentsSign[index] = sign; - coefficentsMagnitude[index] = 1; - this.setNeighborsSignificance(i, j, index); - processingFlags[index] |= firstMagnitudeBitMask; - index = index0; - - for (var i2 = i0; i2 <= i; i2++, index += width) { - bitsDecoded[index]++; - } - - i1++; - } - - for (i = i0 + i1; i < iNext; i++, index += width) { - if (coefficentsMagnitude[index] || (processingFlags[index] & processedMask) !== 0) { - continue; - } - - var contextLabel = labels[neighborsSignificance[index]]; - var decision = decoder.readBit(contexts, contextLabel); - - if (decision === 1) { - sign = this.decodeSignBit(i, j, index); - coefficentsSign[index] = sign; - coefficentsMagnitude[index] = 1; - this.setNeighborsSignificance(i, j, index); - processingFlags[index] |= firstMagnitudeBitMask; - } - - bitsDecoded[index]++; - } - } - } - }, - checkSegmentationSymbol: function BitModel_checkSegmentationSymbol() { - var decoder = this.decoder; - var contexts = this.contexts; - var symbol = decoder.readBit(contexts, UNIFORM_CONTEXT) << 3 | decoder.readBit(contexts, UNIFORM_CONTEXT) << 2 | decoder.readBit(contexts, UNIFORM_CONTEXT) << 1 | decoder.readBit(contexts, UNIFORM_CONTEXT); - - if (symbol !== 0xa) { - throw new JpxError("Invalid segmentation symbol"); - } - } - }; - return BitModel; - }(); - - var Transform = function TransformClosure() { - function Transform() {} - - Transform.prototype.calculate = function transformCalculate(subbands, u0, v0) { - var ll = subbands[0]; - - for (var i = 1, ii = subbands.length; i < ii; i++) { - ll = this.iterate(ll, subbands[i], u0, v0); - } - - return ll; - }; - - Transform.prototype.extend = function extend(buffer, offset, size) { - var i1 = offset - 1, - j1 = offset + 1; - var i2 = offset + size - 2, - j2 = offset + size; - buffer[i1--] = buffer[j1++]; - buffer[j2++] = buffer[i2--]; - buffer[i1--] = buffer[j1++]; - buffer[j2++] = buffer[i2--]; - buffer[i1--] = buffer[j1++]; - buffer[j2++] = buffer[i2--]; - buffer[i1] = buffer[j1]; - buffer[j2] = buffer[i2]; - }; - - Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh, u0, v0) { - var llWidth = ll.width, - llHeight = ll.height, - llItems = ll.items; - var width = hl_lh_hh.width; - var height = hl_lh_hh.height; - var items = hl_lh_hh.items; - var i, j, k, l, u, v; - - for (k = 0, i = 0; i < llHeight; i++) { - l = i * 2 * width; - - for (j = 0; j < llWidth; j++, k++, l += 2) { - items[l] = llItems[k]; - } - } - - llItems = ll.items = null; - var bufferPadding = 4; - var rowBuffer = new Float32Array(width + 2 * bufferPadding); - - if (width === 1) { - if ((u0 & 1) !== 0) { - for (v = 0, k = 0; v < height; v++, k += width) { - items[k] *= 0.5; - } - } - } else { - for (v = 0, k = 0; v < height; v++, k += width) { - rowBuffer.set(items.subarray(k, k + width), bufferPadding); - this.extend(rowBuffer, bufferPadding, width); - this.filter(rowBuffer, bufferPadding, width); - items.set(rowBuffer.subarray(bufferPadding, bufferPadding + width), k); - } - } - - var numBuffers = 16; - var colBuffers = []; - - for (i = 0; i < numBuffers; i++) { - colBuffers.push(new Float32Array(height + 2 * bufferPadding)); - } - - var b, - currentBuffer = 0; - ll = bufferPadding + height; - - if (height === 1) { - if ((v0 & 1) !== 0) { - for (u = 0; u < width; u++) { - items[u] *= 0.5; - } - } - } else { - for (u = 0; u < width; u++) { - if (currentBuffer === 0) { - numBuffers = Math.min(width - u, numBuffers); - - for (k = u, l = bufferPadding; l < ll; k += width, l++) { - for (b = 0; b < numBuffers; b++) { - colBuffers[b][l] = items[k + b]; - } - } - - currentBuffer = numBuffers; - } - - currentBuffer--; - var buffer = colBuffers[currentBuffer]; - this.extend(buffer, bufferPadding, height); - this.filter(buffer, bufferPadding, height); - - if (currentBuffer === 0) { - k = u - numBuffers + 1; - - for (l = bufferPadding; l < ll; k += width, l++) { - for (b = 0; b < numBuffers; b++) { - items[k + b] = colBuffers[b][l]; - } - } - } - } - } - - return { - width, - height, - items - }; - }; - - return Transform; - }(); - - var IrreversibleTransform = function IrreversibleTransformClosure() { - function IrreversibleTransform() { - Transform.call(this); - } - - IrreversibleTransform.prototype = Object.create(Transform.prototype); - - IrreversibleTransform.prototype.filter = function irreversibleTransformFilter(x, offset, length) { - var len = length >> 1; - offset = offset | 0; - var j, n, current, next; - var alpha = -1.586134342059924; - var beta = -0.052980118572961; - var gamma = 0.882911075530934; - var delta = 0.443506852043971; - var K = 1.230174104914001; - var K_ = 1 / K; - j = offset - 3; - - for (n = len + 4; n--; j += 2) { - x[j] *= K_; - } - - j = offset - 2; - current = delta * x[j - 1]; - - for (n = len + 3; n--; j += 2) { - next = delta * x[j + 1]; - x[j] = K * x[j] - current - next; - - if (n--) { - j += 2; - current = delta * x[j + 1]; - x[j] = K * x[j] - current - next; - } else { - break; - } - } - - j = offset - 1; - current = gamma * x[j - 1]; - - for (n = len + 2; n--; j += 2) { - next = gamma * x[j + 1]; - x[j] -= current + next; - - if (n--) { - j += 2; - current = gamma * x[j + 1]; - x[j] -= current + next; - } else { - break; - } - } - - j = offset; - current = beta * x[j - 1]; - - for (n = len + 1; n--; j += 2) { - next = beta * x[j + 1]; - x[j] -= current + next; - - if (n--) { - j += 2; - current = beta * x[j + 1]; - x[j] -= current + next; - } else { - break; - } - } - - if (len !== 0) { - j = offset + 1; - current = alpha * x[j - 1]; - - for (n = len; n--; j += 2) { - next = alpha * x[j + 1]; - x[j] -= current + next; - - if (n--) { - j += 2; - current = alpha * x[j + 1]; - x[j] -= current + next; - } else { - break; - } - } - } - }; - - return IrreversibleTransform; - }(); - - var ReversibleTransform = function ReversibleTransformClosure() { - function ReversibleTransform() { - Transform.call(this); - } - - ReversibleTransform.prototype = Object.create(Transform.prototype); - - ReversibleTransform.prototype.filter = function reversibleTransformFilter(x, offset, length) { - var len = length >> 1; - offset = offset | 0; - var j, n; - - for (j = offset, n = len + 1; n--; j += 2) { - x[j] -= x[j - 1] + x[j + 1] + 2 >> 2; - } - - for (j = offset + 1, n = len; n--; j += 2) { - x[j] += x[j - 1] + x[j + 1] >> 1; - } - }; - - return ReversibleTransform; - }(); - - return JpxImage; -}(); - -exports.JpxImage = JpxImage; - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.calculateSHA512 = exports.calculateSHA384 = exports.calculateSHA256 = exports.calculateMD5 = exports.PDF20 = exports.PDF17 = exports.CipherTransformFactory = exports.ARCFourCipher = exports.AES256Cipher = exports.AES128Cipher = void 0; - -var _util = __w_pdfjs_require__(2); - -var _primitives = __w_pdfjs_require__(5); - -var _stream = __w_pdfjs_require__(12); - -var ARCFourCipher = function ARCFourCipherClosure() { - function ARCFourCipher(key) { - this.a = 0; - this.b = 0; - var s = new Uint8Array(256); - var i, - j = 0, - tmp, - keyLength = key.length; - - for (i = 0; i < 256; ++i) { - s[i] = i; - } - - for (i = 0; i < 256; ++i) { - tmp = s[i]; - j = j + tmp + key[i % keyLength] & 0xff; - s[i] = s[j]; - s[j] = tmp; - } - - this.s = s; - } - - ARCFourCipher.prototype = { - encryptBlock: function ARCFourCipher_encryptBlock(data) { - var i, - n = data.length, - tmp, - tmp2; - var a = this.a, - b = this.b, - s = this.s; - var output = new Uint8Array(n); - - for (i = 0; i < n; ++i) { - a = a + 1 & 0xff; - tmp = s[a]; - b = b + tmp & 0xff; - tmp2 = s[b]; - s[a] = tmp2; - s[b] = tmp; - output[i] = data[i] ^ s[tmp + tmp2 & 0xff]; - } - - this.a = a; - this.b = b; - return output; - } - }; - ARCFourCipher.prototype.decryptBlock = ARCFourCipher.prototype.encryptBlock; - ARCFourCipher.prototype.encrypt = ARCFourCipher.prototype.encryptBlock; - return ARCFourCipher; -}(); - -exports.ARCFourCipher = ARCFourCipher; - -var calculateMD5 = function calculateMD5Closure() { - var r = new Uint8Array([7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]); - var k = new Int32Array([-680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162, 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632, 643717713, -373897302, -701558691, 38016083, -660478335, -405537848, 568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784, 1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556, -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222, -722521979, 76029189, -640364487, -421815835, 530742520, -995338651, -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606, -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649, -145523070, -1120210379, 718787259, -343485551]); - - function hash(data, offset, length) { - var h0 = 1732584193, - h1 = -271733879, - h2 = -1732584194, - h3 = 271733878; - var paddedLength = length + 72 & ~63; - var padded = new Uint8Array(paddedLength); - var i, j, n; - - for (i = 0; i < length; ++i) { - padded[i] = data[offset++]; - } - - padded[i++] = 0x80; - n = paddedLength - 8; - - while (i < n) { - padded[i++] = 0; - } - - padded[i++] = length << 3 & 0xff; - padded[i++] = length >> 5 & 0xff; - padded[i++] = length >> 13 & 0xff; - padded[i++] = length >> 21 & 0xff; - padded[i++] = length >>> 29 & 0xff; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - var w = new Int32Array(16); - - for (i = 0; i < paddedLength;) { - for (j = 0; j < 16; ++j, i += 4) { - w[j] = padded[i] | padded[i + 1] << 8 | padded[i + 2] << 16 | padded[i + 3] << 24; - } - - var a = h0, - b = h1, - c = h2, - d = h3, - f, - g; - - for (j = 0; j < 64; ++j) { - if (j < 16) { - f = b & c | ~b & d; - g = j; - } else if (j < 32) { - f = d & b | ~d & c; - g = 5 * j + 1 & 15; - } else if (j < 48) { - f = b ^ c ^ d; - g = 3 * j + 5 & 15; - } else { - f = c ^ (b | ~d); - g = 7 * j & 15; - } - - var tmp = d, - rotateArg = a + f + k[j] + w[g] | 0, - rotate = r[j]; - d = c; - c = b; - b = b + (rotateArg << rotate | rotateArg >>> 32 - rotate) | 0; - a = tmp; - } - - h0 = h0 + a | 0; - h1 = h1 + b | 0; - h2 = h2 + c | 0; - h3 = h3 + d | 0; - } - - return new Uint8Array([h0 & 0xFF, h0 >> 8 & 0xFF, h0 >> 16 & 0xFF, h0 >>> 24 & 0xFF, h1 & 0xFF, h1 >> 8 & 0xFF, h1 >> 16 & 0xFF, h1 >>> 24 & 0xFF, h2 & 0xFF, h2 >> 8 & 0xFF, h2 >> 16 & 0xFF, h2 >>> 24 & 0xFF, h3 & 0xFF, h3 >> 8 & 0xFF, h3 >> 16 & 0xFF, h3 >>> 24 & 0xFF]); - } - - return hash; -}(); - -exports.calculateMD5 = calculateMD5; - -var Word64 = function Word64Closure() { - function Word64(highInteger, lowInteger) { - this.high = highInteger | 0; - this.low = lowInteger | 0; - } - - Word64.prototype = { - and: function Word64_and(word) { - this.high &= word.high; - this.low &= word.low; - }, - xor: function Word64_xor(word) { - this.high ^= word.high; - this.low ^= word.low; - }, - or: function Word64_or(word) { - this.high |= word.high; - this.low |= word.low; - }, - shiftRight: function Word64_shiftRight(places) { - if (places >= 32) { - this.low = this.high >>> places - 32 | 0; - this.high = 0; - } else { - this.low = this.low >>> places | this.high << 32 - places; - this.high = this.high >>> places | 0; - } - }, - shiftLeft: function Word64_shiftLeft(places) { - if (places >= 32) { - this.high = this.low << places - 32; - this.low = 0; - } else { - this.high = this.high << places | this.low >>> 32 - places; - this.low = this.low << places; - } - }, - rotateRight: function Word64_rotateRight(places) { - var low, high; - - if (places & 32) { - high = this.low; - low = this.high; - } else { - low = this.low; - high = this.high; - } - - places &= 31; - this.low = low >>> places | high << 32 - places; - this.high = high >>> places | low << 32 - places; - }, - not: function Word64_not() { - this.high = ~this.high; - this.low = ~this.low; - }, - add: function Word64_add(word) { - var lowAdd = (this.low >>> 0) + (word.low >>> 0); - var highAdd = (this.high >>> 0) + (word.high >>> 0); - - if (lowAdd > 0xffffffff) { - highAdd += 1; - } - - this.low = lowAdd | 0; - this.high = highAdd | 0; - }, - copyTo: function Word64_copyTo(bytes, offset) { - bytes[offset] = this.high >>> 24 & 0xff; - bytes[offset + 1] = this.high >> 16 & 0xff; - bytes[offset + 2] = this.high >> 8 & 0xff; - bytes[offset + 3] = this.high & 0xff; - bytes[offset + 4] = this.low >>> 24 & 0xff; - bytes[offset + 5] = this.low >> 16 & 0xff; - bytes[offset + 6] = this.low >> 8 & 0xff; - bytes[offset + 7] = this.low & 0xff; - }, - assign: function Word64_assign(word) { - this.high = word.high; - this.low = word.low; - } - }; - return Word64; -}(); - -var calculateSHA256 = function calculateSHA256Closure() { - function rotr(x, n) { - return x >>> n | x << 32 - n; - } - - function ch(x, y, z) { - return x & y ^ ~x & z; - } - - function maj(x, y, z) { - return x & y ^ x & z ^ y & z; - } - - function sigma(x) { - return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); - } - - function sigmaPrime(x) { - return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); - } - - function littleSigma(x) { - return rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3; - } - - function littleSigmaPrime(x) { - return rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10; - } - - var k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]; - - function hash(data, offset, length) { - var h0 = 0x6a09e667, - h1 = 0xbb67ae85, - h2 = 0x3c6ef372, - h3 = 0xa54ff53a, - h4 = 0x510e527f, - h5 = 0x9b05688c, - h6 = 0x1f83d9ab, - h7 = 0x5be0cd19; - var paddedLength = Math.ceil((length + 9) / 64) * 64; - var padded = new Uint8Array(paddedLength); - var i, j, n; - - for (i = 0; i < length; ++i) { - padded[i] = data[offset++]; - } - - padded[i++] = 0x80; - n = paddedLength - 8; - - while (i < n) { - padded[i++] = 0; - } - - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = length >>> 29 & 0xff; - padded[i++] = length >> 21 & 0xff; - padded[i++] = length >> 13 & 0xff; - padded[i++] = length >> 5 & 0xff; - padded[i++] = length << 3 & 0xff; - var w = new Uint32Array(64); - - for (i = 0; i < paddedLength;) { - for (j = 0; j < 16; ++j) { - w[j] = padded[i] << 24 | padded[i + 1] << 16 | padded[i + 2] << 8 | padded[i + 3]; - i += 4; - } - - for (j = 16; j < 64; ++j) { - w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] + littleSigma(w[j - 15]) + w[j - 16] | 0; - } - - var a = h0, - b = h1, - c = h2, - d = h3, - e = h4, - f = h5, - g = h6, - h = h7, - t1, - t2; - - for (j = 0; j < 64; ++j) { - t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j]; - t2 = sigma(a) + maj(a, b, c); - h = g; - g = f; - f = e; - e = d + t1 | 0; - d = c; - c = b; - b = a; - a = t1 + t2 | 0; - } - - h0 = h0 + a | 0; - h1 = h1 + b | 0; - h2 = h2 + c | 0; - h3 = h3 + d | 0; - h4 = h4 + e | 0; - h5 = h5 + f | 0; - h6 = h6 + g | 0; - h7 = h7 + h | 0; - } - - return new Uint8Array([h0 >> 24 & 0xFF, h0 >> 16 & 0xFF, h0 >> 8 & 0xFF, h0 & 0xFF, h1 >> 24 & 0xFF, h1 >> 16 & 0xFF, h1 >> 8 & 0xFF, h1 & 0xFF, h2 >> 24 & 0xFF, h2 >> 16 & 0xFF, h2 >> 8 & 0xFF, h2 & 0xFF, h3 >> 24 & 0xFF, h3 >> 16 & 0xFF, h3 >> 8 & 0xFF, h3 & 0xFF, h4 >> 24 & 0xFF, h4 >> 16 & 0xFF, h4 >> 8 & 0xFF, h4 & 0xFF, h5 >> 24 & 0xFF, h5 >> 16 & 0xFF, h5 >> 8 & 0xFF, h5 & 0xFF, h6 >> 24 & 0xFF, h6 >> 16 & 0xFF, h6 >> 8 & 0xFF, h6 & 0xFF, h7 >> 24 & 0xFF, h7 >> 16 & 0xFF, h7 >> 8 & 0xFF, h7 & 0xFF]); - } - - return hash; -}(); - -exports.calculateSHA256 = calculateSHA256; - -var calculateSHA512 = function calculateSHA512Closure() { - function ch(result, x, y, z, tmp) { - result.assign(x); - result.and(y); - tmp.assign(x); - tmp.not(); - tmp.and(z); - result.xor(tmp); - } - - function maj(result, x, y, z, tmp) { - result.assign(x); - result.and(y); - tmp.assign(x); - tmp.and(z); - result.xor(tmp); - tmp.assign(y); - tmp.and(z); - result.xor(tmp); - } - - function sigma(result, x, tmp) { - result.assign(x); - result.rotateRight(28); - tmp.assign(x); - tmp.rotateRight(34); - result.xor(tmp); - tmp.assign(x); - tmp.rotateRight(39); - result.xor(tmp); - } - - function sigmaPrime(result, x, tmp) { - result.assign(x); - result.rotateRight(14); - tmp.assign(x); - tmp.rotateRight(18); - result.xor(tmp); - tmp.assign(x); - tmp.rotateRight(41); - result.xor(tmp); - } - - function littleSigma(result, x, tmp) { - result.assign(x); - result.rotateRight(1); - tmp.assign(x); - tmp.rotateRight(8); - result.xor(tmp); - tmp.assign(x); - tmp.shiftRight(7); - result.xor(tmp); - } - - function littleSigmaPrime(result, x, tmp) { - result.assign(x); - result.rotateRight(19); - tmp.assign(x); - tmp.rotateRight(61); - result.xor(tmp); - tmp.assign(x); - tmp.shiftRight(6); - result.xor(tmp); - } - - var k = [new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd), new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc), new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019), new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118), new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe), new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2), new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1), new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694), new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3), new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65), new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483), new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5), new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210), new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4), new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725), new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70), new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926), new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df), new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8), new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b), new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001), new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30), new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910), new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8), new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53), new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8), new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb), new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3), new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60), new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec), new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9), new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b), new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207), new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178), new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6), new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b), new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493), new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c), new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a), new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)]; - - function hash(data, offset, length, mode384) { - mode384 = !!mode384; - var h0, h1, h2, h3, h4, h5, h6, h7; - - if (!mode384) { - h0 = new Word64(0x6a09e667, 0xf3bcc908); - h1 = new Word64(0xbb67ae85, 0x84caa73b); - h2 = new Word64(0x3c6ef372, 0xfe94f82b); - h3 = new Word64(0xa54ff53a, 0x5f1d36f1); - h4 = new Word64(0x510e527f, 0xade682d1); - h5 = new Word64(0x9b05688c, 0x2b3e6c1f); - h6 = new Word64(0x1f83d9ab, 0xfb41bd6b); - h7 = new Word64(0x5be0cd19, 0x137e2179); - } else { - h0 = new Word64(0xcbbb9d5d, 0xc1059ed8); - h1 = new Word64(0x629a292a, 0x367cd507); - h2 = new Word64(0x9159015a, 0x3070dd17); - h3 = new Word64(0x152fecd8, 0xf70e5939); - h4 = new Word64(0x67332667, 0xffc00b31); - h5 = new Word64(0x8eb44a87, 0x68581511); - h6 = new Word64(0xdb0c2e0d, 0x64f98fa7); - h7 = new Word64(0x47b5481d, 0xbefa4fa4); - } - - var paddedLength = Math.ceil((length + 17) / 128) * 128; - var padded = new Uint8Array(paddedLength); - var i, j, n; - - for (i = 0; i < length; ++i) { - padded[i] = data[offset++]; - } - - padded[i++] = 0x80; - n = paddedLength - 16; - - while (i < n) { - padded[i++] = 0; - } - - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = 0; - padded[i++] = length >>> 29 & 0xff; - padded[i++] = length >> 21 & 0xff; - padded[i++] = length >> 13 & 0xff; - padded[i++] = length >> 5 & 0xff; - padded[i++] = length << 3 & 0xff; - var w = new Array(80); - - for (i = 0; i < 80; i++) { - w[i] = new Word64(0, 0); - } - - var a = new Word64(0, 0), - b = new Word64(0, 0), - c = new Word64(0, 0); - var d = new Word64(0, 0), - e = new Word64(0, 0), - f = new Word64(0, 0); - var g = new Word64(0, 0), - h = new Word64(0, 0); - var t1 = new Word64(0, 0), - t2 = new Word64(0, 0); - var tmp1 = new Word64(0, 0), - tmp2 = new Word64(0, 0), - tmp3; - - for (i = 0; i < paddedLength;) { - for (j = 0; j < 16; ++j) { - w[j].high = padded[i] << 24 | padded[i + 1] << 16 | padded[i + 2] << 8 | padded[i + 3]; - w[j].low = padded[i + 4] << 24 | padded[i + 5] << 16 | padded[i + 6] << 8 | padded[i + 7]; - i += 8; - } - - for (j = 16; j < 80; ++j) { - tmp3 = w[j]; - littleSigmaPrime(tmp3, w[j - 2], tmp2); - tmp3.add(w[j - 7]); - littleSigma(tmp1, w[j - 15], tmp2); - tmp3.add(tmp1); - tmp3.add(w[j - 16]); - } - - a.assign(h0); - b.assign(h1); - c.assign(h2); - d.assign(h3); - e.assign(h4); - f.assign(h5); - g.assign(h6); - h.assign(h7); - - for (j = 0; j < 80; ++j) { - t1.assign(h); - sigmaPrime(tmp1, e, tmp2); - t1.add(tmp1); - ch(tmp1, e, f, g, tmp2); - t1.add(tmp1); - t1.add(k[j]); - t1.add(w[j]); - sigma(t2, a, tmp2); - maj(tmp1, a, b, c, tmp2); - t2.add(tmp1); - tmp3 = h; - h = g; - g = f; - f = e; - d.add(t1); - e = d; - d = c; - c = b; - b = a; - tmp3.assign(t1); - tmp3.add(t2); - a = tmp3; - } - - h0.add(a); - h1.add(b); - h2.add(c); - h3.add(d); - h4.add(e); - h5.add(f); - h6.add(g); - h7.add(h); - } - - var result; - - if (!mode384) { - result = new Uint8Array(64); - h0.copyTo(result, 0); - h1.copyTo(result, 8); - h2.copyTo(result, 16); - h3.copyTo(result, 24); - h4.copyTo(result, 32); - h5.copyTo(result, 40); - h6.copyTo(result, 48); - h7.copyTo(result, 56); - } else { - result = new Uint8Array(48); - h0.copyTo(result, 0); - h1.copyTo(result, 8); - h2.copyTo(result, 16); - h3.copyTo(result, 24); - h4.copyTo(result, 32); - h5.copyTo(result, 40); - } - - return result; - } - - return hash; -}(); - -exports.calculateSHA512 = calculateSHA512; - -var calculateSHA384 = function calculateSHA384Closure() { - function hash(data, offset, length) { - return calculateSHA512(data, offset, length, true); - } - - return hash; -}(); - -exports.calculateSHA384 = calculateSHA384; - -var NullCipher = function NullCipherClosure() { - function NullCipher() {} - - NullCipher.prototype = { - decryptBlock: function NullCipher_decryptBlock(data) { - return data; - }, - encrypt: function NullCipher_encrypt(data) { - return data; - } - }; - return NullCipher; -}(); - -class AESBaseCipher { - constructor() { - if (this.constructor === AESBaseCipher) { - (0, _util.unreachable)("Cannot initialize AESBaseCipher."); - } - - this._s = new Uint8Array([0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]); - this._inv_s = new Uint8Array([0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]); - this._mix = new Uint32Array([0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]); - this._mixCol = new Uint8Array(256); - - for (let i = 0; i < 256; i++) { - if (i < 128) { - this._mixCol[i] = i << 1; - } else { - this._mixCol[i] = i << 1 ^ 0x1b; - } - } - - this.buffer = new Uint8Array(16); - this.bufferPosition = 0; - } - - _expandKey(cipherKey) { - (0, _util.unreachable)("Cannot call `_expandKey` on the base class"); - } - - _decrypt(input, key) { - let t, u, v; - const state = new Uint8Array(16); - state.set(input); - - for (let j = 0, k = this._keySize; j < 16; ++j, ++k) { - state[j] ^= key[k]; - } - - for (let i = this._cyclesOfRepetition - 1; i >= 1; --i) { - t = state[13]; - state[13] = state[9]; - state[9] = state[5]; - state[5] = state[1]; - state[1] = t; - t = state[14]; - u = state[10]; - state[14] = state[6]; - state[10] = state[2]; - state[6] = t; - state[2] = u; - t = state[15]; - u = state[11]; - v = state[7]; - state[15] = state[3]; - state[11] = t; - state[7] = u; - state[3] = v; - - for (let j = 0; j < 16; ++j) { - state[j] = this._inv_s[state[j]]; - } - - for (let j = 0, k = i * 16; j < 16; ++j, ++k) { - state[j] ^= key[k]; - } - - for (let j = 0; j < 16; j += 4) { - const s0 = this._mix[state[j]]; - const s1 = this._mix[state[j + 1]]; - const s2 = this._mix[state[j + 2]]; - const s3 = this._mix[state[j + 3]]; - t = s0 ^ s1 >>> 8 ^ s1 << 24 ^ s2 >>> 16 ^ s2 << 16 ^ s3 >>> 24 ^ s3 << 8; - state[j] = t >>> 24 & 0xff; - state[j + 1] = t >> 16 & 0xff; - state[j + 2] = t >> 8 & 0xff; - state[j + 3] = t & 0xff; - } - } - - t = state[13]; - state[13] = state[9]; - state[9] = state[5]; - state[5] = state[1]; - state[1] = t; - t = state[14]; - u = state[10]; - state[14] = state[6]; - state[10] = state[2]; - state[6] = t; - state[2] = u; - t = state[15]; - u = state[11]; - v = state[7]; - state[15] = state[3]; - state[11] = t; - state[7] = u; - state[3] = v; - - for (let j = 0; j < 16; ++j) { - state[j] = this._inv_s[state[j]]; - state[j] ^= key[j]; - } - - return state; - } - - _encrypt(input, key) { - const s = this._s; - let t, u, v; - const state = new Uint8Array(16); - state.set(input); - - for (let j = 0; j < 16; ++j) { - state[j] ^= key[j]; - } - - for (let i = 1; i < this._cyclesOfRepetition; i++) { - for (let j = 0; j < 16; ++j) { - state[j] = s[state[j]]; - } - - v = state[1]; - state[1] = state[5]; - state[5] = state[9]; - state[9] = state[13]; - state[13] = v; - v = state[2]; - u = state[6]; - state[2] = state[10]; - state[6] = state[14]; - state[10] = v; - state[14] = u; - v = state[3]; - u = state[7]; - t = state[11]; - state[3] = state[15]; - state[7] = v; - state[11] = u; - state[15] = t; - - for (let j = 0; j < 16; j += 4) { - const s0 = state[j + 0]; - const s1 = state[j + 1]; - const s2 = state[j + 2]; - const s3 = state[j + 3]; - t = s0 ^ s1 ^ s2 ^ s3; - state[j + 0] ^= t ^ this._mixCol[s0 ^ s1]; - state[j + 1] ^= t ^ this._mixCol[s1 ^ s2]; - state[j + 2] ^= t ^ this._mixCol[s2 ^ s3]; - state[j + 3] ^= t ^ this._mixCol[s3 ^ s0]; - } - - for (let j = 0, k = i * 16; j < 16; ++j, ++k) { - state[j] ^= key[k]; - } - } - - for (let j = 0; j < 16; ++j) { - state[j] = s[state[j]]; - } - - v = state[1]; - state[1] = state[5]; - state[5] = state[9]; - state[9] = state[13]; - state[13] = v; - v = state[2]; - u = state[6]; - state[2] = state[10]; - state[6] = state[14]; - state[10] = v; - state[14] = u; - v = state[3]; - u = state[7]; - t = state[11]; - state[3] = state[15]; - state[7] = v; - state[11] = u; - state[15] = t; - - for (let j = 0, k = this._keySize; j < 16; ++j, ++k) { - state[j] ^= key[k]; - } - - return state; - } - - _decryptBlock2(data, finalize) { - const sourceLength = data.length; - let buffer = this.buffer, - bufferLength = this.bufferPosition; - const result = []; - let iv = this.iv; - - for (let i = 0; i < sourceLength; ++i) { - buffer[bufferLength] = data[i]; - ++bufferLength; - - if (bufferLength < 16) { - continue; - } - - const plain = this._decrypt(buffer, this._key); - - for (let j = 0; j < 16; ++j) { - plain[j] ^= iv[j]; - } - - iv = buffer; - result.push(plain); - buffer = new Uint8Array(16); - bufferLength = 0; - } - - this.buffer = buffer; - this.bufferLength = bufferLength; - this.iv = iv; - - if (result.length === 0) { - return new Uint8Array(0); - } - - let outputLength = 16 * result.length; - - if (finalize) { - const lastBlock = result[result.length - 1]; - let psLen = lastBlock[15]; - - if (psLen <= 16) { - for (let i = 15, ii = 16 - psLen; i >= ii; --i) { - if (lastBlock[i] !== psLen) { - psLen = 0; - break; - } - } - - outputLength -= psLen; - result[result.length - 1] = lastBlock.subarray(0, 16 - psLen); - } - } - - const output = new Uint8Array(outputLength); - - for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { - output.set(result[i], j); - } - - return output; - } - - decryptBlock(data, finalize, iv = null) { - const sourceLength = data.length; - const buffer = this.buffer; - let bufferLength = this.bufferPosition; - - if (iv) { - this.iv = iv; - } else { - for (let i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) { - buffer[bufferLength] = data[i]; - } - - if (bufferLength < 16) { - this.bufferLength = bufferLength; - return new Uint8Array(0); - } - - this.iv = buffer; - data = data.subarray(16); - } - - this.buffer = new Uint8Array(16); - this.bufferLength = 0; - this.decryptBlock = this._decryptBlock2; - return this.decryptBlock(data, finalize); - } - - encrypt(data, iv) { - const sourceLength = data.length; - let buffer = this.buffer, - bufferLength = this.bufferPosition; - const result = []; - - if (!iv) { - iv = new Uint8Array(16); - } - - for (let i = 0; i < sourceLength; ++i) { - buffer[bufferLength] = data[i]; - ++bufferLength; - - if (bufferLength < 16) { - continue; - } - - for (let j = 0; j < 16; ++j) { - buffer[j] ^= iv[j]; - } - - const cipher = this._encrypt(buffer, this._key); - - iv = cipher; - result.push(cipher); - buffer = new Uint8Array(16); - bufferLength = 0; - } - - this.buffer = buffer; - this.bufferLength = bufferLength; - this.iv = iv; - - if (result.length === 0) { - return new Uint8Array(0); - } - - const outputLength = 16 * result.length; - const output = new Uint8Array(outputLength); - - for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { - output.set(result[i], j); - } - - return output; - } - -} - -class AES128Cipher extends AESBaseCipher { - constructor(key) { - super(); - this._cyclesOfRepetition = 10; - this._keySize = 160; - this._rcon = new Uint8Array([0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d]); - this._key = this._expandKey(key); - } - - _expandKey(cipherKey) { - const b = 176; - const s = this._s; - const rcon = this._rcon; - const result = new Uint8Array(b); - result.set(cipherKey); - - for (let j = 16, i = 1; j < b; ++i) { - let t1 = result[j - 3]; - let t2 = result[j - 2]; - let t3 = result[j - 1]; - let t4 = result[j - 4]; - t1 = s[t1]; - t2 = s[t2]; - t3 = s[t3]; - t4 = s[t4]; - t1 = t1 ^ rcon[i]; - - for (let n = 0; n < 4; ++n) { - result[j] = t1 ^= result[j - 16]; - j++; - result[j] = t2 ^= result[j - 16]; - j++; - result[j] = t3 ^= result[j - 16]; - j++; - result[j] = t4 ^= result[j - 16]; - j++; - } - } - - return result; - } - -} - -exports.AES128Cipher = AES128Cipher; - -class AES256Cipher extends AESBaseCipher { - constructor(key) { - super(); - this._cyclesOfRepetition = 14; - this._keySize = 224; - this._key = this._expandKey(key); - } - - _expandKey(cipherKey) { - const b = 240; - const s = this._s; - const result = new Uint8Array(b); - result.set(cipherKey); - let r = 1; - let t1, t2, t3, t4; - - for (let j = 32, i = 1; j < b; ++i) { - if (j % 32 === 16) { - t1 = s[t1]; - t2 = s[t2]; - t3 = s[t3]; - t4 = s[t4]; - } else if (j % 32 === 0) { - t1 = result[j - 3]; - t2 = result[j - 2]; - t3 = result[j - 1]; - t4 = result[j - 4]; - t1 = s[t1]; - t2 = s[t2]; - t3 = s[t3]; - t4 = s[t4]; - t1 = t1 ^ r; - - if ((r <<= 1) >= 256) { - r = (r ^ 0x1b) & 0xff; - } - } - - for (let n = 0; n < 4; ++n) { - result[j] = t1 ^= result[j - 32]; - j++; - result[j] = t2 ^= result[j - 32]; - j++; - result[j] = t3 ^= result[j - 32]; - j++; - result[j] = t4 ^= result[j - 32]; - j++; - } - } - - return result; - } - -} - -exports.AES256Cipher = AES256Cipher; - -var PDF17 = function PDF17Closure() { - function compareByteArrays(array1, array2) { - if (array1.length !== array2.length) { - return false; - } - - for (var i = 0; i < array1.length; i++) { - if (array1[i] !== array2[i]) { - return false; - } - } - - return true; - } - - function PDF17() {} - - PDF17.prototype = { - checkOwnerPassword: function PDF17_checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) { - var hashData = new Uint8Array(password.length + 56); - hashData.set(password, 0); - hashData.set(ownerValidationSalt, password.length); - hashData.set(userBytes, password.length + ownerValidationSalt.length); - var result = calculateSHA256(hashData, 0, hashData.length); - return compareByteArrays(result, ownerPassword); - }, - checkUserPassword: function PDF17_checkUserPassword(password, userValidationSalt, userPassword) { - var hashData = new Uint8Array(password.length + 8); - hashData.set(password, 0); - hashData.set(userValidationSalt, password.length); - var result = calculateSHA256(hashData, 0, hashData.length); - return compareByteArrays(result, userPassword); - }, - getOwnerKey: function PDF17_getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) { - var hashData = new Uint8Array(password.length + 56); - hashData.set(password, 0); - hashData.set(ownerKeySalt, password.length); - hashData.set(userBytes, password.length + ownerKeySalt.length); - var key = calculateSHA256(hashData, 0, hashData.length); - var cipher = new AES256Cipher(key); - return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); - }, - getUserKey: function PDF17_getUserKey(password, userKeySalt, userEncryption) { - var hashData = new Uint8Array(password.length + 8); - hashData.set(password, 0); - hashData.set(userKeySalt, password.length); - var key = calculateSHA256(hashData, 0, hashData.length); - var cipher = new AES256Cipher(key); - return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); - } - }; - return PDF17; -}(); - -exports.PDF17 = PDF17; - -var PDF20 = function PDF20Closure() { - function concatArrays(array1, array2) { - var t = new Uint8Array(array1.length + array2.length); - t.set(array1, 0); - t.set(array2, array1.length); - return t; - } - - function calculatePDF20Hash(password, input, userBytes) { - var k = calculateSHA256(input, 0, input.length).subarray(0, 32); - var e = [0]; - var i = 0; - - while (i < 64 || e[e.length - 1] > i - 32) { - var arrayLength = password.length + k.length + userBytes.length; - var k1 = new Uint8Array(arrayLength * 64); - var array = concatArrays(password, k); - array = concatArrays(array, userBytes); - - for (var j = 0, pos = 0; j < 64; j++, pos += arrayLength) { - k1.set(array, pos); - } - - var cipher = new AES128Cipher(k.subarray(0, 16)); - e = cipher.encrypt(k1, k.subarray(16, 32)); - var remainder = 0; - - for (var z = 0; z < 16; z++) { - remainder *= 256 % 3; - remainder %= 3; - remainder += (e[z] >>> 0) % 3; - remainder %= 3; - } - - if (remainder === 0) { - k = calculateSHA256(e, 0, e.length); - } else if (remainder === 1) { - k = calculateSHA384(e, 0, e.length); - } else if (remainder === 2) { - k = calculateSHA512(e, 0, e.length); - } - - i++; - } - - return k.subarray(0, 32); - } - - function PDF20() {} - - function compareByteArrays(array1, array2) { - if (array1.length !== array2.length) { - return false; - } - - for (var i = 0; i < array1.length; i++) { - if (array1[i] !== array2[i]) { - return false; - } - } - - return true; - } - - PDF20.prototype = { - hash: function PDF20_hash(password, concatBytes, userBytes) { - return calculatePDF20Hash(password, concatBytes, userBytes); - }, - checkOwnerPassword: function PDF20_checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) { - var hashData = new Uint8Array(password.length + 56); - hashData.set(password, 0); - hashData.set(ownerValidationSalt, password.length); - hashData.set(userBytes, password.length + ownerValidationSalt.length); - var result = calculatePDF20Hash(password, hashData, userBytes); - return compareByteArrays(result, ownerPassword); - }, - checkUserPassword: function PDF20_checkUserPassword(password, userValidationSalt, userPassword) { - var hashData = new Uint8Array(password.length + 8); - hashData.set(password, 0); - hashData.set(userValidationSalt, password.length); - var result = calculatePDF20Hash(password, hashData, []); - return compareByteArrays(result, userPassword); - }, - getOwnerKey: function PDF20_getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) { - var hashData = new Uint8Array(password.length + 56); - hashData.set(password, 0); - hashData.set(ownerKeySalt, password.length); - hashData.set(userBytes, password.length + ownerKeySalt.length); - var key = calculatePDF20Hash(password, hashData, userBytes); - var cipher = new AES256Cipher(key); - return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); - }, - getUserKey: function PDF20_getUserKey(password, userKeySalt, userEncryption) { - var hashData = new Uint8Array(password.length + 8); - hashData.set(password, 0); - hashData.set(userKeySalt, password.length); - var key = calculatePDF20Hash(password, hashData, []); - var cipher = new AES256Cipher(key); - return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); - } - }; - return PDF20; -}(); - -exports.PDF20 = PDF20; - -var CipherTransform = function CipherTransformClosure() { - function CipherTransform(stringCipherConstructor, streamCipherConstructor) { - this.StringCipherConstructor = stringCipherConstructor; - this.StreamCipherConstructor = streamCipherConstructor; - } - - CipherTransform.prototype = { - createStream: function CipherTransform_createStream(stream, length) { - var cipher = new this.StreamCipherConstructor(); - return new _stream.DecryptStream(stream, length, function cipherTransformDecryptStream(data, finalize) { - return cipher.decryptBlock(data, finalize); - }); - }, - decryptString: function CipherTransform_decryptString(s) { - var cipher = new this.StringCipherConstructor(); - var data = (0, _util.stringToBytes)(s); - data = cipher.decryptBlock(data, true); - return (0, _util.bytesToString)(data); - }, - encryptString: function CipherTransform_encryptString(s) { - const cipher = new this.StringCipherConstructor(); - - if (cipher instanceof AESBaseCipher) { - const strLen = s.length; - const pad = 16 - strLen % 16; - - if (pad !== 16) { - s = s.padEnd(16 * Math.ceil(strLen / 16), String.fromCharCode(pad)); - } - - const iv = new Uint8Array(16); - - if (typeof crypto !== "undefined") { - crypto.getRandomValues(iv); - } else { - for (let i = 0; i < 16; i++) { - iv[i] = Math.floor(256 * Math.random()); - } - } - - let data = (0, _util.stringToBytes)(s); - data = cipher.encrypt(data, iv); - const buf = new Uint8Array(16 + data.length); - buf.set(iv); - buf.set(data, 16); - return (0, _util.bytesToString)(buf); - } - - let data = (0, _util.stringToBytes)(s); - data = cipher.encrypt(data); - return (0, _util.bytesToString)(data); - } - }; - return CipherTransform; -}(); - -var CipherTransformFactory = function CipherTransformFactoryClosure() { - var defaultPasswordBytes = new Uint8Array([0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]); - - function createEncryptionKey20(revision, password, ownerPassword, ownerValidationSalt, ownerKeySalt, uBytes, userPassword, userValidationSalt, userKeySalt, ownerEncryption, userEncryption, perms) { - if (password) { - var passwordLength = Math.min(127, password.length); - password = password.subarray(0, passwordLength); - } else { - password = []; - } - - var pdfAlgorithm; - - if (revision === 6) { - pdfAlgorithm = new PDF20(); - } else { - pdfAlgorithm = new PDF17(); - } - - if (pdfAlgorithm.checkUserPassword(password, userValidationSalt, userPassword)) { - return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption); - } else if (password.length && pdfAlgorithm.checkOwnerPassword(password, ownerValidationSalt, uBytes, ownerPassword)) { - return pdfAlgorithm.getOwnerKey(password, ownerKeySalt, uBytes, ownerEncryption); - } - - return null; - } - - function prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata) { - var hashDataSize = 40 + ownerPassword.length + fileId.length; - var hashData = new Uint8Array(hashDataSize), - i = 0, - j, - n; - - if (password) { - n = Math.min(32, password.length); - - for (; i < n; ++i) { - hashData[i] = password[i]; - } - } - - j = 0; - - while (i < 32) { - hashData[i++] = defaultPasswordBytes[j++]; - } - - for (j = 0, n = ownerPassword.length; j < n; ++j) { - hashData[i++] = ownerPassword[j]; - } - - hashData[i++] = flags & 0xff; - hashData[i++] = flags >> 8 & 0xff; - hashData[i++] = flags >> 16 & 0xff; - hashData[i++] = flags >>> 24 & 0xff; - - for (j = 0, n = fileId.length; j < n; ++j) { - hashData[i++] = fileId[j]; - } - - if (revision >= 4 && !encryptMetadata) { - hashData[i++] = 0xff; - hashData[i++] = 0xff; - hashData[i++] = 0xff; - hashData[i++] = 0xff; - } - - var hash = calculateMD5(hashData, 0, i); - var keyLengthInBytes = keyLength >> 3; - - if (revision >= 3) { - for (j = 0; j < 50; ++j) { - hash = calculateMD5(hash, 0, keyLengthInBytes); - } - } - - var encryptionKey = hash.subarray(0, keyLengthInBytes); - var cipher, checkData; - - if (revision >= 3) { - for (i = 0; i < 32; ++i) { - hashData[i] = defaultPasswordBytes[i]; - } - - for (j = 0, n = fileId.length; j < n; ++j) { - hashData[i++] = fileId[j]; - } - - cipher = new ARCFourCipher(encryptionKey); - checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i)); - n = encryptionKey.length; - var derivedKey = new Uint8Array(n), - k; - - for (j = 1; j <= 19; ++j) { - for (k = 0; k < n; ++k) { - derivedKey[k] = encryptionKey[k] ^ j; - } - - cipher = new ARCFourCipher(derivedKey); - checkData = cipher.encryptBlock(checkData); - } - - for (j = 0, n = checkData.length; j < n; ++j) { - if (userPassword[j] !== checkData[j]) { - return null; - } - } - } else { - cipher = new ARCFourCipher(encryptionKey); - checkData = cipher.encryptBlock(defaultPasswordBytes); - - for (j = 0, n = checkData.length; j < n; ++j) { - if (userPassword[j] !== checkData[j]) { - return null; - } - } - } - - return encryptionKey; - } - - function decodeUserPassword(password, ownerPassword, revision, keyLength) { - var hashData = new Uint8Array(32), - i = 0, - j, - n; - n = Math.min(32, password.length); - - for (; i < n; ++i) { - hashData[i] = password[i]; - } - - j = 0; - - while (i < 32) { - hashData[i++] = defaultPasswordBytes[j++]; - } - - var hash = calculateMD5(hashData, 0, i); - var keyLengthInBytes = keyLength >> 3; - - if (revision >= 3) { - for (j = 0; j < 50; ++j) { - hash = calculateMD5(hash, 0, hash.length); - } - } - - var cipher, userPassword; - - if (revision >= 3) { - userPassword = ownerPassword; - var derivedKey = new Uint8Array(keyLengthInBytes), - k; - - for (j = 19; j >= 0; j--) { - for (k = 0; k < keyLengthInBytes; ++k) { - derivedKey[k] = hash[k] ^ j; - } - - cipher = new ARCFourCipher(derivedKey); - userPassword = cipher.encryptBlock(userPassword); - } - } else { - cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes)); - userPassword = cipher.encryptBlock(ownerPassword); - } - - return userPassword; - } - - var identityName = _primitives.Name.get("Identity"); - - function CipherTransformFactory(dict, fileId, password) { - var filter = dict.get("Filter"); - - if (!(0, _primitives.isName)(filter, "Standard")) { - throw new _util.FormatError("unknown encryption method"); - } - - this.dict = dict; - var algorithm = dict.get("V"); - - if (!Number.isInteger(algorithm) || algorithm !== 1 && algorithm !== 2 && algorithm !== 4 && algorithm !== 5) { - throw new _util.FormatError("unsupported encryption algorithm"); - } - - this.algorithm = algorithm; - var keyLength = dict.get("Length"); - - if (!keyLength) { - if (algorithm <= 3) { - keyLength = 40; - } else { - var cfDict = dict.get("CF"); - var streamCryptoName = dict.get("StmF"); - - if ((0, _primitives.isDict)(cfDict) && (0, _primitives.isName)(streamCryptoName)) { - cfDict.suppressEncryption = true; - var handlerDict = cfDict.get(streamCryptoName.name); - keyLength = handlerDict && handlerDict.get("Length") || 128; - - if (keyLength < 40) { - keyLength <<= 3; - } - } - } - } - - if (!Number.isInteger(keyLength) || keyLength < 40 || keyLength % 8 !== 0) { - throw new _util.FormatError("invalid key length"); - } - - var ownerPassword = (0, _util.stringToBytes)(dict.get("O")).subarray(0, 32); - var userPassword = (0, _util.stringToBytes)(dict.get("U")).subarray(0, 32); - var flags = dict.get("P"); - var revision = dict.get("R"); - var encryptMetadata = (algorithm === 4 || algorithm === 5) && dict.get("EncryptMetadata") !== false; - this.encryptMetadata = encryptMetadata; - var fileIdBytes = (0, _util.stringToBytes)(fileId); - var passwordBytes; - - if (password) { - if (revision === 6) { - try { - password = (0, _util.utf8StringToString)(password); - } catch (ex) { - (0, _util.warn)("CipherTransformFactory: " + "Unable to convert UTF8 encoded password."); - } - } - - passwordBytes = (0, _util.stringToBytes)(password); - } - - var encryptionKey; - - if (algorithm !== 5) { - encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata); - } else { - var ownerValidationSalt = (0, _util.stringToBytes)(dict.get("O")).subarray(32, 40); - var ownerKeySalt = (0, _util.stringToBytes)(dict.get("O")).subarray(40, 48); - var uBytes = (0, _util.stringToBytes)(dict.get("U")).subarray(0, 48); - var userValidationSalt = (0, _util.stringToBytes)(dict.get("U")).subarray(32, 40); - var userKeySalt = (0, _util.stringToBytes)(dict.get("U")).subarray(40, 48); - var ownerEncryption = (0, _util.stringToBytes)(dict.get("OE")); - var userEncryption = (0, _util.stringToBytes)(dict.get("UE")); - var perms = (0, _util.stringToBytes)(dict.get("Perms")); - encryptionKey = createEncryptionKey20(revision, passwordBytes, ownerPassword, ownerValidationSalt, ownerKeySalt, uBytes, userPassword, userValidationSalt, userKeySalt, ownerEncryption, userEncryption, perms); - } - - if (!encryptionKey && !password) { - throw new _util.PasswordException("No password given", _util.PasswordResponses.NEED_PASSWORD); - } else if (!encryptionKey && password) { - var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword, revision, keyLength); - encryptionKey = prepareKeyData(fileIdBytes, decodedPassword, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata); - } - - if (!encryptionKey) { - throw new _util.PasswordException("Incorrect Password", _util.PasswordResponses.INCORRECT_PASSWORD); - } - - this.encryptionKey = encryptionKey; - - if (algorithm >= 4) { - var cf = dict.get("CF"); - - if ((0, _primitives.isDict)(cf)) { - cf.suppressEncryption = true; - } - - this.cf = cf; - this.stmf = dict.get("StmF") || identityName; - this.strf = dict.get("StrF") || identityName; - this.eff = dict.get("EFF") || this.stmf; - } - } - - function buildObjectKey(num, gen, encryptionKey, isAes) { - var key = new Uint8Array(encryptionKey.length + 9), - i, - n; - - for (i = 0, n = encryptionKey.length; i < n; ++i) { - key[i] = encryptionKey[i]; - } - - key[i++] = num & 0xff; - key[i++] = num >> 8 & 0xff; - key[i++] = num >> 16 & 0xff; - key[i++] = gen & 0xff; - key[i++] = gen >> 8 & 0xff; - - if (isAes) { - key[i++] = 0x73; - key[i++] = 0x41; - key[i++] = 0x6c; - key[i++] = 0x54; - } - - var hash = calculateMD5(key, 0, i); - return hash.subarray(0, Math.min(encryptionKey.length + 5, 16)); - } - - function buildCipherConstructor(cf, name, num, gen, key) { - if (!(0, _primitives.isName)(name)) { - throw new _util.FormatError("Invalid crypt filter name."); - } - - var cryptFilter = cf.get(name.name); - var cfm; - - if (cryptFilter !== null && cryptFilter !== undefined) { - cfm = cryptFilter.get("CFM"); - } - - if (!cfm || cfm.name === "None") { - return function cipherTransformFactoryBuildCipherConstructorNone() { - return new NullCipher(); - }; - } - - if (cfm.name === "V2") { - return function cipherTransformFactoryBuildCipherConstructorV2() { - return new ARCFourCipher(buildObjectKey(num, gen, key, false)); - }; - } - - if (cfm.name === "AESV2") { - return function cipherTransformFactoryBuildCipherConstructorAESV2() { - return new AES128Cipher(buildObjectKey(num, gen, key, true)); - }; - } - - if (cfm.name === "AESV3") { - return function cipherTransformFactoryBuildCipherConstructorAESV3() { - return new AES256Cipher(key); - }; - } - - throw new _util.FormatError("Unknown crypto method"); - } - - CipherTransformFactory.prototype = { - createCipherTransform: function CipherTransformFactory_createCipherTransform(num, gen) { - if (this.algorithm === 4 || this.algorithm === 5) { - return new CipherTransform(buildCipherConstructor(this.cf, this.stmf, num, gen, this.encryptionKey), buildCipherConstructor(this.cf, this.strf, num, gen, this.encryptionKey)); - } - - var key = buildObjectKey(num, gen, this.encryptionKey, false); - - var cipherConstructor = function buildCipherCipherConstructor() { - return new ARCFourCipher(key); - }; - - return new CipherTransform(cipherConstructor, cipherConstructor); - } - }; - return CipherTransformFactory; -}(); - -exports.CipherTransformFactory = CipherTransformFactory; - -/***/ }), -/* 23 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); +})); exports.ColorSpace = void 0; var _util = __w_pdfjs_require__(2); var _primitives = __w_pdfjs_require__(5); -var _core_utils = __w_pdfjs_require__(8); +var _base_stream = __w_pdfjs_require__(7); + +var _core_utils = __w_pdfjs_require__(6); function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) { const COMPONENTS = 3; @@ -17942,32 +9018,32 @@ class ColorSpace { static _parse(cs, xref, resources = null, pdfFunctionFactory) { cs = xref.fetchIfRef(cs); - if ((0, _primitives.isName)(cs)) { + if (cs instanceof _primitives.Name) { switch (cs.name) { - case "DeviceGray": case "G": + case "DeviceGray": return this.singletons.gray; - case "DeviceRGB": case "RGB": + case "DeviceRGB": return this.singletons.rgb; - case "DeviceCMYK": case "CMYK": + case "DeviceCMYK": return this.singletons.cmyk; case "Pattern": return new PatternCS(null); default: - if ((0, _primitives.isDict)(resources)) { + if (resources instanceof _primitives.Dict) { const colorSpaces = resources.get("ColorSpace"); - if ((0, _primitives.isDict)(colorSpaces)) { + if (colorSpaces instanceof _primitives.Dict) { const resourcesCS = colorSpaces.get(cs.name); if (resourcesCS) { - if ((0, _primitives.isName)(resourcesCS)) { + if (resourcesCS instanceof _primitives.Name) { return this._parse(resourcesCS, xref, resources, pdfFunctionFactory); } @@ -17986,16 +9062,16 @@ class ColorSpace { let params, numComps, baseCS, whitePoint, blackPoint, gamma; switch (mode) { - case "DeviceGray": case "G": + case "DeviceGray": return this.singletons.gray; - case "DeviceRGB": case "RGB": + case "DeviceRGB": return this.singletons.rgb; - case "DeviceCMYK": case "CMYK": + case "DeviceCMYK": return this.singletons.cmyk; case "CalGray": @@ -18048,8 +9124,8 @@ class ColorSpace { return new PatternCS(baseCS); - case "Indexed": case "I": + case "Indexed": baseCS = this._parse(cs[1], xref, resources, pdfFunctionFactory); const hiVal = xref.fetchIfRef(cs[2]) + 1; const lookup = xref.fetchIfRef(cs[3]); @@ -18194,7 +9270,7 @@ class IndexedCS extends ColorSpace { const length = base.numComps * highVal; this.lookup = new Uint8Array(length); - if ((0, _primitives.isStream)(lookup)) { + if (lookup instanceof _base_stream.BaseStream) { const bytes = lookup.getBytes(length); this.lookup.set(bytes); } else if (typeof lookup === "string") { @@ -18362,7 +9438,7 @@ const CalGrayCS = function CalGrayCSClosure() { const A = src[srcOffset] * scale; const AG = A ** cs.G; const L = cs.YW * AG; - const val = Math.max(295.8 * L ** 0.333333333333333333 - 40.8, 0); + const val = Math.max(295.8 * L ** 0.3333333333333333 - 40.8, 0); dest[destOffset] = val; dest[destOffset + 1] = val; dest[destOffset + 2] = val; @@ -18638,7 +9714,7 @@ const LabCS = function LabCSClosure() { let result; if (x >= 6 / 29) { - result = x * x * x; + result = x ** 3; } else { result = 108 / 841 * (x - 4 / 29); } @@ -18767,2734 +9843,81 @@ const LabCS = function LabCSClosure() { }(); /***/ }), -/* 24 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 15 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.GlobalImageCache = exports.LocalGStateCache = exports.LocalFunctionCache = exports.LocalColorSpaceCache = exports.LocalImageCache = void 0; +})); +exports.PartialEvaluator = exports.EvaluatorPreprocessor = void 0; var _util = __w_pdfjs_require__(2); +var _cmap = __w_pdfjs_require__(16); + var _primitives = __w_pdfjs_require__(5); -class BaseLocalCache { - constructor(options) { - if (this.constructor === BaseLocalCache) { - (0, _util.unreachable)("Cannot initialize BaseLocalCache."); - } +var _fonts = __w_pdfjs_require__(34); - if (!options || !options.onlyRefs) { - this._nameRefMap = new Map(); - this._imageMap = new Map(); - } +var _fonts_utils = __w_pdfjs_require__(38); - this._imageCache = new _primitives.RefSetCache(); - } +var _encodings = __w_pdfjs_require__(37); - getByName(name) { - const ref = this._nameRefMap.get(name); +var _standard_fonts = __w_pdfjs_require__(41); - if (ref) { - return this.getByRef(ref); - } +var _unicode = __w_pdfjs_require__(40); - return this._imageMap.get(name) || null; - } +var _pattern = __w_pdfjs_require__(50); - getByRef(ref) { - return this._imageCache.get(ref) || null; - } +var _xfa_fonts = __w_pdfjs_require__(51); - set(name, ref, data) { - (0, _util.unreachable)("Abstract method `set` called."); - } +var _to_unicode_map = __w_pdfjs_require__(42); -} +var _function = __w_pdfjs_require__(57); -class LocalImageCache extends BaseLocalCache { - set(name, ref = null, data) { - if (!name) { - throw new Error('LocalImageCache.set - expected "name" argument.'); - } +var _parser = __w_pdfjs_require__(17); - if (ref) { - if (this._imageCache.has(ref)) { - return; - } +var _image_utils = __w_pdfjs_require__(59); - this._nameRefMap.set(name, ref); +var _stream = __w_pdfjs_require__(10); - this._imageCache.put(ref, data); +var _base_stream = __w_pdfjs_require__(7); - return; - } +var _bidi = __w_pdfjs_require__(60); - if (this._imageMap.has(name)) { - return; - } +var _colorspace = __w_pdfjs_require__(14); - this._imageMap.set(name, data); - } +var _decode_stream = __w_pdfjs_require__(19); -} +var _glyphlist = __w_pdfjs_require__(39); -exports.LocalImageCache = LocalImageCache; +var _core_utils = __w_pdfjs_require__(6); -class LocalColorSpaceCache extends BaseLocalCache { - set(name = null, ref = null, data) { - if (!name && !ref) { - throw new Error('LocalColorSpaceCache.set - expected "name" and/or "ref" argument.'); - } +var _metrics = __w_pdfjs_require__(45); - if (ref) { - if (this._imageCache.has(ref)) { - return; - } +var _murmurhash = __w_pdfjs_require__(61); - if (name) { - this._nameRefMap.set(name, ref); - } +var _operator_list = __w_pdfjs_require__(62); - this._imageCache.put(ref, data); - - return; - } - - if (this._imageMap.has(name)) { - return; - } - - this._imageMap.set(name, data); - } - -} - -exports.LocalColorSpaceCache = LocalColorSpaceCache; - -class LocalFunctionCache extends BaseLocalCache { - constructor(options) { - super({ - onlyRefs: true - }); - } - - getByName(name) { - (0, _util.unreachable)("Should not call `getByName` method."); - } - - set(name = null, ref, data) { - if (!ref) { - throw new Error('LocalFunctionCache.set - expected "ref" argument.'); - } - - if (this._imageCache.has(ref)) { - return; - } - - this._imageCache.put(ref, data); - } - -} - -exports.LocalFunctionCache = LocalFunctionCache; - -class LocalGStateCache extends BaseLocalCache { - set(name, ref = null, data) { - if (!name) { - throw new Error('LocalGStateCache.set - expected "name" argument.'); - } - - if (ref) { - if (this._imageCache.has(ref)) { - return; - } - - this._nameRefMap.set(name, ref); - - this._imageCache.put(ref, data); - - return; - } - - if (this._imageMap.has(name)) { - return; - } - - this._imageMap.set(name, data); - } - -} - -exports.LocalGStateCache = LocalGStateCache; - -class GlobalImageCache { - static get NUM_PAGES_THRESHOLD() { - return (0, _util.shadow)(this, "NUM_PAGES_THRESHOLD", 2); - } - - static get MAX_IMAGES_TO_CACHE() { - return (0, _util.shadow)(this, "MAX_IMAGES_TO_CACHE", 10); - } - - constructor() { - this._refCache = new _primitives.RefSetCache(); - this._imageCache = new _primitives.RefSetCache(); - } - - shouldCache(ref, pageIndex) { - const pageIndexSet = this._refCache.get(ref); - - const numPages = pageIndexSet ? pageIndexSet.size + (pageIndexSet.has(pageIndex) ? 0 : 1) : 1; - - if (numPages < GlobalImageCache.NUM_PAGES_THRESHOLD) { - return false; - } - - if (!this._imageCache.has(ref) && this._imageCache.size >= GlobalImageCache.MAX_IMAGES_TO_CACHE) { - return false; - } - - return true; - } - - addPageIndex(ref, pageIndex) { - let pageIndexSet = this._refCache.get(ref); - - if (!pageIndexSet) { - pageIndexSet = new Set(); - - this._refCache.put(ref, pageIndexSet); - } - - pageIndexSet.add(pageIndex); - } - - getData(ref, pageIndex) { - const pageIndexSet = this._refCache.get(ref); - - if (!pageIndexSet) { - return null; - } - - if (pageIndexSet.size < GlobalImageCache.NUM_PAGES_THRESHOLD) { - return null; - } - - if (!this._imageCache.has(ref)) { - return null; - } - - pageIndexSet.add(pageIndex); - return this._imageCache.get(ref); - } - - setData(ref, data) { - if (!this._refCache.has(ref)) { - throw new Error('GlobalImageCache.setData - expected "addPageIndex" to have been called.'); - } - - if (this._imageCache.has(ref)) { - return; - } - - if (this._imageCache.size >= GlobalImageCache.MAX_IMAGES_TO_CACHE) { - (0, _util.info)("GlobalImageCache.setData - ignoring image above MAX_IMAGES_TO_CACHE."); - return; - } - - this._imageCache.put(ref, data); - } - - clear(onlyData = false) { - if (!onlyData) { - this._refCache.clear(); - } - - this._imageCache.clear(); - } - -} - -exports.GlobalImageCache = GlobalImageCache; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getQuadPoints = getQuadPoints; -exports.MarkupAnnotation = exports.AnnotationFactory = exports.AnnotationBorderStyle = exports.Annotation = void 0; - -var _util = __w_pdfjs_require__(2); - -var _obj = __w_pdfjs_require__(10); - -var _primitives = __w_pdfjs_require__(5); - -var _colorspace = __w_pdfjs_require__(23); - -var _core_utils = __w_pdfjs_require__(8); - -var _operator_list = __w_pdfjs_require__(26); - -var _stream = __w_pdfjs_require__(12); - -var _writer = __w_pdfjs_require__(27); - -class AnnotationFactory { - static create(xref, ref, pdfManager, idFactory) { - return pdfManager.ensureCatalog("acroForm").then(acroForm => { - return pdfManager.ensure(this, "_create", [xref, ref, pdfManager, idFactory, acroForm]); - }); - } - - static _create(xref, ref, pdfManager, idFactory, acroForm) { - const dict = xref.fetchIfRef(ref); - - if (!(0, _primitives.isDict)(dict)) { - return undefined; - } - - const id = (0, _primitives.isRef)(ref) ? ref.toString() : `annot_${idFactory.createObjId()}`; - let subtype = dict.get("Subtype"); - subtype = (0, _primitives.isName)(subtype) ? subtype.name : null; - const parameters = { - xref, - ref, - dict, - subtype, - id, - pdfManager, - acroForm: acroForm instanceof _primitives.Dict ? acroForm : _primitives.Dict.empty - }; - - switch (subtype) { - case "Link": - return new LinkAnnotation(parameters); - - case "Text": - return new TextAnnotation(parameters); - - case "Widget": - let fieldType = (0, _core_utils.getInheritableProperty)({ - dict, - key: "FT" - }); - fieldType = (0, _primitives.isName)(fieldType) ? fieldType.name : null; - - switch (fieldType) { - case "Tx": - return new TextWidgetAnnotation(parameters); - - case "Btn": - return new ButtonWidgetAnnotation(parameters); - - case "Ch": - return new ChoiceWidgetAnnotation(parameters); - } - - (0, _util.warn)('Unimplemented widget field type "' + fieldType + '", ' + "falling back to base field type."); - return new WidgetAnnotation(parameters); - - case "Popup": - return new PopupAnnotation(parameters); - - case "FreeText": - return new FreeTextAnnotation(parameters); - - case "Line": - return new LineAnnotation(parameters); - - case "Square": - return new SquareAnnotation(parameters); - - case "Circle": - return new CircleAnnotation(parameters); - - case "PolyLine": - return new PolylineAnnotation(parameters); - - case "Polygon": - return new PolygonAnnotation(parameters); - - case "Caret": - return new CaretAnnotation(parameters); - - case "Ink": - return new InkAnnotation(parameters); - - case "Highlight": - return new HighlightAnnotation(parameters); - - case "Underline": - return new UnderlineAnnotation(parameters); - - case "Squiggly": - return new SquigglyAnnotation(parameters); - - case "StrikeOut": - return new StrikeOutAnnotation(parameters); - - case "Stamp": - return new StampAnnotation(parameters); - - case "FileAttachment": - return new FileAttachmentAnnotation(parameters); - - default: - if (!subtype) { - (0, _util.warn)("Annotation is missing the required /Subtype."); - } else { - (0, _util.warn)('Unimplemented annotation type "' + subtype + '", ' + "falling back to base annotation."); - } - - return new Annotation(parameters); - } - } - -} - -exports.AnnotationFactory = AnnotationFactory; - -function getQuadPoints(dict, rect) { - if (!dict.has("QuadPoints")) { - return null; - } - - const quadPoints = dict.getArray("QuadPoints"); - - if (!Array.isArray(quadPoints) || quadPoints.length % 8 > 0) { - return null; - } - - const quadPointsLists = []; - - for (let i = 0, ii = quadPoints.length / 8; i < ii; i++) { - quadPointsLists.push([]); - - for (let j = i * 8, jj = i * 8 + 8; j < jj; j += 2) { - const x = quadPoints[j]; - const y = quadPoints[j + 1]; - - if (x < rect[0] || x > rect[2] || y < rect[1] || y > rect[3]) { - return null; - } - - quadPointsLists[i].push({ - x, - y - }); - } - } - - return quadPointsLists; -} - -function getTransformMatrix(rect, bbox, matrix) { - const [minX, minY, maxX, maxY] = _util.Util.getAxialAlignedBoundingBox(bbox, matrix); - - if (minX === maxX || minY === maxY) { - return [1, 0, 0, 1, rect[0], rect[1]]; - } - - const xRatio = (rect[2] - rect[0]) / (maxX - minX); - const yRatio = (rect[3] - rect[1]) / (maxY - minY); - return [xRatio, 0, 0, yRatio, rect[0] - minX * xRatio, rect[1] - minY * yRatio]; -} - -class Annotation { - constructor(params) { - const dict = params.dict; - this.setContents(dict.get("Contents")); - this.setModificationDate(dict.get("M")); - this.setFlags(dict.get("F")); - this.setRectangle(dict.getArray("Rect")); - this.setColor(dict.getArray("C")); - this.setBorderStyle(dict); - this.setAppearance(dict); - this.data = { - annotationFlags: this.flags, - borderStyle: this.borderStyle, - color: this.color, - contents: this.contents, - hasAppearance: !!this.appearance, - id: params.id, - modificationDate: this.modificationDate, - rect: this.rectangle, - subtype: params.subtype - }; - } - - _hasFlag(flags, flag) { - return !!(flags & flag); - } - - _isViewable(flags) { - return !this._hasFlag(flags, _util.AnnotationFlag.INVISIBLE) && !this._hasFlag(flags, _util.AnnotationFlag.HIDDEN) && !this._hasFlag(flags, _util.AnnotationFlag.NOVIEW); - } - - _isPrintable(flags) { - return this._hasFlag(flags, _util.AnnotationFlag.PRINT) && !this._hasFlag(flags, _util.AnnotationFlag.INVISIBLE) && !this._hasFlag(flags, _util.AnnotationFlag.HIDDEN); - } - - get viewable() { - if (this.flags === 0) { - return true; - } - - return this._isViewable(this.flags); - } - - get printable() { - if (this.flags === 0) { - return false; - } - - return this._isPrintable(this.flags); - } - - setContents(contents) { - this.contents = (0, _util.stringToPDFString)(contents || ""); - } - - setModificationDate(modificationDate) { - this.modificationDate = (0, _util.isString)(modificationDate) ? modificationDate : null; - } - - setFlags(flags) { - this.flags = Number.isInteger(flags) && flags > 0 ? flags : 0; - } - - hasFlag(flag) { - return this._hasFlag(this.flags, flag); - } - - setRectangle(rectangle) { - if (Array.isArray(rectangle) && rectangle.length === 4) { - this.rectangle = _util.Util.normalizeRect(rectangle); - } else { - this.rectangle = [0, 0, 0, 0]; - } - } - - setColor(color) { - const rgbColor = new Uint8ClampedArray(3); - - if (!Array.isArray(color)) { - this.color = rgbColor; - return; - } - - switch (color.length) { - case 0: - this.color = null; - break; - - case 1: - _colorspace.ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0); - - this.color = rgbColor; - break; - - case 3: - _colorspace.ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0); - - this.color = rgbColor; - break; - - case 4: - _colorspace.ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0); - - this.color = rgbColor; - break; - - default: - this.color = rgbColor; - break; - } - } - - setBorderStyle(borderStyle) { - this.borderStyle = new AnnotationBorderStyle(); - - if (!(0, _primitives.isDict)(borderStyle)) { - return; - } - - if (borderStyle.has("BS")) { - const dict = borderStyle.get("BS"); - const dictType = dict.get("Type"); - - if (!dictType || (0, _primitives.isName)(dictType, "Border")) { - this.borderStyle.setWidth(dict.get("W"), this.rectangle); - this.borderStyle.setStyle(dict.get("S")); - this.borderStyle.setDashArray(dict.getArray("D")); - } - } else if (borderStyle.has("Border")) { - const array = borderStyle.getArray("Border"); - - if (Array.isArray(array) && array.length >= 3) { - this.borderStyle.setHorizontalCornerRadius(array[0]); - this.borderStyle.setVerticalCornerRadius(array[1]); - this.borderStyle.setWidth(array[2], this.rectangle); - - if (array.length === 4) { - this.borderStyle.setDashArray(array[3]); - } - } - } else { - this.borderStyle.setWidth(0); - } - } - - setAppearance(dict) { - this.appearance = null; - const appearanceStates = dict.get("AP"); - - if (!(0, _primitives.isDict)(appearanceStates)) { - return; - } - - const normalAppearanceState = appearanceStates.get("N"); - - if ((0, _primitives.isStream)(normalAppearanceState)) { - this.appearance = normalAppearanceState; - return; - } - - if (!(0, _primitives.isDict)(normalAppearanceState)) { - return; - } - - const as = dict.get("AS"); - - if (!(0, _primitives.isName)(as) || !normalAppearanceState.has(as.name)) { - return; - } - - this.appearance = normalAppearanceState.get(as.name); - } - - loadResources(keys) { - return this.appearance.dict.getAsync("Resources").then(resources => { - if (!resources) { - return undefined; - } - - const objectLoader = new _obj.ObjectLoader(resources, keys, resources.xref); - return objectLoader.load().then(function () { - return resources; - }); - }); - } - - getOperatorList(evaluator, task, renderForms, annotationStorage) { - if (!this.appearance) { - return Promise.resolve(new _operator_list.OperatorList()); - } - - const appearance = this.appearance; - const data = this.data; - const appearanceDict = appearance.dict; - const resourcesPromise = this.loadResources(["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"]); - const bbox = appearanceDict.getArray("BBox") || [0, 0, 1, 1]; - const matrix = appearanceDict.getArray("Matrix") || [1, 0, 0, 1, 0, 0]; - const transform = getTransformMatrix(data.rect, bbox, matrix); - return resourcesPromise.then(resources => { - const opList = new _operator_list.OperatorList(); - opList.addOp(_util.OPS.beginAnnotation, [data.rect, transform, matrix]); - return evaluator.getOperatorList({ - stream: appearance, - task, - resources, - operatorList: opList - }).then(() => { - opList.addOp(_util.OPS.endAnnotation, []); - appearance.reset(); - return opList; - }); - }); - } - - async save(evaluator, task, annotationStorage) { - return null; - } - -} - -exports.Annotation = Annotation; - -class AnnotationBorderStyle { - constructor() { - this.width = 1; - this.style = _util.AnnotationBorderStyleType.SOLID; - this.dashArray = [3]; - this.horizontalCornerRadius = 0; - this.verticalCornerRadius = 0; - } - - setWidth(width, rect = [0, 0, 0, 0]) { - if ((0, _primitives.isName)(width)) { - this.width = 0; - return; - } - - if (Number.isInteger(width)) { - if (width > 0) { - const maxWidth = (rect[2] - rect[0]) / 2; - const maxHeight = (rect[3] - rect[1]) / 2; - - if (maxWidth > 0 && maxHeight > 0 && (width > maxWidth || width > maxHeight)) { - (0, _util.warn)(`AnnotationBorderStyle.setWidth - ignoring width: ${width}`); - width = 1; - } - } - - this.width = width; - } - } - - setStyle(style) { - if (!(0, _primitives.isName)(style)) { - return; - } - - switch (style.name) { - case "S": - this.style = _util.AnnotationBorderStyleType.SOLID; - break; - - case "D": - this.style = _util.AnnotationBorderStyleType.DASHED; - break; - - case "B": - this.style = _util.AnnotationBorderStyleType.BEVELED; - break; - - case "I": - this.style = _util.AnnotationBorderStyleType.INSET; - break; - - case "U": - this.style = _util.AnnotationBorderStyleType.UNDERLINE; - break; - - default: - break; - } - } - - setDashArray(dashArray) { - if (Array.isArray(dashArray) && dashArray.length > 0) { - let isValid = true; - let allZeros = true; - - for (const element of dashArray) { - const validNumber = +element >= 0; - - if (!validNumber) { - isValid = false; - break; - } else if (element > 0) { - allZeros = false; - } - } - - if (isValid && !allZeros) { - this.dashArray = dashArray; - } else { - this.width = 0; - } - } else if (dashArray) { - this.width = 0; - } - } - - setHorizontalCornerRadius(radius) { - if (Number.isInteger(radius)) { - this.horizontalCornerRadius = radius; - } - } - - setVerticalCornerRadius(radius) { - if (Number.isInteger(radius)) { - this.verticalCornerRadius = radius; - } - } - -} - -exports.AnnotationBorderStyle = AnnotationBorderStyle; - -class MarkupAnnotation extends Annotation { - constructor(parameters) { - super(parameters); - const dict = parameters.dict; - - if (dict.has("IRT")) { - const rawIRT = dict.getRaw("IRT"); - this.data.inReplyTo = (0, _primitives.isRef)(rawIRT) ? rawIRT.toString() : null; - const rt = dict.get("RT"); - this.data.replyType = (0, _primitives.isName)(rt) ? rt.name : _util.AnnotationReplyType.REPLY; - } - - if (this.data.replyType === _util.AnnotationReplyType.GROUP) { - const parent = dict.get("IRT"); - this.data.title = (0, _util.stringToPDFString)(parent.get("T") || ""); - this.setContents(parent.get("Contents")); - this.data.contents = this.contents; - - if (!parent.has("CreationDate")) { - this.data.creationDate = null; - } else { - this.setCreationDate(parent.get("CreationDate")); - this.data.creationDate = this.creationDate; - } - - if (!parent.has("M")) { - this.data.modificationDate = null; - } else { - this.setModificationDate(parent.get("M")); - this.data.modificationDate = this.modificationDate; - } - - this.data.hasPopup = parent.has("Popup"); - - if (!parent.has("C")) { - this.data.color = null; - } else { - this.setColor(parent.getArray("C")); - this.data.color = this.color; - } - } else { - this.data.title = (0, _util.stringToPDFString)(dict.get("T") || ""); - this.setCreationDate(dict.get("CreationDate")); - this.data.creationDate = this.creationDate; - this.data.hasPopup = dict.has("Popup"); - - if (!dict.has("C")) { - this.data.color = null; - } - } - } - - setCreationDate(creationDate) { - this.creationDate = (0, _util.isString)(creationDate) ? creationDate : null; - } - -} - -exports.MarkupAnnotation = MarkupAnnotation; - -class WidgetAnnotation extends Annotation { - constructor(params) { - super(params); - const dict = params.dict; - const data = this.data; - this.ref = params.ref; - data.annotationType = _util.AnnotationType.WIDGET; - data.fieldName = this._constructFieldName(dict); - const fieldValue = (0, _core_utils.getInheritableProperty)({ - dict, - key: "V", - getArray: true - }); - data.fieldValue = this._decodeFormValue(fieldValue); - data.alternativeText = (0, _util.stringToPDFString)(dict.get("TU") || ""); - data.defaultAppearance = (0, _core_utils.getInheritableProperty)({ - dict, - key: "DA" - }) || params.acroForm.get("DA") || ""; - const fieldType = (0, _core_utils.getInheritableProperty)({ - dict, - key: "FT" - }); - data.fieldType = (0, _primitives.isName)(fieldType) ? fieldType.name : null; - this.fieldResources = (0, _core_utils.getInheritableProperty)({ - dict, - key: "DR" - }) || params.acroForm.get("DR") || _primitives.Dict.empty; - data.fieldFlags = (0, _core_utils.getInheritableProperty)({ - dict, - key: "Ff" - }); - - if (!Number.isInteger(data.fieldFlags) || data.fieldFlags < 0) { - data.fieldFlags = 0; - } - - data.readOnly = this.hasFieldFlag(_util.AnnotationFieldFlag.READONLY); - - if (data.fieldType === "Sig") { - data.fieldValue = null; - this.setFlags(_util.AnnotationFlag.HIDDEN); - } - } - - _constructFieldName(dict) { - if (!dict.has("T") && !dict.has("Parent")) { - (0, _util.warn)("Unknown field name, falling back to empty field name."); - return ""; - } - - if (!dict.has("Parent")) { - return (0, _util.stringToPDFString)(dict.get("T")); - } - - const fieldName = []; - - if (dict.has("T")) { - fieldName.unshift((0, _util.stringToPDFString)(dict.get("T"))); - } - - let loopDict = dict; - - while (loopDict.has("Parent")) { - loopDict = loopDict.get("Parent"); - - if (!(0, _primitives.isDict)(loopDict)) { - break; - } - - if (loopDict.has("T")) { - fieldName.unshift((0, _util.stringToPDFString)(loopDict.get("T"))); - } - } - - return fieldName.join("."); - } - - _decodeFormValue(formValue) { - if (Array.isArray(formValue)) { - return formValue.filter(item => (0, _util.isString)(item)).map(item => (0, _util.stringToPDFString)(item)); - } else if ((0, _primitives.isName)(formValue)) { - return (0, _util.stringToPDFString)(formValue.name); - } else if ((0, _util.isString)(formValue)) { - return (0, _util.stringToPDFString)(formValue); - } - - return null; - } - - hasFieldFlag(flag) { - return !!(this.data.fieldFlags & flag); - } - - getOperatorList(evaluator, task, renderForms, annotationStorage) { - if (renderForms) { - return Promise.resolve(new _operator_list.OperatorList()); - } - - if (!this._hasText) { - return super.getOperatorList(evaluator, task, renderForms, annotationStorage); - } - - return this._getAppearance(evaluator, task, annotationStorage).then(content => { - if (this.appearance && content === null) { - return super.getOperatorList(evaluator, task, renderForms, annotationStorage); - } - - const operatorList = new _operator_list.OperatorList(); - - if (!this.data.defaultAppearance || content === null) { - return operatorList; - } - - const matrix = [1, 0, 0, 1, 0, 0]; - const bbox = [0, 0, this.data.rect[2] - this.data.rect[0], this.data.rect[3] - this.data.rect[1]]; - const transform = getTransformMatrix(this.data.rect, bbox, matrix); - operatorList.addOp(_util.OPS.beginAnnotation, [this.data.rect, transform, matrix]); - const stream = new _stream.StringStream(content); - return evaluator.getOperatorList({ - stream, - task, - resources: this.fieldResources, - operatorList - }).then(function () { - operatorList.addOp(_util.OPS.endAnnotation, []); - return operatorList; - }); - }); - } - - async save(evaluator, task, annotationStorage) { - if (this.data.fieldValue === annotationStorage[this.data.id]) { - return null; - } - - let appearance = await this._getAppearance(evaluator, task, annotationStorage); - - if (appearance === null) { - return null; - } - - const dict = evaluator.xref.fetchIfRef(this.ref); - - if (!(0, _primitives.isDict)(dict)) { - return null; - } - - const bbox = [0, 0, this.data.rect[2] - this.data.rect[0], this.data.rect[3] - this.data.rect[1]]; - const newRef = evaluator.xref.getNewRef(); - const AP = new _primitives.Dict(evaluator.xref); - AP.set("N", newRef); - const value = annotationStorage[this.data.id]; - const encrypt = evaluator.xref.encrypt; - let originalTransform = null; - let newTransform = null; - - if (encrypt) { - originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen); - newTransform = encrypt.createCipherTransform(newRef.num, newRef.gen); - appearance = newTransform.encryptString(appearance); - } - - dict.set("V", value); - dict.set("AP", AP); - dict.set("M", `D:${(0, _util.getModificationDate)()}`); - const appearanceDict = new _primitives.Dict(evaluator.xref); - appearanceDict.set("Length", appearance.length); - appearanceDict.set("Subtype", _primitives.Name.get("Form")); - appearanceDict.set("Resources", this.fieldResources); - appearanceDict.set("BBox", bbox); - const bufferOriginal = [`${this.ref.num} ${this.ref.gen} obj\n`]; - (0, _writer.writeDict)(dict, bufferOriginal, originalTransform); - bufferOriginal.push("\nendobj\n"); - const bufferNew = [`${newRef.num} ${newRef.gen} obj\n`]; - (0, _writer.writeDict)(appearanceDict, bufferNew, newTransform); - bufferNew.push(" stream\n"); - bufferNew.push(appearance); - bufferNew.push("\nendstream\nendobj\n"); - return [{ - ref: this.ref, - data: bufferOriginal.join("") - }, { - ref: newRef, - data: bufferNew.join("") - }]; - } - - async _getAppearance(evaluator, task, annotationStorage) { - const isPassword = this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD); - - if (!annotationStorage || isPassword) { - return null; - } - - const value = annotationStorage[this.data.id]; - - if (value === "") { - return ""; - } - - const defaultPadding = 2; - const hPadding = defaultPadding; - const totalHeight = this.data.rect[3] - this.data.rect[1]; - const totalWidth = this.data.rect[2] - this.data.rect[0]; - const fontInfo = await this._getFontData(evaluator, task); - const [font, fontName] = fontInfo; - let fontSize = fontInfo[2]; - fontSize = this._computeFontSize(font, fontName, fontSize, totalHeight); - let descent = font.descent; - - if (isNaN(descent)) { - descent = 0; - } - - const vPadding = defaultPadding + Math.abs(descent) * fontSize; - const defaultAppearance = this.data.defaultAppearance; - const alignment = this.data.textAlignment; - - if (this.data.comb) { - return this._getCombAppearance(defaultAppearance, value, totalWidth, hPadding, vPadding); - } - - if (this.data.multiLine) { - return this._getMultilineAppearance(defaultAppearance, value, font, fontSize, totalWidth, totalHeight, alignment, hPadding, vPadding); - } - - if (alignment === 0 || alignment > 2) { - return "/Tx BMC q BT " + defaultAppearance + ` 1 0 0 1 ${hPadding} ${vPadding} Tm (${(0, _util.escapeString)(value)}) Tj` + " ET Q EMC"; - } - - const renderedText = this._renderText(value, font, fontSize, totalWidth, alignment, hPadding, vPadding); - - return "/Tx BMC q BT " + defaultAppearance + ` 1 0 0 1 0 0 Tm ${renderedText}` + " ET Q EMC"; - } - - async _getFontData(evaluator, task) { - const operatorList = new _operator_list.OperatorList(); - const initialState = { - fontSize: 0, - font: null, - fontName: null, - - clone() { - return this; - } - - }; - await evaluator.getOperatorList({ - stream: new _stream.StringStream(this.data.defaultAppearance), - task, - resources: this.fieldResources, - operatorList, - initialState - }); - return [initialState.font, initialState.fontName, initialState.fontSize]; - } - - _computeFontSize(font, fontName, fontSize, height) { - if (fontSize === null || fontSize === 0) { - const em = font.charsToGlyphs("M", true)[0].width / 1000; - const capHeight = 0.7 * em; - fontSize = Math.max(1, Math.floor(height / (1.5 * capHeight))); - let fontRegex = new RegExp(`/${fontName}\\s+[0-9\.]+\\s+Tf`); - - if (this.data.defaultAppearance.search(fontRegex) === -1) { - fontRegex = new RegExp(`/${fontName}\\s+Tf`); - } - - this.data.defaultAppearance = this.data.defaultAppearance.replace(fontRegex, `/${fontName} ${fontSize} Tf`); - } - - return fontSize; - } - - _renderText(text, font, fontSize, totalWidth, alignment, hPadding, vPadding) { - const glyphs = font.charsToGlyphs(text); - const scale = fontSize / 1000; - let width = 0; - - for (const glyph of glyphs) { - width += glyph.width * scale; - } - - let shift; - - if (alignment === 1) { - shift = (totalWidth - width) / 2; - } else if (alignment === 2) { - shift = totalWidth - width - hPadding; - } else { - shift = hPadding; - } - - shift = shift.toFixed(2); - vPadding = vPadding.toFixed(2); - return `${shift} ${vPadding} Td (${(0, _util.escapeString)(text)}) Tj`; - } - -} - -class TextWidgetAnnotation extends WidgetAnnotation { - constructor(params) { - super(params); - this._hasText = true; - const dict = params.dict; - - if (!(0, _util.isString)(this.data.fieldValue)) { - this.data.fieldValue = ""; - } - - let alignment = (0, _core_utils.getInheritableProperty)({ - dict, - key: "Q" - }); - - if (!Number.isInteger(alignment) || alignment < 0 || alignment > 2) { - alignment = null; - } - - this.data.textAlignment = alignment; - let maximumLength = (0, _core_utils.getInheritableProperty)({ - dict, - key: "MaxLen" - }); - - if (!Number.isInteger(maximumLength) || maximumLength < 0) { - maximumLength = null; - } - - this.data.maxLen = maximumLength; - this.data.multiLine = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTILINE); - this.data.comb = this.hasFieldFlag(_util.AnnotationFieldFlag.COMB) && !this.hasFieldFlag(_util.AnnotationFieldFlag.MULTILINE) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD) && !this.hasFieldFlag(_util.AnnotationFieldFlag.FILESELECT) && this.data.maxLen !== null; - } - - _getCombAppearance(defaultAppearance, text, width, hPadding, vPadding) { - const combWidth = (width / this.data.maxLen).toFixed(2); - const buf = []; - - for (const character of text) { - buf.push(`(${(0, _util.escapeString)(character)}) Tj`); - } - - const renderedComb = buf.join(` ${combWidth} 0 Td `); - return "/Tx BMC q BT " + defaultAppearance + ` 1 0 0 1 ${hPadding} ${vPadding} Tm ${renderedComb}` + " ET Q EMC"; - } - - _getMultilineAppearance(defaultAppearance, text, font, fontSize, width, height, alignment, hPadding, vPadding) { - const lines = text.split(/\r\n|\r|\n/); - const buf = []; - const totalWidth = width - 2 * hPadding; - - for (const line of lines) { - const chunks = this._splitLine(line, font, fontSize, totalWidth); - - for (const chunk of chunks) { - const padding = buf.length === 0 ? hPadding : 0; - buf.push(this._renderText(chunk, font, fontSize, width, alignment, padding, -fontSize)); - } - } - - const renderedText = buf.join("\n"); - return "/Tx BMC q BT " + defaultAppearance + ` 1 0 0 1 0 ${height} Tm ${renderedText}` + " ET Q EMC"; - } - - _splitLine(line, font, fontSize, width) { - if (line.length <= 1) { - return [line]; - } - - const scale = fontSize / 1000; - const whitespace = font.charsToGlyphs(" ", true)[0].width * scale; - const chunks = []; - let lastSpacePos = -1, - startChunk = 0, - currentWidth = 0; - - for (let i = 0, ii = line.length; i < ii; i++) { - const character = line.charAt(i); - - if (character === " ") { - if (currentWidth + whitespace > width) { - chunks.push(line.substring(startChunk, i)); - startChunk = i; - currentWidth = whitespace; - lastSpacePos = -1; - } else { - currentWidth += whitespace; - lastSpacePos = i; - } - } else { - const charWidth = font.charsToGlyphs(character, false)[0].width * scale; - - if (currentWidth + charWidth > width) { - if (lastSpacePos !== -1) { - chunks.push(line.substring(startChunk, lastSpacePos + 1)); - startChunk = i = lastSpacePos + 1; - lastSpacePos = -1; - currentWidth = 0; - } else { - chunks.push(line.substring(startChunk, i)); - startChunk = i; - currentWidth = charWidth; - } - } else { - currentWidth += charWidth; - } - } - } - - if (startChunk < line.length) { - chunks.push(line.substring(startChunk, line.length)); - } - - return chunks; - } - -} - -class ButtonWidgetAnnotation extends WidgetAnnotation { - constructor(params) { - super(params); - this.checkedAppearance = null; - this.uncheckedAppearance = null; - this.data.checkBox = !this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON); - this.data.radioButton = this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON); - this.data.pushButton = this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON); - - if (this.data.checkBox) { - this._processCheckBox(params); - } else if (this.data.radioButton) { - this._processRadioButton(params); - } else if (this.data.pushButton) { - this._processPushButton(params); - } else { - (0, _util.warn)("Invalid field flags for button widget annotation"); - } - } - - getOperatorList(evaluator, task, renderForms, annotationStorage) { - if (this.data.pushButton) { - return super.getOperatorList(evaluator, task, false, annotationStorage); - } - - if (annotationStorage) { - const value = annotationStorage[this.data.id] || false; - let appearance; - - if (value) { - appearance = this.checkedAppearance; - } else { - appearance = this.uncheckedAppearance; - } - - if (appearance) { - const savedAppearance = this.appearance; - this.appearance = appearance; - const operatorList = super.getOperatorList(evaluator, task, renderForms, annotationStorage); - this.appearance = savedAppearance; - return operatorList; - } - - return Promise.resolve(new _operator_list.OperatorList()); - } - - return super.getOperatorList(evaluator, task, renderForms, annotationStorage); - } - - async save(evaluator, task, annotationStorage) { - if (this.data.checkBox) { - return this._saveCheckbox(evaluator, task, annotationStorage); - } - - if (this.data.radioButton) { - return this._saveRadioButton(evaluator, task, annotationStorage); - } - - return super.save(evaluator, task, annotationStorage); - } - - async _saveCheckbox(evaluator, task, annotationStorage) { - const defaultValue = this.data.fieldValue && this.data.fieldValue !== "Off"; - const value = annotationStorage[this.data.id]; - - if (defaultValue === value) { - return null; - } - - const dict = evaluator.xref.fetchIfRef(this.ref); - - if (!(0, _primitives.isDict)(dict)) { - return null; - } - - const name = _primitives.Name.get(value ? this.data.exportValue : "Off"); - - dict.set("V", name); - dict.set("AS", name); - dict.set("M", `D:${(0, _util.getModificationDate)()}`); - const encrypt = evaluator.xref.encrypt; - let originalTransform = null; - - if (encrypt) { - originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen); - } - - const buffer = [`${this.ref.num} ${this.ref.gen} obj\n`]; - (0, _writer.writeDict)(dict, buffer, originalTransform); - buffer.push("\nendobj\n"); - return [{ - ref: this.ref, - data: buffer.join("") - }]; - } - - async _saveRadioButton(evaluator, task, annotationStorage) { - const defaultValue = this.data.fieldValue === this.data.buttonValue; - const value = annotationStorage[this.data.id]; - - if (defaultValue === value) { - return null; - } - - const dict = evaluator.xref.fetchIfRef(this.ref); - - if (!(0, _primitives.isDict)(dict)) { - return null; - } - - const name = _primitives.Name.get(value ? this.data.buttonValue : "Off"); - - let parentBuffer = null; - const encrypt = evaluator.xref.encrypt; - - if (value) { - if ((0, _primitives.isRef)(this.parent)) { - const parent = evaluator.xref.fetch(this.parent); - let parentTransform = null; - - if (encrypt) { - parentTransform = encrypt.createCipherTransform(this.parent.num, this.parent.gen); - } - - parent.set("V", name); - parentBuffer = [`${this.parent.num} ${this.parent.gen} obj\n`]; - (0, _writer.writeDict)(parent, parentBuffer, parentTransform); - parentBuffer.push("\nendobj\n"); - } else if ((0, _primitives.isDict)(this.parent)) { - this.parent.set("V", name); - } - } - - dict.set("AS", name); - dict.set("M", `D:${(0, _util.getModificationDate)()}`); - let originalTransform = null; - - if (encrypt) { - originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen); - } - - const buffer = [`${this.ref.num} ${this.ref.gen} obj\n`]; - (0, _writer.writeDict)(dict, buffer, originalTransform); - buffer.push("\nendobj\n"); - const newRefs = [{ - ref: this.ref, - data: buffer.join("") - }]; - - if (parentBuffer !== null) { - newRefs.push({ - ref: this.parent, - data: parentBuffer.join("") - }); - } - - return newRefs; - } - - _processCheckBox(params) { - const customAppearance = params.dict.get("AP"); - - if (!(0, _primitives.isDict)(customAppearance)) { - return; - } - - const normalAppearance = customAppearance.get("N"); - - if (!(0, _primitives.isDict)(normalAppearance)) { - return; - } - - const exportValues = normalAppearance.getKeys(); - - if (!exportValues.includes("Off")) { - exportValues.push("Off"); - } - - if (exportValues.length !== 2) { - return; - } - - this.data.exportValue = exportValues[0] === "Off" ? exportValues[1] : exportValues[0]; - this.checkedAppearance = normalAppearance.get(this.data.exportValue); - this.uncheckedAppearance = normalAppearance.get("Off") || null; - } - - _processRadioButton(params) { - this.data.fieldValue = this.data.buttonValue = null; - const fieldParent = params.dict.get("Parent"); - - if ((0, _primitives.isDict)(fieldParent) && fieldParent.has("V")) { - const fieldParentValue = fieldParent.get("V"); - - if ((0, _primitives.isName)(fieldParentValue)) { - this.parent = params.dict.getRaw("Parent"); - this.data.fieldValue = this._decodeFormValue(fieldParentValue); - } - } - - const appearanceStates = params.dict.get("AP"); - - if (!(0, _primitives.isDict)(appearanceStates)) { - return; - } - - const normalAppearance = appearanceStates.get("N"); - - if (!(0, _primitives.isDict)(normalAppearance)) { - return; - } - - for (const key of normalAppearance.getKeys()) { - if (key !== "Off") { - this.data.buttonValue = key; - break; - } - } - - this.checkedAppearance = normalAppearance.get(this.data.buttonValue); - this.uncheckedAppearance = normalAppearance.get("Off") || null; - } - - _processPushButton(params) { - if (!params.dict.has("A")) { - (0, _util.warn)("Push buttons without action dictionaries are not supported"); - return; - } - - _obj.Catalog.parseDestDictionary({ - destDict: params.dict, - resultObj: this.data, - docBaseUrl: params.pdfManager.docBaseUrl - }); - } - -} - -class ChoiceWidgetAnnotation extends WidgetAnnotation { - constructor(params) { - super(params); - this.data.options = []; - const options = (0, _core_utils.getInheritableProperty)({ - dict: params.dict, - key: "Opt" - }); - - if (Array.isArray(options)) { - const xref = params.xref; - - for (let i = 0, ii = options.length; i < ii; i++) { - const option = xref.fetchIfRef(options[i]); - const isOptionArray = Array.isArray(option); - this.data.options[i] = { - exportValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[0]) : option), - displayValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[1]) : option) - }; - } - } - - if ((0, _util.isString)(this.data.fieldValue)) { - this.data.fieldValue = [this.data.fieldValue]; - } else if (!this.data.fieldValue) { - this.data.fieldValue = []; - } - - this.data.combo = this.hasFieldFlag(_util.AnnotationFieldFlag.COMBO); - this.data.multiSelect = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTISELECT); - this._hasText = true; - } - -} - -class TextAnnotation extends MarkupAnnotation { - constructor(parameters) { - const DEFAULT_ICON_SIZE = 22; - super(parameters); - const dict = parameters.dict; - this.data.annotationType = _util.AnnotationType.TEXT; - - if (this.data.hasAppearance) { - this.data.name = "NoIcon"; - } else { - this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE; - this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE; - this.data.name = dict.has("Name") ? dict.get("Name").name : "Note"; - } - - if (dict.has("State")) { - this.data.state = dict.get("State") || null; - this.data.stateModel = dict.get("StateModel") || null; - } else { - this.data.state = null; - this.data.stateModel = null; - } - } - -} - -class LinkAnnotation extends Annotation { - constructor(params) { - super(params); - this.data.annotationType = _util.AnnotationType.LINK; - const quadPoints = getQuadPoints(params.dict, this.rectangle); - - if (quadPoints) { - this.data.quadPoints = quadPoints; - } - - _obj.Catalog.parseDestDictionary({ - destDict: params.dict, - resultObj: this.data, - docBaseUrl: params.pdfManager.docBaseUrl - }); - } - -} - -class PopupAnnotation extends Annotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.POPUP; - let parentItem = parameters.dict.get("Parent"); - - if (!parentItem) { - (0, _util.warn)("Popup annotation has a missing or invalid parent annotation."); - return; - } - - const parentSubtype = parentItem.get("Subtype"); - this.data.parentType = (0, _primitives.isName)(parentSubtype) ? parentSubtype.name : null; - const rawParent = parameters.dict.getRaw("Parent"); - this.data.parentId = (0, _primitives.isRef)(rawParent) ? rawParent.toString() : null; - const rt = parentItem.get("RT"); - - if ((0, _primitives.isName)(rt, _util.AnnotationReplyType.GROUP)) { - parentItem = parentItem.get("IRT"); - } - - if (!parentItem.has("M")) { - this.data.modificationDate = null; - } else { - this.setModificationDate(parentItem.get("M")); - this.data.modificationDate = this.modificationDate; - } - - if (!parentItem.has("C")) { - this.data.color = null; - } else { - this.setColor(parentItem.getArray("C")); - this.data.color = this.color; - } - - if (!this.viewable) { - const parentFlags = parentItem.get("F"); - - if (this._isViewable(parentFlags)) { - this.setFlags(parentFlags); - } - } - - this.data.title = (0, _util.stringToPDFString)(parentItem.get("T") || ""); - this.data.contents = (0, _util.stringToPDFString)(parentItem.get("Contents") || ""); - } - -} - -class FreeTextAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.FREETEXT; - } - -} - -class LineAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.LINE; - this.data.lineCoordinates = _util.Util.normalizeRect(parameters.dict.getArray("L")); - } - -} - -class SquareAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.SQUARE; - } - -} - -class CircleAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.CIRCLE; - } - -} - -class PolylineAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.POLYLINE; - const rawVertices = parameters.dict.getArray("Vertices"); - this.data.vertices = []; - - for (let i = 0, ii = rawVertices.length; i < ii; i += 2) { - this.data.vertices.push({ - x: rawVertices[i], - y: rawVertices[i + 1] - }); - } - } - -} - -class PolygonAnnotation extends PolylineAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.POLYGON; - } - -} - -class CaretAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.CARET; - } - -} - -class InkAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.INK; - const xref = parameters.xref; - const originalInkLists = parameters.dict.getArray("InkList"); - this.data.inkLists = []; - - for (let i = 0, ii = originalInkLists.length; i < ii; ++i) { - this.data.inkLists.push([]); - - for (let j = 0, jj = originalInkLists[i].length; j < jj; j += 2) { - this.data.inkLists[i].push({ - x: xref.fetchIfRef(originalInkLists[i][j]), - y: xref.fetchIfRef(originalInkLists[i][j + 1]) - }); - } - } - } - -} - -class HighlightAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.HIGHLIGHT; - const quadPoints = getQuadPoints(parameters.dict, this.rectangle); - - if (quadPoints) { - this.data.quadPoints = quadPoints; - } - } - -} - -class UnderlineAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.UNDERLINE; - const quadPoints = getQuadPoints(parameters.dict, this.rectangle); - - if (quadPoints) { - this.data.quadPoints = quadPoints; - } - } - -} - -class SquigglyAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.SQUIGGLY; - const quadPoints = getQuadPoints(parameters.dict, this.rectangle); - - if (quadPoints) { - this.data.quadPoints = quadPoints; - } - } - -} - -class StrikeOutAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.STRIKEOUT; - const quadPoints = getQuadPoints(parameters.dict, this.rectangle); - - if (quadPoints) { - this.data.quadPoints = quadPoints; - } - } - -} - -class StampAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - this.data.annotationType = _util.AnnotationType.STAMP; - } - -} - -class FileAttachmentAnnotation extends MarkupAnnotation { - constructor(parameters) { - super(parameters); - const file = new _obj.FileSpec(parameters.dict.get("FS"), parameters.xref); - this.data.annotationType = _util.AnnotationType.FILEATTACHMENT; - this.data.file = file.serializable; - } - -} - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.OperatorList = void 0; - -var _util = __w_pdfjs_require__(2); - -var QueueOptimizer = function QueueOptimizerClosure() { - function addState(parentState, pattern, checkFn, iterateFn, processFn) { - var state = parentState; - - for (var i = 0, ii = pattern.length - 1; i < ii; i++) { - var item = pattern[i]; - state = state[item] || (state[item] = []); - } - - state[pattern[pattern.length - 1]] = { - checkFn, - iterateFn, - processFn - }; - } - - function handlePaintSolidColorImageMask(iFirstSave, count, fnArray, argsArray) { - var iFirstPIMXO = iFirstSave + 2; - - for (var i = 0; i < count; i++) { - var arg = argsArray[iFirstPIMXO + 4 * i]; - var imageMask = arg.length === 1 && arg[0]; - - if (imageMask && imageMask.width === 1 && imageMask.height === 1 && (!imageMask.data.length || imageMask.data.length === 1 && imageMask.data[0] === 0)) { - fnArray[iFirstPIMXO + 4 * i] = _util.OPS.paintSolidColorImageMask; - continue; - } - - break; - } - - return count - i; - } - - var InitialState = []; - addState(InitialState, [_util.OPS.save, _util.OPS.transform, _util.OPS.paintInlineImageXObject, _util.OPS.restore], null, function iterateInlineImageGroup(context, i) { - var fnArray = context.fnArray; - var iFirstSave = context.iCurr - 3; - var pos = (i - iFirstSave) % 4; - - switch (pos) { - case 0: - return fnArray[i] === _util.OPS.save; - - case 1: - return fnArray[i] === _util.OPS.transform; - - case 2: - return fnArray[i] === _util.OPS.paintInlineImageXObject; - - case 3: - return fnArray[i] === _util.OPS.restore; - } - - throw new Error(`iterateInlineImageGroup - invalid pos: ${pos}`); - }, function foundInlineImageGroup(context, i) { - var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10; - var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200; - var MAX_WIDTH = 1000; - var IMAGE_PADDING = 1; - var fnArray = context.fnArray, - argsArray = context.argsArray; - var curr = context.iCurr; - var iFirstSave = curr - 3; - var iFirstTransform = curr - 2; - var iFirstPIIXO = curr - 1; - var count = Math.min(Math.floor((i - iFirstSave) / 4), MAX_IMAGES_IN_INLINE_IMAGES_BLOCK); - - if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) { - return i - (i - iFirstSave) % 4; - } - - var maxX = 0; - var map = [], - maxLineHeight = 0; - var currentX = IMAGE_PADDING, - currentY = IMAGE_PADDING; - var q; - - for (q = 0; q < count; q++) { - var transform = argsArray[iFirstTransform + (q << 2)]; - var img = argsArray[iFirstPIIXO + (q << 2)][0]; - - if (currentX + img.width > MAX_WIDTH) { - maxX = Math.max(maxX, currentX); - currentY += maxLineHeight + 2 * IMAGE_PADDING; - currentX = 0; - maxLineHeight = 0; - } - - map.push({ - transform, - x: currentX, - y: currentY, - w: img.width, - h: img.height - }); - currentX += img.width + 2 * IMAGE_PADDING; - maxLineHeight = Math.max(maxLineHeight, img.height); - } - - var imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING; - var imgHeight = currentY + maxLineHeight + IMAGE_PADDING; - var imgData = new Uint8ClampedArray(imgWidth * imgHeight * 4); - var imgRowSize = imgWidth << 2; - - for (q = 0; q < count; q++) { - var data = argsArray[iFirstPIIXO + (q << 2)][0].data; - var rowSize = map[q].w << 2; - var dataOffset = 0; - var offset = map[q].x + map[q].y * imgWidth << 2; - imgData.set(data.subarray(0, rowSize), offset - imgRowSize); - - for (var k = 0, kk = map[q].h; k < kk; k++) { - imgData.set(data.subarray(dataOffset, dataOffset + rowSize), offset); - dataOffset += rowSize; - offset += imgRowSize; - } - - imgData.set(data.subarray(dataOffset - rowSize, dataOffset), offset); - - while (offset >= 0) { - data[offset - 4] = data[offset]; - data[offset - 3] = data[offset + 1]; - data[offset - 2] = data[offset + 2]; - data[offset - 1] = data[offset + 3]; - data[offset + rowSize] = data[offset + rowSize - 4]; - data[offset + rowSize + 1] = data[offset + rowSize - 3]; - data[offset + rowSize + 2] = data[offset + rowSize - 2]; - data[offset + rowSize + 3] = data[offset + rowSize - 1]; - offset -= imgRowSize; - } - } - - fnArray.splice(iFirstSave, count * 4, _util.OPS.paintInlineImageXObjectGroup); - argsArray.splice(iFirstSave, count * 4, [{ - width: imgWidth, - height: imgHeight, - kind: _util.ImageKind.RGBA_32BPP, - data: imgData - }, map]); - return iFirstSave + 1; - }); - addState(InitialState, [_util.OPS.save, _util.OPS.transform, _util.OPS.paintImageMaskXObject, _util.OPS.restore], null, function iterateImageMaskGroup(context, i) { - var fnArray = context.fnArray; - var iFirstSave = context.iCurr - 3; - var pos = (i - iFirstSave) % 4; - - switch (pos) { - case 0: - return fnArray[i] === _util.OPS.save; - - case 1: - return fnArray[i] === _util.OPS.transform; - - case 2: - return fnArray[i] === _util.OPS.paintImageMaskXObject; - - case 3: - return fnArray[i] === _util.OPS.restore; - } - - throw new Error(`iterateImageMaskGroup - invalid pos: ${pos}`); - }, function foundImageMaskGroup(context, i) { - var MIN_IMAGES_IN_MASKS_BLOCK = 10; - var MAX_IMAGES_IN_MASKS_BLOCK = 100; - var MAX_SAME_IMAGES_IN_MASKS_BLOCK = 1000; - var fnArray = context.fnArray, - argsArray = context.argsArray; - var curr = context.iCurr; - var iFirstSave = curr - 3; - var iFirstTransform = curr - 2; - var iFirstPIMXO = curr - 1; - var count = Math.floor((i - iFirstSave) / 4); - count = handlePaintSolidColorImageMask(iFirstSave, count, fnArray, argsArray); - - if (count < MIN_IMAGES_IN_MASKS_BLOCK) { - return i - (i - iFirstSave) % 4; - } - - var q; - var isSameImage = false; - var iTransform, transformArgs; - var firstPIMXOArg0 = argsArray[iFirstPIMXO][0]; - const firstTransformArg0 = argsArray[iFirstTransform][0], - firstTransformArg1 = argsArray[iFirstTransform][1], - firstTransformArg2 = argsArray[iFirstTransform][2], - firstTransformArg3 = argsArray[iFirstTransform][3]; - - if (firstTransformArg1 === firstTransformArg2) { - isSameImage = true; - iTransform = iFirstTransform + 4; - var iPIMXO = iFirstPIMXO + 4; - - for (q = 1; q < count; q++, iTransform += 4, iPIMXO += 4) { - transformArgs = argsArray[iTransform]; - - if (argsArray[iPIMXO][0] !== firstPIMXOArg0 || transformArgs[0] !== firstTransformArg0 || transformArgs[1] !== firstTransformArg1 || transformArgs[2] !== firstTransformArg2 || transformArgs[3] !== firstTransformArg3) { - if (q < MIN_IMAGES_IN_MASKS_BLOCK) { - isSameImage = false; - } else { - count = q; - } - - break; - } - } - } - - if (isSameImage) { - count = Math.min(count, MAX_SAME_IMAGES_IN_MASKS_BLOCK); - var positions = new Float32Array(count * 2); - iTransform = iFirstTransform; - - for (q = 0; q < count; q++, iTransform += 4) { - transformArgs = argsArray[iTransform]; - positions[q << 1] = transformArgs[4]; - positions[(q << 1) + 1] = transformArgs[5]; - } - - fnArray.splice(iFirstSave, count * 4, _util.OPS.paintImageMaskXObjectRepeat); - argsArray.splice(iFirstSave, count * 4, [firstPIMXOArg0, firstTransformArg0, firstTransformArg1, firstTransformArg2, firstTransformArg3, positions]); - } else { - count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK); - var images = []; - - for (q = 0; q < count; q++) { - transformArgs = argsArray[iFirstTransform + (q << 2)]; - var maskParams = argsArray[iFirstPIMXO + (q << 2)][0]; - images.push({ - data: maskParams.data, - width: maskParams.width, - height: maskParams.height, - transform: transformArgs - }); - } - - fnArray.splice(iFirstSave, count * 4, _util.OPS.paintImageMaskXObjectGroup); - argsArray.splice(iFirstSave, count * 4, [images]); - } - - return iFirstSave + 1; - }); - addState(InitialState, [_util.OPS.save, _util.OPS.transform, _util.OPS.paintImageXObject, _util.OPS.restore], function (context) { - var argsArray = context.argsArray; - var iFirstTransform = context.iCurr - 2; - return argsArray[iFirstTransform][1] === 0 && argsArray[iFirstTransform][2] === 0; - }, function iterateImageGroup(context, i) { - var fnArray = context.fnArray, - argsArray = context.argsArray; - var iFirstSave = context.iCurr - 3; - var pos = (i - iFirstSave) % 4; - - switch (pos) { - case 0: - return fnArray[i] === _util.OPS.save; - - case 1: - if (fnArray[i] !== _util.OPS.transform) { - return false; - } - - var iFirstTransform = context.iCurr - 2; - var firstTransformArg0 = argsArray[iFirstTransform][0]; - var firstTransformArg3 = argsArray[iFirstTransform][3]; - - if (argsArray[i][0] !== firstTransformArg0 || argsArray[i][1] !== 0 || argsArray[i][2] !== 0 || argsArray[i][3] !== firstTransformArg3) { - return false; - } - - return true; - - case 2: - if (fnArray[i] !== _util.OPS.paintImageXObject) { - return false; - } - - var iFirstPIXO = context.iCurr - 1; - var firstPIXOArg0 = argsArray[iFirstPIXO][0]; - - if (argsArray[i][0] !== firstPIXOArg0) { - return false; - } - - return true; - - case 3: - return fnArray[i] === _util.OPS.restore; - } - - throw new Error(`iterateImageGroup - invalid pos: ${pos}`); - }, function (context, i) { - var MIN_IMAGES_IN_BLOCK = 3; - var MAX_IMAGES_IN_BLOCK = 1000; - var fnArray = context.fnArray, - argsArray = context.argsArray; - var curr = context.iCurr; - var iFirstSave = curr - 3; - var iFirstTransform = curr - 2; - var iFirstPIXO = curr - 1; - var firstPIXOArg0 = argsArray[iFirstPIXO][0]; - var firstTransformArg0 = argsArray[iFirstTransform][0]; - var firstTransformArg3 = argsArray[iFirstTransform][3]; - var count = Math.min(Math.floor((i - iFirstSave) / 4), MAX_IMAGES_IN_BLOCK); - - if (count < MIN_IMAGES_IN_BLOCK) { - return i - (i - iFirstSave) % 4; - } - - var positions = new Float32Array(count * 2); - var iTransform = iFirstTransform; - - for (var q = 0; q < count; q++, iTransform += 4) { - var transformArgs = argsArray[iTransform]; - positions[q << 1] = transformArgs[4]; - positions[(q << 1) + 1] = transformArgs[5]; - } - - var args = [firstPIXOArg0, firstTransformArg0, firstTransformArg3, positions]; - fnArray.splice(iFirstSave, count * 4, _util.OPS.paintImageXObjectRepeat); - argsArray.splice(iFirstSave, count * 4, args); - return iFirstSave + 1; - }); - addState(InitialState, [_util.OPS.beginText, _util.OPS.setFont, _util.OPS.setTextMatrix, _util.OPS.showText, _util.OPS.endText], null, function iterateShowTextGroup(context, i) { - var fnArray = context.fnArray, - argsArray = context.argsArray; - var iFirstSave = context.iCurr - 4; - var pos = (i - iFirstSave) % 5; - - switch (pos) { - case 0: - return fnArray[i] === _util.OPS.beginText; - - case 1: - return fnArray[i] === _util.OPS.setFont; - - case 2: - return fnArray[i] === _util.OPS.setTextMatrix; - - case 3: - if (fnArray[i] !== _util.OPS.showText) { - return false; - } - - var iFirstSetFont = context.iCurr - 3; - var firstSetFontArg0 = argsArray[iFirstSetFont][0]; - var firstSetFontArg1 = argsArray[iFirstSetFont][1]; - - if (argsArray[i][0] !== firstSetFontArg0 || argsArray[i][1] !== firstSetFontArg1) { - return false; - } - - return true; - - case 4: - return fnArray[i] === _util.OPS.endText; - } - - throw new Error(`iterateShowTextGroup - invalid pos: ${pos}`); - }, function (context, i) { - var MIN_CHARS_IN_BLOCK = 3; - var MAX_CHARS_IN_BLOCK = 1000; - var fnArray = context.fnArray, - argsArray = context.argsArray; - var curr = context.iCurr; - var iFirstBeginText = curr - 4; - var iFirstSetFont = curr - 3; - var iFirstSetTextMatrix = curr - 2; - var iFirstShowText = curr - 1; - var iFirstEndText = curr; - var firstSetFontArg0 = argsArray[iFirstSetFont][0]; - var firstSetFontArg1 = argsArray[iFirstSetFont][1]; - var count = Math.min(Math.floor((i - iFirstBeginText) / 5), MAX_CHARS_IN_BLOCK); - - if (count < MIN_CHARS_IN_BLOCK) { - return i - (i - iFirstBeginText) % 5; - } - - var iFirst = iFirstBeginText; - - if (iFirstBeginText >= 4 && fnArray[iFirstBeginText - 4] === fnArray[iFirstSetFont] && fnArray[iFirstBeginText - 3] === fnArray[iFirstSetTextMatrix] && fnArray[iFirstBeginText - 2] === fnArray[iFirstShowText] && fnArray[iFirstBeginText - 1] === fnArray[iFirstEndText] && argsArray[iFirstBeginText - 4][0] === firstSetFontArg0 && argsArray[iFirstBeginText - 4][1] === firstSetFontArg1) { - count++; - iFirst -= 5; - } - - var iEndText = iFirst + 4; - - for (var q = 1; q < count; q++) { - fnArray.splice(iEndText, 3); - argsArray.splice(iEndText, 3); - iEndText += 2; - } - - return iEndText + 1; - }); - - function QueueOptimizer(queue) { - this.queue = queue; - this.state = null; - this.context = { - iCurr: 0, - fnArray: queue.fnArray, - argsArray: queue.argsArray - }; - this.match = null; - this.lastProcessed = 0; - } - - QueueOptimizer.prototype = { - _optimize() { - const fnArray = this.queue.fnArray; - let i = this.lastProcessed, - ii = fnArray.length; - let state = this.state; - let match = this.match; - - if (!state && !match && i + 1 === ii && !InitialState[fnArray[i]]) { - this.lastProcessed = ii; - return; - } - - const context = this.context; - - while (i < ii) { - if (match) { - const iterate = (0, match.iterateFn)(context, i); - - if (iterate) { - i++; - continue; - } - - i = (0, match.processFn)(context, i + 1); - ii = fnArray.length; - match = null; - state = null; - - if (i >= ii) { - break; - } - } - - state = (state || InitialState)[fnArray[i]]; - - if (!state || Array.isArray(state)) { - i++; - continue; - } - - context.iCurr = i; - i++; - - if (state.checkFn && !(0, state.checkFn)(context)) { - state = null; - continue; - } - - match = state; - state = null; - } - - this.state = state; - this.match = match; - this.lastProcessed = i; - }, - - push(fn, args) { - this.queue.fnArray.push(fn); - this.queue.argsArray.push(args); - - this._optimize(); - }, - - flush() { - while (this.match) { - const length = this.queue.fnArray.length; - this.lastProcessed = (0, this.match.processFn)(this.context, length); - this.match = null; - this.state = null; - - this._optimize(); - } - }, - - reset() { - this.state = null; - this.match = null; - this.lastProcessed = 0; - } - - }; - return QueueOptimizer; -}(); - -var NullOptimizer = function NullOptimizerClosure() { - function NullOptimizer(queue) { - this.queue = queue; - } - - NullOptimizer.prototype = { - push(fn, args) { - this.queue.fnArray.push(fn); - this.queue.argsArray.push(args); - }, - - flush() {}, - - reset() {} - - }; - return NullOptimizer; -}(); - -var OperatorList = function OperatorListClosure() { - var CHUNK_SIZE = 1000; - var CHUNK_SIZE_ABOUT = CHUNK_SIZE - 5; - - function OperatorList(intent, streamSink) { - this._streamSink = streamSink; - this.fnArray = []; - this.argsArray = []; - - if (streamSink && intent !== "oplist") { - this.optimizer = new QueueOptimizer(this); - } else { - this.optimizer = new NullOptimizer(this); - } - - this.dependencies = new Set(); - this._totalLength = 0; - this.weight = 0; - this._resolved = streamSink ? null : Promise.resolve(); - } - - OperatorList.prototype = { - get length() { - return this.argsArray.length; - }, - - get ready() { - return this._resolved || this._streamSink.ready; - }, - - get totalLength() { - return this._totalLength + this.length; - }, - - addOp(fn, args) { - this.optimizer.push(fn, args); - this.weight++; - - if (this._streamSink) { - if (this.weight >= CHUNK_SIZE) { - this.flush(); - } else if (this.weight >= CHUNK_SIZE_ABOUT && (fn === _util.OPS.restore || fn === _util.OPS.endText)) { - this.flush(); - } - } - }, - - addDependency(dependency) { - if (this.dependencies.has(dependency)) { - return; - } - - this.dependencies.add(dependency); - this.addOp(_util.OPS.dependency, [dependency]); - }, - - addDependencies(dependencies) { - for (const dependency of dependencies) { - this.addDependency(dependency); - } - }, - - addOpList(opList) { - if (!(opList instanceof OperatorList)) { - (0, _util.warn)('addOpList - ignoring invalid "opList" parameter.'); - return; - } - - for (const dependency of opList.dependencies) { - this.dependencies.add(dependency); - } - - for (var i = 0, ii = opList.length; i < ii; i++) { - this.addOp(opList.fnArray[i], opList.argsArray[i]); - } - }, - - getIR() { - return { - fnArray: this.fnArray, - argsArray: this.argsArray, - length: this.length - }; - }, - - get _transfers() { - const transfers = []; - const { - fnArray, - argsArray, - length - } = this; - - for (let i = 0; i < length; i++) { - switch (fnArray[i]) { - case _util.OPS.paintInlineImageXObject: - case _util.OPS.paintInlineImageXObjectGroup: - case _util.OPS.paintImageMaskXObject: - const arg = argsArray[i][0]; - ; - - if (!arg.cached) { - transfers.push(arg.data.buffer); - } - - break; - } - } - - return transfers; - }, - - flush(lastChunk = false) { - this.optimizer.flush(); - const length = this.length; - this._totalLength += length; - - this._streamSink.enqueue({ - fnArray: this.fnArray, - argsArray: this.argsArray, - lastChunk, - length - }, 1, this._transfers); - - this.dependencies.clear(); - this.fnArray.length = 0; - this.argsArray.length = 0; - this.weight = 0; - this.optimizer.reset(); - } - - }; - return OperatorList; -}(); - -exports.OperatorList = OperatorList; - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.writeDict = writeDict; -exports.incrementalUpdate = incrementalUpdate; - -var _util = __w_pdfjs_require__(2); - -var _primitives = __w_pdfjs_require__(5); - -var _crypto = __w_pdfjs_require__(22); - -function writeDict(dict, buffer, transform) { - buffer.push("<<"); - - for (const key of dict.getKeys()) { - buffer.push(` /${key} `); - writeValue(dict.getRaw(key), buffer, transform); - } - - buffer.push(">>"); -} - -function writeStream(stream, buffer, transform) { - writeDict(stream.dict, buffer, transform); - buffer.push(" stream\n"); - let string = (0, _util.bytesToString)(stream.getBytes()); - - if (transform !== null) { - string = transform.encryptString(string); - } - - buffer.push(string); - buffer.push("\nendstream\n"); -} - -function writeArray(array, buffer, transform) { - buffer.push("["); - let first = true; - - for (const val of array) { - if (!first) { - buffer.push(" "); - } else { - first = false; - } - - writeValue(val, buffer, transform); - } - - buffer.push("]"); -} - -function numberToString(value) { - if (Number.isInteger(value)) { - return value.toString(); - } - - const roundedValue = Math.round(value * 100); - - if (roundedValue % 100 === 0) { - return (roundedValue / 100).toString(); - } - - if (roundedValue % 10 === 0) { - return value.toFixed(1); - } - - return value.toFixed(2); -} - -function writeValue(value, buffer, transform) { - if ((0, _primitives.isName)(value)) { - buffer.push(`/${value.name}`); - } else if ((0, _primitives.isRef)(value)) { - buffer.push(`${value.num} ${value.gen} R`); - } else if (Array.isArray(value)) { - writeArray(value, buffer, transform); - } else if (typeof value === "string") { - if (transform !== null) { - value = transform.encryptString(value); - } - - buffer.push(`(${(0, _util.escapeString)(value)})`); - } else if (typeof value === "number") { - buffer.push(numberToString(value)); - } else if ((0, _primitives.isDict)(value)) { - writeDict(value, buffer, transform); - } else if ((0, _primitives.isStream)(value)) { - writeStream(value, buffer, transform); - } -} - -function writeInt(number, size, offset, buffer) { - for (let i = size + offset - 1; i > offset - 1; i--) { - buffer[i] = number & 0xff; - number >>= 8; - } - - return offset + size; -} - -function writeString(string, offset, buffer) { - for (let i = 0, len = string.length; i < len; i++) { - buffer[offset + i] = string.charCodeAt(i) & 0xff; - } -} - -function computeMD5(filesize, xrefInfo) { - const time = Math.floor(Date.now() / 1000); - const filename = xrefInfo.filename || ""; - const md5Buffer = [time.toString(), filename, filesize.toString()]; - let md5BufferLen = md5Buffer.reduce((a, str) => a + str.length, 0); - - for (const value of Object.values(xrefInfo.info)) { - md5Buffer.push(value); - md5BufferLen += value.length; - } - - const array = new Uint8Array(md5BufferLen); - let offset = 0; - - for (const str of md5Buffer) { - writeString(str, offset, array); - offset += str.length; - } - - return (0, _util.bytesToString)((0, _crypto.calculateMD5)(array)); -} - -function incrementalUpdate(originalData, xrefInfo, newRefs) { - const newXref = new _primitives.Dict(null); - const refForXrefTable = xrefInfo.newRef; - let buffer, baseOffset; - const lastByte = originalData[originalData.length - 1]; - - if (lastByte === 0x0a || lastByte === 0x0d) { - buffer = []; - baseOffset = originalData.length; - } else { - buffer = ["\n"]; - baseOffset = originalData.length + 1; - } - - newXref.set("Size", refForXrefTable.num + 1); - newXref.set("Prev", xrefInfo.startXRef); - newXref.set("Type", _primitives.Name.get("XRef")); - - if (xrefInfo.rootRef !== null) { - newXref.set("Root", xrefInfo.rootRef); - } - - if (xrefInfo.infoRef !== null) { - newXref.set("Info", xrefInfo.infoRef); - } - - if (xrefInfo.encrypt !== null) { - newXref.set("Encrypt", xrefInfo.encrypt); - } - - newRefs.push({ - ref: refForXrefTable, - data: "" - }); - newRefs = newRefs.sort((a, b) => { - return a.ref.num - b.ref.num; - }); - const xrefTableData = [[0, 1, 0xffff]]; - const indexes = [0, 1]; - let maxOffset = 0; - - for (const { - ref, - data - } of newRefs) { - maxOffset = Math.max(maxOffset, baseOffset); - xrefTableData.push([1, baseOffset, Math.min(ref.gen, 0xffff)]); - baseOffset += data.length; - indexes.push(ref.num); - indexes.push(1); - buffer.push(data); - } - - newXref.set("Index", indexes); - - if (xrefInfo.fileIds.length !== 0) { - const md5 = computeMD5(baseOffset, xrefInfo); - newXref.set("ID", [xrefInfo.fileIds[0], md5]); - } - - const offsetSize = Math.ceil(Math.log2(maxOffset) / 8); - const sizes = [1, offsetSize, 2]; - const structSize = sizes[0] + sizes[1] + sizes[2]; - const tableLength = structSize * xrefTableData.length; - newXref.set("W", sizes); - newXref.set("Length", tableLength); - buffer.push(`${refForXrefTable.num} ${refForXrefTable.gen} obj\n`); - writeDict(newXref, buffer, null); - buffer.push(" stream\n"); - const bufferLen = buffer.reduce((a, str) => a + str.length, 0); - const footer = `\nendstream\nendobj\nstartxref\n${baseOffset}\n%%EOF\n`; - const array = new Uint8Array(originalData.length + bufferLen + tableLength + footer.length); - array.set(originalData); - let offset = originalData.length; - - for (const str of buffer) { - writeString(str, offset, array); - offset += str.length; - } - - for (const [type, objOffset, gen] of xrefTableData) { - offset = writeInt(type, sizes[0], offset, array); - offset = writeInt(objOffset, sizes[1], offset, array); - offset = writeInt(gen, sizes[2], offset, array); - } - - writeString(footer, offset, array); - return array; -} - -/***/ }), -/* 28 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.PartialEvaluator = void 0; - -var _util = __w_pdfjs_require__(2); - -var _cmap = __w_pdfjs_require__(29); - -var _primitives = __w_pdfjs_require__(5); - -var _fonts = __w_pdfjs_require__(30); - -var _encodings = __w_pdfjs_require__(33); - -var _core_utils = __w_pdfjs_require__(8); - -var _unicode = __w_pdfjs_require__(36); - -var _standard_fonts = __w_pdfjs_require__(35); - -var _pattern = __w_pdfjs_require__(39); - -var _function = __w_pdfjs_require__(40); - -var _parser = __w_pdfjs_require__(11); - -var _image_utils = __w_pdfjs_require__(24); - -var _bidi = __w_pdfjs_require__(42); - -var _colorspace = __w_pdfjs_require__(23); - -var _stream = __w_pdfjs_require__(12); - -var _glyphlist = __w_pdfjs_require__(34); - -var _metrics = __w_pdfjs_require__(43); - -var _murmurhash = __w_pdfjs_require__(44); - -var _operator_list = __w_pdfjs_require__(26); - -var _image = __w_pdfjs_require__(45); +var _image = __w_pdfjs_require__(63); const DefaultPartialEvaluatorOptions = Object.freeze({ maxImageSize: -1, disableFontFace: false, ignoreErrors: false, isEvalSupported: true, - fontExtraProperties: false + fontExtraProperties: false, + useSystemFonts: true, + cMapUrl: null, + standardFontDataUrl: null }); const PatternType = { TILING: 1, SHADING: 2 }; +const TEXT_CHUNK_BATCH_SIZE = 10; const deferred = Promise.resolve(); function normalizeBlendMode(value, parsingArray = false) { @@ -21511,7 +9934,7 @@ function normalizeBlendMode(value, parsingArray = false) { return "source-over"; } - if (!(0, _primitives.isName)(value)) { + if (!(value instanceof _primitives.Name)) { if (parsingArray) { return null; } @@ -21578,6 +10001,12 @@ function normalizeBlendMode(value, parsingArray = false) { return "source-over"; } +function incrementCachedImageMaskCount(data) { + if (data.fn === _util.OPS.paintImageMaskXObject && data.args[0] && data.args[0].count > 0) { + data.args[0].count++; + } +} + class TimeSlotManager { static get TIME_SLOT_DURATION_MS() { return (0, _util.shadow)(this, "TIME_SLOT_DURATION_MS", 20); @@ -21615,6 +10044,7 @@ class PartialEvaluator { idFactory, fontCache, builtInCMapCache, + standardFontDataCache, globalImageCache, options = null }) { @@ -21624,6 +10054,7 @@ class PartialEvaluator { this.idFactory = idFactory; this.fontCache = fontCache; this.builtInCMapCache = builtInCMapCache; + this.standardFontDataCache = standardFontDataCache; this.globalImageCache = globalImageCache; this.options = options || DefaultPartialEvaluatorOptions; this.parsingType3Font = false; @@ -21638,29 +10069,33 @@ class PartialEvaluator { return (0, _util.shadow)(this, "_pdfFunctionFactory", pdfFunctionFactory); } - clone(newOptions = DefaultPartialEvaluatorOptions) { - var newEvaluator = Object.create(this); - newEvaluator.options = newOptions; + clone(newOptions = null) { + const newEvaluator = Object.create(this); + newEvaluator.options = Object.assign(Object.create(null), this.options, newOptions); return newEvaluator; } - hasBlendModes(resources) { + hasBlendModes(resources, nonBlendModesSet) { if (!(resources instanceof _primitives.Dict)) { return false; } - const processed = new _primitives.RefSet(); + if (resources.objId && nonBlendModesSet.has(resources.objId)) { + return false; + } + + const processed = new _primitives.RefSet(nonBlendModesSet); if (resources.objId) { processed.put(resources.objId); } - var nodes = [resources], - xref = this.xref; + const nodes = [resources], + xref = this.xref; while (nodes.length) { - var node = nodes.shift(); - var graphicStates = node.get("ExtGState"); + const node = nodes.shift(); + const graphicStates = node.get("ExtGState"); if (graphicStates instanceof _primitives.Dict) { for (let graphicState of graphicStates.getRawValues()) { @@ -21672,10 +10107,6 @@ class PartialEvaluator { try { graphicState = xref.fetch(graphicState); } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - processed.put(graphicState); (0, _util.info)(`hasBlendModes - ignoring ExtGState: "${ex}".`); continue; @@ -21710,7 +10141,7 @@ class PartialEvaluator { } } - var xObjects = node.get("XObject"); + const xObjects = node.get("XObject"); if (!(xObjects instanceof _primitives.Dict)) { continue; @@ -21725,17 +10156,13 @@ class PartialEvaluator { try { xObject = xref.fetch(xObject); } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - processed.put(xObject); (0, _util.info)(`hasBlendModes - ignoring XObject: "${ex}".`); continue; } } - if (!(0, _primitives.isStream)(xObject)) { + if (!(xObject instanceof _base_stream.BaseStream)) { continue; } @@ -21743,7 +10170,7 @@ class PartialEvaluator { processed.put(xObject.dict.objId); } - var xResources = xObject.dict.get("Resources"); + const xResources = xObject.dict.get("Resources"); if (!(xResources instanceof _primitives.Dict)) { continue; @@ -21761,6 +10188,10 @@ class PartialEvaluator { } } + for (const ref of processed) { + nonBlendModesSet.put(ref); + } + return false; } @@ -21771,27 +10202,25 @@ class PartialEvaluator { return cachedData; } - const readableStream = this.handler.sendWithStream("FetchBuiltInCMap", { - name - }); - const reader = readableStream.getReader(); - const data = await new Promise(function (resolve, reject) { - function pump() { - reader.read().then(function ({ - value, - done - }) { - if (done) { - return; - } + let data; - resolve(value); - pump(); - }, reject); + if (this.options.cMapUrl !== null) { + const url = `${this.options.cMapUrl}${name}.bcmap`; + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`fetchBuiltInCMap: failed to fetch file "${url}" with "${response.statusText}".`); } - pump(); - }); + data = { + cMapData: new Uint8Array(await response.arrayBuffer()), + compressionType: _util.CMapCompressionType.BINARY + }; + } else { + data = await this.handler.sendWithPromise("FetchBuiltInCMap", { + name + }); + } if (data.compressionType !== _util.CMapCompressionType.NONE) { this.builtInCMapCache.set(name, data); @@ -21800,10 +10229,52 @@ class PartialEvaluator { return data; } + async fetchStandardFontData(name) { + const cachedData = this.standardFontDataCache.get(name); + + if (cachedData) { + return new _stream.Stream(cachedData); + } + + if (this.options.useSystemFonts && name !== "Symbol" && name !== "ZapfDingbats") { + return null; + } + + const standardFontNameToFileName = (0, _standard_fonts.getFontNameToFileMap)(), + filename = standardFontNameToFileName[name]; + let data; + + if (this.options.standardFontDataUrl !== null) { + const url = `${this.options.standardFontDataUrl}${filename}`; + const response = await fetch(url); + + if (!response.ok) { + (0, _util.warn)(`fetchStandardFontData: failed to fetch file "${url}" with "${response.statusText}".`); + } else { + data = await response.arrayBuffer(); + } + } else { + try { + data = await this.handler.sendWithPromise("FetchStandardFontData", { + filename + }); + } catch (e) { + (0, _util.warn)(`fetchStandardFontData: failed to fetch file "${filename}" with "${e}".`); + } + } + + if (!data) { + return null; + } + + this.standardFontDataCache.set(name, data); + return new _stream.Stream(data); + } + async buildFormXObject(resources, xobj, smask, operatorList, task, initialState, localColorSpaceCache) { - var dict = xobj.dict; - var matrix = dict.getArray("Matrix"); - var bbox = dict.getArray("BBox"); + const dict = xobj.dict; + const matrix = dict.getArray("Matrix"); + let bbox = dict.getArray("BBox"); if (Array.isArray(bbox) && bbox.length === 4) { bbox = _util.Util.normalizeRect(bbox); @@ -21811,25 +10282,28 @@ class PartialEvaluator { bbox = null; } - let optionalContent = null; + let optionalContent, groupOptions; if (dict.has("OC")) { optionalContent = await this.parseMarkedContentProps(dict.get("OC"), resources); + } + + if (optionalContent !== undefined) { operatorList.addOp(_util.OPS.beginMarkedContentProps, ["OC", optionalContent]); } - var group = dict.get("Group"); + const group = dict.get("Group"); if (group) { - var groupOptions = { + groupOptions = { matrix, bbox, smask, isolated: false, knockout: false }; - var groupSubtype = group.get("S"); - var colorSpace = null; + const groupSubtype = group.get("S"); + let colorSpace = null; if ((0, _primitives.isName)(groupSubtype, "Transparency")) { groupOptions.isolated = group.get("I") || false; @@ -21860,7 +10334,8 @@ class PartialEvaluator { operatorList.addOp(_util.OPS.beginGroup, [groupOptions]); } - operatorList.addOp(_util.OPS.paintFormXObjectBegin, [matrix, bbox]); + const args = group ? [matrix, null] : [matrix, bbox]; + operatorList.addOp(_util.OPS.paintFormXObjectBegin, args); return this.getOperatorList({ stream: xobj, task, @@ -21874,14 +10349,14 @@ class PartialEvaluator { operatorList.addOp(_util.OPS.endGroup, [groupOptions]); } - if (optionalContent) { + if (optionalContent !== undefined) { operatorList.addOp(_util.OPS.endMarkedContent, []); } }); } _sendImgData(objId, imgData, cacheGlobally = false) { - const transfers = imgData ? [imgData.data.buffer] : null; + const transfers = imgData ? [imgData.bitmap || imgData.data.buffer] : null; if (this.parsingType3Font || cacheGlobally) { return this.handler.send("commonobj", [objId, "Image", imgData], transfers); @@ -21899,56 +10374,119 @@ class PartialEvaluator { localImageCache, localColorSpaceCache }) { - var dict = image.dict; + const dict = image.dict; const imageRef = dict.objId; - var w = dict.get("Width", "W"); - var h = dict.get("Height", "H"); + const w = dict.get("W", "Width"); + const h = dict.get("H", "Height"); - if (!(w && (0, _util.isNum)(w)) || !(h && (0, _util.isNum)(h))) { + if (!(w && typeof w === "number") || !(h && typeof h === "number")) { (0, _util.warn)("Image dimensions are missing, or not numbers."); - return undefined; + return; } - var maxImageSize = this.options.maxImageSize; + const maxImageSize = this.options.maxImageSize; if (maxImageSize !== -1 && w * h > maxImageSize) { - (0, _util.warn)("Image exceeded maximum allowed size and was removed."); - return undefined; + const msg = "Image exceeded maximum allowed size and was removed."; + + if (this.options.ignoreErrors) { + (0, _util.warn)(msg); + return; + } + + throw new Error(msg); } - var imageMask = dict.get("ImageMask", "IM") || false; - var imgData, args; + let optionalContent; + + if (dict.has("OC")) { + optionalContent = await this.parseMarkedContentProps(dict.get("OC"), resources); + } + + const imageMask = dict.get("IM", "ImageMask") || false; + let imgData, args; if (imageMask) { - var width = dict.get("Width", "W"); - var height = dict.get("Height", "H"); - var bitStrideLength = width + 7 >> 3; - var imgArray = image.getBytes(bitStrideLength * height, true); - var decode = dict.getArray("Decode", "D"); + const interpolate = dict.get("I", "Interpolate"); + const bitStrideLength = w + 7 >> 3; + const imgArray = image.getBytes(bitStrideLength * h); + const decode = dict.getArray("D", "Decode"); + + if (this.parsingType3Font) { + imgData = _image.PDFImage.createRawMask({ + imgArray, + width: w, + height: h, + imageIsFromDecodeStream: image instanceof _decode_stream.DecodeStream, + inverseDecode: !!decode && decode[0] > 0, + interpolate + }); + imgData.cached = !!cacheKey; + args = [imgData]; + operatorList.addImageOps(_util.OPS.paintImageMaskXObject, args, optionalContent); + + if (cacheKey) { + localImageCache.set(cacheKey, imageRef, { + fn: _util.OPS.paintImageMaskXObject, + args, + optionalContent + }); + } + + return; + } + imgData = _image.PDFImage.createMask({ imgArray, - width, - height, - imageIsFromDecodeStream: image instanceof _stream.DecodeStream, - inverseDecode: !!decode && decode[0] > 0 + width: w, + height: h, + imageIsFromDecodeStream: image instanceof _decode_stream.DecodeStream, + inverseDecode: !!decode && decode[0] > 0, + interpolate }); - imgData.cached = !!cacheKey; - args = [imgData]; - operatorList.addOp(_util.OPS.paintImageMaskXObject, args); + + if (imgData.isSingleOpaquePixel) { + operatorList.addImageOps(_util.OPS.paintSolidColorImageMask, [], optionalContent); + + if (cacheKey) { + localImageCache.set(cacheKey, imageRef, { + fn: _util.OPS.paintSolidColorImageMask, + args: [], + optionalContent + }); + } + + return; + } + + const objId = `mask_${this.idFactory.createObjId()}`; + operatorList.addDependency(objId); + + this._sendImgData(objId, imgData); + + args = [{ + data: objId, + width: imgData.width, + height: imgData.height, + interpolate: imgData.interpolate, + count: 1 + }]; + operatorList.addImageOps(_util.OPS.paintImageMaskXObject, args, optionalContent); if (cacheKey) { localImageCache.set(cacheKey, imageRef, { fn: _util.OPS.paintImageMaskXObject, - args + args, + optionalContent }); } - return undefined; + return; } - var softMask = dict.get("SMask", "SM") || false; - var mask = dict.get("Mask") || false; - var SMALL_IMAGE_DIMENSIONS = 200; + const softMask = dict.get("SM", "SMask") || false; + const mask = dict.get("Mask") || false; + const SMALL_IMAGE_DIMENSIONS = 200; if (isInline && !softMask && !mask && w + h < SMALL_IMAGE_DIMENSIONS) { const imageObj = new _image.PDFImage({ @@ -21960,8 +10498,8 @@ class PartialEvaluator { localColorSpaceCache }); imgData = imageObj.createImageData(true); - operatorList.addOp(_util.OPS.paintInlineImageXObject, [imgData]); - return undefined; + operatorList.addImageOps(_util.OPS.paintInlineImageXObject, [imgData], optionalContent); + return; } let objId = `img_${this.idFactory.createObjId()}`, @@ -21989,18 +10527,24 @@ class PartialEvaluator { localColorSpaceCache }).then(imageObj => { imgData = imageObj.createImageData(false); + + if (cacheKey && imageRef && cacheGlobally) { + this.globalImageCache.addByteSize(imageRef, imgData.data.length); + } + return this._sendImgData(objId, imgData, cacheGlobally); }).catch(reason => { (0, _util.warn)(`Unable to decode image "${objId}": "${reason}".`); return this._sendImgData(objId, null, cacheGlobally); }); - operatorList.addOp(_util.OPS.paintImageXObject, args); + operatorList.addImageOps(_util.OPS.paintImageXObject, args, optionalContent); if (cacheKey) { localImageCache.set(cacheKey, imageRef, { fn: _util.OPS.paintImageXObject, - args + args, + optionalContent }); if (imageRef) { @@ -22011,30 +10555,30 @@ class PartialEvaluator { this.globalImageCache.setData(imageRef, { objId, fn: _util.OPS.paintImageXObject, - args + args, + optionalContent, + byteSize: 0 }); } } } - - return undefined; } handleSMask(smask, resources, operatorList, task, stateManager, localColorSpaceCache) { - var smaskContent = smask.get("G"); - var smaskOptions = { + const smaskContent = smask.get("G"); + const smaskOptions = { subtype: smask.get("S").name, backdrop: smask.get("BC") }; - var transferObj = smask.get("TR"); + const transferObj = smask.get("TR"); if ((0, _function.isPDFFunction)(transferObj)) { const transferFn = this._pdfFunctionFactory.create(transferObj); - var transferMap = new Uint8Array(256); - var tmp = new Float32Array(1); + const transferMap = new Uint8Array(256); + const tmp = new Float32Array(1); - for (var i = 0; i < 256; i++) { + for (let i = 0; i < 256; i++) { tmp[0] = i / 255; transferFn(tmp, 0, tmp, 0); transferMap[i] = tmp[0] * 255 | 0; @@ -22098,7 +10642,7 @@ class PartialEvaluator { return transferMaps; } - handleTilingType(fn, args, resources, pattern, patternDict, operatorList, task) { + handleTilingType(fn, color, resources, pattern, patternDict, operatorList, task, localTilingPatternCache) { const tilingOpList = new _operator_list.OperatorList(); const patternResources = _primitives.Dict.merge({ @@ -22112,14 +10656,18 @@ class PartialEvaluator { resources: patternResources, operatorList: tilingOpList }).then(function () { - return (0, _pattern.getTilingPatternIR)({ - fnArray: tilingOpList.fnArray, - argsArray: tilingOpList.argsArray - }, patternDict, args); - }).then(function (tilingPatternIR) { + const operatorListIR = tilingOpList.getIR(); + const tilingPatternIR = (0, _pattern.getTilingPatternIR)(operatorListIR, patternDict, color); operatorList.addDependencies(tilingOpList.dependencies); operatorList.addOp(fn, tilingPatternIR); - }, reason => { + + if (patternDict.objId) { + localTilingPatternCache.set(null, patternDict.objId, { + operatorListIR, + dict: patternDict + }); + } + }).catch(reason => { if (reason instanceof _util.AbortException) { return; } @@ -22136,17 +10684,9 @@ class PartialEvaluator { }); } - handleSetFont(resources, fontArgs, fontRef, operatorList, task, state) { - var fontName, - fontSize = 0; - - if (fontArgs) { - fontArgs = fontArgs.slice(); - fontName = fontArgs[0].name; - fontSize = fontArgs[1]; - } - - return this.loadFont(fontName, fontRef, resources).then(translated => { + handleSetFont(resources, fontArgs, fontRef, operatorList, task, state, fallbackFontDict = null, cssFontInfo = null) { + const fontName = fontArgs && fontArgs[0] instanceof _primitives.Name ? fontArgs[0].name : null; + return this.loadFont(fontName, fontRef, resources, fallbackFontDict, cssFontInfo).then(translated => { if (!translated.font.isType3Font) { return translated; } @@ -22162,13 +10702,11 @@ class PartialEvaluator { loadedName: "g_font_error", font: new _fonts.ErrorFont(`Type3 font load error: ${reason}`), dict: translated.font, - extraProperties: this.options.fontExtraProperties + evaluatorOptions: this.options }); }); }).then(translated => { state.font = translated.font; - state.fontSize = fontSize; - state.fontName = fontName; translated.send(this.handler); return translated.loadedName; }); @@ -22182,7 +10720,7 @@ class PartialEvaluator { const isAddToPathSet = !!(state.textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG); if (isAddToPathSet || state.fillColorSpace.name === "Pattern" || font.disableFontFace || this.options.disableFontFace) { - PartialEvaluator.buildFontPaths(font, glyphs, this.handler); + PartialEvaluator.buildFontPaths(font, glyphs, this.handler, this.options); } } @@ -22219,11 +10757,11 @@ class PartialEvaluator { }) { const gStateRef = gState.objId; let isSimpleGState = true; - var gStateObj = []; - var gStateKeys = gState.getKeys(); - var promise = Promise.resolve(); + const gStateObj = []; + const gStateKeys = gState.getKeys(); + let promise = Promise.resolve(); - for (var i = 0, ii = gStateKeys.length; i < ii; i++) { + for (let i = 0, ii = gStateKeys.length; i < ii; i++) { const key = gStateKeys[i]; const value = gState.get(key); @@ -22263,7 +10801,7 @@ class PartialEvaluator { break; } - if ((0, _primitives.isDict)(value)) { + if (value instanceof _primitives.Dict) { isSimpleGState = false; promise = promise.then(() => { return this.handleSMask(value, resources, operatorList, task, stateManager, localColorSpaceCache); @@ -22313,27 +10851,25 @@ class PartialEvaluator { }); } - loadFont(fontName, font, resources) { - const errorFont = () => { - return Promise.resolve(new TranslatedFont({ + loadFont(fontName, font, resources, fallbackFontDict = null, cssFontInfo = null) { + const errorFont = async () => { + return new TranslatedFont({ loadedName: "g_font_error", font: new _fonts.ErrorFont(`Font "${fontName}" is not available.`), dict: font, - extraProperties: this.options.fontExtraProperties - })); + evaluatorOptions: this.options + }); }; - var fontRef, - xref = this.xref; + const xref = this.xref; + let fontRef; if (font) { - if (!(0, _primitives.isRef)(font)) { - throw new _util.FormatError('The "font" object should be a reference.'); + if (font instanceof _primitives.Ref) { + fontRef = font; } - - fontRef = font; } else { - var fontRes = resources.get("Font"); + const fontRes = resources.get("Font"); if (fontRes) { fontRef = fontRes.getRaw(fontName); @@ -22352,7 +10888,16 @@ class PartialEvaluator { featureId: _util.UNSUPPORTED_FEATURES.errorFontMissing }); (0, _util.warn)(`${partialMsg} -- attempting to fallback to a default font.`); - fontRef = PartialEvaluator.fallbackFontDict; + + if (fallbackFontDict) { + fontRef = fallbackFontDict; + } else { + fontRef = PartialEvaluator.fallbackFontDict; + } + } + + if (this.parsingType3Font && this.type3FontRefs.has(fontRef)) { + return errorFont(); } if (this.fontCache.has(fontRef)) { @@ -22361,36 +10906,45 @@ class PartialEvaluator { font = xref.fetchIfRef(fontRef); - if (!(0, _primitives.isDict)(font)) { + if (!(font instanceof _primitives.Dict)) { return errorFont(); } - if (font.translated) { - return font.translated; + if (font.cacheKey && this.fontCache.has(font.cacheKey)) { + return this.fontCache.get(font.cacheKey); + } + + const fontCapability = (0, _util.createPromiseCapability)(); + let preEvaluatedFont; + + try { + preEvaluatedFont = this.preEvaluateFont(font); + preEvaluatedFont.cssFontInfo = cssFontInfo; + } catch (reason) { + (0, _util.warn)(`loadFont - preEvaluateFont failed: "${reason}".`); + return errorFont(); } - var fontCapability = (0, _util.createPromiseCapability)(); - var preEvaluatedFont = this.preEvaluateFont(font); const { descriptor, hash } = preEvaluatedFont; - var fontRefIsRef = (0, _primitives.isRef)(fontRef), - fontID; + const fontRefIsRef = fontRef instanceof _primitives.Ref; + let fontID; if (fontRefIsRef) { fontID = `f${fontRef.toString()}`; } - if (hash && (0, _primitives.isDict)(descriptor)) { + if (hash && descriptor instanceof _primitives.Dict) { if (!descriptor.fontAliases) { descriptor.fontAliases = Object.create(null); } - var fontAliases = descriptor.fontAliases; + const fontAliases = descriptor.fontAliases; if (fontAliases[hash]) { - var aliasFontRef = fontAliases[hash].aliasRef; + const aliasFontRef = fontAliases[hash].aliasRef; if (fontRefIsRef && aliasFontRef && this.fontCache.has(aliasFontRef)) { this.fontCache.putAlias(fontRef, aliasFontRef); @@ -22416,77 +10970,92 @@ class PartialEvaluator { fontID = this.idFactory.createFontId(); } - this.fontCache.put(`id_${fontID}`, fontCapability.promise); + font.cacheKey = `cacheKey_${fontID}`; + this.fontCache.put(font.cacheKey, fontCapability.promise); } (0, _util.assert)(fontID && fontID.startsWith("f"), 'The "fontID" must be (correctly) defined.'); font.loadedName = `${this.idFactory.getDocId()}_${fontID}`; - font.translated = fontCapability.promise; - var translatedPromise; - - try { - translatedPromise = this.translateFont(preEvaluatedFont); - } catch (e) { - translatedPromise = Promise.reject(e); - } - - translatedPromise.then(translatedFont => { + this.translateFont(preEvaluatedFont).then(translatedFont => { if (translatedFont.fontType !== undefined) { - var xrefFontStats = xref.stats.fontTypes; - xrefFontStats[translatedFont.fontType] = true; + xref.stats.addFontType(translatedFont.fontType); } fontCapability.resolve(new TranslatedFont({ loadedName: font.loadedName, font: translatedFont, dict: font, - extraProperties: this.options.fontExtraProperties + evaluatorOptions: this.options })); }).catch(reason => { this.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorFontTranslate }); + (0, _util.warn)(`loadFont - translateFont failed: "${reason}".`); try { - var fontFile3 = descriptor && descriptor.get("FontFile3"); - var subtype = fontFile3 && fontFile3.get("Subtype"); - var fontType = (0, _fonts.getFontType)(preEvaluatedFont.type, subtype && subtype.name); - var xrefFontStats = xref.stats.fontTypes; - xrefFontStats[fontType] = true; + const fontFile3 = descriptor && descriptor.get("FontFile3"); + const subtype = fontFile3 && fontFile3.get("Subtype"); + const fontType = (0, _fonts_utils.getFontType)(preEvaluatedFont.type, subtype && subtype.name); + + if (fontType !== undefined) { + xref.stats.addFontType(fontType); + } } catch (ex) {} fontCapability.resolve(new TranslatedFont({ loadedName: font.loadedName, font: new _fonts.ErrorFont(reason instanceof Error ? reason.message : reason), dict: font, - extraProperties: this.options.fontExtraProperties + evaluatorOptions: this.options })); }); return fontCapability.promise; } buildPath(operatorList, fn, args, parsingText = false) { - var lastIndex = operatorList.length - 1; + const lastIndex = operatorList.length - 1; if (!args) { args = []; } + let minMax; + if (lastIndex < 0 || operatorList.fnArray[lastIndex] !== _util.OPS.constructPath) { if (parsingText) { (0, _util.warn)(`Encountered path operator "${fn}" inside of a text object.`); operatorList.addOp(_util.OPS.save, null); } - operatorList.addOp(_util.OPS.constructPath, [[fn], args]); + minMax = [Infinity, -Infinity, Infinity, -Infinity]; + operatorList.addOp(_util.OPS.constructPath, [[fn], args, minMax]); if (parsingText) { operatorList.addOp(_util.OPS.restore, null); } } else { - var opArgs = operatorList.argsArray[lastIndex]; + const opArgs = operatorList.argsArray[lastIndex]; opArgs[0].push(fn); Array.prototype.push.apply(opArgs[1], args); + minMax = opArgs[2]; + } + + switch (fn) { + case _util.OPS.rectangle: + minMax[0] = Math.min(minMax[0], args[0], args[0] + args[2]); + minMax[1] = Math.max(minMax[1], args[0], args[0] + args[2]); + minMax[2] = Math.min(minMax[2], args[1], args[1] + args[3]); + minMax[3] = Math.max(minMax[3], args[1], args[1] + args[3]); + break; + + case _util.OPS.moveTo: + case _util.OPS.lineTo: + minMax[0] = Math.min(minMax[0], args[0]); + minMax[1] = Math.max(minMax[1], args[0]); + minMax[2] = Math.min(minMax[2], args[1]); + minMax[3] = Math.max(minMax[3], args[1]); + break; } } @@ -22518,38 +11087,121 @@ class PartialEvaluator { }); } - async handleColorN(operatorList, fn, args, cs, patterns, resources, task, localColorSpaceCache) { - var patternName = args[args.length - 1]; - var pattern; + parseShading({ + shading, + resources, + localColorSpaceCache, + localShadingPatternCache + }) { + let id = localShadingPatternCache.get(shading); - if ((0, _primitives.isName)(patternName) && (pattern = patterns.get(patternName.name))) { - var dict = (0, _primitives.isStream)(pattern) ? pattern.dict : pattern; - var typeNum = dict.get("PatternType"); + if (!id) { + var shadingFill = _pattern.Pattern.parseShading(shading, this.xref, resources, this.handler, this._pdfFunctionFactory, localColorSpaceCache); - if (typeNum === PatternType.TILING) { - var color = cs.base ? cs.base.getRgb(args, 0) : null; - return this.handleTilingType(fn, color, resources, pattern, dict, operatorList, task); - } else if (typeNum === PatternType.SHADING) { - var shading = dict.get("Shading"); - var matrix = dict.getArray("Matrix"); - pattern = _pattern.Pattern.parseShading(shading, matrix, this.xref, resources, this.handler, this._pdfFunctionFactory, localColorSpaceCache); - operatorList.addOp(fn, pattern.getIR()); - return undefined; + const patternIR = shadingFill.getIR(); + id = `pattern_${this.idFactory.createObjId()}`; + localShadingPatternCache.set(shading, id); + this.handler.send("obj", [id, this.pageIndex, "Pattern", patternIR]); + } + + return id; + } + + handleColorN(operatorList, fn, args, cs, patterns, resources, task, localColorSpaceCache, localTilingPatternCache, localShadingPatternCache) { + const patternName = args.pop(); + + if (patternName instanceof _primitives.Name) { + const rawPattern = patterns.getRaw(patternName.name); + const localTilingPattern = rawPattern instanceof _primitives.Ref && localTilingPatternCache.getByRef(rawPattern); + + if (localTilingPattern) { + try { + const color = cs.base ? cs.base.getRgb(args, 0) : null; + const tilingPatternIR = (0, _pattern.getTilingPatternIR)(localTilingPattern.operatorListIR, localTilingPattern.dict, color); + operatorList.addOp(fn, tilingPatternIR); + return undefined; + } catch (ex) {} } - throw new _util.FormatError(`Unknown PatternType: ${typeNum}`); + const pattern = this.xref.fetchIfRef(rawPattern); + + if (pattern) { + const dict = pattern instanceof _base_stream.BaseStream ? pattern.dict : pattern; + const typeNum = dict.get("PatternType"); + + if (typeNum === PatternType.TILING) { + const color = cs.base ? cs.base.getRgb(args, 0) : null; + return this.handleTilingType(fn, color, resources, pattern, dict, operatorList, task, localTilingPatternCache); + } else if (typeNum === PatternType.SHADING) { + const shading = dict.get("Shading"); + const matrix = dict.getArray("Matrix"); + const objId = this.parseShading({ + shading, + resources, + localColorSpaceCache, + localShadingPatternCache + }); + operatorList.addOp(fn, ["Shading", objId, matrix]); + return undefined; + } + + throw new _util.FormatError(`Unknown PatternType: ${typeNum}`); + } } throw new _util.FormatError(`Unknown PatternName: ${patternName}`); } + _parseVisibilityExpression(array, nestingCounter, currentResult) { + const MAX_NESTING = 10; + + if (++nestingCounter > MAX_NESTING) { + (0, _util.warn)("Visibility expression is too deeply nested"); + return; + } + + const length = array.length; + const operator = this.xref.fetchIfRef(array[0]); + + if (length < 2 || !(operator instanceof _primitives.Name)) { + (0, _util.warn)("Invalid visibility expression"); + return; + } + + switch (operator.name) { + case "And": + case "Or": + case "Not": + currentResult.push(operator.name); + break; + + default: + (0, _util.warn)(`Invalid operator ${operator.name} in visibility expression`); + return; + } + + for (let i = 1; i < length; i++) { + const raw = array[i]; + const object = this.xref.fetchIfRef(raw); + + if (Array.isArray(object)) { + const nestedResult = []; + currentResult.push(nestedResult); + + this._parseVisibilityExpression(object, nestingCounter, nestedResult); + } else if (raw instanceof _primitives.Ref) { + currentResult.push(raw.toString()); + } + } + } + async parseMarkedContentProps(contentProperties, resources) { let optionalContent; - if ((0, _primitives.isName)(contentProperties)) { + if (contentProperties instanceof _primitives.Name) { const properties = resources.get("Properties"); optionalContent = properties.get(contentProperties.name); - } else if ((0, _primitives.isDict)(contentProperties)) { + } else if (contentProperties instanceof _primitives.Dict) { optionalContent = contentProperties; } else { throw new _util.FormatError("Optional content properties malformed."); @@ -22563,32 +11215,41 @@ class PartialEvaluator { id: optionalContent.objId }; } else if (optionalContentType === "OCMD") { + const expression = optionalContent.get("VE"); + + if (Array.isArray(expression)) { + const result = []; + + this._parseVisibilityExpression(expression, 0, result); + + if (result.length > 0) { + return { + type: "OCMD", + expression: result + }; + } + } + const optionalContentGroups = optionalContent.get("OCGs"); - if (Array.isArray(optionalContentGroups) || (0, _primitives.isDict)(optionalContentGroups)) { + if (Array.isArray(optionalContentGroups) || optionalContentGroups instanceof _primitives.Dict) { const groupIds = []; if (Array.isArray(optionalContentGroups)) { - optionalContent.get("OCGs").forEach(ocg => { + for (const ocg of optionalContentGroups) { groupIds.push(ocg.toString()); - }); + } } else { groupIds.push(optionalContentGroups.objId); } - let expression = null; - - if (optionalContent.get("VE")) { - expression = true; - } - return { type: optionalContentType, ids: groupIds, - policy: (0, _primitives.isName)(optionalContent.get("P")) ? optionalContent.get("P").name : null, - expression + policy: optionalContent.get("P") instanceof _primitives.Name ? optionalContent.get("P").name : null, + expression: null }; - } else if ((0, _primitives.isRef)(optionalContentGroups)) { + } else if (optionalContentGroups instanceof _primitives.Ref) { return { type: optionalContentType, id: optionalContentGroups.toString() @@ -22604,7 +11265,8 @@ class PartialEvaluator { task, resources, operatorList, - initialState = null + initialState = null, + fallbackFontDict = null }) { resources = resources || _primitives.Dict.empty; initialState = initialState || new EvalState(); @@ -22613,23 +11275,25 @@ class PartialEvaluator { throw new Error('getOperatorList: missing "operatorList" parameter'); } - var self = this; - var xref = this.xref; + const self = this; + const xref = this.xref; let parsingText = false; const localImageCache = new _image_utils.LocalImageCache(); const localColorSpaceCache = new _image_utils.LocalColorSpaceCache(); const localGStateCache = new _image_utils.LocalGStateCache(); + const localTilingPatternCache = new _image_utils.LocalTilingPatternCache(); + const localShadingPatternCache = new Map(); - var xobjs = resources.get("XObject") || _primitives.Dict.empty; + const xobjs = resources.get("XObject") || _primitives.Dict.empty; - var patterns = resources.get("Pattern") || _primitives.Dict.empty; + const patterns = resources.get("Pattern") || _primitives.Dict.empty; - var stateManager = new StateManager(initialState); - var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager); - var timeSlotManager = new TimeSlotManager(); + const stateManager = new StateManager(initialState); + const preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager); + const timeSlotManager = new TimeSlotManager(); function closePendingRestoreOPS(argument) { - for (var i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) { + for (let i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) { operatorList.addOp(_util.OPS.restore, []); } } @@ -22647,12 +11311,8 @@ class PartialEvaluator { task.ensureNotTerminated(); timeSlotManager.reset(); - var stop, - operation = {}, - i, - ii, - cs, - name; + const operation = {}; + let stop, i, ii, cs, name, isValidName; while (!(stop = timeSlotManager.check())) { operation.args = null; @@ -22661,25 +11321,27 @@ class PartialEvaluator { break; } - var args = operation.args; - var fn = operation.fn; + let args = operation.args; + let fn = operation.fn; switch (fn | 0) { case _util.OPS.paintXObject: + isValidName = args[0] instanceof _primitives.Name; name = args[0].name; - if (name) { + if (isValidName) { const localImage = localImageCache.getByName(name); if (localImage) { - operatorList.addOp(localImage.fn, localImage.args); + operatorList.addImageOps(localImage.fn, localImage.args, localImage.optionalContent); + incrementCachedImageMaskCount(localImage); args = null; continue; } } next(new Promise(function (resolveXObject, rejectXObject) { - if (!name) { + if (!isValidName) { throw new _util.FormatError("XObject must be referred to by name."); } @@ -22689,7 +11351,8 @@ class PartialEvaluator { const localImage = localImageCache.getByRef(xobj); if (localImage) { - operatorList.addOp(localImage.fn, localImage.args); + operatorList.addImageOps(localImage.fn, localImage.args, localImage.optionalContent); + incrementCachedImageMaskCount(localImage); resolveXObject(); return; } @@ -22698,7 +11361,7 @@ class PartialEvaluator { if (globalImage) { operatorList.addDependency(globalImage.objId); - operatorList.addOp(globalImage.fn, globalImage.args); + operatorList.addImageOps(globalImage.fn, globalImage.args, globalImage.optionalContent); resolveXObject(); return; } @@ -22706,13 +11369,13 @@ class PartialEvaluator { xobj = xref.fetch(xobj); } - if (!(0, _primitives.isStream)(xobj)) { + if (!(xobj instanceof _base_stream.BaseStream)) { throw new _util.FormatError("XObject should be a stream"); } const type = xobj.dict.get("Subtype"); - if (!(0, _primitives.isName)(type)) { + if (!(type instanceof _primitives.Name)) { throw new _util.FormatError("XObject should have a Name subtype"); } @@ -22759,7 +11422,7 @@ class PartialEvaluator { case _util.OPS.setFont: var fontSize = args[1]; - next(self.handleSetFont(resources, args, null, operatorList, task, stateManager.state).then(function (loadedName) { + next(self.handleSetFont(resources, args, null, operatorList, task, stateManager.state, fallbackFontDict).then(function (loadedName) { operatorList.addDependency(loadedName); operatorList.addOp(_util.OPS.setFont, [loadedName, fontSize]); })); @@ -22780,7 +11443,8 @@ class PartialEvaluator { const localImage = localImageCache.getByName(cacheKey); if (localImage) { - operatorList.addOp(localImage.fn, localImage.args); + operatorList.addImageOps(localImage.fn, localImage.args, localImage.optionalContent); + incrementCachedImageMaskCount(localImage); args = null; continue; } @@ -22818,11 +11482,11 @@ class PartialEvaluator { var state = stateManager.state; for (i = 0; i < arrLength; ++i) { - var arrItem = arr[i]; + const arrItem = arr[i]; - if ((0, _util.isString)(arrItem)) { + if (typeof arrItem === "string") { Array.prototype.push.apply(combinedGlyphs, self.handleText(arrItem, state)); - } else if ((0, _util.isNum)(arrItem)) { + } else if (typeof arrItem === "number") { combinedGlyphs.push(arrItem); } } @@ -22951,7 +11615,7 @@ class PartialEvaluator { cs = stateManager.state.fillColorSpace; if (cs.name === "Pattern") { - next(self.handleColorN(operatorList, _util.OPS.setFillColorN, args, cs, patterns, resources, task, localColorSpaceCache)); + next(self.handleColorN(operatorList, _util.OPS.setFillColorN, args, cs, patterns, resources, task, localColorSpaceCache, localTilingPatternCache, localShadingPatternCache)); return; } @@ -22963,7 +11627,7 @@ class PartialEvaluator { cs = stateManager.state.strokeColorSpace; if (cs.name === "Pattern") { - next(self.handleColorN(operatorList, _util.OPS.setStrokeColorN, args, cs, patterns, resources, task, localColorSpaceCache)); + next(self.handleColorN(operatorList, _util.OPS.setStrokeColorN, args, cs, patterns, resources, task, localColorSpaceCache, localTilingPatternCache, localShadingPatternCache)); return; } @@ -22984,17 +11648,21 @@ class PartialEvaluator { throw new _util.FormatError("No shading object found"); } - var shadingFill = _pattern.Pattern.parseShading(shading, null, xref, resources, self.handler, self._pdfFunctionFactory, localColorSpaceCache); - - var patternIR = shadingFill.getIR(); - args = [patternIR]; + const patternId = self.parseShading({ + shading, + resources, + localColorSpaceCache, + localShadingPatternCache + }); + args = [patternId]; fn = _util.OPS.shadingFill; break; case _util.OPS.setGState: + isValidName = args[0] instanceof _primitives.Name; name = args[0].name; - if (name) { + if (isValidName) { const localGStateObj = localGStateCache.getByName(name); if (localGStateObj) { @@ -23008,7 +11676,7 @@ class PartialEvaluator { } next(new Promise(function (resolveGState, rejectGState) { - if (!name) { + if (!isValidName) { throw new _util.FormatError("GState must be referred to by name."); } @@ -23068,7 +11736,7 @@ class PartialEvaluator { continue; case _util.OPS.beginMarkedContentProps: - if (!(0, _primitives.isName)(args[0])) { + if (!(args[0] instanceof _primitives.Name)) { (0, _util.warn)(`Expected name for beginMarkedContentProps arg0=${args[0]}`); continue; } @@ -23094,7 +11762,7 @@ class PartialEvaluator { return; } - args = [args[0].name]; + args = [args[0].name, args[1] instanceof _primitives.Dict ? args[1].get("MCID") : null]; break; case _util.OPS.beginMarkedContent: @@ -23148,67 +11816,73 @@ class PartialEvaluator { task, resources, stateManager = null, - normalizeWhitespace = false, combineTextItems = false, + includeMarkedContent = false, sink, - seenStyles = Object.create(null) + seenStyles = new Set(), + viewBox }) { resources = resources || _primitives.Dict.empty; stateManager = stateManager || new StateManager(new TextState()); - var WhitespaceRegexp = /\s/g; - var textContent = { + const NormalizedUnicodes = (0, _unicode.getNormalizedUnicodes)(); + const textContent = { items: [], styles: Object.create(null) }; - var textContentItem = { + const textContentItem = { initialized: false, str: [], + totalWidth: 0, + totalHeight: 0, width: 0, height: 0, vertical: false, - lastAdvanceWidth: 0, - lastAdvanceHeight: 0, + prevTransform: null, textAdvanceScale: 0, - spaceWidth: 0, - fakeSpaceMin: Infinity, - fakeMultiSpaceMin: Infinity, - fakeMultiSpaceMax: -0, - textRunBreakAllowed: false, + spaceInFlowMin: 0, + spaceInFlowMax: 0, + trackingSpaceMin: Infinity, + negativeSpaceMax: -Infinity, + notASpace: -Infinity, transform: null, - fontName: null + fontName: null, + hasEOL: false }; - var SPACE_FACTOR = 0.3; - var MULTI_SPACE_FACTOR = 1.5; - var MULTI_SPACE_FACTOR_MAX = 4; - var self = this; - var xref = this.xref; - var xobjs = null; + const twoLastChars = [" ", " "]; + let twoLastCharsPos = 0; + + function saveLastChar(char) { + const nextPos = (twoLastCharsPos + 1) % 2; + const ret = twoLastChars[twoLastCharsPos] !== " " && twoLastChars[nextPos] === " "; + twoLastChars[twoLastCharsPos] = char; + twoLastCharsPos = nextPos; + return ret; + } + + function resetLastChars() { + twoLastChars[0] = twoLastChars[1] = " "; + twoLastCharsPos = 0; + } + + const TRACKING_SPACE_FACTOR = 0.1; + const NOT_A_SPACE_FACTOR = 0.03; + const NEGATIVE_SPACE_FACTOR = -0.2; + const SPACE_IN_FLOW_MIN_FACTOR = 0.1; + const SPACE_IN_FLOW_MAX_FACTOR = 0.6; + const self = this; + const xref = this.xref; + const showSpacedTextBuffer = []; + let xobjs = null; const emptyXObjectCache = new _image_utils.LocalImageCache(); const emptyGStateCache = new _image_utils.LocalGStateCache(); - var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager); - var textState; + const preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager); + let textState; - function ensureTextContentItem() { - if (textContentItem.initialized) { - return textContentItem; - } + function getCurrentTextTransform() { + const font = textState.font; + const tsm = [textState.fontSize * textState.textHScale, 0, 0, textState.fontSize, 0, textState.textRise]; - var font = textState.font; - - if (!(font.loadedName in seenStyles)) { - seenStyles[font.loadedName] = true; - textContent.styles[font.loadedName] = { - fontFamily: font.fallbackName, - ascent: font.ascent, - descent: font.descent, - vertical: font.vertical - }; - } - - textContentItem.fontName = font.loadedName; - var tsm = [textState.fontSize * textState.textHScale, 0, 0, textState.fontSize, 0, textState.textRise]; - - if (font.isType3Font && textState.fontSize <= 1 && !(0, _util.isArrayEqual)(textState.fontMatrix, _util.FONT_IDENTITY_MATRIX)) { + if (font.isType3Font && (textState.fontSize <= 1 || font.isCharBBox) && !(0, _util.isArrayEqual)(textState.fontMatrix, _util.FONT_IDENTITY_MATRIX)) { const glyphHeight = font.bbox[3] - font.bbox[1]; if (glyphHeight > 0) { @@ -23216,171 +11890,413 @@ class PartialEvaluator { } } - var trm = _util.Util.transform(textState.ctm, _util.Util.transform(textState.textMatrix, tsm)); + return _util.Util.transform(textState.ctm, _util.Util.transform(textState.textMatrix, tsm)); + } - textContentItem.transform = trm; + function ensureTextContentItem() { + if (textContentItem.initialized) { + return textContentItem; + } + + const font = textState.font, + loadedName = font.loadedName; + + if (!seenStyles.has(loadedName)) { + seenStyles.add(loadedName); + textContent.styles[loadedName] = { + fontFamily: font.fallbackName, + ascent: font.ascent, + descent: font.descent, + vertical: font.vertical + }; + } + + textContentItem.fontName = loadedName; + const trm = textContentItem.transform = getCurrentTextTransform(); if (!font.vertical) { - textContentItem.width = 0; - textContentItem.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]); + textContentItem.width = textContentItem.totalWidth = 0; + textContentItem.height = textContentItem.totalHeight = Math.hypot(trm[2], trm[3]); textContentItem.vertical = false; } else { - textContentItem.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]); - textContentItem.height = 0; + textContentItem.width = textContentItem.totalWidth = Math.hypot(trm[0], trm[1]); + textContentItem.height = textContentItem.totalHeight = 0; textContentItem.vertical = true; } - var a = textState.textLineMatrix[0]; - var b = textState.textLineMatrix[1]; - var scaleLineX = Math.sqrt(a * a + b * b); - a = textState.ctm[0]; - b = textState.ctm[1]; - var scaleCtmX = Math.sqrt(a * a + b * b); + const scaleLineX = Math.hypot(textState.textLineMatrix[0], textState.textLineMatrix[1]); + const scaleCtmX = Math.hypot(textState.ctm[0], textState.ctm[1]); textContentItem.textAdvanceScale = scaleCtmX * scaleLineX; - textContentItem.lastAdvanceWidth = 0; - textContentItem.lastAdvanceHeight = 0; - var spaceWidth = font.spaceWidth / 1000 * textState.fontSize; - - if (spaceWidth) { - textContentItem.spaceWidth = spaceWidth; - textContentItem.fakeSpaceMin = spaceWidth * SPACE_FACTOR; - textContentItem.fakeMultiSpaceMin = spaceWidth * MULTI_SPACE_FACTOR; - textContentItem.fakeMultiSpaceMax = spaceWidth * MULTI_SPACE_FACTOR_MAX; - textContentItem.textRunBreakAllowed = !font.isMonospace; - } else { - textContentItem.spaceWidth = 0; - textContentItem.fakeSpaceMin = Infinity; - textContentItem.fakeMultiSpaceMin = Infinity; - textContentItem.fakeMultiSpaceMax = 0; - textContentItem.textRunBreakAllowed = false; - } - + textContentItem.trackingSpaceMin = textState.fontSize * TRACKING_SPACE_FACTOR; + textContentItem.notASpace = textState.fontSize * NOT_A_SPACE_FACTOR; + textContentItem.negativeSpaceMax = textState.fontSize * NEGATIVE_SPACE_FACTOR; + textContentItem.spaceInFlowMin = textState.fontSize * SPACE_IN_FLOW_MIN_FACTOR; + textContentItem.spaceInFlowMax = textState.fontSize * SPACE_IN_FLOW_MAX_FACTOR; + textContentItem.hasEOL = false; textContentItem.initialized = true; return textContentItem; } - function replaceWhitespace(str) { - var i = 0, - ii = str.length, - code; - - while (i < ii && (code = str.charCodeAt(i)) >= 0x20 && code <= 0x7f) { - i++; + function updateAdvanceScale() { + if (!textContentItem.initialized) { + return; } - return i < ii ? str.replace(WhitespaceRegexp, " ") : str; + const scaleLineX = Math.hypot(textState.textLineMatrix[0], textState.textLineMatrix[1]); + const scaleCtmX = Math.hypot(textState.ctm[0], textState.ctm[1]); + const scaleFactor = scaleCtmX * scaleLineX; + + if (scaleFactor === textContentItem.textAdvanceScale) { + return; + } + + if (!textContentItem.vertical) { + textContentItem.totalWidth += textContentItem.width * textContentItem.textAdvanceScale; + textContentItem.width = 0; + } else { + textContentItem.totalHeight += textContentItem.height * textContentItem.textAdvanceScale; + textContentItem.height = 0; + } + + textContentItem.textAdvanceScale = scaleFactor; } function runBidiTransform(textChunk) { - var str = textChunk.str.join(""); - var bidiResult = (0, _bidi.bidi)(str, -1, textChunk.vertical); + const text = textChunk.str.join(""); + const bidiResult = (0, _bidi.bidi)(text, -1, textChunk.vertical); return { - str: normalizeWhitespace ? replaceWhitespace(bidiResult.str) : bidiResult.str, + str: bidiResult.str, dir: bidiResult.dir, - width: textChunk.width, - height: textChunk.height, + width: Math.abs(textChunk.totalWidth), + height: Math.abs(textChunk.totalHeight), transform: textChunk.transform, - fontName: textChunk.fontName + fontName: textChunk.fontName, + hasEOL: textChunk.hasEOL }; } function handleSetFont(fontName, fontRef) { return self.loadFont(fontName, fontRef, resources).then(function (translated) { + if (!translated.font.isType3Font) { + return translated; + } + + return translated.loadType3Data(self, resources, task).catch(function () {}).then(function () { + return translated; + }); + }).then(function (translated) { textState.font = translated.font; textState.fontMatrix = translated.font.fontMatrix || _util.FONT_IDENTITY_MATRIX; }); } - function buildTextContentItem(chars) { - var font = textState.font; - var textChunk = ensureTextContentItem(); - var width = 0; - var height = 0; - var glyphs = font.charsToGlyphs(chars); + function applyInverseRotation(x, y, matrix) { + const scale = Math.hypot(matrix[0], matrix[1]); + return [(matrix[0] * x + matrix[1] * y) / scale, (matrix[2] * x + matrix[3] * y) / scale]; + } - for (var i = 0; i < glyphs.length; i++) { - var glyph = glyphs[i]; - var glyphWidth = null; + function compareWithLastPosition() { + const currentTransform = getCurrentTextTransform(); + let posX = currentTransform[4]; + let posY = currentTransform[5]; + const shiftedX = posX - viewBox[0]; + const shiftedY = posY - viewBox[1]; - if (font.vertical && glyph.vmetric) { - glyphWidth = glyph.vmetric[0]; - } else { - glyphWidth = glyph.width; + if (shiftedX < 0 || shiftedX > viewBox[2] || shiftedY < 0 || shiftedY > viewBox[3]) { + return false; + } + + if (!combineTextItems || !textState.font || !textContentItem.prevTransform) { + return true; + } + + let lastPosX = textContentItem.prevTransform[4]; + let lastPosY = textContentItem.prevTransform[5]; + + if (lastPosX === posX && lastPosY === posY) { + return true; + } + + let rotate = -1; + + if (currentTransform[0] && currentTransform[1] === 0 && currentTransform[2] === 0) { + rotate = currentTransform[0] > 0 ? 0 : 180; + } else if (currentTransform[1] && currentTransform[0] === 0 && currentTransform[3] === 0) { + rotate = currentTransform[1] > 0 ? 90 : 270; + } + + switch (rotate) { + case 0: + break; + + case 90: + [posX, posY] = [posY, posX]; + [lastPosX, lastPosY] = [lastPosY, lastPosX]; + break; + + case 180: + [posX, posY, lastPosX, lastPosY] = [-posX, -posY, -lastPosX, -lastPosY]; + break; + + case 270: + [posX, posY] = [-posY, -posX]; + [lastPosX, lastPosY] = [-lastPosY, -lastPosX]; + break; + + default: + [posX, posY] = applyInverseRotation(posX, posY, currentTransform); + [lastPosX, lastPosY] = applyInverseRotation(lastPosX, lastPosY, textContentItem.prevTransform); + } + + if (textState.font.vertical) { + const advanceY = (lastPosY - posY) / textContentItem.textAdvanceScale; + const advanceX = posX - lastPosX; + const textOrientation = Math.sign(textContentItem.height); + + if (advanceY < textOrientation * textContentItem.negativeSpaceMax) { + if (Math.abs(advanceX) > 0.5 * textContentItem.width) { + appendEOL(); + return true; + } + + resetLastChars(); + flushTextContentItem(); + return true; } - var glyphUnicode = glyph.unicode; - var NormalizedUnicodes = (0, _unicode.getNormalizedUnicodes)(); - - if (NormalizedUnicodes[glyphUnicode] !== undefined) { - glyphUnicode = NormalizedUnicodes[glyphUnicode]; + if (Math.abs(advanceX) > textContentItem.width) { + appendEOL(); + return true; } - glyphUnicode = (0, _unicode.reverseIfRtl)(glyphUnicode); - var charSpacing = textState.charSpacing; + if (advanceY <= textOrientation * textContentItem.notASpace) { + resetLastChars(); + } - if (glyph.isSpace) { - var wordSpacing = textState.wordSpacing; - charSpacing += wordSpacing; - - if (wordSpacing > 0) { - addFakeSpaces(wordSpacing, textChunk.str); + if (advanceY <= textOrientation * textContentItem.trackingSpaceMin) { + textContentItem.height += advanceY; + } else if (!addFakeSpaces(advanceY, textContentItem.prevTransform, textOrientation)) { + if (textContentItem.str.length === 0) { + resetLastChars(); + textContent.items.push({ + str: " ", + dir: "ltr", + width: 0, + height: Math.abs(advanceY), + transform: textContentItem.prevTransform, + fontName: textContentItem.fontName, + hasEOL: false + }); + } else { + textContentItem.height += advanceY; } } - var tx = 0; - var ty = 0; + return true; + } - if (!font.vertical) { - var w0 = glyphWidth * textState.fontMatrix[0]; - tx = (w0 * textState.fontSize + charSpacing) * textState.textHScale; - width += tx; - } else { - var w1 = glyphWidth * textState.fontMatrix[0]; - ty = w1 * textState.fontSize + charSpacing; - height += ty; + const advanceX = (posX - lastPosX) / textContentItem.textAdvanceScale; + const advanceY = posY - lastPosY; + const textOrientation = Math.sign(textContentItem.width); + + if (advanceX < textOrientation * textContentItem.negativeSpaceMax) { + if (Math.abs(advanceY) > 0.5 * textContentItem.height) { + appendEOL(); + return true; } - textState.translateTextMatrix(tx, ty); - textChunk.str.push(glyphUnicode); + resetLastChars(); + flushTextContentItem(); + return true; } - if (!font.vertical) { - textChunk.lastAdvanceWidth = width; - textChunk.width += width; - } else { - textChunk.lastAdvanceHeight = height; - textChunk.height += Math.abs(height); + if (Math.abs(advanceY) > textContentItem.height) { + appendEOL(); + return true; } - return textChunk; + if (advanceX <= textOrientation * textContentItem.notASpace) { + resetLastChars(); + } + + if (advanceX <= textOrientation * textContentItem.trackingSpaceMin) { + textContentItem.width += advanceX; + } else if (!addFakeSpaces(advanceX, textContentItem.prevTransform, textOrientation)) { + if (textContentItem.str.length === 0) { + resetLastChars(); + textContent.items.push({ + str: " ", + dir: "ltr", + width: Math.abs(advanceX), + height: 0, + transform: textContentItem.prevTransform, + fontName: textContentItem.fontName, + hasEOL: false + }); + } else { + textContentItem.width += advanceX; + } + } + + return true; } - function addFakeSpaces(width, strBuf) { - if (width < textContentItem.fakeSpaceMin) { + function buildTextContentItem({ + chars, + extraSpacing + }) { + const font = textState.font; + + if (!chars) { + const charSpacing = textState.charSpacing + extraSpacing; + + if (charSpacing) { + if (!font.vertical) { + textState.translateTextMatrix(charSpacing * textState.textHScale, 0); + } else { + textState.translateTextMatrix(0, -charSpacing); + } + } + return; } - if (width < textContentItem.fakeMultiSpaceMin) { - strBuf.push(" "); - return; + const glyphs = font.charsToGlyphs(chars); + const scale = textState.fontMatrix[0] * textState.fontSize; + + for (let i = 0, ii = glyphs.length; i < ii; i++) { + const glyph = glyphs[i]; + + if (glyph.isInvisibleFormatMark) { + continue; + } + + let charSpacing = textState.charSpacing + (i + 1 === ii ? extraSpacing : 0); + let glyphWidth = glyph.width; + + if (font.vertical) { + glyphWidth = glyph.vmetric ? glyph.vmetric[0] : -glyphWidth; + } + + let scaledDim = glyphWidth * scale; + + if (glyph.isWhitespace) { + if (!font.vertical) { + charSpacing += scaledDim + textState.wordSpacing; + textState.translateTextMatrix(charSpacing * textState.textHScale, 0); + } else { + charSpacing += -scaledDim + textState.wordSpacing; + textState.translateTextMatrix(0, -charSpacing); + } + + saveLastChar(" "); + continue; + } + + if (!compareWithLastPosition()) { + continue; + } + + const textChunk = ensureTextContentItem(); + + if (glyph.isZeroWidthDiacritic) { + scaledDim = 0; + } + + if (!font.vertical) { + scaledDim *= textState.textHScale; + textState.translateTextMatrix(scaledDim, 0); + textChunk.width += scaledDim; + } else { + textState.translateTextMatrix(0, scaledDim); + scaledDim = Math.abs(scaledDim); + textChunk.height += scaledDim; + } + + if (scaledDim) { + textChunk.prevTransform = getCurrentTextTransform(); + } + + let glyphUnicode = glyph.unicode; + glyphUnicode = NormalizedUnicodes[glyphUnicode] || glyphUnicode; + glyphUnicode = (0, _unicode.reverseIfRtl)(glyphUnicode); + + if (saveLastChar(glyphUnicode)) { + textChunk.str.push(" "); + } + + textChunk.str.push(glyphUnicode); + + if (charSpacing) { + if (!font.vertical) { + textState.translateTextMatrix(charSpacing * textState.textHScale, 0); + } else { + textState.translateTextMatrix(0, -charSpacing); + } + } + } + } + + function appendEOL() { + resetLastChars(); + + if (textContentItem.initialized) { + textContentItem.hasEOL = true; + flushTextContentItem(); + } else { + textContent.items.push({ + str: "", + dir: "ltr", + width: 0, + height: 0, + transform: getCurrentTextTransform(), + fontName: textState.font.loadedName, + hasEOL: true + }); + } + } + + function addFakeSpaces(width, transf, textOrientation) { + if (textOrientation * textContentItem.spaceInFlowMin <= width && width <= textOrientation * textContentItem.spaceInFlowMax) { + if (textContentItem.initialized) { + resetLastChars(); + textContentItem.str.push(" "); + } + + return false; } - var fakeSpaces = Math.round(width / textContentItem.spaceWidth); + const fontName = textContentItem.fontName; + let height = 0; - while (fakeSpaces-- > 0) { - strBuf.push(" "); + if (textContentItem.vertical) { + height = width; + width = 0; } + + flushTextContentItem(); + resetLastChars(); + textContent.items.push({ + str: " ", + dir: "ltr", + width: Math.abs(width), + height: Math.abs(height), + transform: transf || getCurrentTextTransform(), + fontName, + hasEOL: false + }); + return true; } function flushTextContentItem() { - if (!textContentItem.initialized) { + if (!textContentItem.initialized || !textContentItem.str) { return; } if (!textContentItem.vertical) { - textContentItem.width *= textContentItem.textAdvanceScale; + textContentItem.totalWidth += textContentItem.width * textContentItem.textAdvanceScale; } else { - textContentItem.height *= textContentItem.textAdvanceScale; + textContentItem.totalHeight += textContentItem.height * textContentItem.textAdvanceScale; } textContent.items.push(runBidiTransform(textContentItem)); @@ -23388,20 +12304,26 @@ class PartialEvaluator { textContentItem.str.length = 0; } - function enqueueChunk() { + function enqueueChunk(batch = false) { const length = textContent.items.length; - if (length > 0) { - sink.enqueue(textContent, length); - textContent.items = []; - textContent.styles = Object.create(null); + if (length === 0) { + return; } + + if (batch && length < TEXT_CHUNK_BATCH_SIZE) { + return; + } + + sink.enqueue(textContent, length); + textContent.items = []; + textContent.styles = Object.create(null); } - var timeSlotManager = new TimeSlotManager(); + const timeSlotManager = new TimeSlotManager(); return new Promise(function promiseBody(resolve, reject) { const next = function (promise) { - enqueueChunk(); + enqueueChunk(true); Promise.all([promise, sink.ready]).then(function () { try { promiseBody(resolve, reject); @@ -23413,8 +12335,8 @@ class PartialEvaluator { task.ensureNotTerminated(); timeSlotManager.reset(); - var stop, - operation = {}, + const operation = {}; + let stop, args = []; while (!(stop = timeSlotManager.check())) { @@ -23426,9 +12348,8 @@ class PartialEvaluator { } textState = stateManager.state; - var fn = operation.fn; + const fn = operation.fn; args = operation.args; - var advance, diff; switch (fn | 0) { case _util.OPS.setFont: @@ -23446,65 +12367,36 @@ class PartialEvaluator { return; case _util.OPS.setTextRise: - flushTextContentItem(); textState.textRise = args[0]; break; case _util.OPS.setHScale: - flushTextContentItem(); textState.textHScale = args[0] / 100; break; case _util.OPS.setLeading: - flushTextContentItem(); textState.leading = args[0]; break; case _util.OPS.moveText: - var isSameTextLine = !textState.font ? false : (textState.font.vertical ? args[0] : args[1]) === 0; - advance = args[0] - args[1]; - - if (combineTextItems && isSameTextLine && textContentItem.initialized && advance > 0 && advance <= textContentItem.fakeMultiSpaceMax) { - textState.translateTextLineMatrix(args[0], args[1]); - textContentItem.width += args[0] - textContentItem.lastAdvanceWidth; - textContentItem.height += args[1] - textContentItem.lastAdvanceHeight; - diff = args[0] - textContentItem.lastAdvanceWidth - (args[1] - textContentItem.lastAdvanceHeight); - addFakeSpaces(diff, textContentItem.str); - break; - } - - flushTextContentItem(); textState.translateTextLineMatrix(args[0], args[1]); textState.textMatrix = textState.textLineMatrix.slice(); break; case _util.OPS.setLeadingMoveText: - flushTextContentItem(); textState.leading = -args[1]; textState.translateTextLineMatrix(args[0], args[1]); textState.textMatrix = textState.textLineMatrix.slice(); break; case _util.OPS.nextLine: - flushTextContentItem(); textState.carriageReturn(); break; case _util.OPS.setTextMatrix: - advance = textState.calcTextLineMatrixAdvance(args[0], args[1], args[2], args[3], args[4], args[5]); - - if (combineTextItems && advance !== null && textContentItem.initialized && advance.value > 0 && advance.value <= textContentItem.fakeMultiSpaceMax) { - textState.translateTextLineMatrix(advance.width, advance.height); - textContentItem.width += advance.width - textContentItem.lastAdvanceWidth; - textContentItem.height += advance.height - textContentItem.lastAdvanceHeight; - diff = advance.width - textContentItem.lastAdvanceWidth - (advance.height - textContentItem.lastAdvanceHeight); - addFakeSpaces(diff, textContentItem.str); - break; - } - - flushTextContentItem(); textState.setTextMatrix(args[0], args[1], args[2], args[3], args[4], args[5]); textState.setTextLineMatrix(args[0], args[1], args[2], args[3], args[4], args[5]); + updateAdvanceScale(); break; case _util.OPS.setCharSpacing: @@ -23516,7 +12408,6 @@ class PartialEvaluator { break; case _util.OPS.beginText: - flushTextContentItem(); textState.textMatrix = _util.IDENTITY_MATRIX.slice(); textState.textLineMatrix = _util.IDENTITY_MATRIX.slice(); break; @@ -23527,44 +12418,39 @@ class PartialEvaluator { continue; } - var items = args[0]; - var offset; + const spaceFactor = (textState.font.vertical ? 1 : -1) * textState.fontSize / 1000; + const elements = args[0]; - for (var j = 0, jj = items.length; j < jj; j++) { - if (typeof items[j] === "string") { - buildTextContentItem(items[j]); - } else if ((0, _util.isNum)(items[j])) { - ensureTextContentItem(); - advance = items[j] * textState.fontSize / 1000; - var breakTextRun = false; + for (let i = 0, ii = elements.length; i < ii - 1; i++) { + const item = elements[i]; - if (textState.font.vertical) { - offset = advance; - textState.translateTextMatrix(0, offset); - breakTextRun = textContentItem.textRunBreakAllowed && advance > textContentItem.fakeMultiSpaceMax; - - if (!breakTextRun) { - textContentItem.height += offset; - } - } else { - advance = -advance; - offset = advance * textState.textHScale; - textState.translateTextMatrix(offset, 0); - breakTextRun = textContentItem.textRunBreakAllowed && advance > textContentItem.fakeMultiSpaceMax; - - if (!breakTextRun) { - textContentItem.width += offset; - } - } - - if (breakTextRun) { - flushTextContentItem(); - } else if (advance > 0) { - addFakeSpaces(advance, textContentItem.str); - } + if (typeof item === "string") { + showSpacedTextBuffer.push(item); + } else if (typeof item === "number" && item !== 0) { + const str = showSpacedTextBuffer.join(""); + showSpacedTextBuffer.length = 0; + buildTextContentItem({ + chars: str, + extraSpacing: item * spaceFactor + }); } } + const item = elements.at(-1); + + if (typeof item === "string") { + showSpacedTextBuffer.push(item); + } + + if (showSpacedTextBuffer.length > 0) { + const str = showSpacedTextBuffer.join(""); + showSpacedTextBuffer.length = 0; + buildTextContentItem({ + chars: str, + extraSpacing: 0 + }); + } + break; case _util.OPS.showText: @@ -23573,7 +12459,10 @@ class PartialEvaluator { continue; } - buildTextContentItem(args[0]); + buildTextContentItem({ + chars: args[0], + extraSpacing: 0 + }); break; case _util.OPS.nextLineShowText: @@ -23582,9 +12471,11 @@ class PartialEvaluator { continue; } - flushTextContentItem(); textState.carriageReturn(); - buildTextContentItem(args[0]); + buildTextContentItem({ + chars: args[0], + extraSpacing: 0 + }); break; case _util.OPS.nextLineSetSpacingShowText: @@ -23593,11 +12484,13 @@ class PartialEvaluator { continue; } - flushTextContentItem(); textState.wordSpacing = args[0]; textState.charSpacing = args[1]; textState.carriageReturn(); - buildTextContentItem(args[2]); + buildTextContentItem({ + chars: args[2], + extraSpacing: 0 + }); break; case _util.OPS.paintXObject: @@ -23607,14 +12500,15 @@ class PartialEvaluator { xobjs = resources.get("XObject") || _primitives.Dict.empty; } + var isValidName = args[0] instanceof _primitives.Name; var name = args[0].name; - if (name && emptyXObjectCache.getByName(name)) { + if (isValidName && emptyXObjectCache.getByName(name)) { break; } next(new Promise(function (resolveXObject, rejectXObject) { - if (!name) { + if (!isValidName) { throw new _util.FormatError("XObject must be referred to by name."); } @@ -23626,16 +12520,23 @@ class PartialEvaluator { return; } + const globalImage = self.globalImageCache.getData(xobj, self.pageIndex); + + if (globalImage) { + resolveXObject(); + return; + } + xobj = xref.fetch(xobj); } - if (!(0, _primitives.isStream)(xobj)) { + if (!(xobj instanceof _base_stream.BaseStream)) { throw new _util.FormatError("XObject should be a stream"); } const type = xobj.dict.get("Subtype"); - if (!(0, _primitives.isName)(type)) { + if (!(type instanceof _primitives.Name)) { throw new _util.FormatError("XObject should have a Name subtype"); } @@ -23676,10 +12577,11 @@ class PartialEvaluator { task, resources: xobj.dict.get("Resources") || resources, stateManager: xObjStateManager, - normalizeWhitespace, combineTextItems, + includeMarkedContent, sink: sinkWrapper, - seenStyles + seenStyles, + viewBox }).then(function () { if (!sinkWrapper.enqueueInvoked) { emptyXObjectCache.set(name, xobj.dict.objId, true); @@ -23702,14 +12604,15 @@ class PartialEvaluator { return; case _util.OPS.setGState: + isValidName = args[0] instanceof _primitives.Name; name = args[0].name; - if (name && emptyGStateCache.getByName(name)) { + if (isValidName && emptyGStateCache.getByName(name)) { break; } next(new Promise(function (resolveGState, rejectGState) { - if (!name) { + if (!isValidName) { throw new _util.FormatError("GState must be referred to by name."); } @@ -23750,6 +12653,48 @@ class PartialEvaluator { throw reason; })); return; + + case _util.OPS.beginMarkedContent: + flushTextContentItem(); + + if (includeMarkedContent) { + textContent.items.push({ + type: "beginMarkedContent", + tag: args[0] instanceof _primitives.Name ? args[0].name : null + }); + } + + break; + + case _util.OPS.beginMarkedContentProps: + flushTextContentItem(); + + if (includeMarkedContent) { + let mcid = null; + + if (args[1] instanceof _primitives.Dict) { + mcid = args[1].get("MCID"); + } + + textContent.items.push({ + type: "beginMarkedContentProps", + id: Number.isInteger(mcid) ? `${self.idFactory.getPageObjId()}_mcid${mcid}` : null, + tag: args[0] instanceof _primitives.Name ? args[0].name : null + }); + } + + break; + + case _util.OPS.endMarkedContent: + flushTextContentItem(); + + if (includeMarkedContent) { + textContent.items.push({ + type: "endMarkedContent" + }); + } + + break; } if (textContent.items.length >= sink.desiredSize) { @@ -23785,13 +12730,12 @@ class PartialEvaluator { extractDataStructures(dict, baseDict, properties) { const xref = this.xref; let cidToGidBytes; - var toUnicode = dict.get("ToUnicode") || baseDict.get("ToUnicode"); - var toUnicodePromise = toUnicode ? this.readToUnicode(toUnicode) : Promise.resolve(undefined); + const toUnicodePromise = this.readToUnicode(properties.toUnicode || dict.get("ToUnicode") || baseDict.get("ToUnicode")); if (properties.composite) { - var cidSystemInfo = dict.get("CIDSystemInfo"); + const cidSystemInfo = dict.get("CIDSystemInfo"); - if ((0, _primitives.isDict)(cidSystemInfo)) { + if (cidSystemInfo instanceof _primitives.Dict) { properties.cidSystemInfo = { registry: (0, _util.stringToPDFString)(cidSystemInfo.get("Registry")), ordering: (0, _util.stringToPDFString)(cidSystemInfo.get("Ordering")), @@ -23799,44 +12743,58 @@ class PartialEvaluator { }; } - var cidToGidMap = dict.get("CIDToGIDMap"); + try { + const cidToGidMap = dict.get("CIDToGIDMap"); - if ((0, _primitives.isStream)(cidToGidMap)) { - cidToGidBytes = cidToGidMap.getBytes(); + if (cidToGidMap instanceof _base_stream.BaseStream) { + cidToGidBytes = cidToGidMap.getBytes(); + } + } catch (ex) { + if (!this.options.ignoreErrors) { + throw ex; + } + + (0, _util.warn)(`extractDataStructures - ignoring CIDToGIDMap data: "${ex}".`); } } - var differences = []; - var baseEncodingName = null; - var encoding; + const differences = []; + let baseEncodingName = null; + let encoding; if (dict.has("Encoding")) { encoding = dict.get("Encoding"); - if ((0, _primitives.isDict)(encoding)) { + if (encoding instanceof _primitives.Dict) { baseEncodingName = encoding.get("BaseEncoding"); - baseEncodingName = (0, _primitives.isName)(baseEncodingName) ? baseEncodingName.name : null; + baseEncodingName = baseEncodingName instanceof _primitives.Name ? baseEncodingName.name : null; if (encoding.has("Differences")) { - var diffEncoding = encoding.get("Differences"); - var index = 0; + const diffEncoding = encoding.get("Differences"); + let index = 0; - for (var j = 0, jj = diffEncoding.length; j < jj; j++) { - var data = xref.fetchIfRef(diffEncoding[j]); + for (let j = 0, jj = diffEncoding.length; j < jj; j++) { + const data = xref.fetchIfRef(diffEncoding[j]); - if ((0, _util.isNum)(data)) { + if (typeof data === "number") { index = data; - } else if ((0, _primitives.isName)(data)) { + } else if (data instanceof _primitives.Name) { differences[index++] = data.name; } else { throw new _util.FormatError(`Invalid entry in 'Differences' array: ${data}`); } } } - } else if ((0, _primitives.isName)(encoding)) { + } else if (encoding instanceof _primitives.Name) { baseEncodingName = encoding.name; } else { - throw new _util.FormatError("Encoding is not a Name nor a Dict"); + const msg = "Encoding is not a Name nor a Dict"; + + if (!this.options.ignoreErrors) { + throw new _util.FormatError(msg); + } + + (0, _util.warn)(msg); } if (baseEncodingName !== "MacRomanEncoding" && baseEncodingName !== "MacExpertEncoding" && baseEncodingName !== "WinAnsiEncoding") { @@ -23845,10 +12803,10 @@ class PartialEvaluator { } if (baseEncodingName) { - properties.defaultEncoding = (0, _encodings.getEncoding)(baseEncodingName).slice(); + properties.defaultEncoding = (0, _encodings.getEncoding)(baseEncodingName); } else { - var isSymbolicFont = !!(properties.flags & _fonts.FontFlags.Symbolic); - var isNonsymbolicFont = !!(properties.flags & _fonts.FontFlags.Nonsymbolic); + const isSymbolicFont = !!(properties.flags & _fonts_utils.FontFlags.Symbolic); + const isNonsymbolicFont = !!(properties.flags & _fonts_utils.FontFlags.Nonsymbolic); encoding = _encodings.StandardEncoding; if (properties.type === "TrueType" && !isNonsymbolicFont) { @@ -23858,7 +12816,7 @@ class PartialEvaluator { if (isSymbolicFont) { encoding = _encodings.MacRomanEncoding; - if (!properties.file) { + if (!properties.file || properties.isInternalFont) { if (/Symbol/i.test(properties.name)) { encoding = _encodings.SymbolSetEncoding; } else if (/Dingbats|Wingdings/i.test(properties.name)) { @@ -23888,7 +12846,7 @@ class PartialEvaluator { }); } - _buildSimpleFontToUnicode(properties, forceGlyphs = false) { + _simpleFontToUnicode(properties, forceGlyphs = false) { (0, _util.assert)(!properties.composite, "Must be a simple font."); const toUnicode = []; const encoding = properties.defaultEncoding.slice(); @@ -23943,7 +12901,7 @@ class PartialEvaluator { code = +codeStr; if (Number.isNaN(code) && Number.isInteger(parseInt(codeStr, 16))) { - return this._buildSimpleFontToUnicode(properties, true); + return this._simpleFontToUnicode(properties, true); } } @@ -23977,86 +12935,93 @@ class PartialEvaluator { toUnicode[charcode] = String.fromCharCode(glyphsUnicodeMap[glyphName]); } - return new _fonts.ToUnicodeMap(toUnicode); + return toUnicode; } - buildToUnicode(properties) { + async buildToUnicode(properties) { properties.hasIncludedToUnicodeMap = !!properties.toUnicode && properties.toUnicode.length > 0; if (properties.hasIncludedToUnicodeMap) { if (!properties.composite && properties.hasEncoding) { - properties.fallbackToUnicode = this._buildSimpleFontToUnicode(properties); + properties.fallbackToUnicode = this._simpleFontToUnicode(properties); } - return Promise.resolve(properties.toUnicode); + return properties.toUnicode; } if (!properties.composite) { - return Promise.resolve(this._buildSimpleFontToUnicode(properties)); + return new _to_unicode_map.ToUnicodeMap(this._simpleFontToUnicode(properties)); } if (properties.composite && (properties.cMap.builtInCMap && !(properties.cMap instanceof _cmap.IdentityCMap) || properties.cidSystemInfo.registry === "Adobe" && (properties.cidSystemInfo.ordering === "GB1" || properties.cidSystemInfo.ordering === "CNS1" || properties.cidSystemInfo.ordering === "Japan1" || properties.cidSystemInfo.ordering === "Korea1"))) { - const registry = properties.cidSystemInfo.registry; - const ordering = properties.cidSystemInfo.ordering; + const { + registry, + ordering + } = properties.cidSystemInfo; - const ucs2CMapName = _primitives.Name.get(registry + "-" + ordering + "-UCS2"); + const ucs2CMapName = _primitives.Name.get(`${registry}-${ordering}-UCS2`); - return _cmap.CMapFactory.create({ + const ucs2CMap = await _cmap.CMapFactory.create({ encoding: ucs2CMapName, fetchBuiltInCMap: this._fetchBuiltInCMapBound, useCMap: null - }).then(function (ucs2CMap) { - const cMap = properties.cMap; - const toUnicode = []; - cMap.forEach(function (charcode, cid) { - if (cid > 0xffff) { - throw new _util.FormatError("Max size of CID is 65,535"); - } - - const ucs2 = ucs2CMap.lookup(cid); - - if (ucs2) { - toUnicode[charcode] = String.fromCharCode((ucs2.charCodeAt(0) << 8) + ucs2.charCodeAt(1)); - } - }); - return new _fonts.ToUnicodeMap(toUnicode); }); + const toUnicode = []; + properties.cMap.forEach(function (charcode, cid) { + if (cid > 0xffff) { + throw new _util.FormatError("Max size of CID is 65,535"); + } + + const ucs2 = ucs2CMap.lookup(cid); + + if (ucs2) { + toUnicode[charcode] = String.fromCharCode((ucs2.charCodeAt(0) << 8) + ucs2.charCodeAt(1)); + } + }); + return new _to_unicode_map.ToUnicodeMap(toUnicode); } - return Promise.resolve(new _fonts.IdentityToUnicodeMap(properties.firstChar, properties.lastChar)); + return new _to_unicode_map.IdentityToUnicodeMap(properties.firstChar, properties.lastChar); } - readToUnicode(toUnicode) { - var cmapObj = toUnicode; + readToUnicode(cmapObj) { + if (!cmapObj) { + return Promise.resolve(null); + } - if ((0, _primitives.isName)(cmapObj)) { + if (cmapObj instanceof _primitives.Name) { return _cmap.CMapFactory.create({ encoding: cmapObj, fetchBuiltInCMap: this._fetchBuiltInCMapBound, useCMap: null }).then(function (cmap) { if (cmap instanceof _cmap.IdentityCMap) { - return new _fonts.IdentityToUnicodeMap(0, 0xffff); + return new _to_unicode_map.IdentityToUnicodeMap(0, 0xffff); } - return new _fonts.ToUnicodeMap(cmap.getMap()); + return new _to_unicode_map.ToUnicodeMap(cmap.getMap()); }); - } else if ((0, _primitives.isStream)(cmapObj)) { + } else if (cmapObj instanceof _base_stream.BaseStream) { return _cmap.CMapFactory.create({ encoding: cmapObj, fetchBuiltInCMap: this._fetchBuiltInCMapBound, useCMap: null }).then(function (cmap) { if (cmap instanceof _cmap.IdentityCMap) { - return new _fonts.IdentityToUnicodeMap(0, 0xffff); + return new _to_unicode_map.IdentityToUnicodeMap(0, 0xffff); } - var map = new Array(cmap.length); + const map = new Array(cmap.length); cmap.forEach(function (charCode, token) { - var str = []; + if (typeof token === "number") { + map[charCode] = String.fromCodePoint(token); + return; + } - for (var k = 0; k < token.length; k += 2) { - var w1 = token.charCodeAt(k) << 8 | token.charCodeAt(k + 1); + const str = []; + + for (let k = 0; k < token.length; k += 2) { + const w1 = token.charCodeAt(k) << 8 | token.charCodeAt(k + 1); if ((w1 & 0xf800) !== 0xd800) { str.push(w1); @@ -24064,13 +13029,13 @@ class PartialEvaluator { } k += 2; - var w2 = token.charCodeAt(k) << 8 | token.charCodeAt(k + 1); + const w2 = token.charCodeAt(k) << 8 | token.charCodeAt(k + 1); str.push(((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000); } - map[charCode] = String.fromCodePoint.apply(String, str); + map[charCode] = String.fromCodePoint(...str); }); - return new _fonts.ToUnicodeMap(map); + return new _to_unicode_map.ToUnicodeMap(map); }, reason => { if (reason instanceof _util.AbortException) { return null; @@ -24092,10 +13057,10 @@ class PartialEvaluator { } readCidToGidMap(glyphsData, toUnicode) { - var result = []; + const result = []; - for (var j = 0, jj = glyphsData.length; j < jj; j++) { - var glyphID = glyphsData[j++] << 8 | glyphsData[j]; + for (let j = 0, jj = glyphsData.length; j < jj; j++) { + const glyphID = glyphsData[j++] << 8 | glyphsData[j]; const code = j >> 1; if (glyphID === 0 && !toUnicode.has(code)) { @@ -24109,12 +13074,12 @@ class PartialEvaluator { } extractWidths(dict, descriptor, properties) { - var xref = this.xref; - var glyphsWidths = []; - var defaultWidth = 0; - var glyphsVMetrics = []; - var defaultVMetrics; - var i, ii, j, jj, start, code, widths; + const xref = this.xref; + let glyphsWidths = []; + let defaultWidth = 0; + const glyphsVMetrics = []; + let defaultVMetrics; + let i, ii, j, jj, start, code, widths; if (properties.composite) { defaultWidth = dict.has("DW") ? dict.get("DW") : 1000; @@ -24130,7 +13095,7 @@ class PartialEvaluator { glyphsWidths[start++] = xref.fetchIfRef(code[j]); } } else { - var width = xref.fetchIfRef(widths[++i]); + const width = xref.fetchIfRef(widths[++i]); for (j = start; j <= code; j++) { glyphsWidths[j] = width; @@ -24140,7 +13105,7 @@ class PartialEvaluator { } if (properties.vertical) { - var vmetrics = dict.getArray("DW2") || [880, -1000]; + let vmetrics = dict.getArray("DW2") || [880, -1000]; defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]]; vmetrics = dict.get("W2"); @@ -24154,7 +13119,7 @@ class PartialEvaluator { glyphsVMetrics[start++] = [xref.fetchIfRef(code[j++]), xref.fetchIfRef(code[j++]), xref.fetchIfRef(code[j])]; } } else { - var vmetric = [xref.fetchIfRef(vmetrics[++i]), xref.fetchIfRef(vmetrics[++i]), xref.fetchIfRef(vmetrics[++i])]; + const vmetric = [xref.fetchIfRef(vmetrics[++i]), xref.fetchIfRef(vmetrics[++i]), xref.fetchIfRef(vmetrics[++i])]; for (j = start; j <= code; j++) { glyphsVMetrics[j] = vmetric; @@ -24164,7 +13129,7 @@ class PartialEvaluator { } } } else { - var firstChar = properties.firstChar; + const firstChar = properties.firstChar; widths = dict.get("Widths"); if (widths) { @@ -24176,21 +13141,21 @@ class PartialEvaluator { defaultWidth = parseFloat(descriptor.get("MissingWidth")) || 0; } else { - var baseFontName = dict.get("BaseFont"); + const baseFontName = dict.get("BaseFont"); - if ((0, _primitives.isName)(baseFontName)) { - var metrics = this.getBaseFontMetrics(baseFontName.name); + if (baseFontName instanceof _primitives.Name) { + const metrics = this.getBaseFontMetrics(baseFontName.name); glyphsWidths = this.buildCharCodeToWidth(metrics.widths, properties); defaultWidth = metrics.defaultWidth; } } } - var isMonospace = true; - var firstWidth = defaultWidth; + let isMonospace = true; + let firstWidth = defaultWidth; - for (var glyph in glyphsWidths) { - var glyphWidth = glyphsWidths[glyph]; + for (const glyph in glyphsWidths) { + const glyphWidth = glyphsWidths[glyph]; if (!glyphWidth) { continue; @@ -24208,7 +13173,7 @@ class PartialEvaluator { } if (isMonospace) { - properties.flags |= _fonts.FontFlags.FixedPitch; + properties.flags |= _fonts_utils.FontFlags.FixedPitch; } properties.defaultWidth = defaultWidth; @@ -24218,17 +13183,17 @@ class PartialEvaluator { } isSerifFont(baseFontName) { - var fontNameWoStyle = baseFontName.split("-")[0]; + const fontNameWoStyle = baseFontName.split("-")[0]; return fontNameWoStyle in (0, _standard_fonts.getSerifFonts)() || fontNameWoStyle.search(/serif/gi) !== -1; } getBaseFontMetrics(name) { - var defaultWidth = 0; - var widths = []; - var monospace = false; - var stdFontMap = (0, _standard_fonts.getStdFontMap)(); - var lookupName = stdFontMap[name] || name; - var Metrics = (0, _metrics.getMetrics)(); + let defaultWidth = 0; + let widths = Object.create(null); + let monospace = false; + const stdFontMap = (0, _standard_fonts.getStdFontMap)(); + let lookupName = stdFontMap[name] || name; + const Metrics = (0, _metrics.getMetrics)(); if (!(lookupName in Metrics)) { if (this.isSerifFont(name)) { @@ -24238,9 +13203,9 @@ class PartialEvaluator { } } - var glyphWidths = Metrics[lookupName]; + const glyphWidths = Metrics[lookupName]; - if ((0, _util.isNum)(glyphWidths)) { + if (typeof glyphWidths === "number") { defaultWidth = glyphWidths; monospace = true; } else { @@ -24255,11 +13220,11 @@ class PartialEvaluator { } buildCharCodeToWidth(widthsByGlyphName, properties) { - var widths = Object.create(null); - var differences = properties.differences; - var encoding = properties.defaultEncoding; + const widths = Object.create(null); + const differences = properties.differences; + const encoding = properties.defaultEncoding; - for (var charCode = 0; charCode < 256; charCode++) { + for (let charCode = 0; charCode < 256; charCode++) { if (charCode in differences && widthsByGlyphName[differences[charCode]]) { widths[charCode] = widthsByGlyphName[differences[charCode]]; continue; @@ -24275,59 +13240,66 @@ class PartialEvaluator { } preEvaluateFont(dict) { - var baseDict = dict; - var type = dict.get("Subtype"); + const baseDict = dict; + let type = dict.get("Subtype"); - if (!(0, _primitives.isName)(type)) { + if (!(type instanceof _primitives.Name)) { throw new _util.FormatError("invalid font Subtype"); } - var composite = false; - var uint8array; + let composite = false; + let hash, toUnicode; if (type.name === "Type0") { - var df = dict.get("DescendantFonts"); + const df = dict.get("DescendantFonts"); if (!df) { throw new _util.FormatError("Descendant fonts are not specified"); } dict = Array.isArray(df) ? this.xref.fetchIfRef(df[0]) : df; + + if (!(dict instanceof _primitives.Dict)) { + throw new _util.FormatError("Descendant font is not a dictionary."); + } + type = dict.get("Subtype"); - if (!(0, _primitives.isName)(type)) { + if (!(type instanceof _primitives.Name)) { throw new _util.FormatError("invalid font Subtype"); } composite = true; } - var descriptor = dict.get("FontDescriptor"); + const firstChar = dict.get("FirstChar") || 0, + lastChar = dict.get("LastChar") || (composite ? 0xffff : 0xff); + const descriptor = dict.get("FontDescriptor"); if (descriptor) { - var hash = new _murmurhash.MurmurHash3_64(); - var encoding = baseDict.getRaw("Encoding"); + hash = new _murmurhash.MurmurHash3_64(); + const encoding = baseDict.getRaw("Encoding"); - if ((0, _primitives.isName)(encoding)) { + if (encoding instanceof _primitives.Name) { hash.update(encoding.name); - } else if ((0, _primitives.isRef)(encoding)) { + } else if (encoding instanceof _primitives.Ref) { hash.update(encoding.toString()); - } else if ((0, _primitives.isDict)(encoding)) { + } else if (encoding instanceof _primitives.Dict) { for (const entry of encoding.getRawValues()) { - if ((0, _primitives.isName)(entry)) { + if (entry instanceof _primitives.Name) { hash.update(entry.name); - } else if ((0, _primitives.isRef)(entry)) { + } else if (entry instanceof _primitives.Ref) { hash.update(entry.toString()); } else if (Array.isArray(entry)) { - var diffLength = entry.length, - diffBuf = new Array(diffLength); + const diffLength = entry.length, + diffBuf = new Array(diffLength); - for (var j = 0; j < diffLength; j++) { - var diffEntry = entry[j]; + for (let j = 0; j < diffLength; j++) { + const diffEntry = entry[j]; - if ((0, _primitives.isName)(diffEntry)) { + if (diffEntry instanceof _primitives.Name) { diffBuf[j] = diffEntry.name; - } else if ((0, _util.isNum)(diffEntry) || (0, _primitives.isRef)(diffEntry)) { + } else if (typeof diffEntry === "number" || diffEntry instanceof _primitives.Ref) { diffBuf[j] = diffEntry.toString(); } } @@ -24337,24 +13309,66 @@ class PartialEvaluator { } } - const firstChar = dict.get("FirstChar") || 0; - const lastChar = dict.get("LastChar") || (composite ? 0xffff : 0xff); hash.update(`${firstChar}-${lastChar}`); - var toUnicode = dict.get("ToUnicode") || baseDict.get("ToUnicode"); + toUnicode = dict.get("ToUnicode") || baseDict.get("ToUnicode"); - if ((0, _primitives.isStream)(toUnicode)) { - var stream = toUnicode.str || toUnicode; - uint8array = stream.buffer ? new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) : new Uint8Array(stream.bytes.buffer, stream.start, stream.end - stream.start); + if (toUnicode instanceof _base_stream.BaseStream) { + const stream = toUnicode.str || toUnicode; + const uint8array = stream.buffer ? new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) : new Uint8Array(stream.bytes.buffer, stream.start, stream.end - stream.start); hash.update(uint8array); - } else if ((0, _primitives.isName)(toUnicode)) { + } else if (toUnicode instanceof _primitives.Name) { hash.update(toUnicode.name); } - var widths = dict.get("Widths") || baseDict.get("Widths"); + const widths = dict.get("Widths") || baseDict.get("Widths"); - if (widths) { - uint8array = new Uint8Array(new Uint32Array(widths).buffer); - hash.update(uint8array); + if (Array.isArray(widths)) { + const widthsBuf = []; + + for (const entry of widths) { + if (typeof entry === "number" || entry instanceof _primitives.Ref) { + widthsBuf.push(entry.toString()); + } + } + + hash.update(widthsBuf.join()); + } + + if (composite) { + hash.update("compositeFont"); + const compositeWidths = dict.get("W") || baseDict.get("W"); + + if (Array.isArray(compositeWidths)) { + const widthsBuf = []; + + for (const entry of compositeWidths) { + if (typeof entry === "number" || entry instanceof _primitives.Ref) { + widthsBuf.push(entry.toString()); + } else if (Array.isArray(entry)) { + const subWidthsBuf = []; + + for (const element of entry) { + if (typeof element === "number" || element instanceof _primitives.Ref) { + subWidthsBuf.push(element.toString()); + } + } + + widthsBuf.push(`[${subWidthsBuf.join()}]`); + } + } + + hash.update(widthsBuf.join()); + } + + const cidToGidMap = dict.getRaw("CIDToGIDMap") || baseDict.getRaw("CIDToGIDMap"); + + if (cidToGidMap instanceof _primitives.Name) { + hash.update(cidToGidMap.name); + } else if (cidToGidMap instanceof _primitives.Ref) { + hash.update(cidToGidMap.toString()); + } else if (cidToGidMap instanceof _base_stream.BaseStream) { + hash.update(cidToGidMap.peekBytes()); + } } } @@ -24364,47 +13378,69 @@ class PartialEvaluator { baseDict, composite, type: type.name, + firstChar, + lastChar, + toUnicode, hash: hash ? hash.hexdigest() : "" }; } - translateFont(preEvaluatedFont) { - var baseDict = preEvaluatedFont.baseDict; - var dict = preEvaluatedFont.dict; - var composite = preEvaluatedFont.composite; - var descriptor = preEvaluatedFont.descriptor; - var type = preEvaluatedFont.type; - var maxCharIndex = composite ? 0xffff : 0xff; - var properties; - const firstChar = dict.get("FirstChar") || 0; - const lastChar = dict.get("LastChar") || maxCharIndex; + async translateFont({ + descriptor, + dict, + baseDict, + composite, + type, + firstChar, + lastChar, + toUnicode, + cssFontInfo + }) { + const isType3Font = type === "Type3"; + let properties; if (!descriptor) { - if (type === "Type3") { + if (isType3Font) { descriptor = new _primitives.Dict(null); descriptor.set("FontName", _primitives.Name.get(type)); descriptor.set("FontBBox", dict.getArray("FontBBox") || [0, 0, 0, 0]); } else { - var baseFontName = dict.get("BaseFont"); + let baseFontName = dict.get("BaseFont"); - if (!(0, _primitives.isName)(baseFontName)) { + if (!(baseFontName instanceof _primitives.Name)) { throw new _util.FormatError("Base font is not specified"); } baseFontName = baseFontName.name.replace(/[,_]/g, "-"); - var metrics = this.getBaseFontMetrics(baseFontName); - var fontNameWoStyle = baseFontName.split("-")[0]; - var flags = (this.isSerifFont(fontNameWoStyle) ? _fonts.FontFlags.Serif : 0) | (metrics.monospace ? _fonts.FontFlags.FixedPitch : 0) | ((0, _standard_fonts.getSymbolsFonts)()[fontNameWoStyle] ? _fonts.FontFlags.Symbolic : _fonts.FontFlags.Nonsymbolic); + const metrics = this.getBaseFontMetrics(baseFontName); + const fontNameWoStyle = baseFontName.split("-")[0]; + const flags = (this.isSerifFont(fontNameWoStyle) ? _fonts_utils.FontFlags.Serif : 0) | (metrics.monospace ? _fonts_utils.FontFlags.FixedPitch : 0) | ((0, _standard_fonts.getSymbolsFonts)()[fontNameWoStyle] ? _fonts_utils.FontFlags.Symbolic : _fonts_utils.FontFlags.Nonsymbolic); properties = { type, name: baseFontName, + loadedName: baseDict.loadedName, widths: metrics.widths, defaultWidth: metrics.defaultWidth, + isSimulatedFlags: true, flags, firstChar, - lastChar + lastChar, + toUnicode, + xHeight: 0, + capHeight: 0, + italicAngle: 0, + isType3Font }; const widths = dict.get("Widths"); + const standardFontName = (0, _standard_fonts.getStandardFontName)(baseFontName); + let file = null; + + if (standardFontName) { + properties.isStandardFont = true; + file = await this.fetchStandardFontData(standardFontName); + properties.isInternalFont = !!file; + } + return this.extractDataStructures(dict, dict, properties).then(newProperties => { if (widths) { const glyphWidths = []; @@ -24419,28 +13455,28 @@ class PartialEvaluator { newProperties.widths = this.buildCharCodeToWidth(metrics.widths, newProperties); } - return new _fonts.Font(baseFontName, null, newProperties); + return new _fonts.Font(baseFontName, file, newProperties); }); } } - var fontName = descriptor.get("FontName"); - var baseFont = dict.get("BaseFont"); + let fontName = descriptor.get("FontName"); + let baseFont = dict.get("BaseFont"); - if ((0, _util.isString)(fontName)) { + if (typeof fontName === "string") { fontName = _primitives.Name.get(fontName); } - if ((0, _util.isString)(baseFont)) { + if (typeof baseFont === "string") { baseFont = _primitives.Name.get(baseFont); } - if (type !== "Type3") { - var fontNameStr = fontName && fontName.name; - var baseFontStr = baseFont && baseFont.name; + if (!isType3Font) { + const fontNameStr = fontName && fontName.name; + const baseFontStr = baseFont && baseFont.name; if (fontNameStr !== baseFontStr) { - (0, _util.info)(`The FontDescriptor\'s FontName is "${fontNameStr}" but ` + `should be the same as the Font\'s BaseFont "${baseFontStr}".`); + (0, _util.info)(`The FontDescriptor's FontName is "${fontNameStr}" but ` + `should be the same as the Font's BaseFont "${baseFontStr}".`); if (fontNameStr && baseFontStr && baseFontStr.startsWith(fontNameStr)) { fontName = baseFont; @@ -24450,23 +13486,58 @@ class PartialEvaluator { fontName = fontName || baseFont; - if (!(0, _primitives.isName)(fontName)) { + if (!(fontName instanceof _primitives.Name)) { throw new _util.FormatError("invalid font name"); } - var fontFile = descriptor.get("FontFile", "FontFile2", "FontFile3"); + let fontFile, subtype, length1, length2, length3; + + try { + fontFile = descriptor.get("FontFile", "FontFile2", "FontFile3"); + } catch (ex) { + if (!this.options.ignoreErrors) { + throw ex; + } + + (0, _util.warn)(`translateFont - fetching "${fontName.name}" font file: "${ex}".`); + fontFile = new _stream.NullStream(); + } + + let isStandardFont = false; + let isInternalFont = false; + let glyphScaleFactors = null; if (fontFile) { if (fontFile.dict) { - var subtype = fontFile.dict.get("Subtype"); + const subtypeEntry = fontFile.dict.get("Subtype"); - if (subtype) { - subtype = subtype.name; + if (subtypeEntry instanceof _primitives.Name) { + subtype = subtypeEntry.name; } - var length1 = fontFile.dict.get("Length1"); - var length2 = fontFile.dict.get("Length2"); - var length3 = fontFile.dict.get("Length3"); + length1 = fontFile.dict.get("Length1"); + length2 = fontFile.dict.get("Length2"); + length3 = fontFile.dict.get("Length3"); + } + } else if (cssFontInfo) { + const standardFontName = (0, _xfa_fonts.getXfaFontName)(fontName.name); + + if (standardFontName) { + cssFontInfo.fontFamily = `${cssFontInfo.fontFamily}-PdfJS-XFA`; + cssFontInfo.metrics = standardFontName.metrics || null; + glyphScaleFactors = standardFontName.factors || null; + fontFile = await this.fetchStandardFontData(standardFontName.name); + isInternalFont = !!fontFile; + baseDict = dict = (0, _xfa_fonts.getXfaFontDict)(fontName.name); + composite = true; + } + } else if (!isType3Font) { + const standardFontName = (0, _standard_fonts.getStandardFontName)(fontName.name); + + if (standardFontName) { + isStandardFont = true; + fontFile = await this.fetchStandardFontData(standardFontName); + isInternalFont = !!fontFile; } } @@ -24478,62 +13549,70 @@ class PartialEvaluator { length1, length2, length3, + isStandardFont, + isInternalFont, loadedName: baseDict.loadedName, composite, fixedPitch: false, fontMatrix: dict.getArray("FontMatrix") || _util.FONT_IDENTITY_MATRIX, - firstChar: firstChar || 0, - lastChar: lastChar || maxCharIndex, - bbox: descriptor.getArray("FontBBox"), + firstChar, + lastChar, + toUnicode, + bbox: descriptor.getArray("FontBBox") || dict.getArray("FontBBox"), ascent: descriptor.get("Ascent"), descent: descriptor.get("Descent"), - xHeight: descriptor.get("XHeight"), - capHeight: descriptor.get("CapHeight"), + xHeight: descriptor.get("XHeight") || 0, + capHeight: descriptor.get("CapHeight") || 0, flags: descriptor.get("Flags"), - italicAngle: descriptor.get("ItalicAngle"), - isType3Font: false + italicAngle: descriptor.get("ItalicAngle") || 0, + isType3Font, + cssFontInfo, + scaleFactors: glyphScaleFactors }; - var cMapPromise; if (composite) { - var cidEncoding = baseDict.get("Encoding"); + const cidEncoding = baseDict.get("Encoding"); - if ((0, _primitives.isName)(cidEncoding)) { + if (cidEncoding instanceof _primitives.Name) { properties.cidEncoding = cidEncoding.name; } - cMapPromise = _cmap.CMapFactory.create({ + const cMap = await _cmap.CMapFactory.create({ encoding: cidEncoding, fetchBuiltInCMap: this._fetchBuiltInCMapBound, useCMap: null - }).then(function (cMap) { - properties.cMap = cMap; - properties.vertical = properties.cMap.vertical; }); - } else { - cMapPromise = Promise.resolve(undefined); + properties.cMap = cMap; + properties.vertical = properties.cMap.vertical; } - return cMapPromise.then(() => { - return this.extractDataStructures(dict, baseDict, properties); - }).then(newProperties => { + return this.extractDataStructures(dict, baseDict, properties).then(newProperties => { this.extractWidths(dict, descriptor, newProperties); - - if (type === "Type3") { - newProperties.isType3Font = true; - } - return new _fonts.Font(fontName.name, fontFile, newProperties); }); } - static buildFontPaths(font, glyphs, handler) { + static buildFontPaths(font, glyphs, handler, evaluatorOptions) { function buildPath(fontChar) { - if (font.renderer.hasBuiltPath(fontChar)) { - return; - } + const glyphName = `${font.loadedName}_path_${fontChar}`; - handler.send("commonobj", [`${font.loadedName}_path_${fontChar}`, "FontPath", font.renderer.getPathJs(fontChar)]); + try { + if (font.renderer.hasBuiltPath(fontChar)) { + return; + } + + handler.send("commonobj", [glyphName, "FontPath", font.renderer.getPathJs(fontChar)]); + } catch (reason) { + if (evaluatorOptions.ignoreErrors) { + handler.send("UnsupportedFeature", { + featureId: _util.UNSUPPORTED_FEATURES.errorFontBuildPath + }); + (0, _util.warn)(`buildFontPaths - ignoring ${glyphName} glyph: "${reason}".`); + return; + } + + throw reason; + } } for (const glyph of glyphs) { @@ -24564,12 +13643,12 @@ class TranslatedFont { loadedName, font, dict, - extraProperties = false + evaluatorOptions }) { this.loadedName = loadedName; this.font = font; this.dict = dict; - this._extraProperties = extraProperties; + this._evaluatorOptions = evaluatorOptions || DefaultPartialEvaluatorOptions; this.type3Loaded = null; this.type3Dependencies = font.isType3Font ? new Set() : null; this.sent = false; @@ -24581,7 +13660,7 @@ class TranslatedFont { } this.sent = true; - handler.send("commonobj", [this.loadedName, "Font", this.font.exportData(this._extraProperties)]); + handler.send("commonobj", [this.loadedName, "Font", this.font.exportData(this._evaluatorOptions.fontExtraProperties)]); } fallback(handler) { @@ -24590,8 +13669,7 @@ class TranslatedFont { } this.font.disableFontFace = true; - const glyphs = this.font.glyphCacheValues; - PartialEvaluator.buildFontPaths(this.font, glyphs, handler); + PartialEvaluator.buildFontPaths(this.font, this.font.glyphCacheValues, handler, this._evaluatorOptions); } loadType3Data(evaluator, resources, task) { @@ -24603,27 +13681,44 @@ class TranslatedFont { throw new Error("Must be a Type3 font."); } - var type3Options = Object.create(evaluator.options); - type3Options.ignoreErrors = false; - var type3Evaluator = evaluator.clone(type3Options); + const type3Evaluator = evaluator.clone({ + ignoreErrors: false + }); type3Evaluator.parsingType3Font = true; + const type3FontRefs = new _primitives.RefSet(evaluator.type3FontRefs); + + if (this.dict.objId && !type3FontRefs.has(this.dict.objId)) { + type3FontRefs.put(this.dict.objId); + } + + type3Evaluator.type3FontRefs = type3FontRefs; const translatedFont = this.font, type3Dependencies = this.type3Dependencies; - var loadCharProcsPromise = Promise.resolve(); - var charProcs = this.dict.get("CharProcs"); - var fontResources = this.dict.get("Resources") || resources; - var charProcOperatorList = Object.create(null); + let loadCharProcsPromise = Promise.resolve(); + const charProcs = this.dict.get("CharProcs"); + const fontResources = this.dict.get("Resources") || resources; + const charProcOperatorList = Object.create(null); + + const fontBBox = _util.Util.normalizeRect(translatedFont.bbox || [0, 0, 0, 0]), + width = fontBBox[2] - fontBBox[0], + height = fontBBox[3] - fontBBox[1]; + + const fontBBoxSize = Math.hypot(width, height); for (const key of charProcs.getKeys()) { - loadCharProcsPromise = loadCharProcsPromise.then(function () { - var glyphStream = charProcs.get(key); - var operatorList = new _operator_list.OperatorList(); + loadCharProcsPromise = loadCharProcsPromise.then(() => { + const glyphStream = charProcs.get(key); + const operatorList = new _operator_list.OperatorList(); return type3Evaluator.getOperatorList({ stream: glyphStream, task, resources: fontResources, operatorList - }).then(function () { + }).then(() => { + if (operatorList.fnArray[0] === _util.OPS.setCharWidthAndBounds) { + this._removeType3ColorOperators(operatorList, fontBBoxSize); + } + charProcOperatorList[key] = operatorList.getIR(); for (const dependency of operatorList.dependencies) { @@ -24637,28 +13732,112 @@ class TranslatedFont { }); } - this.type3Loaded = loadCharProcsPromise.then(function () { + this.type3Loaded = loadCharProcsPromise.then(() => { translatedFont.charProcOperatorList = charProcOperatorList; + + if (this._bbox) { + translatedFont.isCharBBox = true; + translatedFont.bbox = this._bbox; + } }); return this.type3Loaded; } + _removeType3ColorOperators(operatorList, fontBBoxSize = NaN) { + const charBBox = _util.Util.normalizeRect(operatorList.argsArray[0].slice(2)), + width = charBBox[2] - charBBox[0], + height = charBBox[3] - charBBox[1]; + + const charBBoxSize = Math.hypot(width, height); + + if (width === 0 || height === 0) { + operatorList.fnArray.splice(0, 1); + operatorList.argsArray.splice(0, 1); + } else if (fontBBoxSize === 0 || Math.round(charBBoxSize / fontBBoxSize) >= 10) { + if (!this._bbox) { + this._bbox = [Infinity, Infinity, -Infinity, -Infinity]; + } + + this._bbox[0] = Math.min(this._bbox[0], charBBox[0]); + this._bbox[1] = Math.min(this._bbox[1], charBBox[1]); + this._bbox[2] = Math.max(this._bbox[2], charBBox[2]); + this._bbox[3] = Math.max(this._bbox[3], charBBox[3]); + } + + let i = 0, + ii = operatorList.length; + + while (i < ii) { + switch (operatorList.fnArray[i]) { + case _util.OPS.setCharWidthAndBounds: + break; + + case _util.OPS.setStrokeColorSpace: + case _util.OPS.setFillColorSpace: + case _util.OPS.setStrokeColor: + case _util.OPS.setStrokeColorN: + case _util.OPS.setFillColor: + case _util.OPS.setFillColorN: + case _util.OPS.setStrokeGray: + case _util.OPS.setFillGray: + case _util.OPS.setStrokeRGBColor: + case _util.OPS.setFillRGBColor: + case _util.OPS.setStrokeCMYKColor: + case _util.OPS.setFillCMYKColor: + case _util.OPS.shadingFill: + case _util.OPS.setRenderingIntent: + operatorList.fnArray.splice(i, 1); + operatorList.argsArray.splice(i, 1); + ii--; + continue; + + case _util.OPS.setGState: + const [gStateObj] = operatorList.argsArray[i]; + let j = 0, + jj = gStateObj.length; + + while (j < jj) { + const [gStateKey] = gStateObj[j]; + + switch (gStateKey) { + case "TR": + case "TR2": + case "HT": + case "BG": + case "BG2": + case "UCR": + case "UCR2": + gStateObj.splice(j, 1); + jj--; + continue; + } + + j++; + } + + break; + } + + i++; + } + } + } class StateManager { - constructor(initialState) { + constructor(initialState = new EvalState()) { this.state = initialState; this.stateStack = []; } save() { - var old = this.state; + const old = this.state; this.stateStack.push(this.state); this.state = old.clone(); } restore() { - var prev = this.stateStack.pop(); + const prev = this.stateStack.pop(); if (prev) { this.state = prev; @@ -24688,7 +13867,7 @@ class TextState { } setTextMatrix(a, b, c, d, e, f) { - var m = this.textMatrix; + const m = this.textMatrix; m[0] = a; m[1] = b; m[2] = c; @@ -24698,7 +13877,7 @@ class TextState { } setTextLineMatrix(a, b, c, d, e, f) { - var m = this.textLineMatrix; + const m = this.textLineMatrix; m[0] = a; m[1] = b; m[2] = c; @@ -24708,68 +13887,24 @@ class TextState { } translateTextMatrix(x, y) { - var m = this.textMatrix; + const m = this.textMatrix; m[4] = m[0] * x + m[2] * y + m[4]; m[5] = m[1] * x + m[3] * y + m[5]; } translateTextLineMatrix(x, y) { - var m = this.textLineMatrix; + const m = this.textLineMatrix; m[4] = m[0] * x + m[2] * y + m[4]; m[5] = m[1] * x + m[3] * y + m[5]; } - calcTextLineMatrixAdvance(a, b, c, d, e, f) { - var font = this.font; - - if (!font) { - return null; - } - - var m = this.textLineMatrix; - - if (!(a === m[0] && b === m[1] && c === m[2] && d === m[3])) { - return null; - } - - var txDiff = e - m[4], - tyDiff = f - m[5]; - - if (font.vertical && txDiff !== 0 || !font.vertical && tyDiff !== 0) { - return null; - } - - var tx, - ty, - denominator = a * d - b * c; - - if (font.vertical) { - tx = -tyDiff * c / denominator; - ty = tyDiff * a / denominator; - } else { - tx = txDiff * d / denominator; - ty = -txDiff * b / denominator; - } - - return { - width: tx, - height: ty, - value: font.vertical ? ty : tx - }; - } - - calcRenderMatrix(ctm) { - var tsm = [this.fontSize * this.textHScale, 0, 0, this.fontSize, 0, this.textRise]; - return _util.Util.transform(ctm, _util.Util.transform(this.textMatrix, tsm)); - } - carriageReturn() { this.translateTextLineMatrix(0, -this.leading); this.textMatrix = this.textLineMatrix.slice(); } clone() { - var clone = Object.create(this); + const clone = Object.create(this); clone.textMatrix = this.textMatrix.slice(); clone.textLineMatrix = this.textLineMatrix.slice(); clone.fontMatrix = this.fontMatrix.slice(); @@ -25176,16 +14311,17 @@ class EvaluatorPreprocessor { } static get MAX_INVALID_PATH_OPS() { - return (0, _util.shadow)(this, "MAX_INVALID_PATH_OPS", 20); + return (0, _util.shadow)(this, "MAX_INVALID_PATH_OPS", 10); } - constructor(stream, xref, stateManager) { + constructor(stream, xref, stateManager = new StateManager()) { this.parser = new _parser.Parser({ lexer: new _parser.Lexer(stream, EvaluatorPreprocessor.opMap), xref }); this.stateManager = stateManager; this.nonProcessedArgs = []; + this._isPathOp = false; this._numInvalidPathOPS = 0; } @@ -25194,27 +14330,33 @@ class EvaluatorPreprocessor { } read(operation) { - var args = operation.args; + let args = operation.args; while (true) { - var obj = this.parser.getObj(); + const obj = this.parser.getObj(); if (obj instanceof _primitives.Cmd) { - var cmd = obj.cmd; - var opSpec = EvaluatorPreprocessor.opMap[cmd]; + const cmd = obj.cmd; + const opSpec = EvaluatorPreprocessor.opMap[cmd]; if (!opSpec) { (0, _util.warn)(`Unknown command "${cmd}".`); continue; } - var fn = opSpec.id; - var numArgs = opSpec.numArgs; - var argsLength = args !== null ? args.length : 0; + const fn = opSpec.id; + const numArgs = opSpec.numArgs; + let argsLength = args !== null ? args.length : 0; + + if (!this._isPathOp) { + this._numInvalidPathOPS = 0; + } + + this._isPathOp = fn >= _util.OPS.moveTo && fn <= _util.OPS.endPath; if (!opSpec.variableArgs) { if (argsLength !== numArgs) { - var nonProcessedArgs = this.nonProcessedArgs; + const nonProcessedArgs = this.nonProcessedArgs; while (argsLength > numArgs) { nonProcessedArgs.push(args.shift()); @@ -25234,7 +14376,7 @@ class EvaluatorPreprocessor { if (argsLength < numArgs) { const partialMsg = `command ${cmd}: expected ${numArgs} args, ` + `but received ${argsLength} args.`; - if (fn >= _util.OPS.moveTo && fn <= _util.OPS.endPath && ++this._numInvalidPathOPS > EvaluatorPreprocessor.MAX_INVALID_PATH_OPS) { + if (this._isPathOp && ++this._numInvalidPathOPS > EvaluatorPreprocessor.MAX_INVALID_PATH_OPS) { throw new _util.FormatError(`Invalid ${partialMsg}`); } @@ -25292,29 +14434,32 @@ class EvaluatorPreprocessor { } +exports.EvaluatorPreprocessor = EvaluatorPreprocessor; + /***/ }), -/* 29 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 16 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.CMapFactory = exports.IdentityCMap = exports.CMap = void 0; +})); +exports.IdentityCMap = exports.CMapFactory = exports.CMap = void 0; var _util = __w_pdfjs_require__(2); var _primitives = __w_pdfjs_require__(5); -var _parser = __w_pdfjs_require__(11); +var _base_stream = __w_pdfjs_require__(7); -var _core_utils = __w_pdfjs_require__(8); +var _parser = __w_pdfjs_require__(17); -var _stream = __w_pdfjs_require__(12); +var _core_utils = __w_pdfjs_require__(6); -var BUILT_IN_CMAPS = ["Adobe-GB1-UCS2", "Adobe-CNS1-UCS2", "Adobe-Japan1-UCS2", "Adobe-Korea1-UCS2", "78-EUC-H", "78-EUC-V", "78-H", "78-RKSJ-H", "78-RKSJ-V", "78-V", "78ms-RKSJ-H", "78ms-RKSJ-V", "83pv-RKSJ-H", "90ms-RKSJ-H", "90ms-RKSJ-V", "90msp-RKSJ-H", "90msp-RKSJ-V", "90pv-RKSJ-H", "90pv-RKSJ-V", "Add-H", "Add-RKSJ-H", "Add-RKSJ-V", "Add-V", "Adobe-CNS1-0", "Adobe-CNS1-1", "Adobe-CNS1-2", "Adobe-CNS1-3", "Adobe-CNS1-4", "Adobe-CNS1-5", "Adobe-CNS1-6", "Adobe-GB1-0", "Adobe-GB1-1", "Adobe-GB1-2", "Adobe-GB1-3", "Adobe-GB1-4", "Adobe-GB1-5", "Adobe-Japan1-0", "Adobe-Japan1-1", "Adobe-Japan1-2", "Adobe-Japan1-3", "Adobe-Japan1-4", "Adobe-Japan1-5", "Adobe-Japan1-6", "Adobe-Korea1-0", "Adobe-Korea1-1", "Adobe-Korea1-2", "B5-H", "B5-V", "B5pc-H", "B5pc-V", "CNS-EUC-H", "CNS-EUC-V", "CNS1-H", "CNS1-V", "CNS2-H", "CNS2-V", "ETHK-B5-H", "ETHK-B5-V", "ETen-B5-H", "ETen-B5-V", "ETenms-B5-H", "ETenms-B5-V", "EUC-H", "EUC-V", "Ext-H", "Ext-RKSJ-H", "Ext-RKSJ-V", "Ext-V", "GB-EUC-H", "GB-EUC-V", "GB-H", "GB-V", "GBK-EUC-H", "GBK-EUC-V", "GBK2K-H", "GBK2K-V", "GBKp-EUC-H", "GBKp-EUC-V", "GBT-EUC-H", "GBT-EUC-V", "GBT-H", "GBT-V", "GBTpc-EUC-H", "GBTpc-EUC-V", "GBpc-EUC-H", "GBpc-EUC-V", "H", "HKdla-B5-H", "HKdla-B5-V", "HKdlb-B5-H", "HKdlb-B5-V", "HKgccs-B5-H", "HKgccs-B5-V", "HKm314-B5-H", "HKm314-B5-V", "HKm471-B5-H", "HKm471-B5-V", "HKscs-B5-H", "HKscs-B5-V", "Hankaku", "Hiragana", "KSC-EUC-H", "KSC-EUC-V", "KSC-H", "KSC-Johab-H", "KSC-Johab-V", "KSC-V", "KSCms-UHC-H", "KSCms-UHC-HW-H", "KSCms-UHC-HW-V", "KSCms-UHC-V", "KSCpc-EUC-H", "KSCpc-EUC-V", "Katakana", "NWP-H", "NWP-V", "RKSJ-H", "RKSJ-V", "Roman", "UniCNS-UCS2-H", "UniCNS-UCS2-V", "UniCNS-UTF16-H", "UniCNS-UTF16-V", "UniCNS-UTF32-H", "UniCNS-UTF32-V", "UniCNS-UTF8-H", "UniCNS-UTF8-V", "UniGB-UCS2-H", "UniGB-UCS2-V", "UniGB-UTF16-H", "UniGB-UTF16-V", "UniGB-UTF32-H", "UniGB-UTF32-V", "UniGB-UTF8-H", "UniGB-UTF8-V", "UniJIS-UCS2-H", "UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V", "UniJIS-UCS2-V", "UniJIS-UTF16-H", "UniJIS-UTF16-V", "UniJIS-UTF32-H", "UniJIS-UTF32-V", "UniJIS-UTF8-H", "UniJIS-UTF8-V", "UniJIS2004-UTF16-H", "UniJIS2004-UTF16-V", "UniJIS2004-UTF32-H", "UniJIS2004-UTF32-V", "UniJIS2004-UTF8-H", "UniJIS2004-UTF8-V", "UniJISPro-UCS2-HW-V", "UniJISPro-UCS2-V", "UniJISPro-UTF8-V", "UniJISX0213-UTF32-H", "UniJISX0213-UTF32-V", "UniJISX02132004-UTF32-H", "UniJISX02132004-UTF32-V", "UniKS-UCS2-H", "UniKS-UCS2-V", "UniKS-UTF16-H", "UniKS-UTF16-V", "UniKS-UTF32-H", "UniKS-UTF32-V", "UniKS-UTF8-H", "UniKS-UTF8-V", "V", "WP-Symbol"]; +var _stream = __w_pdfjs_require__(10); + +const BUILT_IN_CMAPS = ["Adobe-GB1-UCS2", "Adobe-CNS1-UCS2", "Adobe-Japan1-UCS2", "Adobe-Korea1-UCS2", "78-EUC-H", "78-EUC-V", "78-H", "78-RKSJ-H", "78-RKSJ-V", "78-V", "78ms-RKSJ-H", "78ms-RKSJ-V", "83pv-RKSJ-H", "90ms-RKSJ-H", "90ms-RKSJ-V", "90msp-RKSJ-H", "90msp-RKSJ-V", "90pv-RKSJ-H", "90pv-RKSJ-V", "Add-H", "Add-RKSJ-H", "Add-RKSJ-V", "Add-V", "Adobe-CNS1-0", "Adobe-CNS1-1", "Adobe-CNS1-2", "Adobe-CNS1-3", "Adobe-CNS1-4", "Adobe-CNS1-5", "Adobe-CNS1-6", "Adobe-GB1-0", "Adobe-GB1-1", "Adobe-GB1-2", "Adobe-GB1-3", "Adobe-GB1-4", "Adobe-GB1-5", "Adobe-Japan1-0", "Adobe-Japan1-1", "Adobe-Japan1-2", "Adobe-Japan1-3", "Adobe-Japan1-4", "Adobe-Japan1-5", "Adobe-Japan1-6", "Adobe-Korea1-0", "Adobe-Korea1-1", "Adobe-Korea1-2", "B5-H", "B5-V", "B5pc-H", "B5pc-V", "CNS-EUC-H", "CNS-EUC-V", "CNS1-H", "CNS1-V", "CNS2-H", "CNS2-V", "ETHK-B5-H", "ETHK-B5-V", "ETen-B5-H", "ETen-B5-V", "ETenms-B5-H", "ETenms-B5-V", "EUC-H", "EUC-V", "Ext-H", "Ext-RKSJ-H", "Ext-RKSJ-V", "Ext-V", "GB-EUC-H", "GB-EUC-V", "GB-H", "GB-V", "GBK-EUC-H", "GBK-EUC-V", "GBK2K-H", "GBK2K-V", "GBKp-EUC-H", "GBKp-EUC-V", "GBT-EUC-H", "GBT-EUC-V", "GBT-H", "GBT-V", "GBTpc-EUC-H", "GBTpc-EUC-V", "GBpc-EUC-H", "GBpc-EUC-V", "H", "HKdla-B5-H", "HKdla-B5-V", "HKdlb-B5-H", "HKdlb-B5-V", "HKgccs-B5-H", "HKgccs-B5-V", "HKm314-B5-H", "HKm314-B5-V", "HKm471-B5-H", "HKm471-B5-V", "HKscs-B5-H", "HKscs-B5-V", "Hankaku", "Hiragana", "KSC-EUC-H", "KSC-EUC-V", "KSC-H", "KSC-Johab-H", "KSC-Johab-V", "KSC-V", "KSCms-UHC-H", "KSCms-UHC-HW-H", "KSCms-UHC-HW-V", "KSCms-UHC-V", "KSCpc-EUC-H", "KSCpc-EUC-V", "Katakana", "NWP-H", "NWP-V", "RKSJ-H", "RKSJ-V", "Roman", "UniCNS-UCS2-H", "UniCNS-UCS2-V", "UniCNS-UTF16-H", "UniCNS-UTF16-V", "UniCNS-UTF32-H", "UniCNS-UTF32-V", "UniCNS-UTF8-H", "UniCNS-UTF8-V", "UniGB-UCS2-H", "UniGB-UCS2-V", "UniGB-UTF16-H", "UniGB-UTF16-V", "UniGB-UTF32-H", "UniGB-UTF32-V", "UniGB-UTF8-H", "UniGB-UTF8-V", "UniJIS-UCS2-H", "UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V", "UniJIS-UCS2-V", "UniJIS-UTF16-H", "UniJIS-UTF16-V", "UniJIS-UTF32-H", "UniJIS-UTF32-V", "UniJIS-UTF8-H", "UniJIS-UTF8-V", "UniJIS2004-UTF16-H", "UniJIS2004-UTF16-V", "UniJIS2004-UTF32-H", "UniJIS2004-UTF32-V", "UniJIS2004-UTF8-H", "UniJIS2004-UTF8-V", "UniJISPro-UCS2-HW-V", "UniJISPro-UCS2-V", "UniJISPro-UTF8-V", "UniJISX0213-UTF32-H", "UniJISX0213-UTF32-V", "UniJISX02132004-UTF32-H", "UniJISX02132004-UTF32-V", "UniKS-UCS2-H", "UniKS-UCS2-V", "UniKS-UTF16-H", "UniKS-UTF16-V", "UniKS-UTF32-H", "UniKS-UTF32-V", "UniKS-UTF8-H", "UniKS-UTF8-V", "V", "WP-Symbol"]; const MAX_MAP_RANGE = 2 ** 24 - 1; class CMap { @@ -25348,11 +14493,18 @@ class CMap { throw new Error("mapBfRange - ignoring data above MAX_MAP_RANGE."); } - var lastByte = dstLow.length - 1; + const lastByte = dstLow.length - 1; while (low <= high) { this._map[low++] = dstLow; - dstLow = dstLow.substring(0, lastByte) + String.fromCharCode(dstLow.charCodeAt(lastByte) + 1); + const nextCharCode = dstLow.charCodeAt(lastByte) + 1; + + if (nextCharCode > 0xff) { + dstLow = dstLow.substring(0, lastByte - 1) + String.fromCharCode(dstLow.charCodeAt(lastByte - 1) + 1) + "\x00"; + continue; + } + + dstLow = dstLow.substring(0, lastByte) + String.fromCharCode(nextCharCode); } } @@ -25443,6 +14595,25 @@ class CMap { out.length = 1; } + getCharCodeLength(charCode) { + const codespaceRanges = this.codespaceRanges; + + for (let n = 0, nn = codespaceRanges.length; n < nn; n++) { + const codespaceRange = codespaceRanges[n]; + + for (let k = 0, kk = codespaceRange.length; k < kk;) { + const low = codespaceRange[k++]; + const high = codespaceRange[k++]; + + if (charCode >= low && charCode <= high) { + return n + 1; + } + } + } + + return 1; + } + get length() { return this._map.length; } @@ -25532,11 +14703,11 @@ class IdentityCMap extends CMap { exports.IdentityCMap = IdentityCMap; -var BinaryCMapReader = function BinaryCMapReaderClosure() { +const BinaryCMapReader = function BinaryCMapReaderClosure() { function hexToInt(a, size) { - var n = 0; + let n = 0; - for (var i = 0; i <= size; i++) { + for (let i = 0; i <= size; i++) { n = n << 8 | a[i]; } @@ -25556,9 +14727,9 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { } function addHex(a, b, size) { - var c = 0; + let c = 0; - for (var i = size; i >= 0; i--) { + for (let i = size; i >= 0; i--) { c += a[i] + b[i]; a[i] = c & 255; c >>= 8; @@ -25566,40 +14737,40 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { } function incHex(a, size) { - var c = 1; + let c = 1; - for (var i = size; i >= 0 && c > 0; i--) { + for (let i = size; i >= 0 && c > 0; i--) { c += a[i]; a[i] = c & 255; c >>= 8; } } - var MAX_NUM_SIZE = 16; - var MAX_ENCODED_NUM_SIZE = 19; + const MAX_NUM_SIZE = 16; + const MAX_ENCODED_NUM_SIZE = 19; - function BinaryCMapStream(data) { - this.buffer = data; - this.pos = 0; - this.end = data.length; - this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE); - } + class BinaryCMapStream { + constructor(data) { + this.buffer = data; + this.pos = 0; + this.end = data.length; + this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE); + } - BinaryCMapStream.prototype = { readByte() { if (this.pos >= this.end) { return -1; } return this.buffer[this.pos++]; - }, + } readNumber() { - var n = 0; - var last; + let n = 0; + let last; do { - var b = this.readByte(); + const b = this.readByte(); if (b < 0) { throw new _util.FormatError("unexpected EOF in bcmap"); @@ -25610,25 +14781,25 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { } while (!last); return n; - }, + } readSigned() { - var n = this.readNumber(); + const n = this.readNumber(); return n & 1 ? ~(n >>> 1) : n >>> 1; - }, + } readHex(num, size) { num.set(this.buffer.subarray(this.pos, this.pos + size + 1)); this.pos += size + 1; - }, + } readHexNumber(num, size) { - var last; - var stack = this.tmpBuf, - sp = 0; + let last; + const stack = this.tmpBuf; + let sp = 0; do { - var b = this.readByte(); + const b = this.readByte(); if (b < 0) { throw new _util.FormatError("unexpected EOF in bcmap"); @@ -25638,13 +14809,13 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { stack[sp++] = b & 0x7f; } while (!last); - var i = size, + let i = size, buffer = 0, bufferSize = 0; while (i >= 0) { while (bufferSize < 8 && stack.length > 0) { - buffer = stack[--sp] << bufferSize | buffer; + buffer |= stack[--sp] << bufferSize; bufferSize += 7; } @@ -25653,48 +14824,48 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { buffer >>= 8; bufferSize -= 8; } - }, + } readHexSigned(num, size) { this.readHexNumber(num, size); - var sign = num[size] & 1 ? 255 : 0; - var c = 0; + const sign = num[size] & 1 ? 255 : 0; + let c = 0; - for (var i = 0; i <= size; i++) { + for (let i = 0; i <= size; i++) { c = (c & 1) << 8 | num[i]; num[i] = c >> 1 ^ sign; } - }, + } readString() { - var len = this.readNumber(); - var s = ""; + const len = this.readNumber(); + let s = ""; - for (var i = 0; i < len; i++) { + for (let i = 0; i < len; i++) { s += String.fromCharCode(this.readNumber()); } return s; } - }; + } - function processBinaryCMap(data, cMap, extend) { - return new Promise(function (resolve, reject) { - var stream = new BinaryCMapStream(data); - var header = stream.readByte(); + class BinaryCMapReader { + async process(data, cMap, extend) { + const stream = new BinaryCMapStream(data); + const header = stream.readByte(); cMap.vertical = !!(header & 1); - var useCMap = null; - var start = new Uint8Array(MAX_NUM_SIZE); - var end = new Uint8Array(MAX_NUM_SIZE); - var char = new Uint8Array(MAX_NUM_SIZE); - var charCode = new Uint8Array(MAX_NUM_SIZE); - var tmp = new Uint8Array(MAX_NUM_SIZE); - var code; - var b; + let useCMap = null; + const start = new Uint8Array(MAX_NUM_SIZE); + const end = new Uint8Array(MAX_NUM_SIZE); + const char = new Uint8Array(MAX_NUM_SIZE); + const charCode = new Uint8Array(MAX_NUM_SIZE); + const tmp = new Uint8Array(MAX_NUM_SIZE); + let code; + let b; while ((b = stream.readByte()) >= 0) { - var type = b >> 5; + const type = b >> 5; if (type === 7) { switch (b & 0x1f) { @@ -25710,16 +14881,15 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { continue; } - var sequence = !!(b & 0x10); - var dataSize = b & 15; + const sequence = !!(b & 0x10); + const dataSize = b & 15; if (dataSize + 1 > MAX_NUM_SIZE) { - throw new Error("processBinaryCMap: Invalid dataSize."); + throw new Error("BinaryCMapReader.process: Invalid dataSize."); } - var ucs2DataSize = 1; - var subitemsCount = stream.readNumber(); - var i; + const ucs2DataSize = 1; + const subitemsCount = stream.readNumber(); switch (type) { case 0: @@ -25728,7 +14898,7 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { addHex(end, start, dataSize); cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize), hexToInt(end, dataSize)); - for (i = 1; i < subitemsCount; i++) { + for (let i = 1; i < subitemsCount; i++) { incHex(end, dataSize); stream.readHexNumber(start, dataSize); addHex(start, end, dataSize); @@ -25745,7 +14915,7 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { addHex(end, start, dataSize); stream.readNumber(); - for (i = 1; i < subitemsCount; i++) { + for (let i = 1; i < subitemsCount; i++) { incHex(end, dataSize); stream.readHexNumber(start, dataSize); addHex(start, end, dataSize); @@ -25761,7 +14931,7 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { code = stream.readNumber(); cMap.mapOne(hexToInt(char, dataSize), code); - for (i = 1; i < subitemsCount; i++) { + for (let i = 1; i < subitemsCount; i++) { incHex(char, dataSize); if (!sequence) { @@ -25782,7 +14952,7 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { code = stream.readNumber(); cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize), code); - for (i = 1; i < subitemsCount; i++) { + for (let i = 1; i < subitemsCount; i++) { incHex(end, dataSize); if (!sequence) { @@ -25805,7 +14975,7 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { stream.readHex(charCode, dataSize); cMap.mapOne(hexToInt(char, ucs2DataSize), hexToStr(charCode, dataSize)); - for (i = 1; i < subitemsCount; i++) { + for (let i = 1; i < subitemsCount; i++) { incHex(char, ucs2DataSize); if (!sequence) { @@ -25828,7 +14998,7 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { stream.readHex(charCode, dataSize); cMap.mapBfRange(hexToInt(start, ucs2DataSize), hexToInt(end, ucs2DataSize), hexToStr(charCode, dataSize)); - for (i = 1; i < subitemsCount; i++) { + for (let i = 1; i < subitemsCount; i++) { incHex(end, ucs2DataSize); if (!sequence) { @@ -25847,33 +15017,27 @@ var BinaryCMapReader = function BinaryCMapReaderClosure() { break; default: - reject(new Error("processBinaryCMap: Unknown type: " + type)); - return; + throw new Error(`BinaryCMapReader.process - unknown type: ${type}`); } } if (useCMap) { - resolve(extend(useCMap)); - return; + return extend(useCMap); } - resolve(cMap); - }); + return cMap; + } + } - function BinaryCMapReader() {} - - BinaryCMapReader.prototype = { - process: processBinaryCMap - }; return BinaryCMapReader; }(); -var CMapFactory = function CMapFactoryClosure() { +const CMapFactory = function CMapFactoryClosure() { function strToInt(str) { - var a = 0; + let a = 0; - for (var i = 0; i < str.length; i++) { + for (let i = 0; i < str.length; i++) { a = a << 8 | str.charCodeAt(i); } @@ -25881,7 +15045,7 @@ var CMapFactory = function CMapFactoryClosure() { } function expectString(obj) { - if (!(0, _util.isString)(obj)) { + if (typeof obj !== "string") { throw new _util.FormatError("Malformed CMap: expected string."); } } @@ -25894,9 +15058,9 @@ var CMapFactory = function CMapFactoryClosure() { function parseBfChar(cMap, lexer) { while (true) { - var obj = lexer.getObj(); + let obj = lexer.getObj(); - if ((0, _primitives.isEOF)(obj)) { + if (obj === _primitives.EOF) { break; } @@ -25905,19 +15069,19 @@ var CMapFactory = function CMapFactoryClosure() { } expectString(obj); - var src = strToInt(obj); + const src = strToInt(obj); obj = lexer.getObj(); expectString(obj); - var dst = obj; + const dst = obj; cMap.mapOne(src, dst); } } function parseBfRange(cMap, lexer) { while (true) { - var obj = lexer.getObj(); + let obj = lexer.getObj(); - if ((0, _primitives.isEOF)(obj)) { + if (obj === _primitives.EOF) { break; } @@ -25926,20 +15090,20 @@ var CMapFactory = function CMapFactoryClosure() { } expectString(obj); - var low = strToInt(obj); + const low = strToInt(obj); obj = lexer.getObj(); expectString(obj); - var high = strToInt(obj); + const high = strToInt(obj); obj = lexer.getObj(); - if (Number.isInteger(obj) || (0, _util.isString)(obj)) { - var dstLow = Number.isInteger(obj) ? String.fromCharCode(obj) : obj; + if (Number.isInteger(obj) || typeof obj === "string") { + const dstLow = Number.isInteger(obj) ? String.fromCharCode(obj) : obj; cMap.mapBfRange(low, high, dstLow); } else if ((0, _primitives.isCmd)(obj, "[")) { obj = lexer.getObj(); - var array = []; + const array = []; - while (!(0, _primitives.isCmd)(obj, "]") && !(0, _primitives.isEOF)(obj)) { + while (!(0, _primitives.isCmd)(obj, "]") && obj !== _primitives.EOF) { array.push(obj); obj = lexer.getObj(); } @@ -25955,9 +15119,9 @@ var CMapFactory = function CMapFactoryClosure() { function parseCidChar(cMap, lexer) { while (true) { - var obj = lexer.getObj(); + let obj = lexer.getObj(); - if ((0, _primitives.isEOF)(obj)) { + if (obj === _primitives.EOF) { break; } @@ -25966,19 +15130,19 @@ var CMapFactory = function CMapFactoryClosure() { } expectString(obj); - var src = strToInt(obj); + const src = strToInt(obj); obj = lexer.getObj(); expectInt(obj); - var dst = obj; + const dst = obj; cMap.mapOne(src, dst); } } function parseCidRange(cMap, lexer) { while (true) { - var obj = lexer.getObj(); + let obj = lexer.getObj(); - if ((0, _primitives.isEOF)(obj)) { + if (obj === _primitives.EOF) { break; } @@ -25987,22 +15151,22 @@ var CMapFactory = function CMapFactoryClosure() { } expectString(obj); - var low = strToInt(obj); + const low = strToInt(obj); obj = lexer.getObj(); expectString(obj); - var high = strToInt(obj); + const high = strToInt(obj); obj = lexer.getObj(); expectInt(obj); - var dstLow = obj; + const dstLow = obj; cMap.mapCidRange(low, high, dstLow); } } function parseCodespaceRange(cMap, lexer) { while (true) { - var obj = lexer.getObj(); + let obj = lexer.getObj(); - if ((0, _primitives.isEOF)(obj)) { + if (obj === _primitives.EOF) { break; } @@ -26010,18 +15174,18 @@ var CMapFactory = function CMapFactoryClosure() { return; } - if (!(0, _util.isString)(obj)) { + if (typeof obj !== "string") { break; } - var low = strToInt(obj); + const low = strToInt(obj); obj = lexer.getObj(); - if (!(0, _util.isString)(obj)) { + if (typeof obj !== "string") { break; } - var high = strToInt(obj); + const high = strToInt(obj); cMap.addCodespaceRange(obj.length, low, high); } @@ -26029,7 +15193,7 @@ var CMapFactory = function CMapFactoryClosure() { } function parseWMode(cMap, lexer) { - var obj = lexer.getObj(); + const obj = lexer.getObj(); if (Number.isInteger(obj)) { cMap.vertical = !!obj; @@ -26037,24 +15201,23 @@ var CMapFactory = function CMapFactoryClosure() { } function parseCMapName(cMap, lexer) { - var obj = lexer.getObj(); + const obj = lexer.getObj(); - if ((0, _primitives.isName)(obj) && (0, _util.isString)(obj.name)) { + if (obj instanceof _primitives.Name) { cMap.name = obj.name; } } - function parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap) { - var previous; - var embeddedUseCMap; + async function parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap) { + let previous, embeddedUseCMap; objLoop: while (true) { try { - var obj = lexer.getObj(); + const obj = lexer.getObj(); - if ((0, _primitives.isEOF)(obj)) { + if (obj === _primitives.EOF) { break; - } else if ((0, _primitives.isName)(obj)) { + } else if (obj instanceof _primitives.Name) { if (obj.name === "WMode") { parseWMode(cMap, lexer); } else if (obj.name === "CMapName") { @@ -26062,13 +15225,13 @@ var CMapFactory = function CMapFactoryClosure() { } previous = obj; - } else if ((0, _primitives.isCmd)(obj)) { + } else if (obj instanceof _primitives.Cmd) { switch (obj.cmd) { case "endcmap": break objLoop; case "usecmap": - if ((0, _primitives.isName)(previous)) { + if (previous instanceof _primitives.Name) { embeddedUseCMap = previous.name; } @@ -26113,85 +15276,81 @@ var CMapFactory = function CMapFactoryClosure() { return extendCMap(cMap, fetchBuiltInCMap, useCMap); } - return Promise.resolve(cMap); + return cMap; } - function extendCMap(cMap, fetchBuiltInCMap, useCMap) { - return createBuiltInCMap(useCMap, fetchBuiltInCMap).then(function (newCMap) { - cMap.useCMap = newCMap; + async function extendCMap(cMap, fetchBuiltInCMap, useCMap) { + cMap.useCMap = await createBuiltInCMap(useCMap, fetchBuiltInCMap); - if (cMap.numCodespaceRanges === 0) { - var useCodespaceRanges = cMap.useCMap.codespaceRanges; + if (cMap.numCodespaceRanges === 0) { + const useCodespaceRanges = cMap.useCMap.codespaceRanges; - for (var i = 0; i < useCodespaceRanges.length; i++) { - cMap.codespaceRanges[i] = useCodespaceRanges[i].slice(); - } - - cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges; + for (let i = 0; i < useCodespaceRanges.length; i++) { + cMap.codespaceRanges[i] = useCodespaceRanges[i].slice(); } - cMap.useCMap.forEach(function (key, value) { - if (!cMap.contains(key)) { - cMap.mapOne(key, cMap.useCMap.lookup(key)); - } - }); - return cMap; + cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges; + } + + cMap.useCMap.forEach(function (key, value) { + if (!cMap.contains(key)) { + cMap.mapOne(key, cMap.useCMap.lookup(key)); + } }); + return cMap; } - function createBuiltInCMap(name, fetchBuiltInCMap) { + async function createBuiltInCMap(name, fetchBuiltInCMap) { if (name === "Identity-H") { - return Promise.resolve(new IdentityCMap(false, 2)); + return new IdentityCMap(false, 2); } else if (name === "Identity-V") { - return Promise.resolve(new IdentityCMap(true, 2)); + return new IdentityCMap(true, 2); } if (!BUILT_IN_CMAPS.includes(name)) { - return Promise.reject(new Error("Unknown CMap name: " + name)); + throw new Error("Unknown CMap name: " + name); } if (!fetchBuiltInCMap) { - return Promise.reject(new Error("Built-in CMap parameters are not provided.")); + throw new Error("Built-in CMap parameters are not provided."); } - return fetchBuiltInCMap(name).then(function (data) { - var cMapData = data.cMapData, - compressionType = data.compressionType; - var cMap = new CMap(true); + const { + cMapData, + compressionType + } = await fetchBuiltInCMap(name); + const cMap = new CMap(true); - if (compressionType === _util.CMapCompressionType.BINARY) { - return new BinaryCMapReader().process(cMapData, cMap, function (useCMap) { - return extendCMap(cMap, fetchBuiltInCMap, useCMap); - }); - } + if (compressionType === _util.CMapCompressionType.BINARY) { + return new BinaryCMapReader().process(cMapData, cMap, useCMap => { + return extendCMap(cMap, fetchBuiltInCMap, useCMap); + }); + } - if (compressionType === _util.CMapCompressionType.NONE) { - var lexer = new _parser.Lexer(new _stream.Stream(cMapData)); - return parseCMap(cMap, lexer, fetchBuiltInCMap, null); - } + if (compressionType === _util.CMapCompressionType.NONE) { + const lexer = new _parser.Lexer(new _stream.Stream(cMapData)); + return parseCMap(cMap, lexer, fetchBuiltInCMap, null); + } - return Promise.reject(new Error("TODO: Only BINARY/NONE CMap compression is currently supported.")); - }); + throw new Error("TODO: Only BINARY/NONE CMap compression is currently supported."); } return { async create(params) { - var encoding = params.encoding; - var fetchBuiltInCMap = params.fetchBuiltInCMap; - var useCMap = params.useCMap; + const encoding = params.encoding; + const fetchBuiltInCMap = params.fetchBuiltInCMap; + const useCMap = params.useCMap; - if ((0, _primitives.isName)(encoding)) { + if (encoding instanceof _primitives.Name) { return createBuiltInCMap(encoding.name, fetchBuiltInCMap); - } else if ((0, _primitives.isStream)(encoding)) { - var cMap = new CMap(); - var lexer = new _parser.Lexer(encoding); - return parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap).then(function (parsedCMap) { - if (parsedCMap.isIdentityCMap) { - return createBuiltInCMap(parsedCMap.name, fetchBuiltInCMap); - } + } else if (encoding instanceof _base_stream.BaseStream) { + const parsedCMap = await parseCMap(new CMap(), new _parser.Lexer(encoding), fetchBuiltInCMap, useCMap); - return parsedCMap; - }); + if (parsedCMap.isIdentityCMap) { + return createBuiltInCMap(parsedCMap.name, fetchBuiltInCMap); + } + + return parsedCMap; } throw new Error("Encoding required."); @@ -26203,59 +15362,9687 @@ var CMapFactory = function CMapFactoryClosure() { exports.CMapFactory = CMapFactory; /***/ }), -/* 30 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 17 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.getFontType = getFontType; -exports.IdentityToUnicodeMap = exports.ToUnicodeMap = exports.FontFlags = exports.Font = exports.ErrorFont = exports.SEAC_ANALYSIS_ENABLED = void 0; +})); +exports.Parser = exports.Linearization = exports.Lexer = void 0; var _util = __w_pdfjs_require__(2); -var _cff_parser = __w_pdfjs_require__(31); +var _primitives = __w_pdfjs_require__(5); -var _glyphlist = __w_pdfjs_require__(34); +var _core_utils = __w_pdfjs_require__(6); -var _encodings = __w_pdfjs_require__(33); +var _ascii_85_stream = __w_pdfjs_require__(18); -var _standard_fonts = __w_pdfjs_require__(35); +var _ascii_hex_stream = __w_pdfjs_require__(20); -var _unicode = __w_pdfjs_require__(36); +var _ccitt_stream = __w_pdfjs_require__(21); -var _core_utils = __w_pdfjs_require__(8); +var _flate_stream = __w_pdfjs_require__(23); -var _font_renderer = __w_pdfjs_require__(37); +var _jbig2_stream = __w_pdfjs_require__(24); -var _cmap = __w_pdfjs_require__(29); +var _jpeg_stream = __w_pdfjs_require__(27); -var _stream = __w_pdfjs_require__(12); +var _jpx_stream = __w_pdfjs_require__(29); -var _type1_parser = __w_pdfjs_require__(38); +var _lzw_stream = __w_pdfjs_require__(31); + +var _stream = __w_pdfjs_require__(10); + +var _predictor_stream = __w_pdfjs_require__(32); + +var _run_length_stream = __w_pdfjs_require__(33); + +const MAX_LENGTH_TO_CACHE = 1000; +const MAX_ADLER32_LENGTH = 5552; + +function computeAdler32(bytes) { + const bytesLength = bytes.length; + let a = 1, + b = 0; + + for (let i = 0; i < bytesLength; ++i) { + a += bytes[i] & 0xff; + b += a; + } + + return b % 65521 << 16 | a % 65521; +} + +class Parser { + constructor({ + lexer, + xref, + allowStreams = false, + recoveryMode = false + }) { + this.lexer = lexer; + this.xref = xref; + this.allowStreams = allowStreams; + this.recoveryMode = recoveryMode; + this.imageCache = Object.create(null); + this.refill(); + } + + refill() { + this.buf1 = this.lexer.getObj(); + this.buf2 = this.lexer.getObj(); + } + + shift() { + if (this.buf2 instanceof _primitives.Cmd && this.buf2.cmd === "ID") { + this.buf1 = this.buf2; + this.buf2 = null; + } else { + this.buf1 = this.buf2; + this.buf2 = this.lexer.getObj(); + } + } + + tryShift() { + try { + this.shift(); + return true; + } catch (e) { + if (e instanceof _core_utils.MissingDataException) { + throw e; + } + + return false; + } + } + + getObj(cipherTransform = null) { + const buf1 = this.buf1; + this.shift(); + + if (buf1 instanceof _primitives.Cmd) { + switch (buf1.cmd) { + case "BI": + return this.makeInlineImage(cipherTransform); + + case "[": + const array = []; + + while (!(0, _primitives.isCmd)(this.buf1, "]") && this.buf1 !== _primitives.EOF) { + array.push(this.getObj(cipherTransform)); + } + + if (this.buf1 === _primitives.EOF) { + if (this.recoveryMode) { + return array; + } + + throw new _core_utils.ParserEOFException("End of file inside array."); + } + + this.shift(); + return array; + + case "<<": + const dict = new _primitives.Dict(this.xref); + + while (!(0, _primitives.isCmd)(this.buf1, ">>") && this.buf1 !== _primitives.EOF) { + if (!(this.buf1 instanceof _primitives.Name)) { + (0, _util.info)("Malformed dictionary: key must be a name object"); + this.shift(); + continue; + } + + const key = this.buf1.name; + this.shift(); + + if (this.buf1 === _primitives.EOF) { + break; + } + + dict.set(key, this.getObj(cipherTransform)); + } + + if (this.buf1 === _primitives.EOF) { + if (this.recoveryMode) { + return dict; + } + + throw new _core_utils.ParserEOFException("End of file inside dictionary."); + } + + if ((0, _primitives.isCmd)(this.buf2, "stream")) { + return this.allowStreams ? this.makeStream(dict, cipherTransform) : dict; + } + + this.shift(); + return dict; + + default: + return buf1; + } + } + + if (Number.isInteger(buf1)) { + if (Number.isInteger(this.buf1) && (0, _primitives.isCmd)(this.buf2, "R")) { + const ref = _primitives.Ref.get(buf1, this.buf1); + + this.shift(); + this.shift(); + return ref; + } + + return buf1; + } + + if (typeof buf1 === "string") { + if (cipherTransform) { + return cipherTransform.decryptString(buf1); + } + + return buf1; + } + + return buf1; + } + + findDefaultInlineStreamEnd(stream) { + const E = 0x45, + I = 0x49, + SPACE = 0x20, + LF = 0xa, + CR = 0xd, + NUL = 0x0; + const lexer = this.lexer, + startPos = stream.pos, + n = 10; + let state = 0, + ch, + maybeEIPos; + + while ((ch = stream.getByte()) !== -1) { + if (state === 0) { + state = ch === E ? 1 : 0; + } else if (state === 1) { + state = ch === I ? 2 : 0; + } else { + (0, _util.assert)(state === 2, "findDefaultInlineStreamEnd - invalid state."); + + if (ch === SPACE || ch === LF || ch === CR) { + maybeEIPos = stream.pos; + const followingBytes = stream.peekBytes(n); + + for (let i = 0, ii = followingBytes.length; i < ii; i++) { + ch = followingBytes[i]; + + if (ch === NUL && followingBytes[i + 1] !== NUL) { + continue; + } + + if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7f)) { + state = 0; + break; + } + } + + if (state !== 2) { + continue; + } + + if (lexer.knownCommands) { + const nextObj = lexer.peekObj(); + + if (nextObj instanceof _primitives.Cmd && !lexer.knownCommands[nextObj.cmd]) { + state = 0; + } + } else { + (0, _util.warn)("findDefaultInlineStreamEnd - `lexer.knownCommands` is undefined."); + } + + if (state === 2) { + break; + } + } else { + state = 0; + } + } + } + + if (ch === -1) { + (0, _util.warn)("findDefaultInlineStreamEnd: " + "Reached the end of the stream without finding a valid EI marker"); + + if (maybeEIPos) { + (0, _util.warn)('... trying to recover by using the last "EI" occurrence.'); + stream.skip(-(stream.pos - maybeEIPos)); + } + } + + let endOffset = 4; + stream.skip(-endOffset); + ch = stream.peekByte(); + stream.skip(endOffset); + + if (!(0, _core_utils.isWhiteSpace)(ch)) { + endOffset--; + } + + return stream.pos - endOffset - startPos; + } + + findDCTDecodeInlineStreamEnd(stream) { + const startPos = stream.pos; + let foundEOI = false, + b, + markerLength; + + while ((b = stream.getByte()) !== -1) { + if (b !== 0xff) { + continue; + } + + switch (stream.getByte()) { + case 0x00: + break; + + case 0xff: + stream.skip(-1); + break; + + case 0xd9: + foundEOI = true; + break; + + case 0xc0: + case 0xc1: + case 0xc2: + case 0xc3: + case 0xc5: + case 0xc6: + case 0xc7: + case 0xc9: + case 0xca: + case 0xcb: + case 0xcd: + case 0xce: + case 0xcf: + case 0xc4: + case 0xcc: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + case 0xe0: + case 0xe1: + case 0xe2: + case 0xe3: + case 0xe4: + case 0xe5: + case 0xe6: + case 0xe7: + case 0xe8: + case 0xe9: + case 0xea: + case 0xeb: + case 0xec: + case 0xed: + case 0xee: + case 0xef: + case 0xfe: + markerLength = stream.getUint16(); + + if (markerLength > 2) { + stream.skip(markerLength - 2); + } else { + stream.skip(-2); + } + + break; + } + + if (foundEOI) { + break; + } + } + + const length = stream.pos - startPos; + + if (b === -1) { + (0, _util.warn)("Inline DCTDecode image stream: " + "EOI marker not found, searching for /EI/ instead."); + stream.skip(-length); + return this.findDefaultInlineStreamEnd(stream); + } + + this.inlineStreamSkipEI(stream); + return length; + } + + findASCII85DecodeInlineStreamEnd(stream) { + const TILDE = 0x7e, + GT = 0x3e; + const startPos = stream.pos; + let ch; + + while ((ch = stream.getByte()) !== -1) { + if (ch === TILDE) { + const tildePos = stream.pos; + ch = stream.peekByte(); + + while ((0, _core_utils.isWhiteSpace)(ch)) { + stream.skip(); + ch = stream.peekByte(); + } + + if (ch === GT) { + stream.skip(); + break; + } + + if (stream.pos > tildePos) { + const maybeEI = stream.peekBytes(2); + + if (maybeEI[0] === 0x45 && maybeEI[1] === 0x49) { + break; + } + } + } + } + + const length = stream.pos - startPos; + + if (ch === -1) { + (0, _util.warn)("Inline ASCII85Decode image stream: " + "EOD marker not found, searching for /EI/ instead."); + stream.skip(-length); + return this.findDefaultInlineStreamEnd(stream); + } + + this.inlineStreamSkipEI(stream); + return length; + } + + findASCIIHexDecodeInlineStreamEnd(stream) { + const GT = 0x3e; + const startPos = stream.pos; + let ch; + + while ((ch = stream.getByte()) !== -1) { + if (ch === GT) { + break; + } + } + + const length = stream.pos - startPos; + + if (ch === -1) { + (0, _util.warn)("Inline ASCIIHexDecode image stream: " + "EOD marker not found, searching for /EI/ instead."); + stream.skip(-length); + return this.findDefaultInlineStreamEnd(stream); + } + + this.inlineStreamSkipEI(stream); + return length; + } + + inlineStreamSkipEI(stream) { + const E = 0x45, + I = 0x49; + let state = 0, + ch; + + while ((ch = stream.getByte()) !== -1) { + if (state === 0) { + state = ch === E ? 1 : 0; + } else if (state === 1) { + state = ch === I ? 2 : 0; + } else if (state === 2) { + break; + } + } + } + + makeInlineImage(cipherTransform) { + const lexer = this.lexer; + const stream = lexer.stream; + const dict = new _primitives.Dict(this.xref); + let dictLength; + + while (!(0, _primitives.isCmd)(this.buf1, "ID") && this.buf1 !== _primitives.EOF) { + if (!(this.buf1 instanceof _primitives.Name)) { + throw new _util.FormatError("Dictionary key must be a name object"); + } + + const key = this.buf1.name; + this.shift(); + + if (this.buf1 === _primitives.EOF) { + break; + } + + dict.set(key, this.getObj(cipherTransform)); + } + + if (lexer.beginInlineImagePos !== -1) { + dictLength = stream.pos - lexer.beginInlineImagePos; + } + + const filter = dict.get("F", "Filter"); + let filterName; + + if (filter instanceof _primitives.Name) { + filterName = filter.name; + } else if (Array.isArray(filter)) { + const filterZero = this.xref.fetchIfRef(filter[0]); + + if (filterZero instanceof _primitives.Name) { + filterName = filterZero.name; + } + } + + const startPos = stream.pos; + let length; + + switch (filterName) { + case "DCT": + case "DCTDecode": + length = this.findDCTDecodeInlineStreamEnd(stream); + break; + + case "A85": + case "ASCII85Decode": + length = this.findASCII85DecodeInlineStreamEnd(stream); + break; + + case "AHx": + case "ASCIIHexDecode": + length = this.findASCIIHexDecodeInlineStreamEnd(stream); + break; + + default: + length = this.findDefaultInlineStreamEnd(stream); + } + + let imageStream = stream.makeSubStream(startPos, length, dict); + let cacheKey; + + if (length < MAX_LENGTH_TO_CACHE && dictLength < MAX_ADLER32_LENGTH) { + const imageBytes = imageStream.getBytes(); + imageStream.reset(); + const initialStreamPos = stream.pos; + stream.pos = lexer.beginInlineImagePos; + const dictBytes = stream.getBytes(dictLength); + stream.pos = initialStreamPos; + cacheKey = computeAdler32(imageBytes) + "_" + computeAdler32(dictBytes); + const cacheEntry = this.imageCache[cacheKey]; + + if (cacheEntry !== undefined) { + this.buf2 = _primitives.Cmd.get("EI"); + this.shift(); + cacheEntry.reset(); + return cacheEntry; + } + } + + if (cipherTransform) { + imageStream = cipherTransform.createStream(imageStream, length); + } + + imageStream = this.filter(imageStream, dict, length); + imageStream.dict = dict; + + if (cacheKey !== undefined) { + imageStream.cacheKey = `inline_${length}_${cacheKey}`; + this.imageCache[cacheKey] = imageStream; + } + + this.buf2 = _primitives.Cmd.get("EI"); + this.shift(); + return imageStream; + } + + _findStreamLength(startPos, signature) { + const { + stream + } = this.lexer; + stream.pos = startPos; + const SCAN_BLOCK_LENGTH = 2048; + const signatureLength = signature.length; + + while (stream.pos < stream.end) { + const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH); + const scanLength = scanBytes.length - signatureLength; + + if (scanLength <= 0) { + break; + } + + let pos = 0; + + while (pos < scanLength) { + let j = 0; + + while (j < signatureLength && scanBytes[pos + j] === signature[j]) { + j++; + } + + if (j >= signatureLength) { + stream.pos += pos; + return stream.pos - startPos; + } + + pos++; + } + + stream.pos += scanLength; + } + + return -1; + } + + makeStream(dict, cipherTransform) { + const lexer = this.lexer; + let stream = lexer.stream; + lexer.skipToNextLine(); + const startPos = stream.pos - 1; + let length = dict.get("Length"); + + if (!Number.isInteger(length)) { + (0, _util.info)(`Bad length "${length && length.toString()}" in stream.`); + length = 0; + } + + stream.pos = startPos + length; + lexer.nextChar(); + + if (this.tryShift() && (0, _primitives.isCmd)(this.buf2, "endstream")) { + this.shift(); + } else { + const ENDSTREAM_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d]); + + let actualLength = this._findStreamLength(startPos, ENDSTREAM_SIGNATURE); + + if (actualLength < 0) { + const MAX_TRUNCATION = 1; + + for (let i = 1; i <= MAX_TRUNCATION; i++) { + const end = ENDSTREAM_SIGNATURE.length - i; + const TRUNCATED_SIGNATURE = ENDSTREAM_SIGNATURE.slice(0, end); + + const maybeLength = this._findStreamLength(startPos, TRUNCATED_SIGNATURE); + + if (maybeLength >= 0) { + const lastByte = stream.peekBytes(end + 1)[end]; + + if (!(0, _core_utils.isWhiteSpace)(lastByte)) { + break; + } + + (0, _util.info)(`Found "${(0, _util.bytesToString)(TRUNCATED_SIGNATURE)}" when ` + "searching for endstream command."); + actualLength = maybeLength; + break; + } + } + + if (actualLength < 0) { + throw new _util.FormatError("Missing endstream command."); + } + } + + length = actualLength; + lexer.nextChar(); + this.shift(); + this.shift(); + } + + this.shift(); + stream = stream.makeSubStream(startPos, length, dict); + + if (cipherTransform) { + stream = cipherTransform.createStream(stream, length); + } + + stream = this.filter(stream, dict, length); + stream.dict = dict; + return stream; + } + + filter(stream, dict, length) { + let filter = dict.get("F", "Filter"); + let params = dict.get("DP", "DecodeParms"); + + if (filter instanceof _primitives.Name) { + if (Array.isArray(params)) { + (0, _util.warn)("/DecodeParms should not be an Array, when /Filter is a Name."); + } + + return this.makeFilter(stream, filter.name, length, params); + } + + let maybeLength = length; + + if (Array.isArray(filter)) { + const filterArray = filter; + const paramsArray = params; + + for (let i = 0, ii = filterArray.length; i < ii; ++i) { + filter = this.xref.fetchIfRef(filterArray[i]); + + if (!(filter instanceof _primitives.Name)) { + throw new _util.FormatError(`Bad filter name "${filter}"`); + } + + params = null; + + if (Array.isArray(paramsArray) && i in paramsArray) { + params = this.xref.fetchIfRef(paramsArray[i]); + } + + stream = this.makeFilter(stream, filter.name, maybeLength, params); + maybeLength = null; + } + } + + return stream; + } + + makeFilter(stream, name, maybeLength, params) { + if (maybeLength === 0) { + (0, _util.warn)(`Empty "${name}" stream.`); + return new _stream.NullStream(); + } + + const xrefStats = this.xref.stats; + + try { + switch (name) { + case "Fl": + case "FlateDecode": + xrefStats.addStreamType(_util.StreamType.FLATE); + + if (params) { + return new _predictor_stream.PredictorStream(new _flate_stream.FlateStream(stream, maybeLength), maybeLength, params); + } + + return new _flate_stream.FlateStream(stream, maybeLength); + + case "LZW": + case "LZWDecode": + xrefStats.addStreamType(_util.StreamType.LZW); + let earlyChange = 1; + + if (params) { + if (params.has("EarlyChange")) { + earlyChange = params.get("EarlyChange"); + } + + return new _predictor_stream.PredictorStream(new _lzw_stream.LZWStream(stream, maybeLength, earlyChange), maybeLength, params); + } + + return new _lzw_stream.LZWStream(stream, maybeLength, earlyChange); + + case "DCT": + case "DCTDecode": + xrefStats.addStreamType(_util.StreamType.DCT); + return new _jpeg_stream.JpegStream(stream, maybeLength, params); + + case "JPX": + case "JPXDecode": + xrefStats.addStreamType(_util.StreamType.JPX); + return new _jpx_stream.JpxStream(stream, maybeLength, params); + + case "A85": + case "ASCII85Decode": + xrefStats.addStreamType(_util.StreamType.A85); + return new _ascii_85_stream.Ascii85Stream(stream, maybeLength); + + case "AHx": + case "ASCIIHexDecode": + xrefStats.addStreamType(_util.StreamType.AHX); + return new _ascii_hex_stream.AsciiHexStream(stream, maybeLength); + + case "CCF": + case "CCITTFaxDecode": + xrefStats.addStreamType(_util.StreamType.CCF); + return new _ccitt_stream.CCITTFaxStream(stream, maybeLength, params); + + case "RL": + case "RunLengthDecode": + xrefStats.addStreamType(_util.StreamType.RLX); + return new _run_length_stream.RunLengthStream(stream, maybeLength); + + case "JBIG2Decode": + xrefStats.addStreamType(_util.StreamType.JBIG); + return new _jbig2_stream.Jbig2Stream(stream, maybeLength, params); + } + + (0, _util.warn)(`Filter "${name}" is not supported.`); + return stream; + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)(`Invalid stream: "${ex}"`); + return new _stream.NullStream(); + } + } + +} + +exports.Parser = Parser; +const specialChars = [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + +function toHexDigit(ch) { + if (ch >= 0x30 && ch <= 0x39) { + return ch & 0x0f; + } + + if (ch >= 0x41 && ch <= 0x46 || ch >= 0x61 && ch <= 0x66) { + return (ch & 0x0f) + 9; + } + + return -1; +} + +class Lexer { + constructor(stream, knownCommands = null) { + this.stream = stream; + this.nextChar(); + this.strBuf = []; + this.knownCommands = knownCommands; + this._hexStringNumWarn = 0; + this.beginInlineImagePos = -1; + } + + nextChar() { + return this.currentChar = this.stream.getByte(); + } + + peekChar() { + return this.stream.peekByte(); + } + + getNumber() { + let ch = this.currentChar; + let eNotation = false; + let divideBy = 0; + let sign = 0; + + if (ch === 0x2d) { + sign = -1; + ch = this.nextChar(); + + if (ch === 0x2d) { + ch = this.nextChar(); + } + } else if (ch === 0x2b) { + sign = 1; + ch = this.nextChar(); + } + + if (ch === 0x0a || ch === 0x0d) { + do { + ch = this.nextChar(); + } while (ch === 0x0a || ch === 0x0d); + } + + if (ch === 0x2e) { + divideBy = 10; + ch = this.nextChar(); + } + + if (ch < 0x30 || ch > 0x39) { + if ((0, _core_utils.isWhiteSpace)(ch) || ch === -1) { + if (divideBy === 10 && sign === 0) { + (0, _util.warn)("Lexer.getNumber - treating a single decimal point as zero."); + return 0; + } + + if (divideBy === 0 && sign === -1) { + (0, _util.warn)("Lexer.getNumber - treating a single minus sign as zero."); + return 0; + } + } + + throw new _util.FormatError(`Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`); + } + + sign = sign || 1; + let baseValue = ch - 0x30; + let powerValue = 0; + let powerValueSign = 1; + + while ((ch = this.nextChar()) >= 0) { + if (ch >= 0x30 && ch <= 0x39) { + const currentDigit = ch - 0x30; + + if (eNotation) { + powerValue = powerValue * 10 + currentDigit; + } else { + if (divideBy !== 0) { + divideBy *= 10; + } + + baseValue = baseValue * 10 + currentDigit; + } + } else if (ch === 0x2e) { + if (divideBy === 0) { + divideBy = 1; + } else { + break; + } + } else if (ch === 0x2d) { + (0, _util.warn)("Badly formatted number: minus sign in the middle"); + } else if (ch === 0x45 || ch === 0x65) { + ch = this.peekChar(); + + if (ch === 0x2b || ch === 0x2d) { + powerValueSign = ch === 0x2d ? -1 : 1; + this.nextChar(); + } else if (ch < 0x30 || ch > 0x39) { + break; + } + + eNotation = true; + } else { + break; + } + } + + if (divideBy !== 0) { + baseValue /= divideBy; + } + + if (eNotation) { + baseValue *= 10 ** (powerValueSign * powerValue); + } + + return sign * baseValue; + } + + getString() { + let numParen = 1; + let done = false; + const strBuf = this.strBuf; + strBuf.length = 0; + let ch = this.nextChar(); + + while (true) { + let charBuffered = false; + + switch (ch | 0) { + case -1: + (0, _util.warn)("Unterminated string"); + done = true; + break; + + case 0x28: + ++numParen; + strBuf.push("("); + break; + + case 0x29: + if (--numParen === 0) { + this.nextChar(); + done = true; + } else { + strBuf.push(")"); + } + + break; + + case 0x5c: + ch = this.nextChar(); + + switch (ch) { + case -1: + (0, _util.warn)("Unterminated string"); + done = true; + break; + + case 0x6e: + strBuf.push("\n"); + break; + + case 0x72: + strBuf.push("\r"); + break; + + case 0x74: + strBuf.push("\t"); + break; + + case 0x62: + strBuf.push("\b"); + break; + + case 0x66: + strBuf.push("\f"); + break; + + case 0x5c: + case 0x28: + case 0x29: + strBuf.push(String.fromCharCode(ch)); + break; + + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + let x = ch & 0x0f; + ch = this.nextChar(); + charBuffered = true; + + if (ch >= 0x30 && ch <= 0x37) { + x = (x << 3) + (ch & 0x0f); + ch = this.nextChar(); + + if (ch >= 0x30 && ch <= 0x37) { + charBuffered = false; + x = (x << 3) + (ch & 0x0f); + } + } + + strBuf.push(String.fromCharCode(x)); + break; + + case 0x0d: + if (this.peekChar() === 0x0a) { + this.nextChar(); + } + + break; + + case 0x0a: + break; + + default: + strBuf.push(String.fromCharCode(ch)); + break; + } + + break; + + default: + strBuf.push(String.fromCharCode(ch)); + break; + } + + if (done) { + break; + } + + if (!charBuffered) { + ch = this.nextChar(); + } + } + + return strBuf.join(""); + } + + getName() { + let ch, previousCh; + const strBuf = this.strBuf; + strBuf.length = 0; + + while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { + if (ch === 0x23) { + ch = this.nextChar(); + + if (specialChars[ch]) { + (0, _util.warn)("Lexer_getName: " + "NUMBER SIGN (#) should be followed by a hexadecimal number."); + strBuf.push("#"); + break; + } + + const x = toHexDigit(ch); + + if (x !== -1) { + previousCh = ch; + ch = this.nextChar(); + const x2 = toHexDigit(ch); + + if (x2 === -1) { + (0, _util.warn)(`Lexer_getName: Illegal digit (${String.fromCharCode(ch)}) ` + "in hexadecimal number."); + strBuf.push("#", String.fromCharCode(previousCh)); + + if (specialChars[ch]) { + break; + } + + strBuf.push(String.fromCharCode(ch)); + continue; + } + + strBuf.push(String.fromCharCode(x << 4 | x2)); + } else { + strBuf.push("#", String.fromCharCode(ch)); + } + } else { + strBuf.push(String.fromCharCode(ch)); + } + } + + if (strBuf.length > 127) { + (0, _util.warn)(`Name token is longer than allowed by the spec: ${strBuf.length}`); + } + + return _primitives.Name.get(strBuf.join("")); + } + + _hexStringWarn(ch) { + const MAX_HEX_STRING_NUM_WARN = 5; + + if (this._hexStringNumWarn++ === MAX_HEX_STRING_NUM_WARN) { + (0, _util.warn)("getHexString - ignoring additional invalid characters."); + return; + } + + if (this._hexStringNumWarn > MAX_HEX_STRING_NUM_WARN) { + return; + } + + (0, _util.warn)(`getHexString - ignoring invalid character: ${ch}`); + } + + getHexString() { + const strBuf = this.strBuf; + strBuf.length = 0; + let ch = this.currentChar; + let isFirstHex = true; + let firstDigit, secondDigit; + this._hexStringNumWarn = 0; + + while (true) { + if (ch < 0) { + (0, _util.warn)("Unterminated hex string"); + break; + } else if (ch === 0x3e) { + this.nextChar(); + break; + } else if (specialChars[ch] === 1) { + ch = this.nextChar(); + continue; + } else { + if (isFirstHex) { + firstDigit = toHexDigit(ch); + + if (firstDigit === -1) { + this._hexStringWarn(ch); + + ch = this.nextChar(); + continue; + } + } else { + secondDigit = toHexDigit(ch); + + if (secondDigit === -1) { + this._hexStringWarn(ch); + + ch = this.nextChar(); + continue; + } + + strBuf.push(String.fromCharCode(firstDigit << 4 | secondDigit)); + } + + isFirstHex = !isFirstHex; + ch = this.nextChar(); + } + } + + return strBuf.join(""); + } + + getObj() { + let comment = false; + let ch = this.currentChar; + + while (true) { + if (ch < 0) { + return _primitives.EOF; + } + + if (comment) { + if (ch === 0x0a || ch === 0x0d) { + comment = false; + } + } else if (ch === 0x25) { + comment = true; + } else if (specialChars[ch] !== 1) { + break; + } + + ch = this.nextChar(); + } + + switch (ch | 0) { + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x2b: + case 0x2d: + case 0x2e: + return this.getNumber(); + + case 0x28: + return this.getString(); + + case 0x2f: + return this.getName(); + + case 0x5b: + this.nextChar(); + return _primitives.Cmd.get("["); + + case 0x5d: + this.nextChar(); + return _primitives.Cmd.get("]"); + + case 0x3c: + ch = this.nextChar(); + + if (ch === 0x3c) { + this.nextChar(); + return _primitives.Cmd.get("<<"); + } + + return this.getHexString(); + + case 0x3e: + ch = this.nextChar(); + + if (ch === 0x3e) { + this.nextChar(); + return _primitives.Cmd.get(">>"); + } + + return _primitives.Cmd.get(">"); + + case 0x7b: + this.nextChar(); + return _primitives.Cmd.get("{"); + + case 0x7d: + this.nextChar(); + return _primitives.Cmd.get("}"); + + case 0x29: + this.nextChar(); + throw new _util.FormatError(`Illegal character: ${ch}`); + } + + let str = String.fromCharCode(ch); + + if (ch < 0x20 || ch > 0x7f) { + const nextCh = this.peekChar(); + + if (nextCh >= 0x20 && nextCh <= 0x7f) { + this.nextChar(); + return _primitives.Cmd.get(str); + } + } + + const knownCommands = this.knownCommands; + let knownCommandFound = knownCommands && knownCommands[str] !== undefined; + + while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { + const possibleCommand = str + String.fromCharCode(ch); + + if (knownCommandFound && knownCommands[possibleCommand] === undefined) { + break; + } + + if (str.length === 128) { + throw new _util.FormatError(`Command token too long: ${str.length}`); + } + + str = possibleCommand; + knownCommandFound = knownCommands && knownCommands[str] !== undefined; + } + + if (str === "true") { + return true; + } + + if (str === "false") { + return false; + } + + if (str === "null") { + return null; + } + + if (str === "BI") { + this.beginInlineImagePos = this.stream.pos; + } + + return _primitives.Cmd.get(str); + } + + peekObj() { + const streamPos = this.stream.pos, + currentChar = this.currentChar, + beginInlineImagePos = this.beginInlineImagePos; + let nextObj; + + try { + nextObj = this.getObj(); + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)(`peekObj: ${ex}`); + } + + this.stream.pos = streamPos; + this.currentChar = currentChar; + this.beginInlineImagePos = beginInlineImagePos; + return nextObj; + } + + skipToNextLine() { + let ch = this.currentChar; + + while (ch >= 0) { + if (ch === 0x0d) { + ch = this.nextChar(); + + if (ch === 0x0a) { + this.nextChar(); + } + + break; + } else if (ch === 0x0a) { + this.nextChar(); + break; + } + + ch = this.nextChar(); + } + } + +} + +exports.Lexer = Lexer; + +class Linearization { + static create(stream) { + function getInt(linDict, name, allowZeroValue = false) { + const obj = linDict.get(name); + + if (Number.isInteger(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) { + return obj; + } + + throw new Error(`The "${name}" parameter in the linearization ` + "dictionary is invalid."); + } + + function getHints(linDict) { + const hints = linDict.get("H"); + let hintsLength; + + if (Array.isArray(hints) && ((hintsLength = hints.length) === 2 || hintsLength === 4)) { + for (let index = 0; index < hintsLength; index++) { + const hint = hints[index]; + + if (!(Number.isInteger(hint) && hint > 0)) { + throw new Error(`Hint (${index}) in the linearization dictionary is invalid.`); + } + } + + return hints; + } + + throw new Error("Hint array in the linearization dictionary is invalid."); + } + + const parser = new Parser({ + lexer: new Lexer(stream), + xref: null + }); + const obj1 = parser.getObj(); + const obj2 = parser.getObj(); + const obj3 = parser.getObj(); + const linDict = parser.getObj(); + let obj, length; + + if (!(Number.isInteger(obj1) && Number.isInteger(obj2) && (0, _primitives.isCmd)(obj3, "obj") && linDict instanceof _primitives.Dict && typeof (obj = linDict.get("Linearized")) === "number" && obj > 0)) { + return null; + } else if ((length = getInt(linDict, "L")) !== stream.length) { + throw new Error('The "L" parameter in the linearization dictionary ' + "does not equal the stream length."); + } + + return { + length, + hints: getHints(linDict), + objectNumberFirst: getInt(linDict, "O"), + endFirst: getInt(linDict, "E"), + numPages: getInt(linDict, "N"), + mainXRefEntriesOffset: getInt(linDict, "T"), + pageFirst: linDict.has("P") ? getInt(linDict, "P", true) : 0 + }; + } + +} + +exports.Linearization = Linearization; + +/***/ }), +/* 18 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Ascii85Stream = void 0; + +var _decode_stream = __w_pdfjs_require__(19); + +var _core_utils = __w_pdfjs_require__(6); + +class Ascii85Stream extends _decode_stream.DecodeStream { + constructor(str, maybeLength) { + if (maybeLength) { + maybeLength *= 0.8; + } + + super(maybeLength); + this.str = str; + this.dict = str.dict; + this.input = new Uint8Array(5); + } + + readBlock() { + const TILDA_CHAR = 0x7e; + const Z_LOWER_CHAR = 0x7a; + const EOF = -1; + const str = this.str; + let c = str.getByte(); + + while ((0, _core_utils.isWhiteSpace)(c)) { + c = str.getByte(); + } + + if (c === EOF || c === TILDA_CHAR) { + this.eof = true; + return; + } + + const bufferLength = this.bufferLength; + let buffer, i; + + if (c === Z_LOWER_CHAR) { + buffer = this.ensureBuffer(bufferLength + 4); + + for (i = 0; i < 4; ++i) { + buffer[bufferLength + i] = 0; + } + + this.bufferLength += 4; + } else { + const input = this.input; + input[0] = c; + + for (i = 1; i < 5; ++i) { + c = str.getByte(); + + while ((0, _core_utils.isWhiteSpace)(c)) { + c = str.getByte(); + } + + input[i] = c; + + if (c === EOF || c === TILDA_CHAR) { + break; + } + } + + buffer = this.ensureBuffer(bufferLength + i - 1); + this.bufferLength += i - 1; + + if (i < 5) { + for (; i < 5; ++i) { + input[i] = 0x21 + 84; + } + + this.eof = true; + } + + let t = 0; + + for (i = 0; i < 5; ++i) { + t = t * 85 + (input[i] - 0x21); + } + + for (i = 3; i >= 0; --i) { + buffer[bufferLength + i] = t & 0xff; + t >>= 8; + } + } + } + +} + +exports.Ascii85Stream = Ascii85Stream; + +/***/ }), +/* 19 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.StreamsSequenceStream = exports.DecodeStream = void 0; + +var _base_stream = __w_pdfjs_require__(7); + +var _stream = __w_pdfjs_require__(10); + +const emptyBuffer = new Uint8Array(0); + +class DecodeStream extends _base_stream.BaseStream { + constructor(maybeMinBufferLength) { + super(); + this._rawMinBufferLength = maybeMinBufferLength || 0; + this.pos = 0; + this.bufferLength = 0; + this.eof = false; + this.buffer = emptyBuffer; + this.minBufferLength = 512; + + if (maybeMinBufferLength) { + while (this.minBufferLength < maybeMinBufferLength) { + this.minBufferLength *= 2; + } + } + } + + get isEmpty() { + while (!this.eof && this.bufferLength === 0) { + this.readBlock(); + } + + return this.bufferLength === 0; + } + + ensureBuffer(requested) { + const buffer = this.buffer; + + if (requested <= buffer.byteLength) { + return buffer; + } + + let size = this.minBufferLength; + + while (size < requested) { + size *= 2; + } + + const buffer2 = new Uint8Array(size); + buffer2.set(buffer); + return this.buffer = buffer2; + } + + getByte() { + const pos = this.pos; + + while (this.bufferLength <= pos) { + if (this.eof) { + return -1; + } + + this.readBlock(); + } + + return this.buffer[this.pos++]; + } + + getBytes(length) { + const pos = this.pos; + let end; + + if (length) { + this.ensureBuffer(pos + length); + end = pos + length; + + while (!this.eof && this.bufferLength < end) { + this.readBlock(); + } + + const bufEnd = this.bufferLength; + + if (end > bufEnd) { + end = bufEnd; + } + } else { + while (!this.eof) { + this.readBlock(); + } + + end = this.bufferLength; + } + + this.pos = end; + return this.buffer.subarray(pos, end); + } + + reset() { + this.pos = 0; + } + + makeSubStream(start, length, dict = null) { + if (length === undefined) { + while (!this.eof) { + this.readBlock(); + } + } else { + const end = start + length; + + while (this.bufferLength <= end && !this.eof) { + this.readBlock(); + } + } + + return new _stream.Stream(this.buffer, start, length, dict); + } + + getBaseStreams() { + return this.str ? this.str.getBaseStreams() : null; + } + +} + +exports.DecodeStream = DecodeStream; + +class StreamsSequenceStream extends DecodeStream { + constructor(streams, onError = null) { + let maybeLength = 0; + + for (const stream of streams) { + maybeLength += stream instanceof DecodeStream ? stream._rawMinBufferLength : stream.length; + } + + super(maybeLength); + this.streams = streams; + this._onError = onError; + } + + readBlock() { + const streams = this.streams; + + if (streams.length === 0) { + this.eof = true; + return; + } + + const stream = streams.shift(); + let chunk; + + try { + chunk = stream.getBytes(); + } catch (reason) { + if (this._onError) { + this._onError(reason, stream.dict && stream.dict.objId); + + return; + } + + throw reason; + } + + const bufferLength = this.bufferLength; + const newLength = bufferLength + chunk.length; + const buffer = this.ensureBuffer(newLength); + buffer.set(chunk, bufferLength); + this.bufferLength = newLength; + } + + getBaseStreams() { + const baseStreamsBuf = []; + + for (const stream of this.streams) { + const baseStreams = stream.getBaseStreams(); + + if (baseStreams) { + baseStreamsBuf.push(...baseStreams); + } + } + + return baseStreamsBuf.length > 0 ? baseStreamsBuf : null; + } + +} + +exports.StreamsSequenceStream = StreamsSequenceStream; + +/***/ }), +/* 20 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.AsciiHexStream = void 0; + +var _decode_stream = __w_pdfjs_require__(19); + +class AsciiHexStream extends _decode_stream.DecodeStream { + constructor(str, maybeLength) { + if (maybeLength) { + maybeLength *= 0.5; + } + + super(maybeLength); + this.str = str; + this.dict = str.dict; + this.firstDigit = -1; + } + + readBlock() { + const UPSTREAM_BLOCK_SIZE = 8000; + const bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE); + + if (!bytes.length) { + this.eof = true; + return; + } + + const maxDecodeLength = bytes.length + 1 >> 1; + const buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength); + let bufferLength = this.bufferLength; + let firstDigit = this.firstDigit; + + for (const ch of bytes) { + let digit; + + if (ch >= 0x30 && ch <= 0x39) { + digit = ch & 0x0f; + } else if (ch >= 0x41 && ch <= 0x46 || ch >= 0x61 && ch <= 0x66) { + digit = (ch & 0x0f) + 9; + } else if (ch === 0x3e) { + this.eof = true; + break; + } else { + continue; + } + + if (firstDigit < 0) { + firstDigit = digit; + } else { + buffer[bufferLength++] = firstDigit << 4 | digit; + firstDigit = -1; + } + } + + if (firstDigit >= 0 && this.eof) { + buffer[bufferLength++] = firstDigit << 4; + firstDigit = -1; + } + + this.firstDigit = firstDigit; + this.bufferLength = bufferLength; + } + +} + +exports.AsciiHexStream = AsciiHexStream; + +/***/ }), +/* 21 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.CCITTFaxStream = void 0; + +var _ccitt = __w_pdfjs_require__(22); + +var _decode_stream = __w_pdfjs_require__(19); + +var _primitives = __w_pdfjs_require__(5); + +class CCITTFaxStream extends _decode_stream.DecodeStream { + constructor(str, maybeLength, params) { + super(maybeLength); + this.str = str; + this.dict = str.dict; + + if (!(params instanceof _primitives.Dict)) { + params = _primitives.Dict.empty; + } + + const source = { + next() { + return str.getByte(); + } + + }; + this.ccittFaxDecoder = new _ccitt.CCITTFaxDecoder(source, { + K: params.get("K"), + EndOfLine: params.get("EndOfLine"), + EncodedByteAlign: params.get("EncodedByteAlign"), + Columns: params.get("Columns"), + Rows: params.get("Rows"), + EndOfBlock: params.get("EndOfBlock"), + BlackIs1: params.get("BlackIs1") + }); + } + + readBlock() { + while (!this.eof) { + const c = this.ccittFaxDecoder.readNextChar(); + + if (c === -1) { + this.eof = true; + return; + } + + this.ensureBuffer(this.bufferLength + 1); + this.buffer[this.bufferLength++] = c; + } + } + +} + +exports.CCITTFaxStream = CCITTFaxStream; + +/***/ }), +/* 22 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.CCITTFaxDecoder = void 0; + +var _util = __w_pdfjs_require__(2); + +const ccittEOL = -2; +const ccittEOF = -1; +const twoDimPass = 0; +const twoDimHoriz = 1; +const twoDimVert0 = 2; +const twoDimVertR1 = 3; +const twoDimVertL1 = 4; +const twoDimVertR2 = 5; +const twoDimVertL2 = 6; +const twoDimVertR3 = 7; +const twoDimVertL3 = 8; +const twoDimTable = [[-1, -1], [-1, -1], [7, twoDimVertL3], [7, twoDimVertR3], [6, twoDimVertL2], [6, twoDimVertL2], [6, twoDimVertR2], [6, twoDimVertR2], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [4, twoDimPass], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimHoriz], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertL1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [3, twoDimVertR1], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0], [1, twoDimVert0]]; +const whiteTable1 = [[-1, -1], [12, ccittEOL], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [11, 1792], [11, 1792], [12, 1984], [12, 2048], [12, 2112], [12, 2176], [12, 2240], [12, 2304], [11, 1856], [11, 1856], [11, 1920], [11, 1920], [12, 2368], [12, 2432], [12, 2496], [12, 2560]]; +const whiteTable2 = [[-1, -1], [-1, -1], [-1, -1], [-1, -1], [8, 29], [8, 29], [8, 30], [8, 30], [8, 45], [8, 45], [8, 46], [8, 46], [7, 22], [7, 22], [7, 22], [7, 22], [7, 23], [7, 23], [7, 23], [7, 23], [8, 47], [8, 47], [8, 48], [8, 48], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [7, 20], [7, 20], [7, 20], [7, 20], [8, 33], [8, 33], [8, 34], [8, 34], [8, 35], [8, 35], [8, 36], [8, 36], [8, 37], [8, 37], [8, 38], [8, 38], [7, 19], [7, 19], [7, 19], [7, 19], [8, 31], [8, 31], [8, 32], [8, 32], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [8, 53], [8, 53], [8, 54], [8, 54], [7, 26], [7, 26], [7, 26], [7, 26], [8, 39], [8, 39], [8, 40], [8, 40], [8, 41], [8, 41], [8, 42], [8, 42], [8, 43], [8, 43], [8, 44], [8, 44], [7, 21], [7, 21], [7, 21], [7, 21], [7, 28], [7, 28], [7, 28], [7, 28], [8, 61], [8, 61], [8, 62], [8, 62], [8, 63], [8, 63], [8, 0], [8, 0], [8, 320], [8, 320], [8, 384], [8, 384], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [7, 27], [7, 27], [7, 27], [7, 27], [8, 59], [8, 59], [8, 60], [8, 60], [9, 1472], [9, 1536], [9, 1600], [9, 1728], [7, 18], [7, 18], [7, 18], [7, 18], [7, 24], [7, 24], [7, 24], [7, 24], [8, 49], [8, 49], [8, 50], [8, 50], [8, 51], [8, 51], [8, 52], [8, 52], [7, 25], [7, 25], [7, 25], [7, 25], [8, 55], [8, 55], [8, 56], [8, 56], [8, 57], [8, 57], [8, 58], [8, 58], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [8, 448], [8, 448], [8, 512], [8, 512], [9, 704], [9, 768], [8, 640], [8, 640], [8, 576], [8, 576], [9, 832], [9, 896], [9, 960], [9, 1024], [9, 1088], [9, 1152], [9, 1216], [9, 1280], [9, 1344], [9, 1408], [7, 256], [7, 256], [7, 256], [7, 256], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7]]; +const blackTable1 = [[-1, -1], [-1, -1], [12, ccittEOL], [12, ccittEOL], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [11, 1792], [11, 1792], [11, 1792], [11, 1792], [12, 1984], [12, 1984], [12, 2048], [12, 2048], [12, 2112], [12, 2112], [12, 2176], [12, 2176], [12, 2240], [12, 2240], [12, 2304], [12, 2304], [11, 1856], [11, 1856], [11, 1856], [11, 1856], [11, 1920], [11, 1920], [11, 1920], [11, 1920], [12, 2368], [12, 2368], [12, 2432], [12, 2432], [12, 2496], [12, 2496], [12, 2560], [12, 2560], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [12, 52], [12, 52], [13, 640], [13, 704], [13, 768], [13, 832], [12, 55], [12, 55], [12, 56], [12, 56], [13, 1280], [13, 1344], [13, 1408], [13, 1472], [12, 59], [12, 59], [12, 60], [12, 60], [13, 1536], [13, 1600], [11, 24], [11, 24], [11, 24], [11, 24], [11, 25], [11, 25], [11, 25], [11, 25], [13, 1664], [13, 1728], [12, 320], [12, 320], [12, 384], [12, 384], [12, 448], [12, 448], [13, 512], [13, 576], [12, 53], [12, 53], [12, 54], [12, 54], [13, 896], [13, 960], [13, 1024], [13, 1088], [13, 1152], [13, 1216], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64]]; +const blackTable2 = [[8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [11, 23], [11, 23], [12, 50], [12, 51], [12, 44], [12, 45], [12, 46], [12, 47], [12, 57], [12, 58], [12, 61], [12, 256], [10, 16], [10, 16], [10, 16], [10, 16], [10, 17], [10, 17], [10, 17], [10, 17], [12, 48], [12, 49], [12, 62], [12, 63], [12, 30], [12, 31], [12, 32], [12, 33], [12, 40], [12, 41], [11, 22], [11, 22], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [12, 128], [12, 192], [12, 26], [12, 27], [12, 28], [12, 29], [11, 19], [11, 19], [11, 20], [11, 20], [12, 34], [12, 35], [12, 36], [12, 37], [12, 38], [12, 39], [11, 21], [11, 21], [12, 42], [12, 43], [10, 0], [10, 0], [10, 0], [10, 0], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12]]; +const blackTable3 = [[-1, -1], [-1, -1], [-1, -1], [-1, -1], [6, 9], [6, 8], [5, 7], [5, 7], [4, 6], [4, 6], [4, 6], [4, 6], [4, 5], [4, 5], [4, 5], [4, 5], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2]]; + +class CCITTFaxDecoder { + constructor(source, options = {}) { + if (!source || typeof source.next !== "function") { + throw new Error('CCITTFaxDecoder - invalid "source" parameter.'); + } + + this.source = source; + this.eof = false; + this.encoding = options.K || 0; + this.eoline = options.EndOfLine || false; + this.byteAlign = options.EncodedByteAlign || false; + this.columns = options.Columns || 1728; + this.rows = options.Rows || 0; + let eoblock = options.EndOfBlock; + + if (eoblock === null || eoblock === undefined) { + eoblock = true; + } + + this.eoblock = eoblock; + this.black = options.BlackIs1 || false; + this.codingLine = new Uint32Array(this.columns + 1); + this.refLine = new Uint32Array(this.columns + 2); + this.codingLine[0] = this.columns; + this.codingPos = 0; + this.row = 0; + this.nextLine2D = this.encoding < 0; + this.inputBits = 0; + this.inputBuf = 0; + this.outputBits = 0; + this.rowsDone = false; + let code1; + + while ((code1 = this._lookBits(12)) === 0) { + this._eatBits(1); + } + + if (code1 === 1) { + this._eatBits(12); + } + + if (this.encoding > 0) { + this.nextLine2D = !this._lookBits(1); + + this._eatBits(1); + } + } + + readNextChar() { + if (this.eof) { + return -1; + } + + const refLine = this.refLine; + const codingLine = this.codingLine; + const columns = this.columns; + let refPos, blackPixels, bits, i; + + if (this.outputBits === 0) { + if (this.rowsDone) { + this.eof = true; + } + + if (this.eof) { + return -1; + } + + this.err = false; + let code1, code2, code3; + + if (this.nextLine2D) { + for (i = 0; codingLine[i] < columns; ++i) { + refLine[i] = codingLine[i]; + } + + refLine[i++] = columns; + refLine[i] = columns; + codingLine[0] = 0; + this.codingPos = 0; + refPos = 0; + blackPixels = 0; + + while (codingLine[this.codingPos] < columns) { + code1 = this._getTwoDimCode(); + + switch (code1) { + case twoDimPass: + this._addPixels(refLine[refPos + 1], blackPixels); + + if (refLine[refPos + 1] < columns) { + refPos += 2; + } + + break; + + case twoDimHoriz: + code1 = code2 = 0; + + if (blackPixels) { + do { + code1 += code3 = this._getBlackCode(); + } while (code3 >= 64); + + do { + code2 += code3 = this._getWhiteCode(); + } while (code3 >= 64); + } else { + do { + code1 += code3 = this._getWhiteCode(); + } while (code3 >= 64); + + do { + code2 += code3 = this._getBlackCode(); + } while (code3 >= 64); + } + + this._addPixels(codingLine[this.codingPos] + code1, blackPixels); + + if (codingLine[this.codingPos] < columns) { + this._addPixels(codingLine[this.codingPos] + code2, blackPixels ^ 1); + } + + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { + refPos += 2; + } + + break; + + case twoDimVertR3: + this._addPixels(refLine[refPos] + 3, blackPixels); + + blackPixels ^= 1; + + if (codingLine[this.codingPos] < columns) { + ++refPos; + + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { + refPos += 2; + } + } + + break; + + case twoDimVertR2: + this._addPixels(refLine[refPos] + 2, blackPixels); + + blackPixels ^= 1; + + if (codingLine[this.codingPos] < columns) { + ++refPos; + + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { + refPos += 2; + } + } + + break; + + case twoDimVertR1: + this._addPixels(refLine[refPos] + 1, blackPixels); + + blackPixels ^= 1; + + if (codingLine[this.codingPos] < columns) { + ++refPos; + + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { + refPos += 2; + } + } + + break; + + case twoDimVert0: + this._addPixels(refLine[refPos], blackPixels); + + blackPixels ^= 1; + + if (codingLine[this.codingPos] < columns) { + ++refPos; + + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { + refPos += 2; + } + } + + break; + + case twoDimVertL3: + this._addPixelsNeg(refLine[refPos] - 3, blackPixels); + + blackPixels ^= 1; + + if (codingLine[this.codingPos] < columns) { + if (refPos > 0) { + --refPos; + } else { + ++refPos; + } + + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { + refPos += 2; + } + } + + break; + + case twoDimVertL2: + this._addPixelsNeg(refLine[refPos] - 2, blackPixels); + + blackPixels ^= 1; + + if (codingLine[this.codingPos] < columns) { + if (refPos > 0) { + --refPos; + } else { + ++refPos; + } + + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { + refPos += 2; + } + } + + break; + + case twoDimVertL1: + this._addPixelsNeg(refLine[refPos] - 1, blackPixels); + + blackPixels ^= 1; + + if (codingLine[this.codingPos] < columns) { + if (refPos > 0) { + --refPos; + } else { + ++refPos; + } + + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { + refPos += 2; + } + } + + break; + + case ccittEOF: + this._addPixels(columns, 0); + + this.eof = true; + break; + + default: + (0, _util.info)("bad 2d code"); + + this._addPixels(columns, 0); + + this.err = true; + } + } + } else { + codingLine[0] = 0; + this.codingPos = 0; + blackPixels = 0; + + while (codingLine[this.codingPos] < columns) { + code1 = 0; + + if (blackPixels) { + do { + code1 += code3 = this._getBlackCode(); + } while (code3 >= 64); + } else { + do { + code1 += code3 = this._getWhiteCode(); + } while (code3 >= 64); + } + + this._addPixels(codingLine[this.codingPos] + code1, blackPixels); + + blackPixels ^= 1; + } + } + + let gotEOL = false; + + if (this.byteAlign) { + this.inputBits &= ~7; + } + + if (!this.eoblock && this.row === this.rows - 1) { + this.rowsDone = true; + } else { + code1 = this._lookBits(12); + + if (this.eoline) { + while (code1 !== ccittEOF && code1 !== 1) { + this._eatBits(1); + + code1 = this._lookBits(12); + } + } else { + while (code1 === 0) { + this._eatBits(1); + + code1 = this._lookBits(12); + } + } + + if (code1 === 1) { + this._eatBits(12); + + gotEOL = true; + } else if (code1 === ccittEOF) { + this.eof = true; + } + } + + if (!this.eof && this.encoding > 0 && !this.rowsDone) { + this.nextLine2D = !this._lookBits(1); + + this._eatBits(1); + } + + if (this.eoblock && gotEOL && this.byteAlign) { + code1 = this._lookBits(12); + + if (code1 === 1) { + this._eatBits(12); + + if (this.encoding > 0) { + this._lookBits(1); + + this._eatBits(1); + } + + if (this.encoding >= 0) { + for (i = 0; i < 4; ++i) { + code1 = this._lookBits(12); + + if (code1 !== 1) { + (0, _util.info)("bad rtc code: " + code1); + } + + this._eatBits(12); + + if (this.encoding > 0) { + this._lookBits(1); + + this._eatBits(1); + } + } + } + + this.eof = true; + } + } else if (this.err && this.eoline) { + while (true) { + code1 = this._lookBits(13); + + if (code1 === ccittEOF) { + this.eof = true; + return -1; + } + + if (code1 >> 1 === 1) { + break; + } + + this._eatBits(1); + } + + this._eatBits(12); + + if (this.encoding > 0) { + this._eatBits(1); + + this.nextLine2D = !(code1 & 1); + } + } + + if (codingLine[0] > 0) { + this.outputBits = codingLine[this.codingPos = 0]; + } else { + this.outputBits = codingLine[this.codingPos = 1]; + } + + this.row++; + } + + let c; + + if (this.outputBits >= 8) { + c = this.codingPos & 1 ? 0 : 0xff; + this.outputBits -= 8; + + if (this.outputBits === 0 && codingLine[this.codingPos] < columns) { + this.codingPos++; + this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; + } + } else { + bits = 8; + c = 0; + + do { + if (typeof this.outputBits !== "number") { + throw new _util.FormatError('Invalid /CCITTFaxDecode data, "outputBits" must be a number.'); + } + + if (this.outputBits > bits) { + c <<= bits; + + if (!(this.codingPos & 1)) { + c |= 0xff >> 8 - bits; + } + + this.outputBits -= bits; + bits = 0; + } else { + c <<= this.outputBits; + + if (!(this.codingPos & 1)) { + c |= 0xff >> 8 - this.outputBits; + } + + bits -= this.outputBits; + this.outputBits = 0; + + if (codingLine[this.codingPos] < columns) { + this.codingPos++; + this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; + } else if (bits > 0) { + c <<= bits; + bits = 0; + } + } + } while (bits); + } + + if (this.black) { + c ^= 0xff; + } + + return c; + } + + _addPixels(a1, blackPixels) { + const codingLine = this.codingLine; + let codingPos = this.codingPos; + + if (a1 > codingLine[codingPos]) { + if (a1 > this.columns) { + (0, _util.info)("row is wrong length"); + this.err = true; + a1 = this.columns; + } + + if (codingPos & 1 ^ blackPixels) { + ++codingPos; + } + + codingLine[codingPos] = a1; + } + + this.codingPos = codingPos; + } + + _addPixelsNeg(a1, blackPixels) { + const codingLine = this.codingLine; + let codingPos = this.codingPos; + + if (a1 > codingLine[codingPos]) { + if (a1 > this.columns) { + (0, _util.info)("row is wrong length"); + this.err = true; + a1 = this.columns; + } + + if (codingPos & 1 ^ blackPixels) { + ++codingPos; + } + + codingLine[codingPos] = a1; + } else if (a1 < codingLine[codingPos]) { + if (a1 < 0) { + (0, _util.info)("invalid code"); + this.err = true; + a1 = 0; + } + + while (codingPos > 0 && a1 < codingLine[codingPos - 1]) { + --codingPos; + } + + codingLine[codingPos] = a1; + } + + this.codingPos = codingPos; + } + + _findTableCode(start, end, table, limit) { + const limitValue = limit || 0; + + for (let i = start; i <= end; ++i) { + let code = this._lookBits(i); + + if (code === ccittEOF) { + return [true, 1, false]; + } + + if (i < end) { + code <<= end - i; + } + + if (!limitValue || code >= limitValue) { + const p = table[code - limitValue]; + + if (p[0] === i) { + this._eatBits(i); + + return [true, p[1], true]; + } + } + } + + return [false, 0, false]; + } + + _getTwoDimCode() { + let code = 0; + let p; + + if (this.eoblock) { + code = this._lookBits(7); + p = twoDimTable[code]; + + if (p && p[0] > 0) { + this._eatBits(p[0]); + + return p[1]; + } + } else { + const result = this._findTableCode(1, 7, twoDimTable); + + if (result[0] && result[2]) { + return result[1]; + } + } + + (0, _util.info)("Bad two dim code"); + return ccittEOF; + } + + _getWhiteCode() { + let code = 0; + let p; + + if (this.eoblock) { + code = this._lookBits(12); + + if (code === ccittEOF) { + return 1; + } + + if (code >> 5 === 0) { + p = whiteTable1[code]; + } else { + p = whiteTable2[code >> 3]; + } + + if (p[0] > 0) { + this._eatBits(p[0]); + + return p[1]; + } + } else { + let result = this._findTableCode(1, 9, whiteTable2); + + if (result[0]) { + return result[1]; + } + + result = this._findTableCode(11, 12, whiteTable1); + + if (result[0]) { + return result[1]; + } + } + + (0, _util.info)("bad white code"); + + this._eatBits(1); + + return 1; + } + + _getBlackCode() { + let code, p; + + if (this.eoblock) { + code = this._lookBits(13); + + if (code === ccittEOF) { + return 1; + } + + if (code >> 7 === 0) { + p = blackTable1[code]; + } else if (code >> 9 === 0 && code >> 7 !== 0) { + p = blackTable2[(code >> 1) - 64]; + } else { + p = blackTable3[code >> 7]; + } + + if (p[0] > 0) { + this._eatBits(p[0]); + + return p[1]; + } + } else { + let result = this._findTableCode(2, 6, blackTable3); + + if (result[0]) { + return result[1]; + } + + result = this._findTableCode(7, 12, blackTable2, 64); + + if (result[0]) { + return result[1]; + } + + result = this._findTableCode(10, 13, blackTable1); + + if (result[0]) { + return result[1]; + } + } + + (0, _util.info)("bad black code"); + + this._eatBits(1); + + return 1; + } + + _lookBits(n) { + let c; + + while (this.inputBits < n) { + if ((c = this.source.next()) === -1) { + if (this.inputBits === 0) { + return ccittEOF; + } + + return this.inputBuf << n - this.inputBits & 0xffff >> 16 - n; + } + + this.inputBuf = this.inputBuf << 8 | c; + this.inputBits += 8; + } + + return this.inputBuf >> this.inputBits - n & 0xffff >> 16 - n; + } + + _eatBits(n) { + if ((this.inputBits -= n) < 0) { + this.inputBits = 0; + } + } + +} + +exports.CCITTFaxDecoder = CCITTFaxDecoder; + +/***/ }), +/* 23 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.FlateStream = void 0; + +var _decode_stream = __w_pdfjs_require__(19); + +var _util = __w_pdfjs_require__(2); + +const codeLenCodeMap = new Int32Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); +const lengthDecode = new Int32Array([0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102]); +const distDecode = new Int32Array([0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001]); +const fixedLitCodeTab = [new Int32Array([0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7, 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff]), 9]; +const fixedDistCodeTab = [new Int32Array([0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000]), 5]; + +class FlateStream extends _decode_stream.DecodeStream { + constructor(str, maybeLength) { + super(maybeLength); + this.str = str; + this.dict = str.dict; + const cmf = str.getByte(); + const flg = str.getByte(); + + if (cmf === -1 || flg === -1) { + throw new _util.FormatError(`Invalid header in flate stream: ${cmf}, ${flg}`); + } + + if ((cmf & 0x0f) !== 0x08) { + throw new _util.FormatError(`Unknown compression method in flate stream: ${cmf}, ${flg}`); + } + + if (((cmf << 8) + flg) % 31 !== 0) { + throw new _util.FormatError(`Bad FCHECK in flate stream: ${cmf}, ${flg}`); + } + + if (flg & 0x20) { + throw new _util.FormatError(`FDICT bit set in flate stream: ${cmf}, ${flg}`); + } + + this.codeSize = 0; + this.codeBuf = 0; + } + + getBits(bits) { + const str = this.str; + let codeSize = this.codeSize; + let codeBuf = this.codeBuf; + let b; + + while (codeSize < bits) { + if ((b = str.getByte()) === -1) { + throw new _util.FormatError("Bad encoding in flate stream"); + } + + codeBuf |= b << codeSize; + codeSize += 8; + } + + b = codeBuf & (1 << bits) - 1; + this.codeBuf = codeBuf >> bits; + this.codeSize = codeSize -= bits; + return b; + } + + getCode(table) { + const str = this.str; + const codes = table[0]; + const maxLen = table[1]; + let codeSize = this.codeSize; + let codeBuf = this.codeBuf; + let b; + + while (codeSize < maxLen) { + if ((b = str.getByte()) === -1) { + break; + } + + codeBuf |= b << codeSize; + codeSize += 8; + } + + const code = codes[codeBuf & (1 << maxLen) - 1]; + const codeLen = code >> 16; + const codeVal = code & 0xffff; + + if (codeLen < 1 || codeSize < codeLen) { + throw new _util.FormatError("Bad encoding in flate stream"); + } + + this.codeBuf = codeBuf >> codeLen; + this.codeSize = codeSize - codeLen; + return codeVal; + } + + generateHuffmanTable(lengths) { + const n = lengths.length; + let maxLen = 0; + let i; + + for (i = 0; i < n; ++i) { + if (lengths[i] > maxLen) { + maxLen = lengths[i]; + } + } + + const size = 1 << maxLen; + const codes = new Int32Array(size); + + for (let len = 1, code = 0, skip = 2; len <= maxLen; ++len, code <<= 1, skip <<= 1) { + for (let val = 0; val < n; ++val) { + if (lengths[val] === len) { + let code2 = 0; + let t = code; + + for (i = 0; i < len; ++i) { + code2 = code2 << 1 | t & 1; + t >>= 1; + } + + for (i = code2; i < size; i += skip) { + codes[i] = len << 16 | val; + } + + ++code; + } + } + } + + return [codes, maxLen]; + } + + readBlock() { + let buffer, len; + const str = this.str; + let hdr = this.getBits(3); + + if (hdr & 1) { + this.eof = true; + } + + hdr >>= 1; + + if (hdr === 0) { + let b; + + if ((b = str.getByte()) === -1) { + throw new _util.FormatError("Bad block header in flate stream"); + } + + let blockLen = b; + + if ((b = str.getByte()) === -1) { + throw new _util.FormatError("Bad block header in flate stream"); + } + + blockLen |= b << 8; + + if ((b = str.getByte()) === -1) { + throw new _util.FormatError("Bad block header in flate stream"); + } + + let check = b; + + if ((b = str.getByte()) === -1) { + throw new _util.FormatError("Bad block header in flate stream"); + } + + check |= b << 8; + + if (check !== (~blockLen & 0xffff) && (blockLen !== 0 || check !== 0)) { + throw new _util.FormatError("Bad uncompressed block length in flate stream"); + } + + this.codeBuf = 0; + this.codeSize = 0; + const bufferLength = this.bufferLength, + end = bufferLength + blockLen; + buffer = this.ensureBuffer(end); + this.bufferLength = end; + + if (blockLen === 0) { + if (str.peekByte() === -1) { + this.eof = true; + } + } else { + const block = str.getBytes(blockLen); + buffer.set(block, bufferLength); + + if (block.length < blockLen) { + this.eof = true; + } + } + + return; + } + + let litCodeTable; + let distCodeTable; + + if (hdr === 1) { + litCodeTable = fixedLitCodeTab; + distCodeTable = fixedDistCodeTab; + } else if (hdr === 2) { + const numLitCodes = this.getBits(5) + 257; + const numDistCodes = this.getBits(5) + 1; + const numCodeLenCodes = this.getBits(4) + 4; + const codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length); + let i; + + for (i = 0; i < numCodeLenCodes; ++i) { + codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3); + } + + const codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); + len = 0; + i = 0; + const codes = numLitCodes + numDistCodes; + const codeLengths = new Uint8Array(codes); + let bitsLength, bitsOffset, what; + + while (i < codes) { + const code = this.getCode(codeLenCodeTab); + + if (code === 16) { + bitsLength = 2; + bitsOffset = 3; + what = len; + } else if (code === 17) { + bitsLength = 3; + bitsOffset = 3; + what = len = 0; + } else if (code === 18) { + bitsLength = 7; + bitsOffset = 11; + what = len = 0; + } else { + codeLengths[i++] = len = code; + continue; + } + + let repeatLength = this.getBits(bitsLength) + bitsOffset; + + while (repeatLength-- > 0) { + codeLengths[i++] = what; + } + } + + litCodeTable = this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes)); + distCodeTable = this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes)); + } else { + throw new _util.FormatError("Unknown block type in flate stream"); + } + + buffer = this.buffer; + let limit = buffer ? buffer.length : 0; + let pos = this.bufferLength; + + while (true) { + let code1 = this.getCode(litCodeTable); + + if (code1 < 256) { + if (pos + 1 >= limit) { + buffer = this.ensureBuffer(pos + 1); + limit = buffer.length; + } + + buffer[pos++] = code1; + continue; + } + + if (code1 === 256) { + this.bufferLength = pos; + return; + } + + code1 -= 257; + code1 = lengthDecode[code1]; + let code2 = code1 >> 16; + + if (code2 > 0) { + code2 = this.getBits(code2); + } + + len = (code1 & 0xffff) + code2; + code1 = this.getCode(distCodeTable); + code1 = distDecode[code1]; + code2 = code1 >> 16; + + if (code2 > 0) { + code2 = this.getBits(code2); + } + + const dist = (code1 & 0xffff) + code2; + + if (pos + len >= limit) { + buffer = this.ensureBuffer(pos + len); + limit = buffer.length; + } + + for (let k = 0; k < len; ++k, ++pos) { + buffer[pos] = buffer[pos - dist]; + } + } + } + +} + +exports.FlateStream = FlateStream; + +/***/ }), +/* 24 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Jbig2Stream = void 0; + +var _base_stream = __w_pdfjs_require__(7); + +var _decode_stream = __w_pdfjs_require__(19); + +var _primitives = __w_pdfjs_require__(5); + +var _jbig = __w_pdfjs_require__(25); + +var _util = __w_pdfjs_require__(2); + +class Jbig2Stream extends _decode_stream.DecodeStream { + constructor(stream, maybeLength, params) { + super(maybeLength); + this.stream = stream; + this.dict = stream.dict; + this.maybeLength = maybeLength; + this.params = params; + } + + get bytes() { + return (0, _util.shadow)(this, "bytes", this.stream.getBytes(this.maybeLength)); + } + + ensureBuffer(requested) {} + + readBlock() { + if (this.eof) { + return; + } + + const jbig2Image = new _jbig.Jbig2Image(); + const chunks = []; + + if (this.params instanceof _primitives.Dict) { + const globalsStream = this.params.get("JBIG2Globals"); + + if (globalsStream instanceof _base_stream.BaseStream) { + const globals = globalsStream.getBytes(); + chunks.push({ + data: globals, + start: 0, + end: globals.length + }); + } + } + + chunks.push({ + data: this.bytes, + start: 0, + end: this.bytes.length + }); + const data = jbig2Image.parseChunks(chunks); + const dataLength = data.length; + + for (let i = 0; i < dataLength; i++) { + data[i] ^= 0xff; + } + + this.buffer = data; + this.bufferLength = dataLength; + this.eof = true; + } + +} + +exports.Jbig2Stream = Jbig2Stream; + +/***/ }), +/* 25 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Jbig2Image = void 0; + +var _util = __w_pdfjs_require__(2); + +var _core_utils = __w_pdfjs_require__(6); + +var _arithmetic_decoder = __w_pdfjs_require__(26); + +var _ccitt = __w_pdfjs_require__(22); + +class Jbig2Error extends _util.BaseException { + constructor(msg) { + super(`JBIG2 error: ${msg}`, "Jbig2Error"); + } + +} + +class ContextCache { + getContexts(id) { + if (id in this) { + return this[id]; + } + + return this[id] = new Int8Array(1 << 16); + } + +} + +class DecodingContext { + constructor(data, start, end) { + this.data = data; + this.start = start; + this.end = end; + } + + get decoder() { + const decoder = new _arithmetic_decoder.ArithmeticDecoder(this.data, this.start, this.end); + return (0, _util.shadow)(this, "decoder", decoder); + } + + get contextCache() { + const cache = new ContextCache(); + return (0, _util.shadow)(this, "contextCache", cache); + } + +} + +function decodeInteger(contextCache, procedure, decoder) { + const contexts = contextCache.getContexts(procedure); + let prev = 1; + + function readBits(length) { + let v = 0; + + for (let i = 0; i < length; i++) { + const bit = decoder.readBit(contexts, prev); + prev = prev < 256 ? prev << 1 | bit : (prev << 1 | bit) & 511 | 256; + v = v << 1 | bit; + } + + return v >>> 0; + } + + const sign = readBits(1); + const value = readBits(1) ? readBits(1) ? readBits(1) ? readBits(1) ? readBits(1) ? readBits(32) + 4436 : readBits(12) + 340 : readBits(8) + 84 : readBits(6) + 20 : readBits(4) + 4 : readBits(2); + + if (sign === 0) { + return value; + } else if (value > 0) { + return -value; + } + + return null; +} + +function decodeIAID(contextCache, decoder, codeLength) { + const contexts = contextCache.getContexts("IAID"); + let prev = 1; + + for (let i = 0; i < codeLength; i++) { + const bit = decoder.readBit(contexts, prev); + prev = prev << 1 | bit; + } + + if (codeLength < 31) { + return prev & (1 << codeLength) - 1; + } + + return prev & 0x7fffffff; +} + +const SegmentTypes = ["SymbolDictionary", null, null, null, "IntermediateTextRegion", null, "ImmediateTextRegion", "ImmediateLosslessTextRegion", null, null, null, null, null, null, null, null, "PatternDictionary", null, null, null, "IntermediateHalftoneRegion", null, "ImmediateHalftoneRegion", "ImmediateLosslessHalftoneRegion", null, null, null, null, null, null, null, null, null, null, null, null, "IntermediateGenericRegion", null, "ImmediateGenericRegion", "ImmediateLosslessGenericRegion", "IntermediateGenericRefinementRegion", null, "ImmediateGenericRefinementRegion", "ImmediateLosslessGenericRefinementRegion", null, null, null, null, "PageInformation", "EndOfPage", "EndOfStripe", "EndOfFile", "Profiles", "Tables", null, null, null, null, null, null, null, null, "Extension"]; +const CodingTemplates = [[{ + x: -1, + y: -2 +}, { + x: 0, + y: -2 +}, { + x: 1, + y: -2 +}, { + x: -2, + y: -1 +}, { + x: -1, + y: -1 +}, { + x: 0, + y: -1 +}, { + x: 1, + y: -1 +}, { + x: 2, + y: -1 +}, { + x: -4, + y: 0 +}, { + x: -3, + y: 0 +}, { + x: -2, + y: 0 +}, { + x: -1, + y: 0 +}], [{ + x: -1, + y: -2 +}, { + x: 0, + y: -2 +}, { + x: 1, + y: -2 +}, { + x: 2, + y: -2 +}, { + x: -2, + y: -1 +}, { + x: -1, + y: -1 +}, { + x: 0, + y: -1 +}, { + x: 1, + y: -1 +}, { + x: 2, + y: -1 +}, { + x: -3, + y: 0 +}, { + x: -2, + y: 0 +}, { + x: -1, + y: 0 +}], [{ + x: -1, + y: -2 +}, { + x: 0, + y: -2 +}, { + x: 1, + y: -2 +}, { + x: -2, + y: -1 +}, { + x: -1, + y: -1 +}, { + x: 0, + y: -1 +}, { + x: 1, + y: -1 +}, { + x: -2, + y: 0 +}, { + x: -1, + y: 0 +}], [{ + x: -3, + y: -1 +}, { + x: -2, + y: -1 +}, { + x: -1, + y: -1 +}, { + x: 0, + y: -1 +}, { + x: 1, + y: -1 +}, { + x: -4, + y: 0 +}, { + x: -3, + y: 0 +}, { + x: -2, + y: 0 +}, { + x: -1, + y: 0 +}]]; +const RefinementTemplates = [{ + coding: [{ + x: 0, + y: -1 + }, { + x: 1, + y: -1 + }, { + x: -1, + y: 0 + }], + reference: [{ + x: 0, + y: -1 + }, { + x: 1, + y: -1 + }, { + x: -1, + y: 0 + }, { + x: 0, + y: 0 + }, { + x: 1, + y: 0 + }, { + x: -1, + y: 1 + }, { + x: 0, + y: 1 + }, { + x: 1, + y: 1 + }] +}, { + coding: [{ + x: -1, + y: -1 + }, { + x: 0, + y: -1 + }, { + x: 1, + y: -1 + }, { + x: -1, + y: 0 + }], + reference: [{ + x: 0, + y: -1 + }, { + x: -1, + y: 0 + }, { + x: 0, + y: 0 + }, { + x: 1, + y: 0 + }, { + x: 0, + y: 1 + }, { + x: 1, + y: 1 + }] +}]; +const ReusedContexts = [0x9b25, 0x0795, 0x00e5, 0x0195]; +const RefinementReusedContexts = [0x0020, 0x0008]; + +function decodeBitmapTemplate0(width, height, decodingContext) { + const decoder = decodingContext.decoder; + const contexts = decodingContext.contextCache.getContexts("GB"); + const bitmap = []; + let contextLabel, i, j, pixel, row, row1, row2; + const OLD_PIXEL_MASK = 0x7bf7; + + for (i = 0; i < height; i++) { + row = bitmap[i] = new Uint8Array(width); + row1 = i < 1 ? row : bitmap[i - 1]; + row2 = i < 2 ? row : bitmap[i - 2]; + contextLabel = row2[0] << 13 | row2[1] << 12 | row2[2] << 11 | row1[0] << 7 | row1[1] << 6 | row1[2] << 5 | row1[3] << 4; + + for (j = 0; j < width; j++) { + row[j] = pixel = decoder.readBit(contexts, contextLabel); + contextLabel = (contextLabel & OLD_PIXEL_MASK) << 1 | (j + 3 < width ? row2[j + 3] << 11 : 0) | (j + 4 < width ? row1[j + 4] << 4 : 0) | pixel; + } + } + + return bitmap; +} + +function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at, decodingContext) { + if (mmr) { + const input = new Reader(decodingContext.data, decodingContext.start, decodingContext.end); + return decodeMMRBitmap(input, width, height, false); + } + + if (templateIndex === 0 && !skip && !prediction && at.length === 4 && at[0].x === 3 && at[0].y === -1 && at[1].x === -3 && at[1].y === -1 && at[2].x === 2 && at[2].y === -2 && at[3].x === -2 && at[3].y === -2) { + return decodeBitmapTemplate0(width, height, decodingContext); + } + + const useskip = !!skip; + const template = CodingTemplates[templateIndex].concat(at); + template.sort(function (a, b) { + return a.y - b.y || a.x - b.x; + }); + const templateLength = template.length; + const templateX = new Int8Array(templateLength); + const templateY = new Int8Array(templateLength); + const changingTemplateEntries = []; + let reuseMask = 0, + minX = 0, + maxX = 0, + minY = 0; + let c, k; + + for (k = 0; k < templateLength; k++) { + templateX[k] = template[k].x; + templateY[k] = template[k].y; + minX = Math.min(minX, template[k].x); + maxX = Math.max(maxX, template[k].x); + minY = Math.min(minY, template[k].y); + + if (k < templateLength - 1 && template[k].y === template[k + 1].y && template[k].x === template[k + 1].x - 1) { + reuseMask |= 1 << templateLength - 1 - k; + } else { + changingTemplateEntries.push(k); + } + } + + const changingEntriesLength = changingTemplateEntries.length; + const changingTemplateX = new Int8Array(changingEntriesLength); + const changingTemplateY = new Int8Array(changingEntriesLength); + const changingTemplateBit = new Uint16Array(changingEntriesLength); + + for (c = 0; c < changingEntriesLength; c++) { + k = changingTemplateEntries[c]; + changingTemplateX[c] = template[k].x; + changingTemplateY[c] = template[k].y; + changingTemplateBit[c] = 1 << templateLength - 1 - k; + } + + const sbb_left = -minX; + const sbb_top = -minY; + const sbb_right = width - maxX; + const pseudoPixelContext = ReusedContexts[templateIndex]; + let row = new Uint8Array(width); + const bitmap = []; + const decoder = decodingContext.decoder; + const contexts = decodingContext.contextCache.getContexts("GB"); + let ltp = 0, + j, + i0, + j0, + contextLabel = 0, + bit, + shift; + + for (let i = 0; i < height; i++) { + if (prediction) { + const sltp = decoder.readBit(contexts, pseudoPixelContext); + ltp ^= sltp; + + if (ltp) { + bitmap.push(row); + continue; + } + } + + row = new Uint8Array(row); + bitmap.push(row); + + for (j = 0; j < width; j++) { + if (useskip && skip[i][j]) { + row[j] = 0; + continue; + } + + if (j >= sbb_left && j < sbb_right && i >= sbb_top) { + contextLabel = contextLabel << 1 & reuseMask; + + for (k = 0; k < changingEntriesLength; k++) { + i0 = i + changingTemplateY[k]; + j0 = j + changingTemplateX[k]; + bit = bitmap[i0][j0]; + + if (bit) { + bit = changingTemplateBit[k]; + contextLabel |= bit; + } + } + } else { + contextLabel = 0; + shift = templateLength - 1; + + for (k = 0; k < templateLength; k++, shift--) { + j0 = j + templateX[k]; + + if (j0 >= 0 && j0 < width) { + i0 = i + templateY[k]; + + if (i0 >= 0) { + bit = bitmap[i0][j0]; + + if (bit) { + contextLabel |= bit << shift; + } + } + } + } + } + + const pixel = decoder.readBit(contexts, contextLabel); + row[j] = pixel; + } + } + + return bitmap; +} + +function decodeRefinement(width, height, templateIndex, referenceBitmap, offsetX, offsetY, prediction, at, decodingContext) { + let codingTemplate = RefinementTemplates[templateIndex].coding; + + if (templateIndex === 0) { + codingTemplate = codingTemplate.concat([at[0]]); + } + + const codingTemplateLength = codingTemplate.length; + const codingTemplateX = new Int32Array(codingTemplateLength); + const codingTemplateY = new Int32Array(codingTemplateLength); + let k; + + for (k = 0; k < codingTemplateLength; k++) { + codingTemplateX[k] = codingTemplate[k].x; + codingTemplateY[k] = codingTemplate[k].y; + } + + let referenceTemplate = RefinementTemplates[templateIndex].reference; + + if (templateIndex === 0) { + referenceTemplate = referenceTemplate.concat([at[1]]); + } + + const referenceTemplateLength = referenceTemplate.length; + const referenceTemplateX = new Int32Array(referenceTemplateLength); + const referenceTemplateY = new Int32Array(referenceTemplateLength); + + for (k = 0; k < referenceTemplateLength; k++) { + referenceTemplateX[k] = referenceTemplate[k].x; + referenceTemplateY[k] = referenceTemplate[k].y; + } + + const referenceWidth = referenceBitmap[0].length; + const referenceHeight = referenceBitmap.length; + const pseudoPixelContext = RefinementReusedContexts[templateIndex]; + const bitmap = []; + const decoder = decodingContext.decoder; + const contexts = decodingContext.contextCache.getContexts("GR"); + let ltp = 0; + + for (let i = 0; i < height; i++) { + if (prediction) { + const sltp = decoder.readBit(contexts, pseudoPixelContext); + ltp ^= sltp; + + if (ltp) { + throw new Jbig2Error("prediction is not supported"); + } + } + + const row = new Uint8Array(width); + bitmap.push(row); + + for (let j = 0; j < width; j++) { + let i0, j0; + let contextLabel = 0; + + for (k = 0; k < codingTemplateLength; k++) { + i0 = i + codingTemplateY[k]; + j0 = j + codingTemplateX[k]; + + if (i0 < 0 || j0 < 0 || j0 >= width) { + contextLabel <<= 1; + } else { + contextLabel = contextLabel << 1 | bitmap[i0][j0]; + } + } + + for (k = 0; k < referenceTemplateLength; k++) { + i0 = i + referenceTemplateY[k] - offsetY; + j0 = j + referenceTemplateX[k] - offsetX; + + if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || j0 >= referenceWidth) { + contextLabel <<= 1; + } else { + contextLabel = contextLabel << 1 | referenceBitmap[i0][j0]; + } + } + + const pixel = decoder.readBit(contexts, contextLabel); + row[j] = pixel; + } + } + + return bitmap; +} + +function decodeSymbolDictionary(huffman, refinement, symbols, numberOfNewSymbols, numberOfExportedSymbols, huffmanTables, templateIndex, at, refinementTemplateIndex, refinementAt, decodingContext, huffmanInput) { + if (huffman && refinement) { + throw new Jbig2Error("symbol refinement with Huffman is not supported"); + } + + const newSymbols = []; + let currentHeight = 0; + let symbolCodeLength = (0, _core_utils.log2)(symbols.length + numberOfNewSymbols); + const decoder = decodingContext.decoder; + const contextCache = decodingContext.contextCache; + let tableB1, symbolWidths; + + if (huffman) { + tableB1 = getStandardTable(1); + symbolWidths = []; + symbolCodeLength = Math.max(symbolCodeLength, 1); + } + + while (newSymbols.length < numberOfNewSymbols) { + const deltaHeight = huffman ? huffmanTables.tableDeltaHeight.decode(huffmanInput) : decodeInteger(contextCache, "IADH", decoder); + currentHeight += deltaHeight; + let currentWidth = 0, + totalWidth = 0; + const firstSymbol = huffman ? symbolWidths.length : 0; + + while (true) { + const deltaWidth = huffman ? huffmanTables.tableDeltaWidth.decode(huffmanInput) : decodeInteger(contextCache, "IADW", decoder); + + if (deltaWidth === null) { + break; + } + + currentWidth += deltaWidth; + totalWidth += currentWidth; + let bitmap; + + if (refinement) { + const numberOfInstances = decodeInteger(contextCache, "IAAI", decoder); + + if (numberOfInstances > 1) { + bitmap = decodeTextRegion(huffman, refinement, currentWidth, currentHeight, 0, numberOfInstances, 1, symbols.concat(newSymbols), symbolCodeLength, 0, 0, 1, 0, huffmanTables, refinementTemplateIndex, refinementAt, decodingContext, 0, huffmanInput); + } else { + const symbolId = decodeIAID(contextCache, decoder, symbolCodeLength); + const rdx = decodeInteger(contextCache, "IARDX", decoder); + const rdy = decodeInteger(contextCache, "IARDY", decoder); + const symbol = symbolId < symbols.length ? symbols[symbolId] : newSymbols[symbolId - symbols.length]; + bitmap = decodeRefinement(currentWidth, currentHeight, refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt, decodingContext); + } + + newSymbols.push(bitmap); + } else if (huffman) { + symbolWidths.push(currentWidth); + } else { + bitmap = decodeBitmap(false, currentWidth, currentHeight, templateIndex, false, null, at, decodingContext); + newSymbols.push(bitmap); + } + } + + if (huffman && !refinement) { + const bitmapSize = huffmanTables.tableBitmapSize.decode(huffmanInput); + huffmanInput.byteAlign(); + let collectiveBitmap; + + if (bitmapSize === 0) { + collectiveBitmap = readUncompressedBitmap(huffmanInput, totalWidth, currentHeight); + } else { + const originalEnd = huffmanInput.end; + const bitmapEnd = huffmanInput.position + bitmapSize; + huffmanInput.end = bitmapEnd; + collectiveBitmap = decodeMMRBitmap(huffmanInput, totalWidth, currentHeight, false); + huffmanInput.end = originalEnd; + huffmanInput.position = bitmapEnd; + } + + const numberOfSymbolsDecoded = symbolWidths.length; + + if (firstSymbol === numberOfSymbolsDecoded - 1) { + newSymbols.push(collectiveBitmap); + } else { + let i, + y, + xMin = 0, + xMax, + bitmapWidth, + symbolBitmap; + + for (i = firstSymbol; i < numberOfSymbolsDecoded; i++) { + bitmapWidth = symbolWidths[i]; + xMax = xMin + bitmapWidth; + symbolBitmap = []; + + for (y = 0; y < currentHeight; y++) { + symbolBitmap.push(collectiveBitmap[y].subarray(xMin, xMax)); + } + + newSymbols.push(symbolBitmap); + xMin = xMax; + } + } + } + } + + const exportedSymbols = [], + flags = []; + let currentFlag = false, + i, + ii; + const totalSymbolsLength = symbols.length + numberOfNewSymbols; + + while (flags.length < totalSymbolsLength) { + let runLength = huffman ? tableB1.decode(huffmanInput) : decodeInteger(contextCache, "IAEX", decoder); + + while (runLength--) { + flags.push(currentFlag); + } + + currentFlag = !currentFlag; + } + + for (i = 0, ii = symbols.length; i < ii; i++) { + if (flags[i]) { + exportedSymbols.push(symbols[i]); + } + } + + for (let j = 0; j < numberOfNewSymbols; i++, j++) { + if (flags[i]) { + exportedSymbols.push(newSymbols[j]); + } + } + + return exportedSymbols; +} + +function decodeTextRegion(huffman, refinement, width, height, defaultPixelValue, numberOfSymbolInstances, stripSize, inputSymbols, symbolCodeLength, transposed, dsOffset, referenceCorner, combinationOperator, huffmanTables, refinementTemplateIndex, refinementAt, decodingContext, logStripSize, huffmanInput) { + if (huffman && refinement) { + throw new Jbig2Error("refinement with Huffman is not supported"); + } + + const bitmap = []; + let i, row; + + for (i = 0; i < height; i++) { + row = new Uint8Array(width); + + if (defaultPixelValue) { + for (let j = 0; j < width; j++) { + row[j] = defaultPixelValue; + } + } + + bitmap.push(row); + } + + const decoder = decodingContext.decoder; + const contextCache = decodingContext.contextCache; + let stripT = huffman ? -huffmanTables.tableDeltaT.decode(huffmanInput) : -decodeInteger(contextCache, "IADT", decoder); + let firstS = 0; + i = 0; + + while (i < numberOfSymbolInstances) { + const deltaT = huffman ? huffmanTables.tableDeltaT.decode(huffmanInput) : decodeInteger(contextCache, "IADT", decoder); + stripT += deltaT; + const deltaFirstS = huffman ? huffmanTables.tableFirstS.decode(huffmanInput) : decodeInteger(contextCache, "IAFS", decoder); + firstS += deltaFirstS; + let currentS = firstS; + + do { + let currentT = 0; + + if (stripSize > 1) { + currentT = huffman ? huffmanInput.readBits(logStripSize) : decodeInteger(contextCache, "IAIT", decoder); + } + + const t = stripSize * stripT + currentT; + const symbolId = huffman ? huffmanTables.symbolIDTable.decode(huffmanInput) : decodeIAID(contextCache, decoder, symbolCodeLength); + const applyRefinement = refinement && (huffman ? huffmanInput.readBit() : decodeInteger(contextCache, "IARI", decoder)); + let symbolBitmap = inputSymbols[symbolId]; + let symbolWidth = symbolBitmap[0].length; + let symbolHeight = symbolBitmap.length; + + if (applyRefinement) { + const rdw = decodeInteger(contextCache, "IARDW", decoder); + const rdh = decodeInteger(contextCache, "IARDH", decoder); + const rdx = decodeInteger(contextCache, "IARDX", decoder); + const rdy = decodeInteger(contextCache, "IARDY", decoder); + symbolWidth += rdw; + symbolHeight += rdh; + symbolBitmap = decodeRefinement(symbolWidth, symbolHeight, refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx, (rdh >> 1) + rdy, false, refinementAt, decodingContext); + } + + const offsetT = t - (referenceCorner & 1 ? 0 : symbolHeight - 1); + const offsetS = currentS - (referenceCorner & 2 ? symbolWidth - 1 : 0); + let s2, t2, symbolRow; + + if (transposed) { + for (s2 = 0; s2 < symbolHeight; s2++) { + row = bitmap[offsetS + s2]; + + if (!row) { + continue; + } + + symbolRow = symbolBitmap[s2]; + const maxWidth = Math.min(width - offsetT, symbolWidth); + + switch (combinationOperator) { + case 0: + for (t2 = 0; t2 < maxWidth; t2++) { + row[offsetT + t2] |= symbolRow[t2]; + } + + break; + + case 2: + for (t2 = 0; t2 < maxWidth; t2++) { + row[offsetT + t2] ^= symbolRow[t2]; + } + + break; + + default: + throw new Jbig2Error(`operator ${combinationOperator} is not supported`); + } + } + + currentS += symbolHeight - 1; + } else { + for (t2 = 0; t2 < symbolHeight; t2++) { + row = bitmap[offsetT + t2]; + + if (!row) { + continue; + } + + symbolRow = symbolBitmap[t2]; + + switch (combinationOperator) { + case 0: + for (s2 = 0; s2 < symbolWidth; s2++) { + row[offsetS + s2] |= symbolRow[s2]; + } + + break; + + case 2: + for (s2 = 0; s2 < symbolWidth; s2++) { + row[offsetS + s2] ^= symbolRow[s2]; + } + + break; + + default: + throw new Jbig2Error(`operator ${combinationOperator} is not supported`); + } + } + + currentS += symbolWidth - 1; + } + + i++; + const deltaS = huffman ? huffmanTables.tableDeltaS.decode(huffmanInput) : decodeInteger(contextCache, "IADS", decoder); + + if (deltaS === null) { + break; + } + + currentS += deltaS + dsOffset; + } while (true); + } + + return bitmap; +} + +function decodePatternDictionary(mmr, patternWidth, patternHeight, maxPatternIndex, template, decodingContext) { + const at = []; + + if (!mmr) { + at.push({ + x: -patternWidth, + y: 0 + }); + + if (template === 0) { + at.push({ + x: -3, + y: -1 + }, { + x: 2, + y: -2 + }, { + x: -2, + y: -2 + }); + } + } + + const collectiveWidth = (maxPatternIndex + 1) * patternWidth; + const collectiveBitmap = decodeBitmap(mmr, collectiveWidth, patternHeight, template, false, null, at, decodingContext); + const patterns = []; + + for (let i = 0; i <= maxPatternIndex; i++) { + const patternBitmap = []; + const xMin = patternWidth * i; + const xMax = xMin + patternWidth; + + for (let y = 0; y < patternHeight; y++) { + patternBitmap.push(collectiveBitmap[y].subarray(xMin, xMax)); + } + + patterns.push(patternBitmap); + } + + return patterns; +} + +function decodeHalftoneRegion(mmr, patterns, template, regionWidth, regionHeight, defaultPixelValue, enableSkip, combinationOperator, gridWidth, gridHeight, gridOffsetX, gridOffsetY, gridVectorX, gridVectorY, decodingContext) { + const skip = null; + + if (enableSkip) { + throw new Jbig2Error("skip is not supported"); + } + + if (combinationOperator !== 0) { + throw new Jbig2Error(`operator "${combinationOperator}" is not supported in halftone region`); + } + + const regionBitmap = []; + let i, j, row; + + for (i = 0; i < regionHeight; i++) { + row = new Uint8Array(regionWidth); + + if (defaultPixelValue) { + for (j = 0; j < regionWidth; j++) { + row[j] = defaultPixelValue; + } + } + + regionBitmap.push(row); + } + + const numberOfPatterns = patterns.length; + const pattern0 = patterns[0]; + const patternWidth = pattern0[0].length, + patternHeight = pattern0.length; + const bitsPerValue = (0, _core_utils.log2)(numberOfPatterns); + const at = []; + + if (!mmr) { + at.push({ + x: template <= 1 ? 3 : 2, + y: -1 + }); + + if (template === 0) { + at.push({ + x: -3, + y: -1 + }, { + x: 2, + y: -2 + }, { + x: -2, + y: -2 + }); + } + } + + const grayScaleBitPlanes = []; + let mmrInput, bitmap; + + if (mmr) { + mmrInput = new Reader(decodingContext.data, decodingContext.start, decodingContext.end); + } + + for (i = bitsPerValue - 1; i >= 0; i--) { + if (mmr) { + bitmap = decodeMMRBitmap(mmrInput, gridWidth, gridHeight, true); + } else { + bitmap = decodeBitmap(false, gridWidth, gridHeight, template, false, skip, at, decodingContext); + } + + grayScaleBitPlanes[i] = bitmap; + } + + let mg, ng, bit, patternIndex, patternBitmap, x, y, patternRow, regionRow; + + for (mg = 0; mg < gridHeight; mg++) { + for (ng = 0; ng < gridWidth; ng++) { + bit = 0; + patternIndex = 0; + + for (j = bitsPerValue - 1; j >= 0; j--) { + bit ^= grayScaleBitPlanes[j][mg][ng]; + patternIndex |= bit << j; + } + + patternBitmap = patterns[patternIndex]; + x = gridOffsetX + mg * gridVectorY + ng * gridVectorX >> 8; + y = gridOffsetY + mg * gridVectorX - ng * gridVectorY >> 8; + + if (x >= 0 && x + patternWidth <= regionWidth && y >= 0 && y + patternHeight <= regionHeight) { + for (i = 0; i < patternHeight; i++) { + regionRow = regionBitmap[y + i]; + patternRow = patternBitmap[i]; + + for (j = 0; j < patternWidth; j++) { + regionRow[x + j] |= patternRow[j]; + } + } + } else { + let regionX, regionY; + + for (i = 0; i < patternHeight; i++) { + regionY = y + i; + + if (regionY < 0 || regionY >= regionHeight) { + continue; + } + + regionRow = regionBitmap[regionY]; + patternRow = patternBitmap[i]; + + for (j = 0; j < patternWidth; j++) { + regionX = x + j; + + if (regionX >= 0 && regionX < regionWidth) { + regionRow[regionX] |= patternRow[j]; + } + } + } + } + } + } + + return regionBitmap; +} + +function readSegmentHeader(data, start) { + const segmentHeader = {}; + segmentHeader.number = (0, _core_utils.readUint32)(data, start); + const flags = data[start + 4]; + const segmentType = flags & 0x3f; + + if (!SegmentTypes[segmentType]) { + throw new Jbig2Error("invalid segment type: " + segmentType); + } + + segmentHeader.type = segmentType; + segmentHeader.typeName = SegmentTypes[segmentType]; + segmentHeader.deferredNonRetain = !!(flags & 0x80); + const pageAssociationFieldSize = !!(flags & 0x40); + const referredFlags = data[start + 5]; + let referredToCount = referredFlags >> 5 & 7; + const retainBits = [referredFlags & 31]; + let position = start + 6; + + if (referredFlags === 7) { + referredToCount = (0, _core_utils.readUint32)(data, position - 1) & 0x1fffffff; + position += 3; + let bytes = referredToCount + 7 >> 3; + retainBits[0] = data[position++]; + + while (--bytes > 0) { + retainBits.push(data[position++]); + } + } else if (referredFlags === 5 || referredFlags === 6) { + throw new Jbig2Error("invalid referred-to flags"); + } + + segmentHeader.retainBits = retainBits; + let referredToSegmentNumberSize = 4; + + if (segmentHeader.number <= 256) { + referredToSegmentNumberSize = 1; + } else if (segmentHeader.number <= 65536) { + referredToSegmentNumberSize = 2; + } + + const referredTo = []; + let i, ii; + + for (i = 0; i < referredToCount; i++) { + let number; + + if (referredToSegmentNumberSize === 1) { + number = data[position]; + } else if (referredToSegmentNumberSize === 2) { + number = (0, _core_utils.readUint16)(data, position); + } else { + number = (0, _core_utils.readUint32)(data, position); + } + + referredTo.push(number); + position += referredToSegmentNumberSize; + } + + segmentHeader.referredTo = referredTo; + + if (!pageAssociationFieldSize) { + segmentHeader.pageAssociation = data[position++]; + } else { + segmentHeader.pageAssociation = (0, _core_utils.readUint32)(data, position); + position += 4; + } + + segmentHeader.length = (0, _core_utils.readUint32)(data, position); + position += 4; + + if (segmentHeader.length === 0xffffffff) { + if (segmentType === 38) { + const genericRegionInfo = readRegionSegmentInformation(data, position); + const genericRegionSegmentFlags = data[position + RegionSegmentInformationFieldLength]; + const genericRegionMmr = !!(genericRegionSegmentFlags & 1); + const searchPatternLength = 6; + const searchPattern = new Uint8Array(searchPatternLength); + + if (!genericRegionMmr) { + searchPattern[0] = 0xff; + searchPattern[1] = 0xac; + } + + searchPattern[2] = genericRegionInfo.height >>> 24 & 0xff; + searchPattern[3] = genericRegionInfo.height >> 16 & 0xff; + searchPattern[4] = genericRegionInfo.height >> 8 & 0xff; + searchPattern[5] = genericRegionInfo.height & 0xff; + + for (i = position, ii = data.length; i < ii; i++) { + let j = 0; + + while (j < searchPatternLength && searchPattern[j] === data[i + j]) { + j++; + } + + if (j === searchPatternLength) { + segmentHeader.length = i + searchPatternLength; + break; + } + } + + if (segmentHeader.length === 0xffffffff) { + throw new Jbig2Error("segment end was not found"); + } + } else { + throw new Jbig2Error("invalid unknown segment length"); + } + } + + segmentHeader.headerEnd = position; + return segmentHeader; +} + +function readSegments(header, data, start, end) { + const segments = []; + let position = start; + + while (position < end) { + const segmentHeader = readSegmentHeader(data, position); + position = segmentHeader.headerEnd; + const segment = { + header: segmentHeader, + data + }; + + if (!header.randomAccess) { + segment.start = position; + position += segmentHeader.length; + segment.end = position; + } + + segments.push(segment); + + if (segmentHeader.type === 51) { + break; + } + } + + if (header.randomAccess) { + for (let i = 0, ii = segments.length; i < ii; i++) { + segments[i].start = position; + position += segments[i].header.length; + segments[i].end = position; + } + } + + return segments; +} + +function readRegionSegmentInformation(data, start) { + return { + width: (0, _core_utils.readUint32)(data, start), + height: (0, _core_utils.readUint32)(data, start + 4), + x: (0, _core_utils.readUint32)(data, start + 8), + y: (0, _core_utils.readUint32)(data, start + 12), + combinationOperator: data[start + 16] & 7 + }; +} + +const RegionSegmentInformationFieldLength = 17; + +function processSegment(segment, visitor) { + const header = segment.header; + const data = segment.data, + end = segment.end; + let position = segment.start; + let args, at, i, atLength; + + switch (header.type) { + case 0: + const dictionary = {}; + const dictionaryFlags = (0, _core_utils.readUint16)(data, position); + dictionary.huffman = !!(dictionaryFlags & 1); + dictionary.refinement = !!(dictionaryFlags & 2); + dictionary.huffmanDHSelector = dictionaryFlags >> 2 & 3; + dictionary.huffmanDWSelector = dictionaryFlags >> 4 & 3; + dictionary.bitmapSizeSelector = dictionaryFlags >> 6 & 1; + dictionary.aggregationInstancesSelector = dictionaryFlags >> 7 & 1; + dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256); + dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512); + dictionary.template = dictionaryFlags >> 10 & 3; + dictionary.refinementTemplate = dictionaryFlags >> 12 & 1; + position += 2; + + if (!dictionary.huffman) { + atLength = dictionary.template === 0 ? 4 : 1; + at = []; + + for (i = 0; i < atLength; i++) { + at.push({ + x: (0, _core_utils.readInt8)(data, position), + y: (0, _core_utils.readInt8)(data, position + 1) + }); + position += 2; + } + + dictionary.at = at; + } + + if (dictionary.refinement && !dictionary.refinementTemplate) { + at = []; + + for (i = 0; i < 2; i++) { + at.push({ + x: (0, _core_utils.readInt8)(data, position), + y: (0, _core_utils.readInt8)(data, position + 1) + }); + position += 2; + } + + dictionary.refinementAt = at; + } + + dictionary.numberOfExportedSymbols = (0, _core_utils.readUint32)(data, position); + position += 4; + dictionary.numberOfNewSymbols = (0, _core_utils.readUint32)(data, position); + position += 4; + args = [dictionary, header.number, header.referredTo, data, position, end]; + break; + + case 6: + case 7: + const textRegion = {}; + textRegion.info = readRegionSegmentInformation(data, position); + position += RegionSegmentInformationFieldLength; + const textRegionSegmentFlags = (0, _core_utils.readUint16)(data, position); + position += 2; + textRegion.huffman = !!(textRegionSegmentFlags & 1); + textRegion.refinement = !!(textRegionSegmentFlags & 2); + textRegion.logStripSize = textRegionSegmentFlags >> 2 & 3; + textRegion.stripSize = 1 << textRegion.logStripSize; + textRegion.referenceCorner = textRegionSegmentFlags >> 4 & 3; + textRegion.transposed = !!(textRegionSegmentFlags & 64); + textRegion.combinationOperator = textRegionSegmentFlags >> 7 & 3; + textRegion.defaultPixelValue = textRegionSegmentFlags >> 9 & 1; + textRegion.dsOffset = textRegionSegmentFlags << 17 >> 27; + textRegion.refinementTemplate = textRegionSegmentFlags >> 15 & 1; + + if (textRegion.huffman) { + const textRegionHuffmanFlags = (0, _core_utils.readUint16)(data, position); + position += 2; + textRegion.huffmanFS = textRegionHuffmanFlags & 3; + textRegion.huffmanDS = textRegionHuffmanFlags >> 2 & 3; + textRegion.huffmanDT = textRegionHuffmanFlags >> 4 & 3; + textRegion.huffmanRefinementDW = textRegionHuffmanFlags >> 6 & 3; + textRegion.huffmanRefinementDH = textRegionHuffmanFlags >> 8 & 3; + textRegion.huffmanRefinementDX = textRegionHuffmanFlags >> 10 & 3; + textRegion.huffmanRefinementDY = textRegionHuffmanFlags >> 12 & 3; + textRegion.huffmanRefinementSizeSelector = !!(textRegionHuffmanFlags & 0x4000); + } + + if (textRegion.refinement && !textRegion.refinementTemplate) { + at = []; + + for (i = 0; i < 2; i++) { + at.push({ + x: (0, _core_utils.readInt8)(data, position), + y: (0, _core_utils.readInt8)(data, position + 1) + }); + position += 2; + } + + textRegion.refinementAt = at; + } + + textRegion.numberOfSymbolInstances = (0, _core_utils.readUint32)(data, position); + position += 4; + args = [textRegion, header.referredTo, data, position, end]; + break; + + case 16: + const patternDictionary = {}; + const patternDictionaryFlags = data[position++]; + patternDictionary.mmr = !!(patternDictionaryFlags & 1); + patternDictionary.template = patternDictionaryFlags >> 1 & 3; + patternDictionary.patternWidth = data[position++]; + patternDictionary.patternHeight = data[position++]; + patternDictionary.maxPatternIndex = (0, _core_utils.readUint32)(data, position); + position += 4; + args = [patternDictionary, header.number, data, position, end]; + break; + + case 22: + case 23: + const halftoneRegion = {}; + halftoneRegion.info = readRegionSegmentInformation(data, position); + position += RegionSegmentInformationFieldLength; + const halftoneRegionFlags = data[position++]; + halftoneRegion.mmr = !!(halftoneRegionFlags & 1); + halftoneRegion.template = halftoneRegionFlags >> 1 & 3; + halftoneRegion.enableSkip = !!(halftoneRegionFlags & 8); + halftoneRegion.combinationOperator = halftoneRegionFlags >> 4 & 7; + halftoneRegion.defaultPixelValue = halftoneRegionFlags >> 7 & 1; + halftoneRegion.gridWidth = (0, _core_utils.readUint32)(data, position); + position += 4; + halftoneRegion.gridHeight = (0, _core_utils.readUint32)(data, position); + position += 4; + halftoneRegion.gridOffsetX = (0, _core_utils.readUint32)(data, position) & 0xffffffff; + position += 4; + halftoneRegion.gridOffsetY = (0, _core_utils.readUint32)(data, position) & 0xffffffff; + position += 4; + halftoneRegion.gridVectorX = (0, _core_utils.readUint16)(data, position); + position += 2; + halftoneRegion.gridVectorY = (0, _core_utils.readUint16)(data, position); + position += 2; + args = [halftoneRegion, header.referredTo, data, position, end]; + break; + + case 38: + case 39: + const genericRegion = {}; + genericRegion.info = readRegionSegmentInformation(data, position); + position += RegionSegmentInformationFieldLength; + const genericRegionSegmentFlags = data[position++]; + genericRegion.mmr = !!(genericRegionSegmentFlags & 1); + genericRegion.template = genericRegionSegmentFlags >> 1 & 3; + genericRegion.prediction = !!(genericRegionSegmentFlags & 8); + + if (!genericRegion.mmr) { + atLength = genericRegion.template === 0 ? 4 : 1; + at = []; + + for (i = 0; i < atLength; i++) { + at.push({ + x: (0, _core_utils.readInt8)(data, position), + y: (0, _core_utils.readInt8)(data, position + 1) + }); + position += 2; + } + + genericRegion.at = at; + } + + args = [genericRegion, data, position, end]; + break; + + case 48: + const pageInfo = { + width: (0, _core_utils.readUint32)(data, position), + height: (0, _core_utils.readUint32)(data, position + 4), + resolutionX: (0, _core_utils.readUint32)(data, position + 8), + resolutionY: (0, _core_utils.readUint32)(data, position + 12) + }; + + if (pageInfo.height === 0xffffffff) { + delete pageInfo.height; + } + + const pageSegmentFlags = data[position + 16]; + (0, _core_utils.readUint16)(data, position + 17); + pageInfo.lossless = !!(pageSegmentFlags & 1); + pageInfo.refinement = !!(pageSegmentFlags & 2); + pageInfo.defaultPixelValue = pageSegmentFlags >> 2 & 1; + pageInfo.combinationOperator = pageSegmentFlags >> 3 & 3; + pageInfo.requiresBuffer = !!(pageSegmentFlags & 32); + pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64); + args = [pageInfo]; + break; + + case 49: + break; + + case 50: + break; + + case 51: + break; + + case 53: + args = [header.number, data, position, end]; + break; + + case 62: + break; + + default: + throw new Jbig2Error(`segment type ${header.typeName}(${header.type}) is not implemented`); + } + + const callbackName = "on" + header.typeName; + + if (callbackName in visitor) { + visitor[callbackName].apply(visitor, args); + } +} + +function processSegments(segments, visitor) { + for (let i = 0, ii = segments.length; i < ii; i++) { + processSegment(segments[i], visitor); + } +} + +function parseJbig2Chunks(chunks) { + const visitor = new SimpleSegmentVisitor(); + + for (let i = 0, ii = chunks.length; i < ii; i++) { + const chunk = chunks[i]; + const segments = readSegments({}, chunk.data, chunk.start, chunk.end); + processSegments(segments, visitor); + } + + return visitor.buffer; +} + +function parseJbig2(data) { + throw new Error("Not implemented: parseJbig2"); +} + +class SimpleSegmentVisitor { + onPageInformation(info) { + this.currentPageInfo = info; + const rowSize = info.width + 7 >> 3; + const buffer = new Uint8ClampedArray(rowSize * info.height); + + if (info.defaultPixelValue) { + buffer.fill(0xff); + } + + this.buffer = buffer; + } + + drawBitmap(regionInfo, bitmap) { + const pageInfo = this.currentPageInfo; + const width = regionInfo.width, + height = regionInfo.height; + const rowSize = pageInfo.width + 7 >> 3; + const combinationOperator = pageInfo.combinationOperatorOverride ? regionInfo.combinationOperator : pageInfo.combinationOperator; + const buffer = this.buffer; + const mask0 = 128 >> (regionInfo.x & 7); + let offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3); + let i, j, mask, offset; + + switch (combinationOperator) { + case 0: + for (i = 0; i < height; i++) { + mask = mask0; + offset = offset0; + + for (j = 0; j < width; j++) { + if (bitmap[i][j]) { + buffer[offset] |= mask; + } + + mask >>= 1; + + if (!mask) { + mask = 128; + offset++; + } + } + + offset0 += rowSize; + } + + break; + + case 2: + for (i = 0; i < height; i++) { + mask = mask0; + offset = offset0; + + for (j = 0; j < width; j++) { + if (bitmap[i][j]) { + buffer[offset] ^= mask; + } + + mask >>= 1; + + if (!mask) { + mask = 128; + offset++; + } + } + + offset0 += rowSize; + } + + break; + + default: + throw new Jbig2Error(`operator ${combinationOperator} is not supported`); + } + } + + onImmediateGenericRegion(region, data, start, end) { + const regionInfo = region.info; + const decodingContext = new DecodingContext(data, start, end); + const bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height, region.template, region.prediction, null, region.at, decodingContext); + this.drawBitmap(regionInfo, bitmap); + } + + onImmediateLosslessGenericRegion() { + this.onImmediateGenericRegion(...arguments); + } + + onSymbolDictionary(dictionary, currentSegment, referredSegments, data, start, end) { + let huffmanTables, huffmanInput; + + if (dictionary.huffman) { + huffmanTables = getSymbolDictionaryHuffmanTables(dictionary, referredSegments, this.customTables); + huffmanInput = new Reader(data, start, end); + } + + let symbols = this.symbols; + + if (!symbols) { + this.symbols = symbols = {}; + } + + const inputSymbols = []; + + for (const referredSegment of referredSegments) { + const referredSymbols = symbols[referredSegment]; + + if (referredSymbols) { + inputSymbols.push(...referredSymbols); + } + } + + const decodingContext = new DecodingContext(data, start, end); + symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman, dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols, dictionary.numberOfExportedSymbols, huffmanTables, dictionary.template, dictionary.at, dictionary.refinementTemplate, dictionary.refinementAt, decodingContext, huffmanInput); + } + + onImmediateTextRegion(region, referredSegments, data, start, end) { + const regionInfo = region.info; + let huffmanTables, huffmanInput; + const symbols = this.symbols; + const inputSymbols = []; + + for (const referredSegment of referredSegments) { + const referredSymbols = symbols[referredSegment]; + + if (referredSymbols) { + inputSymbols.push(...referredSymbols); + } + } + + const symbolCodeLength = (0, _core_utils.log2)(inputSymbols.length); + + if (region.huffman) { + huffmanInput = new Reader(data, start, end); + huffmanTables = getTextRegionHuffmanTables(region, referredSegments, this.customTables, inputSymbols.length, huffmanInput); + } + + const decodingContext = new DecodingContext(data, start, end); + const bitmap = decodeTextRegion(region.huffman, region.refinement, regionInfo.width, regionInfo.height, region.defaultPixelValue, region.numberOfSymbolInstances, region.stripSize, inputSymbols, symbolCodeLength, region.transposed, region.dsOffset, region.referenceCorner, region.combinationOperator, huffmanTables, region.refinementTemplate, region.refinementAt, decodingContext, region.logStripSize, huffmanInput); + this.drawBitmap(regionInfo, bitmap); + } + + onImmediateLosslessTextRegion() { + this.onImmediateTextRegion(...arguments); + } + + onPatternDictionary(dictionary, currentSegment, data, start, end) { + let patterns = this.patterns; + + if (!patterns) { + this.patterns = patterns = {}; + } + + const decodingContext = new DecodingContext(data, start, end); + patterns[currentSegment] = decodePatternDictionary(dictionary.mmr, dictionary.patternWidth, dictionary.patternHeight, dictionary.maxPatternIndex, dictionary.template, decodingContext); + } + + onImmediateHalftoneRegion(region, referredSegments, data, start, end) { + const patterns = this.patterns[referredSegments[0]]; + const regionInfo = region.info; + const decodingContext = new DecodingContext(data, start, end); + const bitmap = decodeHalftoneRegion(region.mmr, patterns, region.template, regionInfo.width, regionInfo.height, region.defaultPixelValue, region.enableSkip, region.combinationOperator, region.gridWidth, region.gridHeight, region.gridOffsetX, region.gridOffsetY, region.gridVectorX, region.gridVectorY, decodingContext); + this.drawBitmap(regionInfo, bitmap); + } + + onImmediateLosslessHalftoneRegion() { + this.onImmediateHalftoneRegion(...arguments); + } + + onTables(currentSegment, data, start, end) { + let customTables = this.customTables; + + if (!customTables) { + this.customTables = customTables = {}; + } + + customTables[currentSegment] = decodeTablesSegment(data, start, end); + } + +} + +class HuffmanLine { + constructor(lineData) { + if (lineData.length === 2) { + this.isOOB = true; + this.rangeLow = 0; + this.prefixLength = lineData[0]; + this.rangeLength = 0; + this.prefixCode = lineData[1]; + this.isLowerRange = false; + } else { + this.isOOB = false; + this.rangeLow = lineData[0]; + this.prefixLength = lineData[1]; + this.rangeLength = lineData[2]; + this.prefixCode = lineData[3]; + this.isLowerRange = lineData[4] === "lower"; + } + } + +} + +class HuffmanTreeNode { + constructor(line) { + this.children = []; + + if (line) { + this.isLeaf = true; + this.rangeLength = line.rangeLength; + this.rangeLow = line.rangeLow; + this.isLowerRange = line.isLowerRange; + this.isOOB = line.isOOB; + } else { + this.isLeaf = false; + } + } + + buildTree(line, shift) { + const bit = line.prefixCode >> shift & 1; + + if (shift <= 0) { + this.children[bit] = new HuffmanTreeNode(line); + } else { + let node = this.children[bit]; + + if (!node) { + this.children[bit] = node = new HuffmanTreeNode(null); + } + + node.buildTree(line, shift - 1); + } + } + + decodeNode(reader) { + if (this.isLeaf) { + if (this.isOOB) { + return null; + } + + const htOffset = reader.readBits(this.rangeLength); + return this.rangeLow + (this.isLowerRange ? -htOffset : htOffset); + } + + const node = this.children[reader.readBit()]; + + if (!node) { + throw new Jbig2Error("invalid Huffman data"); + } + + return node.decodeNode(reader); + } + +} + +class HuffmanTable { + constructor(lines, prefixCodesDone) { + if (!prefixCodesDone) { + this.assignPrefixCodes(lines); + } + + this.rootNode = new HuffmanTreeNode(null); + + for (let i = 0, ii = lines.length; i < ii; i++) { + const line = lines[i]; + + if (line.prefixLength > 0) { + this.rootNode.buildTree(line, line.prefixLength - 1); + } + } + } + + decode(reader) { + return this.rootNode.decodeNode(reader); + } + + assignPrefixCodes(lines) { + const linesLength = lines.length; + let prefixLengthMax = 0; + + for (let i = 0; i < linesLength; i++) { + prefixLengthMax = Math.max(prefixLengthMax, lines[i].prefixLength); + } + + const histogram = new Uint32Array(prefixLengthMax + 1); + + for (let i = 0; i < linesLength; i++) { + histogram[lines[i].prefixLength]++; + } + + let currentLength = 1, + firstCode = 0, + currentCode, + currentTemp, + line; + histogram[0] = 0; + + while (currentLength <= prefixLengthMax) { + firstCode = firstCode + histogram[currentLength - 1] << 1; + currentCode = firstCode; + currentTemp = 0; + + while (currentTemp < linesLength) { + line = lines[currentTemp]; + + if (line.prefixLength === currentLength) { + line.prefixCode = currentCode; + currentCode++; + } + + currentTemp++; + } + + currentLength++; + } + } + +} + +function decodeTablesSegment(data, start, end) { + const flags = data[start]; + const lowestValue = (0, _core_utils.readUint32)(data, start + 1) & 0xffffffff; + const highestValue = (0, _core_utils.readUint32)(data, start + 5) & 0xffffffff; + const reader = new Reader(data, start + 9, end); + const prefixSizeBits = (flags >> 1 & 7) + 1; + const rangeSizeBits = (flags >> 4 & 7) + 1; + const lines = []; + let prefixLength, + rangeLength, + currentRangeLow = lowestValue; + + do { + prefixLength = reader.readBits(prefixSizeBits); + rangeLength = reader.readBits(rangeSizeBits); + lines.push(new HuffmanLine([currentRangeLow, prefixLength, rangeLength, 0])); + currentRangeLow += 1 << rangeLength; + } while (currentRangeLow < highestValue); + + prefixLength = reader.readBits(prefixSizeBits); + lines.push(new HuffmanLine([lowestValue - 1, prefixLength, 32, 0, "lower"])); + prefixLength = reader.readBits(prefixSizeBits); + lines.push(new HuffmanLine([highestValue, prefixLength, 32, 0])); + + if (flags & 1) { + prefixLength = reader.readBits(prefixSizeBits); + lines.push(new HuffmanLine([prefixLength, 0])); + } + + return new HuffmanTable(lines, false); +} + +const standardTablesCache = {}; + +function getStandardTable(number) { + let table = standardTablesCache[number]; + + if (table) { + return table; + } + + let lines; + + switch (number) { + case 1: + lines = [[0, 1, 4, 0x0], [16, 2, 8, 0x2], [272, 3, 16, 0x6], [65808, 3, 32, 0x7]]; + break; + + case 2: + lines = [[0, 1, 0, 0x0], [1, 2, 0, 0x2], [2, 3, 0, 0x6], [3, 4, 3, 0xe], [11, 5, 6, 0x1e], [75, 6, 32, 0x3e], [6, 0x3f]]; + break; + + case 3: + lines = [[-256, 8, 8, 0xfe], [0, 1, 0, 0x0], [1, 2, 0, 0x2], [2, 3, 0, 0x6], [3, 4, 3, 0xe], [11, 5, 6, 0x1e], [-257, 8, 32, 0xff, "lower"], [75, 7, 32, 0x7e], [6, 0x3e]]; + break; + + case 4: + lines = [[1, 1, 0, 0x0], [2, 2, 0, 0x2], [3, 3, 0, 0x6], [4, 4, 3, 0xe], [12, 5, 6, 0x1e], [76, 5, 32, 0x1f]]; + break; + + case 5: + lines = [[-255, 7, 8, 0x7e], [1, 1, 0, 0x0], [2, 2, 0, 0x2], [3, 3, 0, 0x6], [4, 4, 3, 0xe], [12, 5, 6, 0x1e], [-256, 7, 32, 0x7f, "lower"], [76, 6, 32, 0x3e]]; + break; + + case 6: + lines = [[-2048, 5, 10, 0x1c], [-1024, 4, 9, 0x8], [-512, 4, 8, 0x9], [-256, 4, 7, 0xa], [-128, 5, 6, 0x1d], [-64, 5, 5, 0x1e], [-32, 4, 5, 0xb], [0, 2, 7, 0x0], [128, 3, 7, 0x2], [256, 3, 8, 0x3], [512, 4, 9, 0xc], [1024, 4, 10, 0xd], [-2049, 6, 32, 0x3e, "lower"], [2048, 6, 32, 0x3f]]; + break; + + case 7: + lines = [[-1024, 4, 9, 0x8], [-512, 3, 8, 0x0], [-256, 4, 7, 0x9], [-128, 5, 6, 0x1a], [-64, 5, 5, 0x1b], [-32, 4, 5, 0xa], [0, 4, 5, 0xb], [32, 5, 5, 0x1c], [64, 5, 6, 0x1d], [128, 4, 7, 0xc], [256, 3, 8, 0x1], [512, 3, 9, 0x2], [1024, 3, 10, 0x3], [-1025, 5, 32, 0x1e, "lower"], [2048, 5, 32, 0x1f]]; + break; + + case 8: + lines = [[-15, 8, 3, 0xfc], [-7, 9, 1, 0x1fc], [-5, 8, 1, 0xfd], [-3, 9, 0, 0x1fd], [-2, 7, 0, 0x7c], [-1, 4, 0, 0xa], [0, 2, 1, 0x0], [2, 5, 0, 0x1a], [3, 6, 0, 0x3a], [4, 3, 4, 0x4], [20, 6, 1, 0x3b], [22, 4, 4, 0xb], [38, 4, 5, 0xc], [70, 5, 6, 0x1b], [134, 5, 7, 0x1c], [262, 6, 7, 0x3c], [390, 7, 8, 0x7d], [646, 6, 10, 0x3d], [-16, 9, 32, 0x1fe, "lower"], [1670, 9, 32, 0x1ff], [2, 0x1]]; + break; + + case 9: + lines = [[-31, 8, 4, 0xfc], [-15, 9, 2, 0x1fc], [-11, 8, 2, 0xfd], [-7, 9, 1, 0x1fd], [-5, 7, 1, 0x7c], [-3, 4, 1, 0xa], [-1, 3, 1, 0x2], [1, 3, 1, 0x3], [3, 5, 1, 0x1a], [5, 6, 1, 0x3a], [7, 3, 5, 0x4], [39, 6, 2, 0x3b], [43, 4, 5, 0xb], [75, 4, 6, 0xc], [139, 5, 7, 0x1b], [267, 5, 8, 0x1c], [523, 6, 8, 0x3c], [779, 7, 9, 0x7d], [1291, 6, 11, 0x3d], [-32, 9, 32, 0x1fe, "lower"], [3339, 9, 32, 0x1ff], [2, 0x0]]; + break; + + case 10: + lines = [[-21, 7, 4, 0x7a], [-5, 8, 0, 0xfc], [-4, 7, 0, 0x7b], [-3, 5, 0, 0x18], [-2, 2, 2, 0x0], [2, 5, 0, 0x19], [3, 6, 0, 0x36], [4, 7, 0, 0x7c], [5, 8, 0, 0xfd], [6, 2, 6, 0x1], [70, 5, 5, 0x1a], [102, 6, 5, 0x37], [134, 6, 6, 0x38], [198, 6, 7, 0x39], [326, 6, 8, 0x3a], [582, 6, 9, 0x3b], [1094, 6, 10, 0x3c], [2118, 7, 11, 0x7d], [-22, 8, 32, 0xfe, "lower"], [4166, 8, 32, 0xff], [2, 0x2]]; + break; + + case 11: + lines = [[1, 1, 0, 0x0], [2, 2, 1, 0x2], [4, 4, 0, 0xc], [5, 4, 1, 0xd], [7, 5, 1, 0x1c], [9, 5, 2, 0x1d], [13, 6, 2, 0x3c], [17, 7, 2, 0x7a], [21, 7, 3, 0x7b], [29, 7, 4, 0x7c], [45, 7, 5, 0x7d], [77, 7, 6, 0x7e], [141, 7, 32, 0x7f]]; + break; + + case 12: + lines = [[1, 1, 0, 0x0], [2, 2, 0, 0x2], [3, 3, 1, 0x6], [5, 5, 0, 0x1c], [6, 5, 1, 0x1d], [8, 6, 1, 0x3c], [10, 7, 0, 0x7a], [11, 7, 1, 0x7b], [13, 7, 2, 0x7c], [17, 7, 3, 0x7d], [25, 7, 4, 0x7e], [41, 8, 5, 0xfe], [73, 8, 32, 0xff]]; + break; + + case 13: + lines = [[1, 1, 0, 0x0], [2, 3, 0, 0x4], [3, 4, 0, 0xc], [4, 5, 0, 0x1c], [5, 4, 1, 0xd], [7, 3, 3, 0x5], [15, 6, 1, 0x3a], [17, 6, 2, 0x3b], [21, 6, 3, 0x3c], [29, 6, 4, 0x3d], [45, 6, 5, 0x3e], [77, 7, 6, 0x7e], [141, 7, 32, 0x7f]]; + break; + + case 14: + lines = [[-2, 3, 0, 0x4], [-1, 3, 0, 0x5], [0, 1, 0, 0x0], [1, 3, 0, 0x6], [2, 3, 0, 0x7]]; + break; + + case 15: + lines = [[-24, 7, 4, 0x7c], [-8, 6, 2, 0x3c], [-4, 5, 1, 0x1c], [-2, 4, 0, 0xc], [-1, 3, 0, 0x4], [0, 1, 0, 0x0], [1, 3, 0, 0x5], [2, 4, 0, 0xd], [3, 5, 1, 0x1d], [5, 6, 2, 0x3d], [9, 7, 4, 0x7d], [-25, 7, 32, 0x7e, "lower"], [25, 7, 32, 0x7f]]; + break; + + default: + throw new Jbig2Error(`standard table B.${number} does not exist`); + } + + for (let i = 0, ii = lines.length; i < ii; i++) { + lines[i] = new HuffmanLine(lines[i]); + } + + table = new HuffmanTable(lines, true); + standardTablesCache[number] = table; + return table; +} + +class Reader { + constructor(data, start, end) { + this.data = data; + this.start = start; + this.end = end; + this.position = start; + this.shift = -1; + this.currentByte = 0; + } + + readBit() { + if (this.shift < 0) { + if (this.position >= this.end) { + throw new Jbig2Error("end of data while reading bit"); + } + + this.currentByte = this.data[this.position++]; + this.shift = 7; + } + + const bit = this.currentByte >> this.shift & 1; + this.shift--; + return bit; + } + + readBits(numBits) { + let result = 0, + i; + + for (i = numBits - 1; i >= 0; i--) { + result |= this.readBit() << i; + } + + return result; + } + + byteAlign() { + this.shift = -1; + } + + next() { + if (this.position >= this.end) { + return -1; + } + + return this.data[this.position++]; + } + +} + +function getCustomHuffmanTable(index, referredTo, customTables) { + let currentIndex = 0; + + for (let i = 0, ii = referredTo.length; i < ii; i++) { + const table = customTables[referredTo[i]]; + + if (table) { + if (index === currentIndex) { + return table; + } + + currentIndex++; + } + } + + throw new Jbig2Error("can't find custom Huffman table"); +} + +function getTextRegionHuffmanTables(textRegion, referredTo, customTables, numberOfSymbols, reader) { + const codes = []; + + for (let i = 0; i <= 34; i++) { + const codeLength = reader.readBits(4); + codes.push(new HuffmanLine([i, codeLength, 0, 0])); + } + + const runCodesTable = new HuffmanTable(codes, false); + codes.length = 0; + + for (let i = 0; i < numberOfSymbols;) { + const codeLength = runCodesTable.decode(reader); + + if (codeLength >= 32) { + let repeatedLength, numberOfRepeats, j; + + switch (codeLength) { + case 32: + if (i === 0) { + throw new Jbig2Error("no previous value in symbol ID table"); + } + + numberOfRepeats = reader.readBits(2) + 3; + repeatedLength = codes[i - 1].prefixLength; + break; + + case 33: + numberOfRepeats = reader.readBits(3) + 3; + repeatedLength = 0; + break; + + case 34: + numberOfRepeats = reader.readBits(7) + 11; + repeatedLength = 0; + break; + + default: + throw new Jbig2Error("invalid code length in symbol ID table"); + } + + for (j = 0; j < numberOfRepeats; j++) { + codes.push(new HuffmanLine([i, repeatedLength, 0, 0])); + i++; + } + } else { + codes.push(new HuffmanLine([i, codeLength, 0, 0])); + i++; + } + } + + reader.byteAlign(); + const symbolIDTable = new HuffmanTable(codes, false); + let customIndex = 0, + tableFirstS, + tableDeltaS, + tableDeltaT; + + switch (textRegion.huffmanFS) { + case 0: + case 1: + tableFirstS = getStandardTable(textRegion.huffmanFS + 6); + break; + + case 3: + tableFirstS = getCustomHuffmanTable(customIndex, referredTo, customTables); + customIndex++; + break; + + default: + throw new Jbig2Error("invalid Huffman FS selector"); + } + + switch (textRegion.huffmanDS) { + case 0: + case 1: + case 2: + tableDeltaS = getStandardTable(textRegion.huffmanDS + 8); + break; + + case 3: + tableDeltaS = getCustomHuffmanTable(customIndex, referredTo, customTables); + customIndex++; + break; + + default: + throw new Jbig2Error("invalid Huffman DS selector"); + } + + switch (textRegion.huffmanDT) { + case 0: + case 1: + case 2: + tableDeltaT = getStandardTable(textRegion.huffmanDT + 11); + break; + + case 3: + tableDeltaT = getCustomHuffmanTable(customIndex, referredTo, customTables); + customIndex++; + break; + + default: + throw new Jbig2Error("invalid Huffman DT selector"); + } + + if (textRegion.refinement) { + throw new Jbig2Error("refinement with Huffman is not supported"); + } + + return { + symbolIDTable, + tableFirstS, + tableDeltaS, + tableDeltaT + }; +} + +function getSymbolDictionaryHuffmanTables(dictionary, referredTo, customTables) { + let customIndex = 0, + tableDeltaHeight, + tableDeltaWidth; + + switch (dictionary.huffmanDHSelector) { + case 0: + case 1: + tableDeltaHeight = getStandardTable(dictionary.huffmanDHSelector + 4); + break; + + case 3: + tableDeltaHeight = getCustomHuffmanTable(customIndex, referredTo, customTables); + customIndex++; + break; + + default: + throw new Jbig2Error("invalid Huffman DH selector"); + } + + switch (dictionary.huffmanDWSelector) { + case 0: + case 1: + tableDeltaWidth = getStandardTable(dictionary.huffmanDWSelector + 2); + break; + + case 3: + tableDeltaWidth = getCustomHuffmanTable(customIndex, referredTo, customTables); + customIndex++; + break; + + default: + throw new Jbig2Error("invalid Huffman DW selector"); + } + + let tableBitmapSize, tableAggregateInstances; + + if (dictionary.bitmapSizeSelector) { + tableBitmapSize = getCustomHuffmanTable(customIndex, referredTo, customTables); + customIndex++; + } else { + tableBitmapSize = getStandardTable(1); + } + + if (dictionary.aggregationInstancesSelector) { + tableAggregateInstances = getCustomHuffmanTable(customIndex, referredTo, customTables); + } else { + tableAggregateInstances = getStandardTable(1); + } + + return { + tableDeltaHeight, + tableDeltaWidth, + tableBitmapSize, + tableAggregateInstances + }; +} + +function readUncompressedBitmap(reader, width, height) { + const bitmap = []; + + for (let y = 0; y < height; y++) { + const row = new Uint8Array(width); + bitmap.push(row); + + for (let x = 0; x < width; x++) { + row[x] = reader.readBit(); + } + + reader.byteAlign(); + } + + return bitmap; +} + +function decodeMMRBitmap(input, width, height, endOfBlock) { + const params = { + K: -1, + Columns: width, + Rows: height, + BlackIs1: true, + EndOfBlock: endOfBlock + }; + const decoder = new _ccitt.CCITTFaxDecoder(input, params); + const bitmap = []; + let currentByte, + eof = false; + + for (let y = 0; y < height; y++) { + const row = new Uint8Array(width); + bitmap.push(row); + let shift = -1; + + for (let x = 0; x < width; x++) { + if (shift < 0) { + currentByte = decoder.readNextChar(); + + if (currentByte === -1) { + currentByte = 0; + eof = true; + } + + shift = 7; + } + + row[x] = currentByte >> shift & 1; + shift--; + } + } + + if (endOfBlock && !eof) { + const lookForEOFLimit = 5; + + for (let i = 0; i < lookForEOFLimit; i++) { + if (decoder.readNextChar() === -1) { + break; + } + } + } + + return bitmap; +} + +class Jbig2Image { + parseChunks(chunks) { + return parseJbig2Chunks(chunks); + } + + parse(data) { + throw new Error("Not implemented: Jbig2Image.parse"); + } + +} + +exports.Jbig2Image = Jbig2Image; + +/***/ }), +/* 26 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.ArithmeticDecoder = void 0; +const QeTable = [{ + qe: 0x5601, + nmps: 1, + nlps: 1, + switchFlag: 1 +}, { + qe: 0x3401, + nmps: 2, + nlps: 6, + switchFlag: 0 +}, { + qe: 0x1801, + nmps: 3, + nlps: 9, + switchFlag: 0 +}, { + qe: 0x0ac1, + nmps: 4, + nlps: 12, + switchFlag: 0 +}, { + qe: 0x0521, + nmps: 5, + nlps: 29, + switchFlag: 0 +}, { + qe: 0x0221, + nmps: 38, + nlps: 33, + switchFlag: 0 +}, { + qe: 0x5601, + nmps: 7, + nlps: 6, + switchFlag: 1 +}, { + qe: 0x5401, + nmps: 8, + nlps: 14, + switchFlag: 0 +}, { + qe: 0x4801, + nmps: 9, + nlps: 14, + switchFlag: 0 +}, { + qe: 0x3801, + nmps: 10, + nlps: 14, + switchFlag: 0 +}, { + qe: 0x3001, + nmps: 11, + nlps: 17, + switchFlag: 0 +}, { + qe: 0x2401, + nmps: 12, + nlps: 18, + switchFlag: 0 +}, { + qe: 0x1c01, + nmps: 13, + nlps: 20, + switchFlag: 0 +}, { + qe: 0x1601, + nmps: 29, + nlps: 21, + switchFlag: 0 +}, { + qe: 0x5601, + nmps: 15, + nlps: 14, + switchFlag: 1 +}, { + qe: 0x5401, + nmps: 16, + nlps: 14, + switchFlag: 0 +}, { + qe: 0x5101, + nmps: 17, + nlps: 15, + switchFlag: 0 +}, { + qe: 0x4801, + nmps: 18, + nlps: 16, + switchFlag: 0 +}, { + qe: 0x3801, + nmps: 19, + nlps: 17, + switchFlag: 0 +}, { + qe: 0x3401, + nmps: 20, + nlps: 18, + switchFlag: 0 +}, { + qe: 0x3001, + nmps: 21, + nlps: 19, + switchFlag: 0 +}, { + qe: 0x2801, + nmps: 22, + nlps: 19, + switchFlag: 0 +}, { + qe: 0x2401, + nmps: 23, + nlps: 20, + switchFlag: 0 +}, { + qe: 0x2201, + nmps: 24, + nlps: 21, + switchFlag: 0 +}, { + qe: 0x1c01, + nmps: 25, + nlps: 22, + switchFlag: 0 +}, { + qe: 0x1801, + nmps: 26, + nlps: 23, + switchFlag: 0 +}, { + qe: 0x1601, + nmps: 27, + nlps: 24, + switchFlag: 0 +}, { + qe: 0x1401, + nmps: 28, + nlps: 25, + switchFlag: 0 +}, { + qe: 0x1201, + nmps: 29, + nlps: 26, + switchFlag: 0 +}, { + qe: 0x1101, + nmps: 30, + nlps: 27, + switchFlag: 0 +}, { + qe: 0x0ac1, + nmps: 31, + nlps: 28, + switchFlag: 0 +}, { + qe: 0x09c1, + nmps: 32, + nlps: 29, + switchFlag: 0 +}, { + qe: 0x08a1, + nmps: 33, + nlps: 30, + switchFlag: 0 +}, { + qe: 0x0521, + nmps: 34, + nlps: 31, + switchFlag: 0 +}, { + qe: 0x0441, + nmps: 35, + nlps: 32, + switchFlag: 0 +}, { + qe: 0x02a1, + nmps: 36, + nlps: 33, + switchFlag: 0 +}, { + qe: 0x0221, + nmps: 37, + nlps: 34, + switchFlag: 0 +}, { + qe: 0x0141, + nmps: 38, + nlps: 35, + switchFlag: 0 +}, { + qe: 0x0111, + nmps: 39, + nlps: 36, + switchFlag: 0 +}, { + qe: 0x0085, + nmps: 40, + nlps: 37, + switchFlag: 0 +}, { + qe: 0x0049, + nmps: 41, + nlps: 38, + switchFlag: 0 +}, { + qe: 0x0025, + nmps: 42, + nlps: 39, + switchFlag: 0 +}, { + qe: 0x0015, + nmps: 43, + nlps: 40, + switchFlag: 0 +}, { + qe: 0x0009, + nmps: 44, + nlps: 41, + switchFlag: 0 +}, { + qe: 0x0005, + nmps: 45, + nlps: 42, + switchFlag: 0 +}, { + qe: 0x0001, + nmps: 45, + nlps: 43, + switchFlag: 0 +}, { + qe: 0x5601, + nmps: 46, + nlps: 46, + switchFlag: 0 +}]; + +class ArithmeticDecoder { + constructor(data, start, end) { + this.data = data; + this.bp = start; + this.dataEnd = end; + this.chigh = data[start]; + this.clow = 0; + this.byteIn(); + this.chigh = this.chigh << 7 & 0xffff | this.clow >> 9 & 0x7f; + this.clow = this.clow << 7 & 0xffff; + this.ct -= 7; + this.a = 0x8000; + } + + byteIn() { + const data = this.data; + let bp = this.bp; + + if (data[bp] === 0xff) { + if (data[bp + 1] > 0x8f) { + this.clow += 0xff00; + this.ct = 8; + } else { + bp++; + this.clow += data[bp] << 9; + this.ct = 7; + this.bp = bp; + } + } else { + bp++; + this.clow += bp < this.dataEnd ? data[bp] << 8 : 0xff00; + this.ct = 8; + this.bp = bp; + } + + if (this.clow > 0xffff) { + this.chigh += this.clow >> 16; + this.clow &= 0xffff; + } + } + + readBit(contexts, pos) { + let cx_index = contexts[pos] >> 1, + cx_mps = contexts[pos] & 1; + const qeTableIcx = QeTable[cx_index]; + const qeIcx = qeTableIcx.qe; + let d; + let a = this.a - qeIcx; + + if (this.chigh < qeIcx) { + if (a < qeIcx) { + a = qeIcx; + d = cx_mps; + cx_index = qeTableIcx.nmps; + } else { + a = qeIcx; + d = 1 ^ cx_mps; + + if (qeTableIcx.switchFlag === 1) { + cx_mps = d; + } + + cx_index = qeTableIcx.nlps; + } + } else { + this.chigh -= qeIcx; + + if ((a & 0x8000) !== 0) { + this.a = a; + return cx_mps; + } + + if (a < qeIcx) { + d = 1 ^ cx_mps; + + if (qeTableIcx.switchFlag === 1) { + cx_mps = d; + } + + cx_index = qeTableIcx.nlps; + } else { + d = cx_mps; + cx_index = qeTableIcx.nmps; + } + } + + do { + if (this.ct === 0) { + this.byteIn(); + } + + a <<= 1; + this.chigh = this.chigh << 1 & 0xffff | this.clow >> 15 & 1; + this.clow = this.clow << 1 & 0xffff; + this.ct--; + } while ((a & 0x8000) === 0); + + this.a = a; + contexts[pos] = cx_index << 1 | cx_mps; + return d; + } + +} + +exports.ArithmeticDecoder = ArithmeticDecoder; + +/***/ }), +/* 27 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.JpegStream = void 0; + +var _decode_stream = __w_pdfjs_require__(19); + +var _primitives = __w_pdfjs_require__(5); + +var _jpg = __w_pdfjs_require__(28); + +var _util = __w_pdfjs_require__(2); + +class JpegStream extends _decode_stream.DecodeStream { + constructor(stream, maybeLength, params) { + let ch; + + while ((ch = stream.getByte()) !== -1) { + if (ch === 0xff) { + stream.skip(-1); + break; + } + } + + super(maybeLength); + this.stream = stream; + this.dict = stream.dict; + this.maybeLength = maybeLength; + this.params = params; + } + + get bytes() { + return (0, _util.shadow)(this, "bytes", this.stream.getBytes(this.maybeLength)); + } + + ensureBuffer(requested) {} + + readBlock() { + if (this.eof) { + return; + } + + const jpegOptions = { + decodeTransform: undefined, + colorTransform: undefined + }; + const decodeArr = this.dict.getArray("D", "Decode"); + + if (this.forceRGB && Array.isArray(decodeArr)) { + const bitsPerComponent = this.dict.get("BPC", "BitsPerComponent") || 8; + const decodeArrLength = decodeArr.length; + const transform = new Int32Array(decodeArrLength); + let transformNeeded = false; + const maxValue = (1 << bitsPerComponent) - 1; + + for (let i = 0; i < decodeArrLength; i += 2) { + transform[i] = (decodeArr[i + 1] - decodeArr[i]) * 256 | 0; + transform[i + 1] = decodeArr[i] * maxValue | 0; + + if (transform[i] !== 256 || transform[i + 1] !== 0) { + transformNeeded = true; + } + } + + if (transformNeeded) { + jpegOptions.decodeTransform = transform; + } + } + + if (this.params instanceof _primitives.Dict) { + const colorTransform = this.params.get("ColorTransform"); + + if (Number.isInteger(colorTransform)) { + jpegOptions.colorTransform = colorTransform; + } + } + + const jpegImage = new _jpg.JpegImage(jpegOptions); + jpegImage.parse(this.bytes); + const data = jpegImage.getData({ + width: this.drawWidth, + height: this.drawHeight, + forceRGB: this.forceRGB, + isSourcePDF: true + }); + this.buffer = data; + this.bufferLength = data.length; + this.eof = true; + } + +} + +exports.JpegStream = JpegStream; + +/***/ }), +/* 28 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.JpegImage = void 0; + +var _util = __w_pdfjs_require__(2); + +var _core_utils = __w_pdfjs_require__(6); + +class JpegError extends _util.BaseException { + constructor(msg) { + super(`JPEG error: ${msg}`, "JpegError"); + } + +} + +class DNLMarkerError extends _util.BaseException { + constructor(message, scanLines) { + super(message, "DNLMarkerError"); + this.scanLines = scanLines; + } + +} + +class EOIMarkerError extends _util.BaseException { + constructor(msg) { + super(msg, "EOIMarkerError"); + } + +} + +const dctZigZag = new Uint8Array([0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63]); +const dctCos1 = 4017; +const dctSin1 = 799; +const dctCos3 = 3406; +const dctSin3 = 2276; +const dctCos6 = 1567; +const dctSin6 = 3784; +const dctSqrt2 = 5793; +const dctSqrt1d2 = 2896; + +function buildHuffmanTable(codeLengths, values) { + let k = 0, + i, + j, + length = 16; + + while (length > 0 && !codeLengths[length - 1]) { + length--; + } + + const code = [{ + children: [], + index: 0 + }]; + let p = code[0], + q; + + for (i = 0; i < length; i++) { + for (j = 0; j < codeLengths[i]; j++) { + p = code.pop(); + p.children[p.index] = values[k]; + + while (p.index > 0) { + p = code.pop(); + } + + p.index++; + code.push(p); + + while (code.length <= i) { + code.push(q = { + children: [], + index: 0 + }); + p.children[p.index] = q.children; + p = q; + } + + k++; + } + + if (i + 1 < length) { + code.push(q = { + children: [], + index: 0 + }); + p.children[p.index] = q.children; + p = q; + } + } + + return code[0].children; +} + +function getBlockBufferOffset(component, row, col) { + return 64 * ((component.blocksPerLine + 1) * row + col); +} + +function decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successivePrev, successive, parseDNLMarker = false) { + const mcusPerLine = frame.mcusPerLine; + const progressive = frame.progressive; + const startOffset = offset; + let bitsData = 0, + bitsCount = 0; + + function readBit() { + if (bitsCount > 0) { + bitsCount--; + return bitsData >> bitsCount & 1; + } + + bitsData = data[offset++]; + + if (bitsData === 0xff) { + const nextByte = data[offset++]; + + if (nextByte) { + if (nextByte === 0xdc && parseDNLMarker) { + offset += 2; + const scanLines = (0, _core_utils.readUint16)(data, offset); + offset += 2; + + if (scanLines > 0 && scanLines !== frame.scanLines) { + throw new DNLMarkerError("Found DNL marker (0xFFDC) while parsing scan data", scanLines); + } + } else if (nextByte === 0xd9) { + if (parseDNLMarker) { + const maybeScanLines = blockRow * (frame.precision === 8 ? 8 : 0); + + if (maybeScanLines > 0 && Math.round(frame.scanLines / maybeScanLines) >= 10) { + throw new DNLMarkerError("Found EOI marker (0xFFD9) while parsing scan data, " + "possibly caused by incorrect `scanLines` parameter", maybeScanLines); + } + } + + throw new EOIMarkerError("Found EOI marker (0xFFD9) while parsing scan data"); + } + + throw new JpegError(`unexpected marker ${(bitsData << 8 | nextByte).toString(16)}`); + } + } + + bitsCount = 7; + return bitsData >>> 7; + } + + function decodeHuffman(tree) { + let node = tree; + + while (true) { + node = node[readBit()]; + + switch (typeof node) { + case "number": + return node; + + case "object": + continue; + } + + throw new JpegError("invalid huffman sequence"); + } + } + + function receive(length) { + let n = 0; + + while (length > 0) { + n = n << 1 | readBit(); + length--; + } + + return n; + } + + function receiveAndExtend(length) { + if (length === 1) { + return readBit() === 1 ? 1 : -1; + } + + const n = receive(length); + + if (n >= 1 << length - 1) { + return n; + } + + return n + (-1 << length) + 1; + } + + function decodeBaseline(component, blockOffset) { + const t = decodeHuffman(component.huffmanTableDC); + const diff = t === 0 ? 0 : receiveAndExtend(t); + component.blockData[blockOffset] = component.pred += diff; + let k = 1; + + while (k < 64) { + const rs = decodeHuffman(component.huffmanTableAC); + const s = rs & 15, + r = rs >> 4; + + if (s === 0) { + if (r < 15) { + break; + } + + k += 16; + continue; + } + + k += r; + const z = dctZigZag[k]; + component.blockData[blockOffset + z] = receiveAndExtend(s); + k++; + } + } + + function decodeDCFirst(component, blockOffset) { + const t = decodeHuffman(component.huffmanTableDC); + const diff = t === 0 ? 0 : receiveAndExtend(t) << successive; + component.blockData[blockOffset] = component.pred += diff; + } + + function decodeDCSuccessive(component, blockOffset) { + component.blockData[blockOffset] |= readBit() << successive; + } + + let eobrun = 0; + + function decodeACFirst(component, blockOffset) { + if (eobrun > 0) { + eobrun--; + return; + } + + let k = spectralStart; + const e = spectralEnd; + + while (k <= e) { + const rs = decodeHuffman(component.huffmanTableAC); + const s = rs & 15, + r = rs >> 4; + + if (s === 0) { + if (r < 15) { + eobrun = receive(r) + (1 << r) - 1; + break; + } + + k += 16; + continue; + } + + k += r; + const z = dctZigZag[k]; + component.blockData[blockOffset + z] = receiveAndExtend(s) * (1 << successive); + k++; + } + } + + let successiveACState = 0, + successiveACNextValue; + + function decodeACSuccessive(component, blockOffset) { + let k = spectralStart; + const e = spectralEnd; + let r = 0; + let s; + let rs; + + while (k <= e) { + const offsetZ = blockOffset + dctZigZag[k]; + const sign = component.blockData[offsetZ] < 0 ? -1 : 1; + + switch (successiveACState) { + case 0: + rs = decodeHuffman(component.huffmanTableAC); + s = rs & 15; + r = rs >> 4; + + if (s === 0) { + if (r < 15) { + eobrun = receive(r) + (1 << r); + successiveACState = 4; + } else { + r = 16; + successiveACState = 1; + } + } else { + if (s !== 1) { + throw new JpegError("invalid ACn encoding"); + } + + successiveACNextValue = receiveAndExtend(s); + successiveACState = r ? 2 : 3; + } + + continue; + + case 1: + case 2: + if (component.blockData[offsetZ]) { + component.blockData[offsetZ] += sign * (readBit() << successive); + } else { + r--; + + if (r === 0) { + successiveACState = successiveACState === 2 ? 3 : 0; + } + } + + break; + + case 3: + if (component.blockData[offsetZ]) { + component.blockData[offsetZ] += sign * (readBit() << successive); + } else { + component.blockData[offsetZ] = successiveACNextValue << successive; + successiveACState = 0; + } + + break; + + case 4: + if (component.blockData[offsetZ]) { + component.blockData[offsetZ] += sign * (readBit() << successive); + } + + break; + } + + k++; + } + + if (successiveACState === 4) { + eobrun--; + + if (eobrun === 0) { + successiveACState = 0; + } + } + } + + let blockRow = 0; + + function decodeMcu(component, decode, mcu, row, col) { + const mcuRow = mcu / mcusPerLine | 0; + const mcuCol = mcu % mcusPerLine; + blockRow = mcuRow * component.v + row; + const blockCol = mcuCol * component.h + col; + const blockOffset = getBlockBufferOffset(component, blockRow, blockCol); + decode(component, blockOffset); + } + + function decodeBlock(component, decode, mcu) { + blockRow = mcu / component.blocksPerLine | 0; + const blockCol = mcu % component.blocksPerLine; + const blockOffset = getBlockBufferOffset(component, blockRow, blockCol); + decode(component, blockOffset); + } + + const componentsLength = components.length; + let component, i, j, k, n; + let decodeFn; + + if (progressive) { + if (spectralStart === 0) { + decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive; + } else { + decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive; + } + } else { + decodeFn = decodeBaseline; + } + + let mcu = 0, + fileMarker; + let mcuExpected; + + if (componentsLength === 1) { + mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn; + } else { + mcuExpected = mcusPerLine * frame.mcusPerColumn; + } + + let h, v; + + while (mcu <= mcuExpected) { + const mcuToRead = resetInterval ? Math.min(mcuExpected - mcu, resetInterval) : mcuExpected; + + if (mcuToRead > 0) { + for (i = 0; i < componentsLength; i++) { + components[i].pred = 0; + } + + eobrun = 0; + + if (componentsLength === 1) { + component = components[0]; + + for (n = 0; n < mcuToRead; n++) { + decodeBlock(component, decodeFn, mcu); + mcu++; + } + } else { + for (n = 0; n < mcuToRead; n++) { + for (i = 0; i < componentsLength; i++) { + component = components[i]; + h = component.h; + v = component.v; + + for (j = 0; j < v; j++) { + for (k = 0; k < h; k++) { + decodeMcu(component, decodeFn, mcu, j, k); + } + } + } + + mcu++; + } + } + } + + bitsCount = 0; + fileMarker = findNextFileMarker(data, offset); + + if (!fileMarker) { + break; + } + + if (fileMarker.invalid) { + const partialMsg = mcuToRead > 0 ? "unexpected" : "excessive"; + (0, _util.warn)(`decodeScan - ${partialMsg} MCU data, current marker is: ${fileMarker.invalid}`); + offset = fileMarker.offset; + } + + if (fileMarker.marker >= 0xffd0 && fileMarker.marker <= 0xffd7) { + offset += 2; + } else { + break; + } + } + + return offset - startOffset; +} + +function quantizeAndInverse(component, blockBufferOffset, p) { + const qt = component.quantizationTable, + blockData = component.blockData; + let v0, v1, v2, v3, v4, v5, v6, v7; + let p0, p1, p2, p3, p4, p5, p6, p7; + let t; + + if (!qt) { + throw new JpegError("missing required Quantization Table."); + } + + for (let row = 0; row < 64; row += 8) { + p0 = blockData[blockBufferOffset + row]; + p1 = blockData[blockBufferOffset + row + 1]; + p2 = blockData[blockBufferOffset + row + 2]; + p3 = blockData[blockBufferOffset + row + 3]; + p4 = blockData[blockBufferOffset + row + 4]; + p5 = blockData[blockBufferOffset + row + 5]; + p6 = blockData[blockBufferOffset + row + 6]; + p7 = blockData[blockBufferOffset + row + 7]; + p0 *= qt[row]; + + if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) { + t = dctSqrt2 * p0 + 512 >> 10; + p[row] = t; + p[row + 1] = t; + p[row + 2] = t; + p[row + 3] = t; + p[row + 4] = t; + p[row + 5] = t; + p[row + 6] = t; + p[row + 7] = t; + continue; + } + + p1 *= qt[row + 1]; + p2 *= qt[row + 2]; + p3 *= qt[row + 3]; + p4 *= qt[row + 4]; + p5 *= qt[row + 5]; + p6 *= qt[row + 6]; + p7 *= qt[row + 7]; + v0 = dctSqrt2 * p0 + 128 >> 8; + v1 = dctSqrt2 * p4 + 128 >> 8; + v2 = p2; + v3 = p6; + v4 = dctSqrt1d2 * (p1 - p7) + 128 >> 8; + v7 = dctSqrt1d2 * (p1 + p7) + 128 >> 8; + v5 = p3 << 4; + v6 = p5 << 4; + v0 = v0 + v1 + 1 >> 1; + v1 = v0 - v1; + t = v2 * dctSin6 + v3 * dctCos6 + 128 >> 8; + v2 = v2 * dctCos6 - v3 * dctSin6 + 128 >> 8; + v3 = t; + v4 = v4 + v6 + 1 >> 1; + v6 = v4 - v6; + v7 = v7 + v5 + 1 >> 1; + v5 = v7 - v5; + v0 = v0 + v3 + 1 >> 1; + v3 = v0 - v3; + v1 = v1 + v2 + 1 >> 1; + v2 = v1 - v2; + t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12; + v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12; + v7 = t; + t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12; + v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12; + v6 = t; + p[row] = v0 + v7; + p[row + 7] = v0 - v7; + p[row + 1] = v1 + v6; + p[row + 6] = v1 - v6; + p[row + 2] = v2 + v5; + p[row + 5] = v2 - v5; + p[row + 3] = v3 + v4; + p[row + 4] = v3 - v4; + } + + for (let col = 0; col < 8; ++col) { + p0 = p[col]; + p1 = p[col + 8]; + p2 = p[col + 16]; + p3 = p[col + 24]; + p4 = p[col + 32]; + p5 = p[col + 40]; + p6 = p[col + 48]; + p7 = p[col + 56]; + + if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) { + t = dctSqrt2 * p0 + 8192 >> 14; + + if (t < -2040) { + t = 0; + } else if (t >= 2024) { + t = 255; + } else { + t = t + 2056 >> 4; + } + + blockData[blockBufferOffset + col] = t; + blockData[blockBufferOffset + col + 8] = t; + blockData[blockBufferOffset + col + 16] = t; + blockData[blockBufferOffset + col + 24] = t; + blockData[blockBufferOffset + col + 32] = t; + blockData[blockBufferOffset + col + 40] = t; + blockData[blockBufferOffset + col + 48] = t; + blockData[blockBufferOffset + col + 56] = t; + continue; + } + + v0 = dctSqrt2 * p0 + 2048 >> 12; + v1 = dctSqrt2 * p4 + 2048 >> 12; + v2 = p2; + v3 = p6; + v4 = dctSqrt1d2 * (p1 - p7) + 2048 >> 12; + v7 = dctSqrt1d2 * (p1 + p7) + 2048 >> 12; + v5 = p3; + v6 = p5; + v0 = (v0 + v1 + 1 >> 1) + 4112; + v1 = v0 - v1; + t = v2 * dctSin6 + v3 * dctCos6 + 2048 >> 12; + v2 = v2 * dctCos6 - v3 * dctSin6 + 2048 >> 12; + v3 = t; + v4 = v4 + v6 + 1 >> 1; + v6 = v4 - v6; + v7 = v7 + v5 + 1 >> 1; + v5 = v7 - v5; + v0 = v0 + v3 + 1 >> 1; + v3 = v0 - v3; + v1 = v1 + v2 + 1 >> 1; + v2 = v1 - v2; + t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12; + v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12; + v7 = t; + t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12; + v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12; + v6 = t; + p0 = v0 + v7; + p7 = v0 - v7; + p1 = v1 + v6; + p6 = v1 - v6; + p2 = v2 + v5; + p5 = v2 - v5; + p3 = v3 + v4; + p4 = v3 - v4; + + if (p0 < 16) { + p0 = 0; + } else if (p0 >= 4080) { + p0 = 255; + } else { + p0 >>= 4; + } + + if (p1 < 16) { + p1 = 0; + } else if (p1 >= 4080) { + p1 = 255; + } else { + p1 >>= 4; + } + + if (p2 < 16) { + p2 = 0; + } else if (p2 >= 4080) { + p2 = 255; + } else { + p2 >>= 4; + } + + if (p3 < 16) { + p3 = 0; + } else if (p3 >= 4080) { + p3 = 255; + } else { + p3 >>= 4; + } + + if (p4 < 16) { + p4 = 0; + } else if (p4 >= 4080) { + p4 = 255; + } else { + p4 >>= 4; + } + + if (p5 < 16) { + p5 = 0; + } else if (p5 >= 4080) { + p5 = 255; + } else { + p5 >>= 4; + } + + if (p6 < 16) { + p6 = 0; + } else if (p6 >= 4080) { + p6 = 255; + } else { + p6 >>= 4; + } + + if (p7 < 16) { + p7 = 0; + } else if (p7 >= 4080) { + p7 = 255; + } else { + p7 >>= 4; + } + + blockData[blockBufferOffset + col] = p0; + blockData[blockBufferOffset + col + 8] = p1; + blockData[blockBufferOffset + col + 16] = p2; + blockData[blockBufferOffset + col + 24] = p3; + blockData[blockBufferOffset + col + 32] = p4; + blockData[blockBufferOffset + col + 40] = p5; + blockData[blockBufferOffset + col + 48] = p6; + blockData[blockBufferOffset + col + 56] = p7; + } +} + +function buildComponentData(frame, component) { + const blocksPerLine = component.blocksPerLine; + const blocksPerColumn = component.blocksPerColumn; + const computationBuffer = new Int16Array(64); + + for (let blockRow = 0; blockRow < blocksPerColumn; blockRow++) { + for (let blockCol = 0; blockCol < blocksPerLine; blockCol++) { + const offset = getBlockBufferOffset(component, blockRow, blockCol); + quantizeAndInverse(component, offset, computationBuffer); + } + } + + return component.blockData; +} + +function findNextFileMarker(data, currentPos, startPos = currentPos) { + const maxPos = data.length - 1; + let newPos = startPos < currentPos ? startPos : currentPos; + + if (currentPos >= maxPos) { + return null; + } + + const currentMarker = (0, _core_utils.readUint16)(data, currentPos); + + if (currentMarker >= 0xffc0 && currentMarker <= 0xfffe) { + return { + invalid: null, + marker: currentMarker, + offset: currentPos + }; + } + + let newMarker = (0, _core_utils.readUint16)(data, newPos); + + while (!(newMarker >= 0xffc0 && newMarker <= 0xfffe)) { + if (++newPos >= maxPos) { + return null; + } + + newMarker = (0, _core_utils.readUint16)(data, newPos); + } + + return { + invalid: currentMarker.toString(16), + marker: newMarker, + offset: newPos + }; +} + +class JpegImage { + constructor({ + decodeTransform = null, + colorTransform = -1 + } = {}) { + this._decodeTransform = decodeTransform; + this._colorTransform = colorTransform; + } + + parse(data, { + dnlScanLines = null + } = {}) { + function readDataBlock() { + const length = (0, _core_utils.readUint16)(data, offset); + offset += 2; + let endOffset = offset + length - 2; + const fileMarker = findNextFileMarker(data, endOffset, offset); + + if (fileMarker && fileMarker.invalid) { + (0, _util.warn)("readDataBlock - incorrect length, current marker is: " + fileMarker.invalid); + endOffset = fileMarker.offset; + } + + const array = data.subarray(offset, endOffset); + offset += array.length; + return array; + } + + function prepareComponents(frame) { + const mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH); + const mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV); + + for (let i = 0, ii = frame.components.length; i < ii; i++) { + const component = frame.components[i]; + const blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / frame.maxH); + const blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) * component.v / frame.maxV); + const blocksPerLineForMcu = mcusPerLine * component.h; + const blocksPerColumnForMcu = mcusPerColumn * component.v; + const blocksBufferSize = 64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1); + component.blockData = new Int16Array(blocksBufferSize); + component.blocksPerLine = blocksPerLine; + component.blocksPerColumn = blocksPerColumn; + } + + frame.mcusPerLine = mcusPerLine; + frame.mcusPerColumn = mcusPerColumn; + } + + let offset = 0; + let jfif = null; + let adobe = null; + let frame, resetInterval; + let numSOSMarkers = 0; + const quantizationTables = []; + const huffmanTablesAC = [], + huffmanTablesDC = []; + let fileMarker = (0, _core_utils.readUint16)(data, offset); + offset += 2; + + if (fileMarker !== 0xffd8) { + throw new JpegError("SOI not found"); + } + + fileMarker = (0, _core_utils.readUint16)(data, offset); + offset += 2; + + markerLoop: while (fileMarker !== 0xffd9) { + let i, j, l; + + switch (fileMarker) { + case 0xffe0: + case 0xffe1: + case 0xffe2: + case 0xffe3: + case 0xffe4: + case 0xffe5: + case 0xffe6: + case 0xffe7: + case 0xffe8: + case 0xffe9: + case 0xffea: + case 0xffeb: + case 0xffec: + case 0xffed: + case 0xffee: + case 0xffef: + case 0xfffe: + const appData = readDataBlock(); + + if (fileMarker === 0xffe0) { + if (appData[0] === 0x4a && appData[1] === 0x46 && appData[2] === 0x49 && appData[3] === 0x46 && appData[4] === 0) { + jfif = { + version: { + major: appData[5], + minor: appData[6] + }, + densityUnits: appData[7], + xDensity: appData[8] << 8 | appData[9], + yDensity: appData[10] << 8 | appData[11], + thumbWidth: appData[12], + thumbHeight: appData[13], + thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13]) + }; + } + } + + if (fileMarker === 0xffee) { + if (appData[0] === 0x41 && appData[1] === 0x64 && appData[2] === 0x6f && appData[3] === 0x62 && appData[4] === 0x65) { + adobe = { + version: appData[5] << 8 | appData[6], + flags0: appData[7] << 8 | appData[8], + flags1: appData[9] << 8 | appData[10], + transformCode: appData[11] + }; + } + } + + break; + + case 0xffdb: + const quantizationTablesLength = (0, _core_utils.readUint16)(data, offset); + offset += 2; + const quantizationTablesEnd = quantizationTablesLength + offset - 2; + let z; + + while (offset < quantizationTablesEnd) { + const quantizationTableSpec = data[offset++]; + const tableData = new Uint16Array(64); + + if (quantizationTableSpec >> 4 === 0) { + for (j = 0; j < 64; j++) { + z = dctZigZag[j]; + tableData[z] = data[offset++]; + } + } else if (quantizationTableSpec >> 4 === 1) { + for (j = 0; j < 64; j++) { + z = dctZigZag[j]; + tableData[z] = (0, _core_utils.readUint16)(data, offset); + offset += 2; + } + } else { + throw new JpegError("DQT - invalid table spec"); + } + + quantizationTables[quantizationTableSpec & 15] = tableData; + } + + break; + + case 0xffc0: + case 0xffc1: + case 0xffc2: + if (frame) { + throw new JpegError("Only single frame JPEGs supported"); + } + + offset += 2; + frame = {}; + frame.extended = fileMarker === 0xffc1; + frame.progressive = fileMarker === 0xffc2; + frame.precision = data[offset++]; + const sofScanLines = (0, _core_utils.readUint16)(data, offset); + offset += 2; + frame.scanLines = dnlScanLines || sofScanLines; + frame.samplesPerLine = (0, _core_utils.readUint16)(data, offset); + offset += 2; + frame.components = []; + frame.componentIds = {}; + const componentsCount = data[offset++]; + let maxH = 0, + maxV = 0; + + for (i = 0; i < componentsCount; i++) { + const componentId = data[offset]; + const h = data[offset + 1] >> 4; + const v = data[offset + 1] & 15; + + if (maxH < h) { + maxH = h; + } + + if (maxV < v) { + maxV = v; + } + + const qId = data[offset + 2]; + l = frame.components.push({ + h, + v, + quantizationId: qId, + quantizationTable: null + }); + frame.componentIds[componentId] = l - 1; + offset += 3; + } + + frame.maxH = maxH; + frame.maxV = maxV; + prepareComponents(frame); + break; + + case 0xffc4: + const huffmanLength = (0, _core_utils.readUint16)(data, offset); + offset += 2; + + for (i = 2; i < huffmanLength;) { + const huffmanTableSpec = data[offset++]; + const codeLengths = new Uint8Array(16); + let codeLengthSum = 0; + + for (j = 0; j < 16; j++, offset++) { + codeLengthSum += codeLengths[j] = data[offset]; + } + + const huffmanValues = new Uint8Array(codeLengthSum); + + for (j = 0; j < codeLengthSum; j++, offset++) { + huffmanValues[j] = data[offset]; + } + + i += 17 + codeLengthSum; + (huffmanTableSpec >> 4 === 0 ? huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] = buildHuffmanTable(codeLengths, huffmanValues); + } + + break; + + case 0xffdd: + offset += 2; + resetInterval = (0, _core_utils.readUint16)(data, offset); + offset += 2; + break; + + case 0xffda: + const parseDNLMarker = ++numSOSMarkers === 1 && !dnlScanLines; + offset += 2; + const selectorsCount = data[offset++], + components = []; + + for (i = 0; i < selectorsCount; i++) { + const index = data[offset++]; + const componentIndex = frame.componentIds[index]; + const component = frame.components[componentIndex]; + component.index = index; + const tableSpec = data[offset++]; + component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4]; + component.huffmanTableAC = huffmanTablesAC[tableSpec & 15]; + components.push(component); + } + + const spectralStart = data[offset++], + spectralEnd = data[offset++], + successiveApproximation = data[offset++]; + + try { + const processed = decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successiveApproximation >> 4, successiveApproximation & 15, parseDNLMarker); + offset += processed; + } catch (ex) { + if (ex instanceof DNLMarkerError) { + (0, _util.warn)(`${ex.message} -- attempting to re-parse the JPEG image.`); + return this.parse(data, { + dnlScanLines: ex.scanLines + }); + } else if (ex instanceof EOIMarkerError) { + (0, _util.warn)(`${ex.message} -- ignoring the rest of the image data.`); + break markerLoop; + } + + throw ex; + } + + break; + + case 0xffdc: + offset += 4; + break; + + case 0xffff: + if (data[offset] !== 0xff) { + offset--; + } + + break; + + default: + const nextFileMarker = findNextFileMarker(data, offset - 2, offset - 3); + + if (nextFileMarker && nextFileMarker.invalid) { + (0, _util.warn)("JpegImage.parse - unexpected data, current marker is: " + nextFileMarker.invalid); + offset = nextFileMarker.offset; + break; + } + + if (!nextFileMarker || offset >= data.length - 1) { + (0, _util.warn)("JpegImage.parse - reached the end of the image data " + "without finding an EOI marker (0xFFD9)."); + break markerLoop; + } + + throw new JpegError("JpegImage.parse - unknown marker: " + fileMarker.toString(16)); + } + + fileMarker = (0, _core_utils.readUint16)(data, offset); + offset += 2; + } + + this.width = frame.samplesPerLine; + this.height = frame.scanLines; + this.jfif = jfif; + this.adobe = adobe; + this.components = []; + + for (let i = 0, ii = frame.components.length; i < ii; i++) { + const component = frame.components[i]; + const quantizationTable = quantizationTables[component.quantizationId]; + + if (quantizationTable) { + component.quantizationTable = quantizationTable; + } + + this.components.push({ + index: component.index, + output: buildComponentData(frame, component), + scaleX: component.h / frame.maxH, + scaleY: component.v / frame.maxV, + blocksPerLine: component.blocksPerLine, + blocksPerColumn: component.blocksPerColumn + }); + } + + this.numComponents = this.components.length; + return undefined; + } + + _getLinearizedBlockData(width, height, isSourcePDF = false) { + const scaleX = this.width / width, + scaleY = this.height / height; + let component, componentScaleX, componentScaleY, blocksPerScanline; + let x, y, i, j, k; + let index; + let offset = 0; + let output; + const numComponents = this.components.length; + const dataLength = width * height * numComponents; + const data = new Uint8ClampedArray(dataLength); + const xScaleBlockOffset = new Uint32Array(width); + const mask3LSB = 0xfffffff8; + let lastComponentScaleX; + + for (i = 0; i < numComponents; i++) { + component = this.components[i]; + componentScaleX = component.scaleX * scaleX; + componentScaleY = component.scaleY * scaleY; + offset = i; + output = component.output; + blocksPerScanline = component.blocksPerLine + 1 << 3; + + if (componentScaleX !== lastComponentScaleX) { + for (x = 0; x < width; x++) { + j = 0 | x * componentScaleX; + xScaleBlockOffset[x] = (j & mask3LSB) << 3 | j & 7; + } + + lastComponentScaleX = componentScaleX; + } + + for (y = 0; y < height; y++) { + j = 0 | y * componentScaleY; + index = blocksPerScanline * (j & mask3LSB) | (j & 7) << 3; + + for (x = 0; x < width; x++) { + data[offset] = output[index + xScaleBlockOffset[x]]; + offset += numComponents; + } + } + } + + let transform = this._decodeTransform; + + if (!isSourcePDF && numComponents === 4 && !transform) { + transform = new Int32Array([-256, 255, -256, 255, -256, 255, -256, 255]); + } + + if (transform) { + for (i = 0; i < dataLength;) { + for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) { + data[i] = (data[i] * transform[k] >> 8) + transform[k + 1]; + } + } + } + + return data; + } + + get _isColorConversionNeeded() { + if (this.adobe) { + return !!this.adobe.transformCode; + } + + if (this.numComponents === 3) { + if (this._colorTransform === 0) { + return false; + } else if (this.components[0].index === 0x52 && this.components[1].index === 0x47 && this.components[2].index === 0x42) { + return false; + } + + return true; + } + + if (this._colorTransform === 1) { + return true; + } + + return false; + } + + _convertYccToRgb(data) { + let Y, Cb, Cr; + + for (let i = 0, length = data.length; i < length; i += 3) { + Y = data[i]; + Cb = data[i + 1]; + Cr = data[i + 2]; + data[i] = Y - 179.456 + 1.402 * Cr; + data[i + 1] = Y + 135.459 - 0.344 * Cb - 0.714 * Cr; + data[i + 2] = Y - 226.816 + 1.772 * Cb; + } + + return data; + } + + _convertYcckToRgb(data) { + let Y, Cb, Cr, k; + let offset = 0; + + for (let i = 0, length = data.length; i < length; i += 4) { + Y = data[i]; + Cb = data[i + 1]; + Cr = data[i + 2]; + k = data[i + 3]; + data[offset++] = -122.67195406894 + Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr - 5.4080610064599e-5 * Y + 0.00048449797120281 * k - 0.154362151871126) + Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y - 0.00477271405408747 * k + 1.53380253221734) + Y * (0.000961250184130688 * Y - 0.00266257332283933 * k + 0.48357088451265) + k * (-0.000336197177618394 * k + 0.484791561490776); + data[offset++] = 107.268039397724 + Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr + 0.000659397001245577 * Y + 0.000426105652938837 * k - 0.176491792462875) + Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y + 0.000770482631801132 * k - 0.151051492775562) + Y * (0.00126935368114843 * Y - 0.00265090189010898 * k + 0.25802910206845) + k * (-0.000318913117588328 * k - 0.213742400323665); + data[offset++] = -20.810012546947 + Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr + 0.0020741088115012 * Y - 0.00288260236853442 * k + 0.814272968359295) + Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y + 0.000560833691242812 * k - 0.195152027534049) + Y * (0.00174418132927582 * Y - 0.00255243321439347 * k + 0.116935020465145) + k * (-0.000343531996510555 * k + 0.24165260232407); + } + + return data.subarray(0, offset); + } + + _convertYcckToCmyk(data) { + let Y, Cb, Cr; + + for (let i = 0, length = data.length; i < length; i += 4) { + Y = data[i]; + Cb = data[i + 1]; + Cr = data[i + 2]; + data[i] = 434.456 - Y - 1.402 * Cr; + data[i + 1] = 119.541 - Y + 0.344 * Cb + 0.714 * Cr; + data[i + 2] = 481.816 - Y - 1.772 * Cb; + } + + return data; + } + + _convertCmykToRgb(data) { + let c, m, y, k; + let offset = 0; + + for (let i = 0, length = data.length; i < length; i += 4) { + c = data[i]; + m = data[i + 1]; + y = data[i + 2]; + k = data[i + 3]; + data[offset++] = 255 + c * (-0.00006747147073602441 * c + 0.0008379262121013727 * m + 0.0002894718188643294 * y + 0.003264231057537806 * k - 1.1185611867203937) + m * (0.000026374107616089405 * m - 0.00008626949158638572 * y - 0.0002748769067499491 * k - 0.02155688794978967) + y * (-0.00003878099212869363 * y - 0.0003267808279485286 * k + 0.0686742238595345) - k * (0.0003361971776183937 * k + 0.7430659151342254); + data[offset++] = 255 + c * (0.00013596372813588848 * c + 0.000924537132573585 * m + 0.00010567359618683593 * y + 0.0004791864687436512 * k - 0.3109689587515875) + m * (-0.00023545346108370344 * m + 0.0002702845253534714 * y + 0.0020200308977307156 * k - 0.7488052167015494) + y * (0.00006834815998235662 * y + 0.00015168452363460973 * k - 0.09751927774728933) - k * (0.0003189131175883281 * k + 0.7364883807733168); + data[offset++] = 255 + c * (0.000013598650411385307 * c + 0.00012423956175490851 * m + 0.0004751985097583589 * y - 0.0000036729317476630422 * k - 0.05562186980264034) + m * (0.00016141380598724676 * m + 0.0009692239130725186 * y + 0.0007782692450036253 * k - 0.44015232367526463) + y * (5.068882914068769e-7 * y + 0.0017778369011375071 * k - 0.7591454649749609) - k * (0.0003435319965105553 * k + 0.7063770186160144); + } + + return data.subarray(0, offset); + } + + getData({ + width, + height, + forceRGB = false, + isSourcePDF = false + }) { + if (this.numComponents > 4) { + throw new JpegError("Unsupported color mode"); + } + + const data = this._getLinearizedBlockData(width, height, isSourcePDF); + + if (this.numComponents === 1 && forceRGB) { + const dataLength = data.length; + const rgbData = new Uint8ClampedArray(dataLength * 3); + let offset = 0; + + for (let i = 0; i < dataLength; i++) { + const grayColor = data[i]; + rgbData[offset++] = grayColor; + rgbData[offset++] = grayColor; + rgbData[offset++] = grayColor; + } + + return rgbData; + } else if (this.numComponents === 3 && this._isColorConversionNeeded) { + return this._convertYccToRgb(data); + } else if (this.numComponents === 4) { + if (this._isColorConversionNeeded) { + if (forceRGB) { + return this._convertYcckToRgb(data); + } + + return this._convertYcckToCmyk(data); + } else if (forceRGB) { + return this._convertCmykToRgb(data); + } + } + + return data; + } + +} + +exports.JpegImage = JpegImage; + +/***/ }), +/* 29 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.JpxStream = void 0; + +var _decode_stream = __w_pdfjs_require__(19); + +var _jpx = __w_pdfjs_require__(30); + +var _util = __w_pdfjs_require__(2); + +class JpxStream extends _decode_stream.DecodeStream { + constructor(stream, maybeLength, params) { + super(maybeLength); + this.stream = stream; + this.dict = stream.dict; + this.maybeLength = maybeLength; + this.params = params; + } + + get bytes() { + return (0, _util.shadow)(this, "bytes", this.stream.getBytes(this.maybeLength)); + } + + ensureBuffer(requested) {} + + readBlock() { + if (this.eof) { + return; + } + + const jpxImage = new _jpx.JpxImage(); + jpxImage.parse(this.bytes); + const width = jpxImage.width; + const height = jpxImage.height; + const componentsCount = jpxImage.componentsCount; + const tileCount = jpxImage.tiles.length; + + if (tileCount === 1) { + this.buffer = jpxImage.tiles[0].items; + } else { + const data = new Uint8ClampedArray(width * height * componentsCount); + + for (let k = 0; k < tileCount; k++) { + const tileComponents = jpxImage.tiles[k]; + const tileWidth = tileComponents.width; + const tileHeight = tileComponents.height; + const tileLeft = tileComponents.left; + const tileTop = tileComponents.top; + const src = tileComponents.items; + let srcPosition = 0; + let dataPosition = (width * tileTop + tileLeft) * componentsCount; + const imgRowSize = width * componentsCount; + const tileRowSize = tileWidth * componentsCount; + + for (let j = 0; j < tileHeight; j++) { + const rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize); + data.set(rowBytes, dataPosition); + srcPosition += tileRowSize; + dataPosition += imgRowSize; + } + } + + this.buffer = data; + } + + this.bufferLength = this.buffer.length; + this.eof = true; + } + +} + +exports.JpxStream = JpxStream; + +/***/ }), +/* 30 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.JpxImage = void 0; + +var _util = __w_pdfjs_require__(2); + +var _core_utils = __w_pdfjs_require__(6); + +var _arithmetic_decoder = __w_pdfjs_require__(26); + +class JpxError extends _util.BaseException { + constructor(msg) { + super(`JPX error: ${msg}`, "JpxError"); + } + +} + +const SubbandsGainLog2 = { + LL: 0, + LH: 1, + HL: 1, + HH: 2 +}; + +class JpxImage { + constructor() { + this.failOnCorruptedImage = false; + } + + parse(data) { + const head = (0, _core_utils.readUint16)(data, 0); + + if (head === 0xff4f) { + this.parseCodestream(data, 0, data.length); + return; + } + + const length = data.length; + let position = 0; + + while (position < length) { + let headerSize = 8; + let lbox = (0, _core_utils.readUint32)(data, position); + const tbox = (0, _core_utils.readUint32)(data, position + 4); + position += headerSize; + + if (lbox === 1) { + lbox = (0, _core_utils.readUint32)(data, position) * 4294967296 + (0, _core_utils.readUint32)(data, position + 4); + position += 8; + headerSize += 8; + } + + if (lbox === 0) { + lbox = length - position + headerSize; + } + + if (lbox < headerSize) { + throw new JpxError("Invalid box field size"); + } + + const dataLength = lbox - headerSize; + let jumpDataLength = true; + + switch (tbox) { + case 0x6a703268: + jumpDataLength = false; + break; + + case 0x636f6c72: + const method = data[position]; + + if (method === 1) { + const colorspace = (0, _core_utils.readUint32)(data, position + 3); + + switch (colorspace) { + case 16: + case 17: + case 18: + break; + + default: + (0, _util.warn)("Unknown colorspace " + colorspace); + break; + } + } else if (method === 2) { + (0, _util.info)("ICC profile not supported"); + } + + break; + + case 0x6a703263: + this.parseCodestream(data, position, position + dataLength); + break; + + case 0x6a502020: + if ((0, _core_utils.readUint32)(data, position) !== 0x0d0a870a) { + (0, _util.warn)("Invalid JP2 signature"); + } + + break; + + case 0x6a501a1a: + case 0x66747970: + case 0x72726571: + case 0x72657320: + case 0x69686472: + break; + + default: + const headerType = String.fromCharCode(tbox >> 24 & 0xff, tbox >> 16 & 0xff, tbox >> 8 & 0xff, tbox & 0xff); + (0, _util.warn)(`Unsupported header type ${tbox} (${headerType}).`); + break; + } + + if (jumpDataLength) { + position += dataLength; + } + } + } + + parseImageProperties(stream) { + let newByte = stream.getByte(); + + while (newByte >= 0) { + const oldByte = newByte; + newByte = stream.getByte(); + const code = oldByte << 8 | newByte; + + if (code === 0xff51) { + stream.skip(4); + const Xsiz = stream.getInt32() >>> 0; + const Ysiz = stream.getInt32() >>> 0; + const XOsiz = stream.getInt32() >>> 0; + const YOsiz = stream.getInt32() >>> 0; + stream.skip(16); + const Csiz = stream.getUint16(); + this.width = Xsiz - XOsiz; + this.height = Ysiz - YOsiz; + this.componentsCount = Csiz; + this.bitsPerComponent = 8; + return; + } + } + + throw new JpxError("No size marker found in JPX stream"); + } + + parseCodestream(data, start, end) { + const context = {}; + let doNotRecover = false; + + try { + let position = start; + + while (position + 1 < end) { + const code = (0, _core_utils.readUint16)(data, position); + position += 2; + let length = 0, + j, + sqcd, + spqcds, + spqcdSize, + scalarExpounded, + tile; + + switch (code) { + case 0xff4f: + context.mainHeader = true; + break; + + case 0xffd9: + break; + + case 0xff51: + length = (0, _core_utils.readUint16)(data, position); + const siz = {}; + siz.Xsiz = (0, _core_utils.readUint32)(data, position + 4); + siz.Ysiz = (0, _core_utils.readUint32)(data, position + 8); + siz.XOsiz = (0, _core_utils.readUint32)(data, position + 12); + siz.YOsiz = (0, _core_utils.readUint32)(data, position + 16); + siz.XTsiz = (0, _core_utils.readUint32)(data, position + 20); + siz.YTsiz = (0, _core_utils.readUint32)(data, position + 24); + siz.XTOsiz = (0, _core_utils.readUint32)(data, position + 28); + siz.YTOsiz = (0, _core_utils.readUint32)(data, position + 32); + const componentsCount = (0, _core_utils.readUint16)(data, position + 36); + siz.Csiz = componentsCount; + const components = []; + j = position + 38; + + for (let i = 0; i < componentsCount; i++) { + const component = { + precision: (data[j] & 0x7f) + 1, + isSigned: !!(data[j] & 0x80), + XRsiz: data[j + 1], + YRsiz: data[j + 2] + }; + j += 3; + calculateComponentDimensions(component, siz); + components.push(component); + } + + context.SIZ = siz; + context.components = components; + calculateTileGrids(context, components); + context.QCC = []; + context.COC = []; + break; + + case 0xff5c: + length = (0, _core_utils.readUint16)(data, position); + const qcd = {}; + j = position + 2; + sqcd = data[j++]; + + switch (sqcd & 0x1f) { + case 0: + spqcdSize = 8; + scalarExpounded = true; + break; + + case 1: + spqcdSize = 16; + scalarExpounded = false; + break; + + case 2: + spqcdSize = 16; + scalarExpounded = true; + break; + + default: + throw new Error("Invalid SQcd value " + sqcd); + } + + qcd.noQuantization = spqcdSize === 8; + qcd.scalarExpounded = scalarExpounded; + qcd.guardBits = sqcd >> 5; + spqcds = []; + + while (j < length + position) { + const spqcd = {}; + + if (spqcdSize === 8) { + spqcd.epsilon = data[j++] >> 3; + spqcd.mu = 0; + } else { + spqcd.epsilon = data[j] >> 3; + spqcd.mu = (data[j] & 0x7) << 8 | data[j + 1]; + j += 2; + } + + spqcds.push(spqcd); + } + + qcd.SPqcds = spqcds; + + if (context.mainHeader) { + context.QCD = qcd; + } else { + context.currentTile.QCD = qcd; + context.currentTile.QCC = []; + } + + break; + + case 0xff5d: + length = (0, _core_utils.readUint16)(data, position); + const qcc = {}; + j = position + 2; + let cqcc; + + if (context.SIZ.Csiz < 257) { + cqcc = data[j++]; + } else { + cqcc = (0, _core_utils.readUint16)(data, j); + j += 2; + } + + sqcd = data[j++]; + + switch (sqcd & 0x1f) { + case 0: + spqcdSize = 8; + scalarExpounded = true; + break; + + case 1: + spqcdSize = 16; + scalarExpounded = false; + break; + + case 2: + spqcdSize = 16; + scalarExpounded = true; + break; + + default: + throw new Error("Invalid SQcd value " + sqcd); + } + + qcc.noQuantization = spqcdSize === 8; + qcc.scalarExpounded = scalarExpounded; + qcc.guardBits = sqcd >> 5; + spqcds = []; + + while (j < length + position) { + const spqcd = {}; + + if (spqcdSize === 8) { + spqcd.epsilon = data[j++] >> 3; + spqcd.mu = 0; + } else { + spqcd.epsilon = data[j] >> 3; + spqcd.mu = (data[j] & 0x7) << 8 | data[j + 1]; + j += 2; + } + + spqcds.push(spqcd); + } + + qcc.SPqcds = spqcds; + + if (context.mainHeader) { + context.QCC[cqcc] = qcc; + } else { + context.currentTile.QCC[cqcc] = qcc; + } + + break; + + case 0xff52: + length = (0, _core_utils.readUint16)(data, position); + const cod = {}; + j = position + 2; + const scod = data[j++]; + cod.entropyCoderWithCustomPrecincts = !!(scod & 1); + cod.sopMarkerUsed = !!(scod & 2); + cod.ephMarkerUsed = !!(scod & 4); + cod.progressionOrder = data[j++]; + cod.layersCount = (0, _core_utils.readUint16)(data, j); + j += 2; + cod.multipleComponentTransform = data[j++]; + cod.decompositionLevelsCount = data[j++]; + cod.xcb = (data[j++] & 0xf) + 2; + cod.ycb = (data[j++] & 0xf) + 2; + const blockStyle = data[j++]; + cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1); + cod.resetContextProbabilities = !!(blockStyle & 2); + cod.terminationOnEachCodingPass = !!(blockStyle & 4); + cod.verticallyStripe = !!(blockStyle & 8); + cod.predictableTermination = !!(blockStyle & 16); + cod.segmentationSymbolUsed = !!(blockStyle & 32); + cod.reversibleTransformation = data[j++]; + + if (cod.entropyCoderWithCustomPrecincts) { + const precinctsSizes = []; + + while (j < length + position) { + const precinctsSize = data[j++]; + precinctsSizes.push({ + PPx: precinctsSize & 0xf, + PPy: precinctsSize >> 4 + }); + } + + cod.precinctsSizes = precinctsSizes; + } + + const unsupported = []; + + if (cod.selectiveArithmeticCodingBypass) { + unsupported.push("selectiveArithmeticCodingBypass"); + } + + if (cod.terminationOnEachCodingPass) { + unsupported.push("terminationOnEachCodingPass"); + } + + if (cod.verticallyStripe) { + unsupported.push("verticallyStripe"); + } + + if (cod.predictableTermination) { + unsupported.push("predictableTermination"); + } + + if (unsupported.length > 0) { + doNotRecover = true; + (0, _util.warn)(`JPX: Unsupported COD options (${unsupported.join(", ")}).`); + } + + if (context.mainHeader) { + context.COD = cod; + } else { + context.currentTile.COD = cod; + context.currentTile.COC = []; + } + + break; + + case 0xff90: + length = (0, _core_utils.readUint16)(data, position); + tile = {}; + tile.index = (0, _core_utils.readUint16)(data, position + 2); + tile.length = (0, _core_utils.readUint32)(data, position + 4); + tile.dataEnd = tile.length + position - 2; + tile.partIndex = data[position + 8]; + tile.partsCount = data[position + 9]; + context.mainHeader = false; + + if (tile.partIndex === 0) { + tile.COD = context.COD; + tile.COC = context.COC.slice(0); + tile.QCD = context.QCD; + tile.QCC = context.QCC.slice(0); + } + + context.currentTile = tile; + break; + + case 0xff93: + tile = context.currentTile; + + if (tile.partIndex === 0) { + initializeTile(context, tile.index); + buildPackets(context); + } + + length = tile.dataEnd - position; + parseTilePackets(context, data, position, length); + break; + + case 0xff53: + (0, _util.warn)("JPX: Codestream code 0xFF53 (COC) is not implemented."); + + case 0xff55: + case 0xff57: + case 0xff58: + case 0xff64: + length = (0, _core_utils.readUint16)(data, position); + break; + + default: + throw new Error("Unknown codestream code: " + code.toString(16)); + } + + position += length; + } + } catch (e) { + if (doNotRecover || this.failOnCorruptedImage) { + throw new JpxError(e.message); + } else { + (0, _util.warn)(`JPX: Trying to recover from: "${e.message}".`); + } + } + + this.tiles = transformComponents(context); + this.width = context.SIZ.Xsiz - context.SIZ.XOsiz; + this.height = context.SIZ.Ysiz - context.SIZ.YOsiz; + this.componentsCount = context.SIZ.Csiz; + } + +} + +exports.JpxImage = JpxImage; + +function calculateComponentDimensions(component, siz) { + component.x0 = Math.ceil(siz.XOsiz / component.XRsiz); + component.x1 = Math.ceil(siz.Xsiz / component.XRsiz); + component.y0 = Math.ceil(siz.YOsiz / component.YRsiz); + component.y1 = Math.ceil(siz.Ysiz / component.YRsiz); + component.width = component.x1 - component.x0; + component.height = component.y1 - component.y0; +} + +function calculateTileGrids(context, components) { + const siz = context.SIZ; + const tiles = []; + let tile; + const numXtiles = Math.ceil((siz.Xsiz - siz.XTOsiz) / siz.XTsiz); + const numYtiles = Math.ceil((siz.Ysiz - siz.YTOsiz) / siz.YTsiz); + + for (let q = 0; q < numYtiles; q++) { + for (let p = 0; p < numXtiles; p++) { + tile = {}; + tile.tx0 = Math.max(siz.XTOsiz + p * siz.XTsiz, siz.XOsiz); + tile.ty0 = Math.max(siz.YTOsiz + q * siz.YTsiz, siz.YOsiz); + tile.tx1 = Math.min(siz.XTOsiz + (p + 1) * siz.XTsiz, siz.Xsiz); + tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz); + tile.width = tile.tx1 - tile.tx0; + tile.height = tile.ty1 - tile.ty0; + tile.components = []; + tiles.push(tile); + } + } + + context.tiles = tiles; + const componentsCount = siz.Csiz; + + for (let i = 0, ii = componentsCount; i < ii; i++) { + const component = components[i]; + + for (let j = 0, jj = tiles.length; j < jj; j++) { + const tileComponent = {}; + tile = tiles[j]; + tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz); + tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz); + tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz); + tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz); + tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0; + tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0; + tile.components[i] = tileComponent; + } + } +} + +function getBlocksDimensions(context, component, r) { + const codOrCoc = component.codingStyleParameters; + const result = {}; + + if (!codOrCoc.entropyCoderWithCustomPrecincts) { + result.PPx = 15; + result.PPy = 15; + } else { + result.PPx = codOrCoc.precinctsSizes[r].PPx; + result.PPy = codOrCoc.precinctsSizes[r].PPy; + } + + result.xcb_ = r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) : Math.min(codOrCoc.xcb, result.PPx); + result.ycb_ = r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) : Math.min(codOrCoc.ycb, result.PPy); + return result; +} + +function buildPrecincts(context, resolution, dimensions) { + const precinctWidth = 1 << dimensions.PPx; + const precinctHeight = 1 << dimensions.PPy; + const isZeroRes = resolution.resLevel === 0; + const precinctWidthInSubband = 1 << dimensions.PPx + (isZeroRes ? 0 : -1); + const precinctHeightInSubband = 1 << dimensions.PPy + (isZeroRes ? 0 : -1); + const numprecinctswide = resolution.trx1 > resolution.trx0 ? Math.ceil(resolution.trx1 / precinctWidth) - Math.floor(resolution.trx0 / precinctWidth) : 0; + const numprecinctshigh = resolution.try1 > resolution.try0 ? Math.ceil(resolution.try1 / precinctHeight) - Math.floor(resolution.try0 / precinctHeight) : 0; + const numprecincts = numprecinctswide * numprecinctshigh; + resolution.precinctParameters = { + precinctWidth, + precinctHeight, + numprecinctswide, + numprecinctshigh, + numprecincts, + precinctWidthInSubband, + precinctHeightInSubband + }; +} + +function buildCodeblocks(context, subband, dimensions) { + const xcb_ = dimensions.xcb_; + const ycb_ = dimensions.ycb_; + const codeblockWidth = 1 << xcb_; + const codeblockHeight = 1 << ycb_; + const cbx0 = subband.tbx0 >> xcb_; + const cby0 = subband.tby0 >> ycb_; + const cbx1 = subband.tbx1 + codeblockWidth - 1 >> xcb_; + const cby1 = subband.tby1 + codeblockHeight - 1 >> ycb_; + const precinctParameters = subband.resolution.precinctParameters; + const codeblocks = []; + const precincts = []; + let i, j, codeblock, precinctNumber; + + for (j = cby0; j < cby1; j++) { + for (i = cbx0; i < cbx1; i++) { + codeblock = { + cbx: i, + cby: j, + tbx0: codeblockWidth * i, + tby0: codeblockHeight * j, + tbx1: codeblockWidth * (i + 1), + tby1: codeblockHeight * (j + 1) + }; + codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0); + codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0); + codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1); + codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1); + const pi = Math.floor((codeblock.tbx0_ - subband.tbx0) / precinctParameters.precinctWidthInSubband); + const pj = Math.floor((codeblock.tby0_ - subband.tby0) / precinctParameters.precinctHeightInSubband); + precinctNumber = pi + pj * precinctParameters.numprecinctswide; + codeblock.precinctNumber = precinctNumber; + codeblock.subbandType = subband.type; + codeblock.Lblock = 3; + + if (codeblock.tbx1_ <= codeblock.tbx0_ || codeblock.tby1_ <= codeblock.tby0_) { + continue; + } + + codeblocks.push(codeblock); + let precinct = precincts[precinctNumber]; + + if (precinct !== undefined) { + if (i < precinct.cbxMin) { + precinct.cbxMin = i; + } else if (i > precinct.cbxMax) { + precinct.cbxMax = i; + } + + if (j < precinct.cbyMin) { + precinct.cbxMin = j; + } else if (j > precinct.cbyMax) { + precinct.cbyMax = j; + } + } else { + precincts[precinctNumber] = precinct = { + cbxMin: i, + cbyMin: j, + cbxMax: i, + cbyMax: j + }; + } + + codeblock.precinct = precinct; + } + } + + subband.codeblockParameters = { + codeblockWidth: xcb_, + codeblockHeight: ycb_, + numcodeblockwide: cbx1 - cbx0 + 1, + numcodeblockhigh: cby1 - cby0 + 1 + }; + subband.codeblocks = codeblocks; + subband.precincts = precincts; +} + +function createPacket(resolution, precinctNumber, layerNumber) { + const precinctCodeblocks = []; + const subbands = resolution.subbands; + + for (let i = 0, ii = subbands.length; i < ii; i++) { + const subband = subbands[i]; + const codeblocks = subband.codeblocks; + + for (let j = 0, jj = codeblocks.length; j < jj; j++) { + const codeblock = codeblocks[j]; + + if (codeblock.precinctNumber !== precinctNumber) { + continue; + } + + precinctCodeblocks.push(codeblock); + } + } + + return { + layerNumber, + codeblocks: precinctCodeblocks + }; +} + +function LayerResolutionComponentPositionIterator(context) { + const siz = context.SIZ; + const tileIndex = context.currentTile.index; + const tile = context.tiles[tileIndex]; + const layersCount = tile.codingStyleDefaultParameters.layersCount; + const componentsCount = siz.Csiz; + let maxDecompositionLevelsCount = 0; + + for (let q = 0; q < componentsCount; q++) { + maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, tile.components[q].codingStyleParameters.decompositionLevelsCount); + } + + let l = 0, + r = 0, + i = 0, + k = 0; + + this.nextPacket = function JpxImage_nextPacket() { + for (; l < layersCount; l++) { + for (; r <= maxDecompositionLevelsCount; r++) { + for (; i < componentsCount; i++) { + const component = tile.components[i]; + + if (r > component.codingStyleParameters.decompositionLevelsCount) { + continue; + } + + const resolution = component.resolutions[r]; + const numprecincts = resolution.precinctParameters.numprecincts; + + for (; k < numprecincts;) { + const packet = createPacket(resolution, k, l); + k++; + return packet; + } + + k = 0; + } + + i = 0; + } + + r = 0; + } + + throw new JpxError("Out of packets"); + }; +} + +function ResolutionLayerComponentPositionIterator(context) { + const siz = context.SIZ; + const tileIndex = context.currentTile.index; + const tile = context.tiles[tileIndex]; + const layersCount = tile.codingStyleDefaultParameters.layersCount; + const componentsCount = siz.Csiz; + let maxDecompositionLevelsCount = 0; + + for (let q = 0; q < componentsCount; q++) { + maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, tile.components[q].codingStyleParameters.decompositionLevelsCount); + } + + let r = 0, + l = 0, + i = 0, + k = 0; + + this.nextPacket = function JpxImage_nextPacket() { + for (; r <= maxDecompositionLevelsCount; r++) { + for (; l < layersCount; l++) { + for (; i < componentsCount; i++) { + const component = tile.components[i]; + + if (r > component.codingStyleParameters.decompositionLevelsCount) { + continue; + } + + const resolution = component.resolutions[r]; + const numprecincts = resolution.precinctParameters.numprecincts; + + for (; k < numprecincts;) { + const packet = createPacket(resolution, k, l); + k++; + return packet; + } + + k = 0; + } + + i = 0; + } + + l = 0; + } + + throw new JpxError("Out of packets"); + }; +} + +function ResolutionPositionComponentLayerIterator(context) { + const siz = context.SIZ; + const tileIndex = context.currentTile.index; + const tile = context.tiles[tileIndex]; + const layersCount = tile.codingStyleDefaultParameters.layersCount; + const componentsCount = siz.Csiz; + let l, r, c, p; + let maxDecompositionLevelsCount = 0; + + for (c = 0; c < componentsCount; c++) { + const component = tile.components[c]; + maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, component.codingStyleParameters.decompositionLevelsCount); + } + + const maxNumPrecinctsInLevel = new Int32Array(maxDecompositionLevelsCount + 1); + + for (r = 0; r <= maxDecompositionLevelsCount; ++r) { + let maxNumPrecincts = 0; + + for (c = 0; c < componentsCount; ++c) { + const resolutions = tile.components[c].resolutions; + + if (r < resolutions.length) { + maxNumPrecincts = Math.max(maxNumPrecincts, resolutions[r].precinctParameters.numprecincts); + } + } + + maxNumPrecinctsInLevel[r] = maxNumPrecincts; + } + + l = 0; + r = 0; + c = 0; + p = 0; + + this.nextPacket = function JpxImage_nextPacket() { + for (; r <= maxDecompositionLevelsCount; r++) { + for (; p < maxNumPrecinctsInLevel[r]; p++) { + for (; c < componentsCount; c++) { + const component = tile.components[c]; + + if (r > component.codingStyleParameters.decompositionLevelsCount) { + continue; + } + + const resolution = component.resolutions[r]; + const numprecincts = resolution.precinctParameters.numprecincts; + + if (p >= numprecincts) { + continue; + } + + for (; l < layersCount;) { + const packet = createPacket(resolution, p, l); + l++; + return packet; + } + + l = 0; + } + + c = 0; + } + + p = 0; + } + + throw new JpxError("Out of packets"); + }; +} + +function PositionComponentResolutionLayerIterator(context) { + const siz = context.SIZ; + const tileIndex = context.currentTile.index; + const tile = context.tiles[tileIndex]; + const layersCount = tile.codingStyleDefaultParameters.layersCount; + const componentsCount = siz.Csiz; + const precinctsSizes = getPrecinctSizesInImageScale(tile); + const precinctsIterationSizes = precinctsSizes; + let l = 0, + r = 0, + c = 0, + px = 0, + py = 0; + + this.nextPacket = function JpxImage_nextPacket() { + for (; py < precinctsIterationSizes.maxNumHigh; py++) { + for (; px < precinctsIterationSizes.maxNumWide; px++) { + for (; c < componentsCount; c++) { + const component = tile.components[c]; + const decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount; + + for (; r <= decompositionLevelsCount; r++) { + const resolution = component.resolutions[r]; + const sizeInImageScale = precinctsSizes.components[c].resolutions[r]; + const k = getPrecinctIndexIfExist(px, py, sizeInImageScale, precinctsIterationSizes, resolution); + + if (k === null) { + continue; + } + + for (; l < layersCount;) { + const packet = createPacket(resolution, k, l); + l++; + return packet; + } + + l = 0; + } + + r = 0; + } + + c = 0; + } + + px = 0; + } + + throw new JpxError("Out of packets"); + }; +} + +function ComponentPositionResolutionLayerIterator(context) { + const siz = context.SIZ; + const tileIndex = context.currentTile.index; + const tile = context.tiles[tileIndex]; + const layersCount = tile.codingStyleDefaultParameters.layersCount; + const componentsCount = siz.Csiz; + const precinctsSizes = getPrecinctSizesInImageScale(tile); + let l = 0, + r = 0, + c = 0, + px = 0, + py = 0; + + this.nextPacket = function JpxImage_nextPacket() { + for (; c < componentsCount; ++c) { + const component = tile.components[c]; + const precinctsIterationSizes = precinctsSizes.components[c]; + const decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount; + + for (; py < precinctsIterationSizes.maxNumHigh; py++) { + for (; px < precinctsIterationSizes.maxNumWide; px++) { + for (; r <= decompositionLevelsCount; r++) { + const resolution = component.resolutions[r]; + const sizeInImageScale = precinctsIterationSizes.resolutions[r]; + const k = getPrecinctIndexIfExist(px, py, sizeInImageScale, precinctsIterationSizes, resolution); + + if (k === null) { + continue; + } + + for (; l < layersCount;) { + const packet = createPacket(resolution, k, l); + l++; + return packet; + } + + l = 0; + } + + r = 0; + } + + px = 0; + } + + py = 0; + } + + throw new JpxError("Out of packets"); + }; +} + +function getPrecinctIndexIfExist(pxIndex, pyIndex, sizeInImageScale, precinctIterationSizes, resolution) { + const posX = pxIndex * precinctIterationSizes.minWidth; + const posY = pyIndex * precinctIterationSizes.minHeight; + + if (posX % sizeInImageScale.width !== 0 || posY % sizeInImageScale.height !== 0) { + return null; + } + + const startPrecinctRowIndex = posY / sizeInImageScale.width * resolution.precinctParameters.numprecinctswide; + return posX / sizeInImageScale.height + startPrecinctRowIndex; +} + +function getPrecinctSizesInImageScale(tile) { + const componentsCount = tile.components.length; + let minWidth = Number.MAX_VALUE; + let minHeight = Number.MAX_VALUE; + let maxNumWide = 0; + let maxNumHigh = 0; + const sizePerComponent = new Array(componentsCount); + + for (let c = 0; c < componentsCount; c++) { + const component = tile.components[c]; + const decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount; + const sizePerResolution = new Array(decompositionLevelsCount + 1); + let minWidthCurrentComponent = Number.MAX_VALUE; + let minHeightCurrentComponent = Number.MAX_VALUE; + let maxNumWideCurrentComponent = 0; + let maxNumHighCurrentComponent = 0; + let scale = 1; + + for (let r = decompositionLevelsCount; r >= 0; --r) { + const resolution = component.resolutions[r]; + const widthCurrentResolution = scale * resolution.precinctParameters.precinctWidth; + const heightCurrentResolution = scale * resolution.precinctParameters.precinctHeight; + minWidthCurrentComponent = Math.min(minWidthCurrentComponent, widthCurrentResolution); + minHeightCurrentComponent = Math.min(minHeightCurrentComponent, heightCurrentResolution); + maxNumWideCurrentComponent = Math.max(maxNumWideCurrentComponent, resolution.precinctParameters.numprecinctswide); + maxNumHighCurrentComponent = Math.max(maxNumHighCurrentComponent, resolution.precinctParameters.numprecinctshigh); + sizePerResolution[r] = { + width: widthCurrentResolution, + height: heightCurrentResolution + }; + scale <<= 1; + } + + minWidth = Math.min(minWidth, minWidthCurrentComponent); + minHeight = Math.min(minHeight, minHeightCurrentComponent); + maxNumWide = Math.max(maxNumWide, maxNumWideCurrentComponent); + maxNumHigh = Math.max(maxNumHigh, maxNumHighCurrentComponent); + sizePerComponent[c] = { + resolutions: sizePerResolution, + minWidth: minWidthCurrentComponent, + minHeight: minHeightCurrentComponent, + maxNumWide: maxNumWideCurrentComponent, + maxNumHigh: maxNumHighCurrentComponent + }; + } + + return { + components: sizePerComponent, + minWidth, + minHeight, + maxNumWide, + maxNumHigh + }; +} + +function buildPackets(context) { + const siz = context.SIZ; + const tileIndex = context.currentTile.index; + const tile = context.tiles[tileIndex]; + const componentsCount = siz.Csiz; + + for (let c = 0; c < componentsCount; c++) { + const component = tile.components[c]; + const decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount; + const resolutions = []; + const subbands = []; + + for (let r = 0; r <= decompositionLevelsCount; r++) { + const blocksDimensions = getBlocksDimensions(context, component, r); + const resolution = {}; + const scale = 1 << decompositionLevelsCount - r; + resolution.trx0 = Math.ceil(component.tcx0 / scale); + resolution.try0 = Math.ceil(component.tcy0 / scale); + resolution.trx1 = Math.ceil(component.tcx1 / scale); + resolution.try1 = Math.ceil(component.tcy1 / scale); + resolution.resLevel = r; + buildPrecincts(context, resolution, blocksDimensions); + resolutions.push(resolution); + let subband; + + if (r === 0) { + subband = {}; + subband.type = "LL"; + subband.tbx0 = Math.ceil(component.tcx0 / scale); + subband.tby0 = Math.ceil(component.tcy0 / scale); + subband.tbx1 = Math.ceil(component.tcx1 / scale); + subband.tby1 = Math.ceil(component.tcy1 / scale); + subband.resolution = resolution; + buildCodeblocks(context, subband, blocksDimensions); + subbands.push(subband); + resolution.subbands = [subband]; + } else { + const bscale = 1 << decompositionLevelsCount - r + 1; + const resolutionSubbands = []; + subband = {}; + subband.type = "HL"; + subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5); + subband.tby0 = Math.ceil(component.tcy0 / bscale); + subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5); + subband.tby1 = Math.ceil(component.tcy1 / bscale); + subband.resolution = resolution; + buildCodeblocks(context, subband, blocksDimensions); + subbands.push(subband); + resolutionSubbands.push(subband); + subband = {}; + subband.type = "LH"; + subband.tbx0 = Math.ceil(component.tcx0 / bscale); + subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5); + subband.tbx1 = Math.ceil(component.tcx1 / bscale); + subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5); + subband.resolution = resolution; + buildCodeblocks(context, subband, blocksDimensions); + subbands.push(subband); + resolutionSubbands.push(subband); + subband = {}; + subband.type = "HH"; + subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5); + subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5); + subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5); + subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5); + subband.resolution = resolution; + buildCodeblocks(context, subband, blocksDimensions); + subbands.push(subband); + resolutionSubbands.push(subband); + resolution.subbands = resolutionSubbands; + } + } + + component.resolutions = resolutions; + component.subbands = subbands; + } + + const progressionOrder = tile.codingStyleDefaultParameters.progressionOrder; + + switch (progressionOrder) { + case 0: + tile.packetsIterator = new LayerResolutionComponentPositionIterator(context); + break; + + case 1: + tile.packetsIterator = new ResolutionLayerComponentPositionIterator(context); + break; + + case 2: + tile.packetsIterator = new ResolutionPositionComponentLayerIterator(context); + break; + + case 3: + tile.packetsIterator = new PositionComponentResolutionLayerIterator(context); + break; + + case 4: + tile.packetsIterator = new ComponentPositionResolutionLayerIterator(context); + break; + + default: + throw new JpxError(`Unsupported progression order ${progressionOrder}`); + } +} + +function parseTilePackets(context, data, offset, dataLength) { + let position = 0; + let buffer, + bufferSize = 0, + skipNextBit = false; + + function readBits(count) { + while (bufferSize < count) { + const b = data[offset + position]; + position++; + + if (skipNextBit) { + buffer = buffer << 7 | b; + bufferSize += 7; + skipNextBit = false; + } else { + buffer = buffer << 8 | b; + bufferSize += 8; + } + + if (b === 0xff) { + skipNextBit = true; + } + } + + bufferSize -= count; + return buffer >>> bufferSize & (1 << count) - 1; + } + + function skipMarkerIfEqual(value) { + if (data[offset + position - 1] === 0xff && data[offset + position] === value) { + skipBytes(1); + return true; + } else if (data[offset + position] === 0xff && data[offset + position + 1] === value) { + skipBytes(2); + return true; + } + + return false; + } + + function skipBytes(count) { + position += count; + } + + function alignToByte() { + bufferSize = 0; + + if (skipNextBit) { + position++; + skipNextBit = false; + } + } + + function readCodingpasses() { + if (readBits(1) === 0) { + return 1; + } + + if (readBits(1) === 0) { + return 2; + } + + let value = readBits(2); + + if (value < 3) { + return value + 3; + } + + value = readBits(5); + + if (value < 31) { + return value + 6; + } + + value = readBits(7); + return value + 37; + } + + const tileIndex = context.currentTile.index; + const tile = context.tiles[tileIndex]; + const sopMarkerUsed = context.COD.sopMarkerUsed; + const ephMarkerUsed = context.COD.ephMarkerUsed; + const packetsIterator = tile.packetsIterator; + + while (position < dataLength) { + alignToByte(); + + if (sopMarkerUsed && skipMarkerIfEqual(0x91)) { + skipBytes(4); + } + + const packet = packetsIterator.nextPacket(); + + if (!readBits(1)) { + continue; + } + + const layerNumber = packet.layerNumber, + queue = []; + let codeblock; + + for (let i = 0, ii = packet.codeblocks.length; i < ii; i++) { + codeblock = packet.codeblocks[i]; + let precinct = codeblock.precinct; + const codeblockColumn = codeblock.cbx - precinct.cbxMin; + const codeblockRow = codeblock.cby - precinct.cbyMin; + let codeblockIncluded = false; + let firstTimeInclusion = false; + let valueReady, zeroBitPlanesTree; + + if (codeblock.included !== undefined) { + codeblockIncluded = !!readBits(1); + } else { + precinct = codeblock.precinct; + let inclusionTree; + + if (precinct.inclusionTree !== undefined) { + inclusionTree = precinct.inclusionTree; + } else { + const width = precinct.cbxMax - precinct.cbxMin + 1; + const height = precinct.cbyMax - precinct.cbyMin + 1; + inclusionTree = new InclusionTree(width, height, layerNumber); + zeroBitPlanesTree = new TagTree(width, height); + precinct.inclusionTree = inclusionTree; + precinct.zeroBitPlanesTree = zeroBitPlanesTree; + + for (let l = 0; l < layerNumber; l++) { + if (readBits(1) !== 0) { + throw new JpxError("Invalid tag tree"); + } + } + } + + if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) { + while (true) { + if (readBits(1)) { + valueReady = !inclusionTree.nextLevel(); + + if (valueReady) { + codeblock.included = true; + codeblockIncluded = firstTimeInclusion = true; + break; + } + } else { + inclusionTree.incrementValue(layerNumber); + break; + } + } + } + } + + if (!codeblockIncluded) { + continue; + } + + if (firstTimeInclusion) { + zeroBitPlanesTree = precinct.zeroBitPlanesTree; + zeroBitPlanesTree.reset(codeblockColumn, codeblockRow); + + while (true) { + if (readBits(1)) { + valueReady = !zeroBitPlanesTree.nextLevel(); + + if (valueReady) { + break; + } + } else { + zeroBitPlanesTree.incrementValue(); + } + } + + codeblock.zeroBitPlanes = zeroBitPlanesTree.value; + } + + const codingpasses = readCodingpasses(); + + while (readBits(1)) { + codeblock.Lblock++; + } + + const codingpassesLog2 = (0, _core_utils.log2)(codingpasses); + const bits = (codingpasses < 1 << codingpassesLog2 ? codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock; + const codedDataLength = readBits(bits); + queue.push({ + codeblock, + codingpasses, + dataLength: codedDataLength + }); + } + + alignToByte(); + + if (ephMarkerUsed) { + skipMarkerIfEqual(0x92); + } + + while (queue.length > 0) { + const packetItem = queue.shift(); + codeblock = packetItem.codeblock; + + if (codeblock.data === undefined) { + codeblock.data = []; + } + + codeblock.data.push({ + data, + start: offset + position, + end: offset + position + packetItem.dataLength, + codingpasses: packetItem.codingpasses + }); + position += packetItem.dataLength; + } + } + + return position; +} + +function copyCoefficients(coefficients, levelWidth, levelHeight, subband, delta, mb, reversible, segmentationSymbolUsed, resetContextProbabilities) { + const x0 = subband.tbx0; + const y0 = subband.tby0; + const width = subband.tbx1 - subband.tbx0; + const codeblocks = subband.codeblocks; + const right = subband.type.charAt(0) === "H" ? 1 : 0; + const bottom = subband.type.charAt(1) === "H" ? levelWidth : 0; + + for (let i = 0, ii = codeblocks.length; i < ii; ++i) { + const codeblock = codeblocks[i]; + const blockWidth = codeblock.tbx1_ - codeblock.tbx0_; + const blockHeight = codeblock.tby1_ - codeblock.tby0_; + + if (blockWidth === 0 || blockHeight === 0) { + continue; + } + + if (codeblock.data === undefined) { + continue; + } + + const bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType, codeblock.zeroBitPlanes, mb); + let currentCodingpassType = 2; + const data = codeblock.data; + let totalLength = 0, + codingpasses = 0; + let j, jj, dataItem; + + for (j = 0, jj = data.length; j < jj; j++) { + dataItem = data[j]; + totalLength += dataItem.end - dataItem.start; + codingpasses += dataItem.codingpasses; + } + + const encodedData = new Uint8Array(totalLength); + let position = 0; + + for (j = 0, jj = data.length; j < jj; j++) { + dataItem = data[j]; + const chunk = dataItem.data.subarray(dataItem.start, dataItem.end); + encodedData.set(chunk, position); + position += chunk.length; + } + + const decoder = new _arithmetic_decoder.ArithmeticDecoder(encodedData, 0, totalLength); + bitModel.setDecoder(decoder); + + for (j = 0; j < codingpasses; j++) { + switch (currentCodingpassType) { + case 0: + bitModel.runSignificancePropagationPass(); + break; + + case 1: + bitModel.runMagnitudeRefinementPass(); + break; + + case 2: + bitModel.runCleanupPass(); + + if (segmentationSymbolUsed) { + bitModel.checkSegmentationSymbol(); + } + + break; + } + + if (resetContextProbabilities) { + bitModel.reset(); + } + + currentCodingpassType = (currentCodingpassType + 1) % 3; + } + + let offset = codeblock.tbx0_ - x0 + (codeblock.tby0_ - y0) * width; + const sign = bitModel.coefficentsSign; + const magnitude = bitModel.coefficentsMagnitude; + const bitsDecoded = bitModel.bitsDecoded; + const magnitudeCorrection = reversible ? 0 : 0.5; + let k, n, nb; + position = 0; + const interleave = subband.type !== "LL"; + + for (j = 0; j < blockHeight; j++) { + const row = offset / width | 0; + const levelOffset = 2 * row * (levelWidth - width) + right + bottom; + + for (k = 0; k < blockWidth; k++) { + n = magnitude[position]; + + if (n !== 0) { + n = (n + magnitudeCorrection) * delta; + + if (sign[position] !== 0) { + n = -n; + } + + nb = bitsDecoded[position]; + const pos = interleave ? levelOffset + (offset << 1) : offset; + + if (reversible && nb >= mb) { + coefficients[pos] = n; + } else { + coefficients[pos] = n * (1 << mb - nb); + } + } + + offset++; + position++; + } + + offset += width - blockWidth; + } + } +} + +function transformTile(context, tile, c) { + const component = tile.components[c]; + const codingStyleParameters = component.codingStyleParameters; + const quantizationParameters = component.quantizationParameters; + const decompositionLevelsCount = codingStyleParameters.decompositionLevelsCount; + const spqcds = quantizationParameters.SPqcds; + const scalarExpounded = quantizationParameters.scalarExpounded; + const guardBits = quantizationParameters.guardBits; + const segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed; + const resetContextProbabilities = codingStyleParameters.resetContextProbabilities; + const precision = context.components[c].precision; + const reversible = codingStyleParameters.reversibleTransformation; + const transform = reversible ? new ReversibleTransform() : new IrreversibleTransform(); + const subbandCoefficients = []; + let b = 0; + + for (let i = 0; i <= decompositionLevelsCount; i++) { + const resolution = component.resolutions[i]; + const width = resolution.trx1 - resolution.trx0; + const height = resolution.try1 - resolution.try0; + const coefficients = new Float32Array(width * height); + + for (let j = 0, jj = resolution.subbands.length; j < jj; j++) { + let mu, epsilon; + + if (!scalarExpounded) { + mu = spqcds[0].mu; + epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0); + } else { + mu = spqcds[b].mu; + epsilon = spqcds[b].epsilon; + b++; + } + + const subband = resolution.subbands[j]; + const gainLog2 = SubbandsGainLog2[subband.type]; + const delta = reversible ? 1 : 2 ** (precision + gainLog2 - epsilon) * (1 + mu / 2048); + const mb = guardBits + epsilon - 1; + copyCoefficients(coefficients, width, height, subband, delta, mb, reversible, segmentationSymbolUsed, resetContextProbabilities); + } + + subbandCoefficients.push({ + width, + height, + items: coefficients + }); + } + + const result = transform.calculate(subbandCoefficients, component.tcx0, component.tcy0); + return { + left: component.tcx0, + top: component.tcy0, + width: result.width, + height: result.height, + items: result.items + }; +} + +function transformComponents(context) { + const siz = context.SIZ; + const components = context.components; + const componentsCount = siz.Csiz; + const resultImages = []; + + for (let i = 0, ii = context.tiles.length; i < ii; i++) { + const tile = context.tiles[i]; + const transformedTiles = []; + + for (let c = 0; c < componentsCount; c++) { + transformedTiles[c] = transformTile(context, tile, c); + } + + const tile0 = transformedTiles[0]; + const out = new Uint8ClampedArray(tile0.items.length * componentsCount); + const result = { + left: tile0.left, + top: tile0.top, + width: tile0.width, + height: tile0.height, + items: out + }; + let shift, offset; + let pos = 0, + j, + jj, + y0, + y1, + y2; + + if (tile.codingStyleDefaultParameters.multipleComponentTransform) { + const fourComponents = componentsCount === 4; + const y0items = transformedTiles[0].items; + const y1items = transformedTiles[1].items; + const y2items = transformedTiles[2].items; + const y3items = fourComponents ? transformedTiles[3].items : null; + shift = components[0].precision - 8; + offset = (128 << shift) + 0.5; + const component0 = tile.components[0]; + const alpha01 = componentsCount - 3; + jj = y0items.length; + + if (!component0.codingStyleParameters.reversibleTransformation) { + for (j = 0; j < jj; j++, pos += alpha01) { + y0 = y0items[j] + offset; + y1 = y1items[j]; + y2 = y2items[j]; + out[pos++] = y0 + 1.402 * y2 >> shift; + out[pos++] = y0 - 0.34413 * y1 - 0.71414 * y2 >> shift; + out[pos++] = y0 + 1.772 * y1 >> shift; + } + } else { + for (j = 0; j < jj; j++, pos += alpha01) { + y0 = y0items[j] + offset; + y1 = y1items[j]; + y2 = y2items[j]; + const g = y0 - (y2 + y1 >> 2); + out[pos++] = g + y2 >> shift; + out[pos++] = g >> shift; + out[pos++] = g + y1 >> shift; + } + } + + if (fourComponents) { + for (j = 0, pos = 3; j < jj; j++, pos += 4) { + out[pos] = y3items[j] + offset >> shift; + } + } + } else { + for (let c = 0; c < componentsCount; c++) { + const items = transformedTiles[c].items; + shift = components[c].precision - 8; + offset = (128 << shift) + 0.5; + + for (pos = c, j = 0, jj = items.length; j < jj; j++) { + out[pos] = items[j] + offset >> shift; + pos += componentsCount; + } + } + } + + resultImages.push(result); + } + + return resultImages; +} + +function initializeTile(context, tileIndex) { + const siz = context.SIZ; + const componentsCount = siz.Csiz; + const tile = context.tiles[tileIndex]; + + for (let c = 0; c < componentsCount; c++) { + const component = tile.components[c]; + const qcdOrQcc = context.currentTile.QCC[c] !== undefined ? context.currentTile.QCC[c] : context.currentTile.QCD; + component.quantizationParameters = qcdOrQcc; + const codOrCoc = context.currentTile.COC[c] !== undefined ? context.currentTile.COC[c] : context.currentTile.COD; + component.codingStyleParameters = codOrCoc; + } + + tile.codingStyleDefaultParameters = context.currentTile.COD; +} + +class TagTree { + constructor(width, height) { + const levelsLength = (0, _core_utils.log2)(Math.max(width, height)) + 1; + this.levels = []; + + for (let i = 0; i < levelsLength; i++) { + const level = { + width, + height, + items: [] + }; + this.levels.push(level); + width = Math.ceil(width / 2); + height = Math.ceil(height / 2); + } + } + + reset(i, j) { + let currentLevel = 0, + value = 0, + level; + + while (currentLevel < this.levels.length) { + level = this.levels[currentLevel]; + const index = i + j * level.width; + + if (level.items[index] !== undefined) { + value = level.items[index]; + break; + } + + level.index = index; + i >>= 1; + j >>= 1; + currentLevel++; + } + + currentLevel--; + level = this.levels[currentLevel]; + level.items[level.index] = value; + this.currentLevel = currentLevel; + delete this.value; + } + + incrementValue() { + const level = this.levels[this.currentLevel]; + level.items[level.index]++; + } + + nextLevel() { + let currentLevel = this.currentLevel; + let level = this.levels[currentLevel]; + const value = level.items[level.index]; + currentLevel--; + + if (currentLevel < 0) { + this.value = value; + return false; + } + + this.currentLevel = currentLevel; + level = this.levels[currentLevel]; + level.items[level.index] = value; + return true; + } + +} + +class InclusionTree { + constructor(width, height, defaultValue) { + const levelsLength = (0, _core_utils.log2)(Math.max(width, height)) + 1; + this.levels = []; + + for (let i = 0; i < levelsLength; i++) { + const items = new Uint8Array(width * height); + + for (let j = 0, jj = items.length; j < jj; j++) { + items[j] = defaultValue; + } + + const level = { + width, + height, + items + }; + this.levels.push(level); + width = Math.ceil(width / 2); + height = Math.ceil(height / 2); + } + } + + reset(i, j, stopValue) { + let currentLevel = 0; + + while (currentLevel < this.levels.length) { + const level = this.levels[currentLevel]; + const index = i + j * level.width; + level.index = index; + const value = level.items[index]; + + if (value === 0xff) { + break; + } + + if (value > stopValue) { + this.currentLevel = currentLevel; + this.propagateValues(); + return false; + } + + i >>= 1; + j >>= 1; + currentLevel++; + } + + this.currentLevel = currentLevel - 1; + return true; + } + + incrementValue(stopValue) { + const level = this.levels[this.currentLevel]; + level.items[level.index] = stopValue + 1; + this.propagateValues(); + } + + propagateValues() { + let levelIndex = this.currentLevel; + let level = this.levels[levelIndex]; + const currentValue = level.items[level.index]; + + while (--levelIndex >= 0) { + level = this.levels[levelIndex]; + level.items[level.index] = currentValue; + } + } + + nextLevel() { + let currentLevel = this.currentLevel; + let level = this.levels[currentLevel]; + const value = level.items[level.index]; + level.items[level.index] = 0xff; + currentLevel--; + + if (currentLevel < 0) { + return false; + } + + this.currentLevel = currentLevel; + level = this.levels[currentLevel]; + level.items[level.index] = value; + return true; + } + +} + +const BitModel = function BitModelClosure() { + const UNIFORM_CONTEXT = 17; + const RUNLENGTH_CONTEXT = 18; + const LLAndLHContextsLabel = new Uint8Array([0, 5, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 1, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8]); + const HLContextLabel = new Uint8Array([0, 3, 4, 0, 5, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8]); + const HHContextLabel = new Uint8Array([0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8]); + + class BitModel { + constructor(width, height, subband, zeroBitPlanes, mb) { + this.width = width; + this.height = height; + let contextLabelTable; + + if (subband === "HH") { + contextLabelTable = HHContextLabel; + } else if (subband === "HL") { + contextLabelTable = HLContextLabel; + } else { + contextLabelTable = LLAndLHContextsLabel; + } + + this.contextLabelTable = contextLabelTable; + const coefficientCount = width * height; + this.neighborsSignificance = new Uint8Array(coefficientCount); + this.coefficentsSign = new Uint8Array(coefficientCount); + let coefficentsMagnitude; + + if (mb > 14) { + coefficentsMagnitude = new Uint32Array(coefficientCount); + } else if (mb > 6) { + coefficentsMagnitude = new Uint16Array(coefficientCount); + } else { + coefficentsMagnitude = new Uint8Array(coefficientCount); + } + + this.coefficentsMagnitude = coefficentsMagnitude; + this.processingFlags = new Uint8Array(coefficientCount); + const bitsDecoded = new Uint8Array(coefficientCount); + + if (zeroBitPlanes !== 0) { + for (let i = 0; i < coefficientCount; i++) { + bitsDecoded[i] = zeroBitPlanes; + } + } + + this.bitsDecoded = bitsDecoded; + this.reset(); + } + + setDecoder(decoder) { + this.decoder = decoder; + } + + reset() { + this.contexts = new Int8Array(19); + this.contexts[0] = 4 << 1 | 0; + this.contexts[UNIFORM_CONTEXT] = 46 << 1 | 0; + this.contexts[RUNLENGTH_CONTEXT] = 3 << 1 | 0; + } + + setNeighborsSignificance(row, column, index) { + const neighborsSignificance = this.neighborsSignificance; + const width = this.width, + height = this.height; + const left = column > 0; + const right = column + 1 < width; + let i; + + if (row > 0) { + i = index - width; + + if (left) { + neighborsSignificance[i - 1] += 0x10; + } + + if (right) { + neighborsSignificance[i + 1] += 0x10; + } + + neighborsSignificance[i] += 0x04; + } + + if (row + 1 < height) { + i = index + width; + + if (left) { + neighborsSignificance[i - 1] += 0x10; + } + + if (right) { + neighborsSignificance[i + 1] += 0x10; + } + + neighborsSignificance[i] += 0x04; + } + + if (left) { + neighborsSignificance[index - 1] += 0x01; + } + + if (right) { + neighborsSignificance[index + 1] += 0x01; + } + + neighborsSignificance[index] |= 0x80; + } + + runSignificancePropagationPass() { + const decoder = this.decoder; + const width = this.width, + height = this.height; + const coefficentsMagnitude = this.coefficentsMagnitude; + const coefficentsSign = this.coefficentsSign; + const neighborsSignificance = this.neighborsSignificance; + const processingFlags = this.processingFlags; + const contexts = this.contexts; + const labels = this.contextLabelTable; + const bitsDecoded = this.bitsDecoded; + const processedInverseMask = ~1; + const processedMask = 1; + const firstMagnitudeBitMask = 2; + + for (let i0 = 0; i0 < height; i0 += 4) { + for (let j = 0; j < width; j++) { + let index = i0 * width + j; + + for (let i1 = 0; i1 < 4; i1++, index += width) { + const i = i0 + i1; + + if (i >= height) { + break; + } + + processingFlags[index] &= processedInverseMask; + + if (coefficentsMagnitude[index] || !neighborsSignificance[index]) { + continue; + } + + const contextLabel = labels[neighborsSignificance[index]]; + const decision = decoder.readBit(contexts, contextLabel); + + if (decision) { + const sign = this.decodeSignBit(i, j, index); + coefficentsSign[index] = sign; + coefficentsMagnitude[index] = 1; + this.setNeighborsSignificance(i, j, index); + processingFlags[index] |= firstMagnitudeBitMask; + } + + bitsDecoded[index]++; + processingFlags[index] |= processedMask; + } + } + } + } + + decodeSignBit(row, column, index) { + const width = this.width, + height = this.height; + const coefficentsMagnitude = this.coefficentsMagnitude; + const coefficentsSign = this.coefficentsSign; + let contribution, sign0, sign1, significance1; + let contextLabel, decoded; + significance1 = column > 0 && coefficentsMagnitude[index - 1] !== 0; + + if (column + 1 < width && coefficentsMagnitude[index + 1] !== 0) { + sign1 = coefficentsSign[index + 1]; + + if (significance1) { + sign0 = coefficentsSign[index - 1]; + contribution = 1 - sign1 - sign0; + } else { + contribution = 1 - sign1 - sign1; + } + } else if (significance1) { + sign0 = coefficentsSign[index - 1]; + contribution = 1 - sign0 - sign0; + } else { + contribution = 0; + } + + const horizontalContribution = 3 * contribution; + significance1 = row > 0 && coefficentsMagnitude[index - width] !== 0; + + if (row + 1 < height && coefficentsMagnitude[index + width] !== 0) { + sign1 = coefficentsSign[index + width]; + + if (significance1) { + sign0 = coefficentsSign[index - width]; + contribution = 1 - sign1 - sign0 + horizontalContribution; + } else { + contribution = 1 - sign1 - sign1 + horizontalContribution; + } + } else if (significance1) { + sign0 = coefficentsSign[index - width]; + contribution = 1 - sign0 - sign0 + horizontalContribution; + } else { + contribution = horizontalContribution; + } + + if (contribution >= 0) { + contextLabel = 9 + contribution; + decoded = this.decoder.readBit(this.contexts, contextLabel); + } else { + contextLabel = 9 - contribution; + decoded = this.decoder.readBit(this.contexts, contextLabel) ^ 1; + } + + return decoded; + } + + runMagnitudeRefinementPass() { + const decoder = this.decoder; + const width = this.width, + height = this.height; + const coefficentsMagnitude = this.coefficentsMagnitude; + const neighborsSignificance = this.neighborsSignificance; + const contexts = this.contexts; + const bitsDecoded = this.bitsDecoded; + const processingFlags = this.processingFlags; + const processedMask = 1; + const firstMagnitudeBitMask = 2; + const length = width * height; + const width4 = width * 4; + + for (let index0 = 0, indexNext; index0 < length; index0 = indexNext) { + indexNext = Math.min(length, index0 + width4); + + for (let j = 0; j < width; j++) { + for (let index = index0 + j; index < indexNext; index += width) { + if (!coefficentsMagnitude[index] || (processingFlags[index] & processedMask) !== 0) { + continue; + } + + let contextLabel = 16; + + if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) { + processingFlags[index] ^= firstMagnitudeBitMask; + const significance = neighborsSignificance[index] & 127; + contextLabel = significance === 0 ? 15 : 14; + } + + const bit = decoder.readBit(contexts, contextLabel); + coefficentsMagnitude[index] = coefficentsMagnitude[index] << 1 | bit; + bitsDecoded[index]++; + processingFlags[index] |= processedMask; + } + } + } + } + + runCleanupPass() { + const decoder = this.decoder; + const width = this.width, + height = this.height; + const neighborsSignificance = this.neighborsSignificance; + const coefficentsMagnitude = this.coefficentsMagnitude; + const coefficentsSign = this.coefficentsSign; + const contexts = this.contexts; + const labels = this.contextLabelTable; + const bitsDecoded = this.bitsDecoded; + const processingFlags = this.processingFlags; + const processedMask = 1; + const firstMagnitudeBitMask = 2; + const oneRowDown = width; + const twoRowsDown = width * 2; + const threeRowsDown = width * 3; + let iNext; + + for (let i0 = 0; i0 < height; i0 = iNext) { + iNext = Math.min(i0 + 4, height); + const indexBase = i0 * width; + const checkAllEmpty = i0 + 3 < height; + + for (let j = 0; j < width; j++) { + const index0 = indexBase + j; + const allEmpty = checkAllEmpty && processingFlags[index0] === 0 && processingFlags[index0 + oneRowDown] === 0 && processingFlags[index0 + twoRowsDown] === 0 && processingFlags[index0 + threeRowsDown] === 0 && neighborsSignificance[index0] === 0 && neighborsSignificance[index0 + oneRowDown] === 0 && neighborsSignificance[index0 + twoRowsDown] === 0 && neighborsSignificance[index0 + threeRowsDown] === 0; + let i1 = 0, + index = index0; + let i = i0, + sign; + + if (allEmpty) { + const hasSignificantCoefficent = decoder.readBit(contexts, RUNLENGTH_CONTEXT); + + if (!hasSignificantCoefficent) { + bitsDecoded[index0]++; + bitsDecoded[index0 + oneRowDown]++; + bitsDecoded[index0 + twoRowsDown]++; + bitsDecoded[index0 + threeRowsDown]++; + continue; + } + + i1 = decoder.readBit(contexts, UNIFORM_CONTEXT) << 1 | decoder.readBit(contexts, UNIFORM_CONTEXT); + + if (i1 !== 0) { + i = i0 + i1; + index += i1 * width; + } + + sign = this.decodeSignBit(i, j, index); + coefficentsSign[index] = sign; + coefficentsMagnitude[index] = 1; + this.setNeighborsSignificance(i, j, index); + processingFlags[index] |= firstMagnitudeBitMask; + index = index0; + + for (let i2 = i0; i2 <= i; i2++, index += width) { + bitsDecoded[index]++; + } + + i1++; + } + + for (i = i0 + i1; i < iNext; i++, index += width) { + if (coefficentsMagnitude[index] || (processingFlags[index] & processedMask) !== 0) { + continue; + } + + const contextLabel = labels[neighborsSignificance[index]]; + const decision = decoder.readBit(contexts, contextLabel); + + if (decision === 1) { + sign = this.decodeSignBit(i, j, index); + coefficentsSign[index] = sign; + coefficentsMagnitude[index] = 1; + this.setNeighborsSignificance(i, j, index); + processingFlags[index] |= firstMagnitudeBitMask; + } + + bitsDecoded[index]++; + } + } + } + } + + checkSegmentationSymbol() { + const decoder = this.decoder; + const contexts = this.contexts; + const symbol = decoder.readBit(contexts, UNIFORM_CONTEXT) << 3 | decoder.readBit(contexts, UNIFORM_CONTEXT) << 2 | decoder.readBit(contexts, UNIFORM_CONTEXT) << 1 | decoder.readBit(contexts, UNIFORM_CONTEXT); + + if (symbol !== 0xa) { + throw new JpxError("Invalid segmentation symbol"); + } + } + + } + + return BitModel; +}(); + +class Transform { + constructor() { + if (this.constructor === Transform) { + (0, _util.unreachable)("Cannot initialize Transform."); + } + } + + calculate(subbands, u0, v0) { + let ll = subbands[0]; + + for (let i = 1, ii = subbands.length; i < ii; i++) { + ll = this.iterate(ll, subbands[i], u0, v0); + } + + return ll; + } + + extend(buffer, offset, size) { + let i1 = offset - 1, + j1 = offset + 1; + let i2 = offset + size - 2, + j2 = offset + size; + buffer[i1--] = buffer[j1++]; + buffer[j2++] = buffer[i2--]; + buffer[i1--] = buffer[j1++]; + buffer[j2++] = buffer[i2--]; + buffer[i1--] = buffer[j1++]; + buffer[j2++] = buffer[i2--]; + buffer[i1] = buffer[j1]; + buffer[j2] = buffer[i2]; + } + + filter(x, offset, length) { + (0, _util.unreachable)("Abstract method `filter` called"); + } + + iterate(ll, hl_lh_hh, u0, v0) { + const llWidth = ll.width, + llHeight = ll.height; + let llItems = ll.items; + const width = hl_lh_hh.width; + const height = hl_lh_hh.height; + const items = hl_lh_hh.items; + let i, j, k, l, u, v; + + for (k = 0, i = 0; i < llHeight; i++) { + l = i * 2 * width; + + for (j = 0; j < llWidth; j++, k++, l += 2) { + items[l] = llItems[k]; + } + } + + llItems = ll.items = null; + const bufferPadding = 4; + const rowBuffer = new Float32Array(width + 2 * bufferPadding); + + if (width === 1) { + if ((u0 & 1) !== 0) { + for (v = 0, k = 0; v < height; v++, k += width) { + items[k] *= 0.5; + } + } + } else { + for (v = 0, k = 0; v < height; v++, k += width) { + rowBuffer.set(items.subarray(k, k + width), bufferPadding); + this.extend(rowBuffer, bufferPadding, width); + this.filter(rowBuffer, bufferPadding, width); + items.set(rowBuffer.subarray(bufferPadding, bufferPadding + width), k); + } + } + + let numBuffers = 16; + const colBuffers = []; + + for (i = 0; i < numBuffers; i++) { + colBuffers.push(new Float32Array(height + 2 * bufferPadding)); + } + + let b, + currentBuffer = 0; + ll = bufferPadding + height; + + if (height === 1) { + if ((v0 & 1) !== 0) { + for (u = 0; u < width; u++) { + items[u] *= 0.5; + } + } + } else { + for (u = 0; u < width; u++) { + if (currentBuffer === 0) { + numBuffers = Math.min(width - u, numBuffers); + + for (k = u, l = bufferPadding; l < ll; k += width, l++) { + for (b = 0; b < numBuffers; b++) { + colBuffers[b][l] = items[k + b]; + } + } + + currentBuffer = numBuffers; + } + + currentBuffer--; + const buffer = colBuffers[currentBuffer]; + this.extend(buffer, bufferPadding, height); + this.filter(buffer, bufferPadding, height); + + if (currentBuffer === 0) { + k = u - numBuffers + 1; + + for (l = bufferPadding; l < ll; k += width, l++) { + for (b = 0; b < numBuffers; b++) { + items[k + b] = colBuffers[b][l]; + } + } + } + } + } + + return { + width, + height, + items + }; + } + +} + +class IrreversibleTransform extends Transform { + filter(x, offset, length) { + const len = length >> 1; + offset |= 0; + let j, n, current, next; + const alpha = -1.586134342059924; + const beta = -0.052980118572961; + const gamma = 0.882911075530934; + const delta = 0.443506852043971; + const K = 1.230174104914001; + const K_ = 1 / K; + j = offset - 3; + + for (n = len + 4; n--; j += 2) { + x[j] *= K_; + } + + j = offset - 2; + current = delta * x[j - 1]; + + for (n = len + 3; n--; j += 2) { + next = delta * x[j + 1]; + x[j] = K * x[j] - current - next; + + if (n--) { + j += 2; + current = delta * x[j + 1]; + x[j] = K * x[j] - current - next; + } else { + break; + } + } + + j = offset - 1; + current = gamma * x[j - 1]; + + for (n = len + 2; n--; j += 2) { + next = gamma * x[j + 1]; + x[j] -= current + next; + + if (n--) { + j += 2; + current = gamma * x[j + 1]; + x[j] -= current + next; + } else { + break; + } + } + + j = offset; + current = beta * x[j - 1]; + + for (n = len + 1; n--; j += 2) { + next = beta * x[j + 1]; + x[j] -= current + next; + + if (n--) { + j += 2; + current = beta * x[j + 1]; + x[j] -= current + next; + } else { + break; + } + } + + if (len !== 0) { + j = offset + 1; + current = alpha * x[j - 1]; + + for (n = len; n--; j += 2) { + next = alpha * x[j + 1]; + x[j] -= current + next; + + if (n--) { + j += 2; + current = alpha * x[j + 1]; + x[j] -= current + next; + } else { + break; + } + } + } + } + +} + +class ReversibleTransform extends Transform { + filter(x, offset, length) { + const len = length >> 1; + offset |= 0; + let j, n; + + for (j = offset, n = len + 1; n--; j += 2) { + x[j] -= x[j - 1] + x[j + 1] + 2 >> 2; + } + + for (j = offset + 1, n = len; n--; j += 2) { + x[j] += x[j - 1] + x[j + 1] >> 1; + } + } + +} + +/***/ }), +/* 31 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.LZWStream = void 0; + +var _decode_stream = __w_pdfjs_require__(19); + +class LZWStream extends _decode_stream.DecodeStream { + constructor(str, maybeLength, earlyChange) { + super(maybeLength); + this.str = str; + this.dict = str.dict; + this.cachedData = 0; + this.bitsCached = 0; + const maxLzwDictionarySize = 4096; + const lzwState = { + earlyChange, + codeLength: 9, + nextCode: 258, + dictionaryValues: new Uint8Array(maxLzwDictionarySize), + dictionaryLengths: new Uint16Array(maxLzwDictionarySize), + dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize), + currentSequence: new Uint8Array(maxLzwDictionarySize), + currentSequenceLength: 0 + }; + + for (let i = 0; i < 256; ++i) { + lzwState.dictionaryValues[i] = i; + lzwState.dictionaryLengths[i] = 1; + } + + this.lzwState = lzwState; + } + + readBits(n) { + let bitsCached = this.bitsCached; + let cachedData = this.cachedData; + + while (bitsCached < n) { + const c = this.str.getByte(); + + if (c === -1) { + this.eof = true; + return null; + } + + cachedData = cachedData << 8 | c; + bitsCached += 8; + } + + this.bitsCached = bitsCached -= n; + this.cachedData = cachedData; + this.lastCode = null; + return cachedData >>> bitsCached & (1 << n) - 1; + } + + readBlock() { + const blockSize = 512, + decodedSizeDelta = blockSize; + let estimatedDecodedSize = blockSize * 2; + let i, j, q; + const lzwState = this.lzwState; + + if (!lzwState) { + return; + } + + const earlyChange = lzwState.earlyChange; + let nextCode = lzwState.nextCode; + const dictionaryValues = lzwState.dictionaryValues; + const dictionaryLengths = lzwState.dictionaryLengths; + const dictionaryPrevCodes = lzwState.dictionaryPrevCodes; + let codeLength = lzwState.codeLength; + let prevCode = lzwState.prevCode; + const currentSequence = lzwState.currentSequence; + let currentSequenceLength = lzwState.currentSequenceLength; + let decodedLength = 0; + let currentBufferLength = this.bufferLength; + let buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); + + for (i = 0; i < blockSize; i++) { + const code = this.readBits(codeLength); + const hasPrev = currentSequenceLength > 0; + + if (code < 256) { + currentSequence[0] = code; + currentSequenceLength = 1; + } else if (code >= 258) { + if (code < nextCode) { + currentSequenceLength = dictionaryLengths[code]; + + for (j = currentSequenceLength - 1, q = code; j >= 0; j--) { + currentSequence[j] = dictionaryValues[q]; + q = dictionaryPrevCodes[q]; + } + } else { + currentSequence[currentSequenceLength++] = currentSequence[0]; + } + } else if (code === 256) { + codeLength = 9; + nextCode = 258; + currentSequenceLength = 0; + continue; + } else { + this.eof = true; + delete this.lzwState; + break; + } + + if (hasPrev) { + dictionaryPrevCodes[nextCode] = prevCode; + dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1; + dictionaryValues[nextCode] = currentSequence[0]; + nextCode++; + codeLength = nextCode + earlyChange & nextCode + earlyChange - 1 ? codeLength : Math.min(Math.log(nextCode + earlyChange) / 0.6931471805599453 + 1, 12) | 0; + } + + prevCode = code; + decodedLength += currentSequenceLength; + + if (estimatedDecodedSize < decodedLength) { + do { + estimatedDecodedSize += decodedSizeDelta; + } while (estimatedDecodedSize < decodedLength); + + buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); + } + + for (j = 0; j < currentSequenceLength; j++) { + buffer[currentBufferLength++] = currentSequence[j]; + } + } + + lzwState.nextCode = nextCode; + lzwState.codeLength = codeLength; + lzwState.prevCode = prevCode; + lzwState.currentSequenceLength = currentSequenceLength; + this.bufferLength = currentBufferLength; + } + +} + +exports.LZWStream = LZWStream; + +/***/ }), +/* 32 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PredictorStream = void 0; + +var _decode_stream = __w_pdfjs_require__(19); + +var _primitives = __w_pdfjs_require__(5); + +var _util = __w_pdfjs_require__(2); + +class PredictorStream extends _decode_stream.DecodeStream { + constructor(str, maybeLength, params) { + super(maybeLength); + + if (!(params instanceof _primitives.Dict)) { + return str; + } + + const predictor = this.predictor = params.get("Predictor") || 1; + + if (predictor <= 1) { + return str; + } + + if (predictor !== 2 && (predictor < 10 || predictor > 15)) { + throw new _util.FormatError(`Unsupported predictor: ${predictor}`); + } + + if (predictor === 2) { + this.readBlock = this.readBlockTiff; + } else { + this.readBlock = this.readBlockPng; + } + + this.str = str; + this.dict = str.dict; + const colors = this.colors = params.get("Colors") || 1; + const bits = this.bits = params.get("BPC", "BitsPerComponent") || 8; + const columns = this.columns = params.get("Columns") || 1; + this.pixBytes = colors * bits + 7 >> 3; + this.rowBytes = columns * colors * bits + 7 >> 3; + return this; + } + + readBlockTiff() { + const rowBytes = this.rowBytes; + const bufferLength = this.bufferLength; + const buffer = this.ensureBuffer(bufferLength + rowBytes); + const bits = this.bits; + const colors = this.colors; + const rawBytes = this.str.getBytes(rowBytes); + this.eof = !rawBytes.length; + + if (this.eof) { + return; + } + + let inbuf = 0, + outbuf = 0; + let inbits = 0, + outbits = 0; + let pos = bufferLength; + let i; + + if (bits === 1 && colors === 1) { + for (i = 0; i < rowBytes; ++i) { + let c = rawBytes[i] ^ inbuf; + c ^= c >> 1; + c ^= c >> 2; + c ^= c >> 4; + inbuf = (c & 1) << 7; + buffer[pos++] = c; + } + } else if (bits === 8) { + for (i = 0; i < colors; ++i) { + buffer[pos++] = rawBytes[i]; + } + + for (; i < rowBytes; ++i) { + buffer[pos] = buffer[pos - colors] + rawBytes[i]; + pos++; + } + } else if (bits === 16) { + const bytesPerPixel = colors * 2; + + for (i = 0; i < bytesPerPixel; ++i) { + buffer[pos++] = rawBytes[i]; + } + + for (; i < rowBytes; i += 2) { + const sum = ((rawBytes[i] & 0xff) << 8) + (rawBytes[i + 1] & 0xff) + ((buffer[pos - bytesPerPixel] & 0xff) << 8) + (buffer[pos - bytesPerPixel + 1] & 0xff); + buffer[pos++] = sum >> 8 & 0xff; + buffer[pos++] = sum & 0xff; + } + } else { + const compArray = new Uint8Array(colors + 1); + const bitMask = (1 << bits) - 1; + let j = 0, + k = bufferLength; + const columns = this.columns; + + for (i = 0; i < columns; ++i) { + for (let kk = 0; kk < colors; ++kk) { + if (inbits < bits) { + inbuf = inbuf << 8 | rawBytes[j++] & 0xff; + inbits += 8; + } + + compArray[kk] = compArray[kk] + (inbuf >> inbits - bits) & bitMask; + inbits -= bits; + outbuf = outbuf << bits | compArray[kk]; + outbits += bits; + + if (outbits >= 8) { + buffer[k++] = outbuf >> outbits - 8 & 0xff; + outbits -= 8; + } + } + } + + if (outbits > 0) { + buffer[k++] = (outbuf << 8 - outbits) + (inbuf & (1 << 8 - outbits) - 1); + } + } + + this.bufferLength += rowBytes; + } + + readBlockPng() { + const rowBytes = this.rowBytes; + const pixBytes = this.pixBytes; + const predictor = this.str.getByte(); + const rawBytes = this.str.getBytes(rowBytes); + this.eof = !rawBytes.length; + + if (this.eof) { + return; + } + + const bufferLength = this.bufferLength; + const buffer = this.ensureBuffer(bufferLength + rowBytes); + let prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); + + if (prevRow.length === 0) { + prevRow = new Uint8Array(rowBytes); + } + + let i, + j = bufferLength, + up, + c; + + switch (predictor) { + case 0: + for (i = 0; i < rowBytes; ++i) { + buffer[j++] = rawBytes[i]; + } + + break; + + case 1: + for (i = 0; i < pixBytes; ++i) { + buffer[j++] = rawBytes[i]; + } + + for (; i < rowBytes; ++i) { + buffer[j] = buffer[j - pixBytes] + rawBytes[i] & 0xff; + j++; + } + + break; + + case 2: + for (i = 0; i < rowBytes; ++i) { + buffer[j++] = prevRow[i] + rawBytes[i] & 0xff; + } + + break; + + case 3: + for (i = 0; i < pixBytes; ++i) { + buffer[j++] = (prevRow[i] >> 1) + rawBytes[i]; + } + + for (; i < rowBytes; ++i) { + buffer[j] = (prevRow[i] + buffer[j - pixBytes] >> 1) + rawBytes[i] & 0xff; + j++; + } + + break; + + case 4: + for (i = 0; i < pixBytes; ++i) { + up = prevRow[i]; + c = rawBytes[i]; + buffer[j++] = up + c; + } + + for (; i < rowBytes; ++i) { + up = prevRow[i]; + const upLeft = prevRow[i - pixBytes]; + const left = buffer[j - pixBytes]; + const p = left + up - upLeft; + let pa = p - left; + + if (pa < 0) { + pa = -pa; + } + + let pb = p - up; + + if (pb < 0) { + pb = -pb; + } + + let pc = p - upLeft; + + if (pc < 0) { + pc = -pc; + } + + c = rawBytes[i]; + + if (pa <= pb && pa <= pc) { + buffer[j++] = left + c; + } else if (pb <= pc) { + buffer[j++] = up + c; + } else { + buffer[j++] = upLeft + c; + } + } + + break; + + default: + throw new _util.FormatError(`Unsupported predictor: ${predictor}`); + } + + this.bufferLength += rowBytes; + } + +} + +exports.PredictorStream = PredictorStream; + +/***/ }), +/* 33 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.RunLengthStream = void 0; + +var _decode_stream = __w_pdfjs_require__(19); + +class RunLengthStream extends _decode_stream.DecodeStream { + constructor(str, maybeLength) { + super(maybeLength); + this.str = str; + this.dict = str.dict; + } + + readBlock() { + const repeatHeader = this.str.getBytes(2); + + if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] === 128) { + this.eof = true; + return; + } + + let buffer; + let bufferLength = this.bufferLength; + let n = repeatHeader[0]; + + if (n < 128) { + buffer = this.ensureBuffer(bufferLength + n + 1); + buffer[bufferLength++] = repeatHeader[1]; + + if (n > 0) { + const source = this.str.getBytes(n); + buffer.set(source, bufferLength); + bufferLength += n; + } + } else { + n = 257 - n; + const b = repeatHeader[1]; + buffer = this.ensureBuffer(bufferLength + n + 1); + + for (let i = 0; i < n; i++) { + buffer[bufferLength++] = b; + } + } + + this.bufferLength = bufferLength; + } + +} + +exports.RunLengthStream = RunLengthStream; + +/***/ }), +/* 34 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Font = exports.ErrorFont = void 0; + +var _util = __w_pdfjs_require__(2); + +var _cff_parser = __w_pdfjs_require__(35); + +var _fonts_utils = __w_pdfjs_require__(38); + +var _unicode = __w_pdfjs_require__(40); + +var _glyphlist = __w_pdfjs_require__(39); + +var _encodings = __w_pdfjs_require__(37); + +var _standard_fonts = __w_pdfjs_require__(41); + +var _to_unicode_map = __w_pdfjs_require__(42); + +var _cff_font = __w_pdfjs_require__(43); + +var _font_renderer = __w_pdfjs_require__(44); + +var _metrics = __w_pdfjs_require__(45); + +var _glyf = __w_pdfjs_require__(46); + +var _cmap = __w_pdfjs_require__(16); + +var _opentype_file_builder = __w_pdfjs_require__(47); + +var _core_utils = __w_pdfjs_require__(6); + +var _stream = __w_pdfjs_require__(10); + +var _type1_font = __w_pdfjs_require__(48); const PRIVATE_USE_AREAS = [[0xe000, 0xf8ff], [0x100000, 0x10fffd]]; -var PDF_GLYPH_SPACE_UNITS = 1000; -var SEAC_ANALYSIS_ENABLED = true; -exports.SEAC_ANALYSIS_ENABLED = SEAC_ANALYSIS_ENABLED; -const EXPORT_DATA_PROPERTIES = ["ascent", "bbox", "black", "bold", "charProcOperatorList", "composite", "data", "defaultVMetrics", "defaultWidth", "descent", "fallbackName", "fontMatrix", "fontType", "isMonospace", "isSerifFont", "isType3Font", "italic", "loadedName", "mimetype", "missingFile", "name", "remeasure", "subtype", "type", "vertical"]; -const EXPORT_DATA_EXTRA_PROPERTIES = ["cMap", "defaultEncoding", "differences", "isSymbolicFont", "seacMap", "toFontChar", "toUnicode", "vmetrics", "widths"]; -var FontFlags = { - FixedPitch: 1, - Serif: 2, - Symbolic: 4, - Script: 8, - Nonsymbolic: 32, - Italic: 64, - AllCap: 65536, - SmallCap: 131072, - ForceBold: 262144 -}; -exports.FontFlags = FontFlags; -var MacStandardGlyphOrdering = [".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", "thorn", "minus", "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter", "threequarters", "franc", "Gbreve", "gbreve", "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", "ccaron", "dcroat"]; +const PDF_GLYPH_SPACE_UNITS = 1000; +const EXPORT_DATA_PROPERTIES = ["ascent", "bbox", "black", "bold", "charProcOperatorList", "composite", "cssFontInfo", "data", "defaultVMetrics", "defaultWidth", "descent", "fallbackName", "fontMatrix", "fontType", "isType3Font", "italic", "loadedName", "mimetype", "missingFile", "name", "remeasure", "subtype", "type", "vertical"]; +const EXPORT_DATA_EXTRA_PROPERTIES = ["cMap", "defaultEncoding", "differences", "isMonospace", "isSerifFont", "isSymbolicFont", "seacMap", "toFontChar", "toUnicode", "vmetrics", "widths"]; function adjustWidths(properties) { if (!properties.fontMatrix) { @@ -26266,10 +25053,10 @@ function adjustWidths(properties) { return; } - var scale = 0.001 / properties.fontMatrix[0]; - var glyphsWidths = properties.widths; + const scale = 0.001 / properties.fontMatrix[0]; + const glyphsWidths = properties.widths; - for (var glyph in glyphsWidths) { + for (const glyph in glyphsWidths) { glyphsWidths[glyph] *= scale; } @@ -26277,11 +25064,7 @@ function adjustWidths(properties) { } function adjustToUnicode(properties, builtInEncoding) { - if (properties.hasIncludedToUnicodeMap) { - return; - } - - if (properties.hasEncoding) { + if (properties.isInternalFont) { return; } @@ -26289,74 +25072,64 @@ function adjustToUnicode(properties, builtInEncoding) { return; } - if (properties.toUnicode instanceof IdentityToUnicodeMap) { + if (properties.toUnicode instanceof _to_unicode_map.IdentityToUnicodeMap) { return; } - var toUnicode = [], - glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + const toUnicode = [], + glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); - for (var charCode in builtInEncoding) { - var glyphName = builtInEncoding[charCode]; - var unicode = (0, _unicode.getUnicodeForGlyph)(glyphName, glyphsUnicodeMap); + for (const charCode in builtInEncoding) { + if (properties.hasIncludedToUnicodeMap) { + if (properties.toUnicode.has(charCode)) { + continue; + } + } else if (properties.hasEncoding) { + if (properties.differences.length === 0 || properties.differences[charCode] !== undefined) { + continue; + } + } + + const glyphName = builtInEncoding[charCode]; + const unicode = (0, _unicode.getUnicodeForGlyph)(glyphName, glyphsUnicodeMap); if (unicode !== -1) { toUnicode[charCode] = String.fromCharCode(unicode); } } - properties.toUnicode.amend(toUnicode); -} - -function getFontType(type, subtype) { - switch (type) { - case "Type1": - return subtype === "Type1C" ? _util.FontType.TYPE1C : _util.FontType.TYPE1; - - case "CIDFontType0": - return subtype === "CIDFontType0C" ? _util.FontType.CIDFONTTYPE0C : _util.FontType.CIDFONTTYPE0; - - case "OpenType": - return _util.FontType.OPENTYPE; - - case "TrueType": - return _util.FontType.TRUETYPE; - - case "CIDFontType2": - return _util.FontType.CIDFONTTYPE2; - - case "MMType1": - return _util.FontType.MMTYPE1; - - case "Type0": - return _util.FontType.TYPE0; - - default: - return _util.FontType.UNKNOWN; + if (toUnicode.length > 0) { + properties.toUnicode.amend(toUnicode); } } -function recoverGlyphName(name, glyphsUnicodeMap) { - if (glyphsUnicodeMap[name] !== undefined) { - return name; +function amendFallbackToUnicode(properties) { + if (!properties.fallbackToUnicode) { + return; } - var unicode = (0, _unicode.getUnicodeForGlyph)(name, glyphsUnicodeMap); + if (properties.toUnicode instanceof _to_unicode_map.IdentityToUnicodeMap) { + return; + } - if (unicode !== -1) { - for (var key in glyphsUnicodeMap) { - if (glyphsUnicodeMap[key] === unicode) { - return key; - } + const toUnicode = []; + + for (const charCode in properties.fallbackToUnicode) { + if (properties.toUnicode.has(charCode)) { + continue; } + + toUnicode[charCode] = properties.fallbackToUnicode[charCode]; } - (0, _util.info)("Unable to recover a standard glyph name for: " + name); - return name; + if (toUnicode.length > 0) { + properties.toUnicode.amend(toUnicode); + } } -var Glyph = function GlyphClosure() { - function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont) { +class Glyph { + constructor(originalCharCode, fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont) { + this.originalCharCode = originalCharCode; this.fontChar = fontChar; this.unicode = unicode; this.accent = accent; @@ -26365,248 +25138,578 @@ var Glyph = function GlyphClosure() { this.operatorListId = operatorListId; this.isSpace = isSpace; this.isInFont = isInFont; + const category = (0, _unicode.getCharUnicodeCategory)(unicode); + this.isWhitespace = category.isWhitespace; + this.isZeroWidthDiacritic = category.isZeroWidthDiacritic; + this.isInvisibleFormatMark = category.isInvisibleFormatMark; } - Glyph.prototype.matchesForCache = function (fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont) { - return this.fontChar === fontChar && this.unicode === unicode && this.accent === accent && this.width === width && this.vmetric === vmetric && this.operatorListId === operatorListId && this.isSpace === isSpace && this.isInFont === isInFont; + matchesForCache(originalCharCode, fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont) { + return this.originalCharCode === originalCharCode && this.fontChar === fontChar && this.unicode === unicode && this.accent === accent && this.width === width && this.vmetric === vmetric && this.operatorListId === operatorListId && this.isSpace === isSpace && this.isInFont === isInFont; + } + +} + +function int16(b0, b1) { + return (b0 << 8) + b1; +} + +function writeSignedInt16(bytes, index, value) { + bytes[index + 1] = value; + bytes[index] = value >>> 8; +} + +function signedInt16(b0, b1) { + const value = (b0 << 8) + b1; + return value & 1 << 15 ? value - 0x10000 : value; +} + +function int32(b0, b1, b2, b3) { + return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; +} + +function string16(value) { + return String.fromCharCode(value >> 8 & 0xff, value & 0xff); +} + +function safeString16(value) { + if (value > 0x7fff) { + value = 0x7fff; + } else if (value < -0x8000) { + value = -0x8000; + } + + return String.fromCharCode(value >> 8 & 0xff, value & 0xff); +} + +function isTrueTypeFile(file) { + const header = file.peekBytes(4); + return (0, _core_utils.readUint32)(header, 0) === 0x00010000 || (0, _util.bytesToString)(header) === "true"; +} + +function isTrueTypeCollectionFile(file) { + const header = file.peekBytes(4); + return (0, _util.bytesToString)(header) === "ttcf"; +} + +function isOpenTypeFile(file) { + const header = file.peekBytes(4); + return (0, _util.bytesToString)(header) === "OTTO"; +} + +function isType1File(file) { + const header = file.peekBytes(2); + + if (header[0] === 0x25 && header[1] === 0x21) { + return true; + } + + if (header[0] === 0x80 && header[1] === 0x01) { + return true; + } + + return false; +} + +function isCFFFile(file) { + const header = file.peekBytes(4); + + if (header[0] >= 1 && header[3] >= 1 && header[3] <= 4) { + return true; + } + + return false; +} + +function getFontFileType(file, { + type, + subtype, + composite +}) { + let fileType, fileSubtype; + + if (isTrueTypeFile(file) || isTrueTypeCollectionFile(file)) { + if (composite) { + fileType = "CIDFontType2"; + } else { + fileType = "TrueType"; + } + } else if (isOpenTypeFile(file)) { + if (composite) { + fileType = "CIDFontType2"; + } else { + fileType = "OpenType"; + } + } else if (isType1File(file)) { + if (composite) { + fileType = "CIDFontType0"; + } else { + fileType = type === "MMType1" ? "MMType1" : "Type1"; + } + } else if (isCFFFile(file)) { + if (composite) { + fileType = "CIDFontType0"; + fileSubtype = "CIDFontType0C"; + } else { + fileType = type === "MMType1" ? "MMType1" : "Type1"; + fileSubtype = "Type1C"; + } + } else { + (0, _util.warn)("getFontFileType: Unable to detect correct font file Type/Subtype."); + fileType = type; + fileSubtype = subtype; + } + + return [fileType, fileSubtype]; +} + +function applyStandardFontGlyphMap(map, glyphMap) { + for (const charCode in glyphMap) { + map[+charCode] = glyphMap[charCode]; + } +} + +function buildToFontChar(encoding, glyphsUnicodeMap, differences) { + const toFontChar = []; + let unicode; + + for (let i = 0, ii = encoding.length; i < ii; i++) { + unicode = (0, _unicode.getUnicodeForGlyph)(encoding[i], glyphsUnicodeMap); + + if (unicode !== -1) { + toFontChar[i] = unicode; + } + } + + for (const charCode in differences) { + unicode = (0, _unicode.getUnicodeForGlyph)(differences[charCode], glyphsUnicodeMap); + + if (unicode !== -1) { + toFontChar[+charCode] = unicode; + } + } + + return toFontChar; +} + +function convertCidString(charCode, cid, shouldThrow = false) { + switch (cid.length) { + case 1: + return cid.charCodeAt(0); + + case 2: + return cid.charCodeAt(0) << 8 | cid.charCodeAt(1); + } + + const msg = `Unsupported CID string (charCode ${charCode}): "${cid}".`; + + if (shouldThrow) { + throw new _util.FormatError(msg); + } + + (0, _util.warn)(msg); + return cid; +} + +function adjustMapping(charCodeToGlyphId, hasGlyph, newGlyphZeroId, toUnicode) { + const newMap = Object.create(null); + const toUnicodeExtraMap = new Map(); + const toFontChar = []; + const usedGlyphIds = new Set(); + let privateUseAreaIndex = 0; + const privateUseOffetStart = PRIVATE_USE_AREAS[privateUseAreaIndex][0]; + let nextAvailableFontCharCode = privateUseOffetStart; + let privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1]; + + for (let originalCharCode in charCodeToGlyphId) { + originalCharCode |= 0; + let glyphId = charCodeToGlyphId[originalCharCode]; + + if (!hasGlyph(glyphId)) { + continue; + } + + if (nextAvailableFontCharCode > privateUseOffetEnd) { + privateUseAreaIndex++; + + if (privateUseAreaIndex >= PRIVATE_USE_AREAS.length) { + (0, _util.warn)("Ran out of space in font private use area."); + break; + } + + nextAvailableFontCharCode = PRIVATE_USE_AREAS[privateUseAreaIndex][0]; + privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1]; + } + + const fontCharCode = nextAvailableFontCharCode++; + + if (glyphId === 0) { + glyphId = newGlyphZeroId; + } + + let unicode = toUnicode.get(originalCharCode); + + if (typeof unicode === "string") { + unicode = unicode.codePointAt(0); + } + + if (unicode && unicode < privateUseOffetStart && !usedGlyphIds.has(glyphId)) { + toUnicodeExtraMap.set(unicode, glyphId); + usedGlyphIds.add(glyphId); + } + + newMap[fontCharCode] = glyphId; + toFontChar[originalCharCode] = fontCharCode; + } + + return { + toFontChar, + charCodeToGlyphId: newMap, + toUnicodeExtraMap, + nextAvailableFontCharCode }; +} - return Glyph; -}(); +function getRanges(glyphs, toUnicodeExtraMap, numGlyphs) { + const codes = []; -var ToUnicodeMap = function ToUnicodeMapClosure() { - function ToUnicodeMap(cmap = []) { - this._map = cmap; + for (const charCode in glyphs) { + if (glyphs[charCode] >= numGlyphs) { + continue; + } + + codes.push({ + fontCharCode: charCode | 0, + glyphId: glyphs[charCode] + }); } - ToUnicodeMap.prototype = { - get length() { - return this._map.length; - }, - - forEach(callback) { - for (var charCode in this._map) { - callback(charCode, this._map[charCode].charCodeAt(0)); - } - }, - - has(i) { - return this._map[i] !== undefined; - }, - - get(i) { - return this._map[i]; - }, - - charCodeOf(value) { - const map = this._map; - - if (map.length <= 0x10000) { - return map.indexOf(value); + if (toUnicodeExtraMap) { + for (const [unicode, glyphId] of toUnicodeExtraMap) { + if (glyphId >= numGlyphs) { + continue; } - for (const charCode in map) { - if (map[charCode] === value) { - return charCode | 0; - } - } + codes.push({ + fontCharCode: unicode, + glyphId + }); + } + } - return -1; - }, + if (codes.length === 0) { + codes.push({ + fontCharCode: 0, + glyphId: 0 + }); + } - amend(map) { - for (var charCode in map) { - this._map[charCode] = map[charCode]; + codes.sort(function fontGetRangesSort(a, b) { + return a.fontCharCode - b.fontCharCode; + }); + const ranges = []; + const length = codes.length; + + for (let n = 0; n < length;) { + const start = codes[n].fontCharCode; + const codeIndices = [codes[n].glyphId]; + ++n; + let end = start; + + while (n < length && end + 1 === codes[n].fontCharCode) { + codeIndices.push(codes[n].glyphId); + ++end; + ++n; + + if (end === 0xffff) { + break; } } - }; - return ToUnicodeMap; -}(); - -exports.ToUnicodeMap = ToUnicodeMap; - -var IdentityToUnicodeMap = function IdentityToUnicodeMapClosure() { - function IdentityToUnicodeMap(firstChar, lastChar) { - this.firstChar = firstChar; - this.lastChar = lastChar; + ranges.push([start, end, codeIndices]); } - IdentityToUnicodeMap.prototype = { - get length() { - return this.lastChar + 1 - this.firstChar; - }, + return ranges; +} - forEach(callback) { - for (var i = this.firstChar, ii = this.lastChar; i <= ii; i++) { - callback(i, i); +function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) { + const ranges = getRanges(glyphs, toUnicodeExtraMap, numGlyphs); + const numTables = ranges.at(-1)[1] > 0xffff ? 2 : 1; + let cmap = "\x00\x00" + string16(numTables) + "\x00\x03" + "\x00\x01" + (0, _util.string32)(4 + numTables * 8); + let i, ii, j, jj; + + for (i = ranges.length - 1; i >= 0; --i) { + if (ranges[i][0] <= 0xffff) { + break; + } + } + + const bmpLength = i + 1; + + if (ranges[i][0] < 0xffff && ranges[i][1] === 0xffff) { + ranges[i][1] = 0xfffe; + } + + const trailingRangesCount = ranges[i][1] < 0xffff ? 1 : 0; + const segCount = bmpLength + trailingRangesCount; + + const searchParams = _opentype_file_builder.OpenTypeFileBuilder.getSearchParams(segCount, 2); + + let startCount = ""; + let endCount = ""; + let idDeltas = ""; + let idRangeOffsets = ""; + let glyphsIds = ""; + let bias = 0; + let range, start, end, codes; + + for (i = 0, ii = bmpLength; i < ii; i++) { + range = ranges[i]; + start = range[0]; + end = range[1]; + startCount += string16(start); + endCount += string16(end); + codes = range[2]; + let contiguous = true; + + for (j = 1, jj = codes.length; j < jj; ++j) { + if (codes[j] !== codes[j - 1] + 1) { + contiguous = false; + break; } - }, - - has(i) { - return this.firstChar <= i && i <= this.lastChar; - }, - - get(i) { - if (this.firstChar <= i && i <= this.lastChar) { - return String.fromCharCode(i); - } - - return undefined; - }, - - charCodeOf(v) { - return Number.isInteger(v) && v >= this.firstChar && v <= this.lastChar ? v : -1; - }, - - amend(map) { - (0, _util.unreachable)("Should not call amend()"); } - }; - return IdentityToUnicodeMap; -}(); + if (!contiguous) { + const offset = (segCount - i) * 2 + bias * 2; + bias += end - start + 1; + idDeltas += string16(0); + idRangeOffsets += string16(offset); -exports.IdentityToUnicodeMap = IdentityToUnicodeMap; - -var OpenTypeFileBuilder = function OpenTypeFileBuilderClosure() { - function writeInt16(dest, offset, num) { - dest[offset] = num >> 8 & 0xff; - dest[offset + 1] = num & 0xff; - } - - function writeInt32(dest, offset, num) { - dest[offset] = num >> 24 & 0xff; - dest[offset + 1] = num >> 16 & 0xff; - dest[offset + 2] = num >> 8 & 0xff; - dest[offset + 3] = num & 0xff; - } - - function writeData(dest, offset, data) { - var i, ii; - - if (data instanceof Uint8Array) { - dest.set(data, offset); - } else if (typeof data === "string") { - for (i = 0, ii = data.length; i < ii; i++) { - dest[offset++] = data.charCodeAt(i) & 0xff; + for (j = 0, jj = codes.length; j < jj; ++j) { + glyphsIds += string16(codes[j]); } } else { - for (i = 0, ii = data.length; i < ii; i++) { - dest[offset++] = data[i] & 0xff; - } + const startCode = codes[0]; + idDeltas += string16(startCode - start & 0xffff); + idRangeOffsets += string16(0); } } - function OpenTypeFileBuilder(sfnt) { - this.sfnt = sfnt; - this.tables = Object.create(null); + if (trailingRangesCount > 0) { + endCount += "\xFF\xFF"; + startCount += "\xFF\xFF"; + idDeltas += "\x00\x01"; + idRangeOffsets += "\x00\x00"; } - OpenTypeFileBuilder.getSearchParams = function OpenTypeFileBuilder_getSearchParams(entriesCount, entrySize) { - var maxPower2 = 1, - log2 = 0; + const format314 = "\x00\x00" + string16(2 * segCount) + string16(searchParams.range) + string16(searchParams.entry) + string16(searchParams.rangeShift) + endCount + "\x00\x00" + startCount + idDeltas + idRangeOffsets + glyphsIds; + let format31012 = ""; + let header31012 = ""; - while ((maxPower2 ^ entriesCount) > maxPower2) { - maxPower2 <<= 1; - log2++; - } + if (numTables > 1) { + cmap += "\x00\x03" + "\x00\x0A" + (0, _util.string32)(4 + numTables * 8 + 4 + format314.length); + format31012 = ""; - var searchRange = maxPower2 * entrySize; - return { - range: searchRange, - entry: log2, - rangeShift: entrySize * entriesCount - searchRange - }; - }; + for (i = 0, ii = ranges.length; i < ii; i++) { + range = ranges[i]; + start = range[0]; + codes = range[2]; + let code = codes[0]; - var OTF_HEADER_SIZE = 12; - var OTF_TABLE_ENTRY_SIZE = 16; - OpenTypeFileBuilder.prototype = { - toArray: function OpenTypeFileBuilder_toArray() { - var sfnt = this.sfnt; - var tables = this.tables; - var tablesNames = Object.keys(tables); - tablesNames.sort(); - var numTables = tablesNames.length; - var i, j, jj, table, tableName; - var offset = OTF_HEADER_SIZE + numTables * OTF_TABLE_ENTRY_SIZE; - var tableOffsets = [offset]; - - for (i = 0; i < numTables; i++) { - table = tables[tablesNames[i]]; - var paddedLength = (table.length + 3 & ~3) >>> 0; - offset += paddedLength; - tableOffsets.push(offset); - } - - var file = new Uint8Array(offset); - - for (i = 0; i < numTables; i++) { - table = tables[tablesNames[i]]; - writeData(file, tableOffsets[i], table); - } - - if (sfnt === "true") { - sfnt = (0, _util.string32)(0x00010000); - } - - file[0] = sfnt.charCodeAt(0) & 0xff; - file[1] = sfnt.charCodeAt(1) & 0xff; - file[2] = sfnt.charCodeAt(2) & 0xff; - file[3] = sfnt.charCodeAt(3) & 0xff; - writeInt16(file, 4, numTables); - var searchParams = OpenTypeFileBuilder.getSearchParams(numTables, 16); - writeInt16(file, 6, searchParams.range); - writeInt16(file, 8, searchParams.entry); - writeInt16(file, 10, searchParams.rangeShift); - offset = OTF_HEADER_SIZE; - - for (i = 0; i < numTables; i++) { - tableName = tablesNames[i]; - file[offset] = tableName.charCodeAt(0) & 0xff; - file[offset + 1] = tableName.charCodeAt(1) & 0xff; - file[offset + 2] = tableName.charCodeAt(2) & 0xff; - file[offset + 3] = tableName.charCodeAt(3) & 0xff; - var checksum = 0; - - for (j = tableOffsets[i], jj = tableOffsets[i + 1]; j < jj; j += 4) { - var quad = (0, _core_utils.readUint32)(file, j); - checksum = checksum + quad >>> 0; + for (j = 1, jj = codes.length; j < jj; ++j) { + if (codes[j] !== codes[j - 1] + 1) { + end = range[0] + j - 1; + format31012 += (0, _util.string32)(start) + (0, _util.string32)(end) + (0, _util.string32)(code); + start = end + 1; + code = codes[j]; } - - writeInt32(file, offset + 4, checksum); - writeInt32(file, offset + 8, tableOffsets[i]); - writeInt32(file, offset + 12, tables[tableName].length); - offset += OTF_TABLE_ENTRY_SIZE; } - return file; - }, - addTable: function OpenTypeFileBuilder_addTable(tag, data) { - if (tag in this.tables) { - throw new Error("Table " + tag + " already exists"); - } - - this.tables[tag] = data; + format31012 += (0, _util.string32)(start) + (0, _util.string32)(range[1]) + (0, _util.string32)(code); } - }; - return OpenTypeFileBuilder; -}(); -var Font = function FontClosure() { - function Font(name, file, properties) { - var charCode; + header31012 = "\x00\x0C" + "\x00\x00" + (0, _util.string32)(format31012.length + 16) + "\x00\x00\x00\x00" + (0, _util.string32)(format31012.length / 12); + } + + return cmap + "\x00\x04" + string16(format314.length + 4) + format314 + header31012 + format31012; +} + +function validateOS2Table(os2, file) { + file.pos = (file.start || 0) + os2.offset; + const version = file.getUint16(); + file.skip(60); + const selection = file.getUint16(); + + if (version < 4 && selection & 0x0300) { + return false; + } + + const firstChar = file.getUint16(); + const lastChar = file.getUint16(); + + if (firstChar > lastChar) { + return false; + } + + file.skip(6); + const usWinAscent = file.getUint16(); + + if (usWinAscent === 0) { + return false; + } + + os2.data[8] = os2.data[9] = 0; + return true; +} + +function createOS2Table(properties, charstrings, override) { + override = override || { + unitsPerEm: 0, + yMax: 0, + yMin: 0, + ascent: 0, + descent: 0 + }; + let ulUnicodeRange1 = 0; + let ulUnicodeRange2 = 0; + let ulUnicodeRange3 = 0; + let ulUnicodeRange4 = 0; + let firstCharIndex = null; + let lastCharIndex = 0; + + if (charstrings) { + for (let code in charstrings) { + code |= 0; + + if (firstCharIndex > code || !firstCharIndex) { + firstCharIndex = code; + } + + if (lastCharIndex < code) { + lastCharIndex = code; + } + + const position = (0, _unicode.getUnicodeRangeFor)(code); + + if (position < 32) { + ulUnicodeRange1 |= 1 << position; + } else if (position < 64) { + ulUnicodeRange2 |= 1 << position - 32; + } else if (position < 96) { + ulUnicodeRange3 |= 1 << position - 64; + } else if (position < 123) { + ulUnicodeRange4 |= 1 << position - 96; + } else { + throw new _util.FormatError("Unicode ranges Bits > 123 are reserved for internal usage"); + } + } + + if (lastCharIndex > 0xffff) { + lastCharIndex = 0xffff; + } + } else { + firstCharIndex = 0; + lastCharIndex = 255; + } + + const bbox = properties.bbox || [0, 0, 0, 0]; + const unitsPerEm = override.unitsPerEm || 1 / (properties.fontMatrix || _util.FONT_IDENTITY_MATRIX)[0]; + const scale = properties.ascentScaled ? 1.0 : unitsPerEm / PDF_GLYPH_SPACE_UNITS; + const typoAscent = override.ascent || Math.round(scale * (properties.ascent || bbox[3])); + let typoDescent = override.descent || Math.round(scale * (properties.descent || bbox[1])); + + if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) { + typoDescent = -typoDescent; + } + + const winAscent = override.yMax || typoAscent; + const winDescent = -override.yMin || -typoDescent; + return "\x00\x03" + "\x02\x24" + "\x01\xF4" + "\x00\x05" + "\x00\x00" + "\x02\x8A" + "\x02\xBB" + "\x00\x00" + "\x00\x8C" + "\x02\x8A" + "\x02\xBB" + "\x00\x00" + "\x01\xDF" + "\x00\x31" + "\x01\x02" + "\x00\x00" + "\x00\x00\x06" + String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) + "\x00\x00\x00\x00\x00\x00" + (0, _util.string32)(ulUnicodeRange1) + (0, _util.string32)(ulUnicodeRange2) + (0, _util.string32)(ulUnicodeRange3) + (0, _util.string32)(ulUnicodeRange4) + "\x2A\x32\x31\x2A" + string16(properties.italicAngle ? 1 : 0) + string16(firstCharIndex || properties.firstChar) + string16(lastCharIndex || properties.lastChar) + string16(typoAscent) + string16(typoDescent) + "\x00\x64" + string16(winAscent) + string16(winDescent) + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + string16(properties.xHeight) + string16(properties.capHeight) + string16(0) + string16(firstCharIndex || properties.firstChar) + "\x00\x03"; +} + +function createPostTable(properties) { + const angle = Math.floor(properties.italicAngle * 2 ** 16); + return "\x00\x03\x00\x00" + (0, _util.string32)(angle) + "\x00\x00" + "\x00\x00" + (0, _util.string32)(properties.fixedPitch ? 1 : 0) + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00"; +} + +function createPostscriptName(name) { + return name.replace(/[^\x21-\x7E]|[[\](){}<>/%]/g, "").slice(0, 63); +} + +function createNameTable(name, proto) { + if (!proto) { + proto = [[], []]; + } + + const strings = [proto[0][0] || "Original licence", proto[0][1] || name, proto[0][2] || "Unknown", proto[0][3] || "uniqueID", proto[0][4] || name, proto[0][5] || "Version 0.11", proto[0][6] || createPostscriptName(name), proto[0][7] || "Unknown", proto[0][8] || "Unknown", proto[0][9] || "Unknown"]; + const stringsUnicode = []; + let i, ii, j, jj, str; + + for (i = 0, ii = strings.length; i < ii; i++) { + str = proto[1][i] || strings[i]; + const strBufUnicode = []; + + for (j = 0, jj = str.length; j < jj; j++) { + strBufUnicode.push(string16(str.charCodeAt(j))); + } + + stringsUnicode.push(strBufUnicode.join("")); + } + + const names = [strings, stringsUnicode]; + const platforms = ["\x00\x01", "\x00\x03"]; + const encodings = ["\x00\x00", "\x00\x01"]; + const languages = ["\x00\x00", "\x04\x09"]; + const namesRecordCount = strings.length * platforms.length; + let nameTable = "\x00\x00" + string16(namesRecordCount) + string16(namesRecordCount * 12 + 6); + let strOffset = 0; + + for (i = 0, ii = platforms.length; i < ii; i++) { + const strs = names[i]; + + for (j = 0, jj = strs.length; j < jj; j++) { + str = strs[j]; + const nameRecord = platforms[i] + encodings[i] + languages[i] + string16(j) + string16(str.length) + string16(strOffset); + nameTable += nameRecord; + strOffset += str.length; + } + } + + nameTable += strings.join("") + stringsUnicode.join(""); + return nameTable; +} + +class Font { + constructor(name, file, properties) { this.name = name; + this.psName = null; + this.mimetype = null; + this.disableFontFace = false; this.loadedName = properties.loadedName; this.isType3Font = properties.isType3Font; this.missingFile = false; - this.glyphCache = Object.create(null); - this.isSerifFont = !!(properties.flags & FontFlags.Serif); - this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic); - this.isMonospace = !!(properties.flags & FontFlags.FixedPitch); - var type = properties.type; - var subtype = properties.subtype; + this.cssFontInfo = properties.cssFontInfo; + this._charsCache = Object.create(null); + this._glyphCache = Object.create(null); + let isSerifFont = !!(properties.flags & _fonts_utils.FontFlags.Serif); + + if (!isSerifFont && !properties.isSimulatedFlags) { + const baseName = name.replace(/[,_]/g, "-").split("-")[0], + serifFonts = (0, _standard_fonts.getSerifFonts)(); + + for (const namePart of baseName.split("+")) { + if (serifFonts[namePart]) { + isSerifFont = true; + break; + } + } + } + + this.isSerifFont = isSerifFont; + this.isSymbolicFont = !!(properties.flags & _fonts_utils.FontFlags.Symbolic); + this.isMonospace = !!(properties.flags & _fonts_utils.FontFlags.FixedPitch); + let type = properties.type; + let subtype = properties.subtype; this.type = type; this.subtype = subtype; let fallbackName = "sans-serif"; @@ -26623,17 +25726,18 @@ var Font = function FontClosure() { this.defaultWidth = properties.defaultWidth; this.composite = properties.composite; this.cMap = properties.cMap; + this.capHeight = properties.capHeight / PDF_GLYPH_SPACE_UNITS; this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS; this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS; + this.lineHeight = this.ascent - this.descent; this.fontMatrix = properties.fontMatrix; this.bbox = properties.bbox; this.defaultEncoding = properties.defaultEncoding; this.toUnicode = properties.toUnicode; - this.fallbackToUnicode = properties.fallbackToUnicode || new ToUnicodeMap(); this.toFontChar = []; if (properties.type === "Type3") { - for (charCode = 0; charCode < 256; charCode++) { + for (let charCode = 0; charCode < 256; charCode++) { this.toFontChar[charCode] = this.differences[charCode] || properties.defaultEncoding[charCode]; } @@ -26641,7 +25745,7 @@ var Font = function FontClosure() { return; } - this.cidEncoding = properties.cidEncoding; + this.cidEncoding = properties.cidEncoding || ""; this.vertical = !!properties.vertical; if (this.vertical) { @@ -26654,7 +25758,7 @@ var Font = function FontClosure() { (0, _util.warn)('Font file is empty in "' + name + '" (' + this.loadedName + ")"); } - this.fallbackToSystemFont(); + this.fallbackToSystemFont(properties); return; } @@ -26664,9 +25768,9 @@ var Font = function FontClosure() { (0, _util.info)("Inconsistent font file Type/SubType, expected: " + `${this.type}/${this.subtype} but found: ${type}/${subtype}.`); } - try { - var data; + let data; + try { switch (type) { case "MMType1": (0, _util.info)("MMType1 font (" + name + "), falling back to Type1."); @@ -26674,7 +25778,7 @@ var Font = function FontClosure() { case "Type1": case "CIDFontType0": this.mimetype = "font/opentype"; - var cff = subtype === "Type1C" || subtype === "CIDFontType0C" ? new CFFFont(file, properties) : new Type1Font(name, file, properties); + const cff = subtype === "Type1C" || subtype === "CIDFontType0C" ? new _cff_font.CFFFont(file, properties) : new _type1_font.Type1Font(name, file, properties); adjustWidths(properties); data = this.convert(name, cff, properties); break; @@ -26697,12 +25801,13 @@ var Font = function FontClosure() { } } catch (e) { (0, _util.warn)(e); - this.fallbackToSystemFont(); + this.fallbackToSystemFont(properties); return; } + amendFallbackToUnicode(properties); this.data = data; - this.fontType = getFontType(type, subtype); + this.fontType = (0, _fonts_utils.getFontType)(type, subtype, properties.isStandardFont); this.fontMatrix = properties.fontMatrix; this.widths = properties.widths; this.defaultWidth = properties.defaultWidth; @@ -26710,716 +25815,291 @@ var Font = function FontClosure() { this.seacMap = properties.seacMap; } - function int16(b0, b1) { - return (b0 << 8) + b1; + get renderer() { + const renderer = _font_renderer.FontRendererFactory.create(this, _fonts_utils.SEAC_ANALYSIS_ENABLED); + + return (0, _util.shadow)(this, "renderer", renderer); } - function writeSignedInt16(bytes, index, value) { - bytes[index + 1] = value; - bytes[index] = value >>> 8; - } + exportData(extraProperties = false) { + const exportDataProperties = extraProperties ? [...EXPORT_DATA_PROPERTIES, ...EXPORT_DATA_EXTRA_PROPERTIES] : EXPORT_DATA_PROPERTIES; + const data = Object.create(null); + let property, value; - function signedInt16(b0, b1) { - var value = (b0 << 8) + b1; - return value & 1 << 15 ? value - 0x10000 : value; - } + for (property of exportDataProperties) { + value = this[property]; - function int32(b0, b1, b2, b3) { - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - } - - function string16(value) { - return String.fromCharCode(value >> 8 & 0xff, value & 0xff); - } - - function safeString16(value) { - if (value > 0x7fff) { - value = 0x7fff; - } else if (value < -0x8000) { - value = -0x8000; - } - - return String.fromCharCode(value >> 8 & 0xff, value & 0xff); - } - - function isTrueTypeFile(file) { - var header = file.peekBytes(4); - return (0, _core_utils.readUint32)(header, 0) === 0x00010000 || (0, _util.bytesToString)(header) === "true"; - } - - function isTrueTypeCollectionFile(file) { - const header = file.peekBytes(4); - return (0, _util.bytesToString)(header) === "ttcf"; - } - - function isOpenTypeFile(file) { - var header = file.peekBytes(4); - return (0, _util.bytesToString)(header) === "OTTO"; - } - - function isType1File(file) { - var header = file.peekBytes(2); - - if (header[0] === 0x25 && header[1] === 0x21) { - return true; - } - - if (header[0] === 0x80 && header[1] === 0x01) { - return true; - } - - return false; - } - - function isCFFFile(file) { - const header = file.peekBytes(4); - - if (header[0] >= 1 && header[3] >= 1 && header[3] <= 4) { - return true; - } - - return false; - } - - function getFontFileType(file, { - type, - subtype, - composite - }) { - let fileType, fileSubtype; - - if (isTrueTypeFile(file) || isTrueTypeCollectionFile(file)) { - if (composite) { - fileType = "CIDFontType2"; - } else { - fileType = "TrueType"; - } - } else if (isOpenTypeFile(file)) { - if (composite) { - fileType = "CIDFontType2"; - } else { - fileType = "OpenType"; - } - } else if (isType1File(file)) { - if (composite) { - fileType = "CIDFontType0"; - } else { - fileType = type === "MMType1" ? "MMType1" : "Type1"; - } - } else if (isCFFFile(file)) { - if (composite) { - fileType = "CIDFontType0"; - fileSubtype = "CIDFontType0C"; - } else { - fileType = type === "MMType1" ? "MMType1" : "Type1"; - fileSubtype = "Type1C"; - } - } else { - (0, _util.warn)("getFontFileType: Unable to detect correct font file Type/Subtype."); - fileType = type; - fileSubtype = subtype; - } - - return [fileType, fileSubtype]; - } - - function buildToFontChar(encoding, glyphsUnicodeMap, differences) { - var toFontChar = [], - unicode; - - for (var i = 0, ii = encoding.length; i < ii; i++) { - unicode = (0, _unicode.getUnicodeForGlyph)(encoding[i], glyphsUnicodeMap); - - if (unicode !== -1) { - toFontChar[i] = unicode; + if (value !== undefined) { + data[property] = value; } } - for (var charCode in differences) { - unicode = (0, _unicode.getUnicodeForGlyph)(differences[charCode], glyphsUnicodeMap); - - if (unicode !== -1) { - toFontChar[+charCode] = unicode; - } - } - - return toFontChar; + return data; } - function adjustMapping(charCodeToGlyphId, hasGlyph, newGlyphZeroId) { - var newMap = Object.create(null); - var toFontChar = []; - var privateUseAreaIndex = 0; - var nextAvailableFontCharCode = PRIVATE_USE_AREAS[privateUseAreaIndex][0]; - var privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1]; - - for (var originalCharCode in charCodeToGlyphId) { - originalCharCode |= 0; - var glyphId = charCodeToGlyphId[originalCharCode]; - - if (!hasGlyph(glyphId)) { - continue; - } - - if (nextAvailableFontCharCode > privateUseOffetEnd) { - privateUseAreaIndex++; - - if (privateUseAreaIndex >= PRIVATE_USE_AREAS.length) { - (0, _util.warn)("Ran out of space in font private use area."); - break; - } - - nextAvailableFontCharCode = PRIVATE_USE_AREAS[privateUseAreaIndex][0]; - privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1]; - } - - var fontCharCode = nextAvailableFontCharCode++; - - if (glyphId === 0) { - glyphId = newGlyphZeroId; - } - - newMap[fontCharCode] = glyphId; - toFontChar[originalCharCode] = fontCharCode; - } - - return { - toFontChar, - charCodeToGlyphId: newMap, - nextAvailableFontCharCode - }; - } - - function getRanges(glyphs, numGlyphs) { - var codes = []; - - for (var charCode in glyphs) { - if (glyphs[charCode] >= numGlyphs) { - continue; - } - - codes.push({ - fontCharCode: charCode | 0, - glyphId: glyphs[charCode] - }); - } - - if (codes.length === 0) { - codes.push({ - fontCharCode: 0, - glyphId: 0 - }); - } - - codes.sort(function fontGetRangesSort(a, b) { - return a.fontCharCode - b.fontCharCode; - }); - var ranges = []; - var length = codes.length; - - for (var n = 0; n < length;) { - var start = codes[n].fontCharCode; - var codeIndices = [codes[n].glyphId]; - ++n; - var end = start; - - while (n < length && end + 1 === codes[n].fontCharCode) { - codeIndices.push(codes[n].glyphId); - ++end; - ++n; - - if (end === 0xffff) { - break; - } - } - - ranges.push([start, end, codeIndices]); - } - - return ranges; - } - - function createCmapTable(glyphs, numGlyphs) { - var ranges = getRanges(glyphs, numGlyphs); - var numTables = ranges[ranges.length - 1][1] > 0xffff ? 2 : 1; - var cmap = "\x00\x00" + string16(numTables) + "\x00\x03" + "\x00\x01" + (0, _util.string32)(4 + numTables * 8); - var i, ii, j, jj; - - for (i = ranges.length - 1; i >= 0; --i) { - if (ranges[i][0] <= 0xffff) { - break; - } - } - - var bmpLength = i + 1; - - if (ranges[i][0] < 0xffff && ranges[i][1] === 0xffff) { - ranges[i][1] = 0xfffe; - } - - var trailingRangesCount = ranges[i][1] < 0xffff ? 1 : 0; - var segCount = bmpLength + trailingRangesCount; - var searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2); - var startCount = ""; - var endCount = ""; - var idDeltas = ""; - var idRangeOffsets = ""; - var glyphsIds = ""; - var bias = 0; - var range, start, end, codes; - - for (i = 0, ii = bmpLength; i < ii; i++) { - range = ranges[i]; - start = range[0]; - end = range[1]; - startCount += string16(start); - endCount += string16(end); - codes = range[2]; - var contiguous = true; - - for (j = 1, jj = codes.length; j < jj; ++j) { - if (codes[j] !== codes[j - 1] + 1) { - contiguous = false; - break; - } - } - - if (!contiguous) { - var offset = (segCount - i) * 2 + bias * 2; - bias += end - start + 1; - idDeltas += string16(0); - idRangeOffsets += string16(offset); - - for (j = 0, jj = codes.length; j < jj; ++j) { - glyphsIds += string16(codes[j]); - } - } else { - var startCode = codes[0]; - idDeltas += string16(startCode - start & 0xffff); - idRangeOffsets += string16(0); - } - } - - if (trailingRangesCount > 0) { - endCount += "\xFF\xFF"; - startCount += "\xFF\xFF"; - idDeltas += "\x00\x01"; - idRangeOffsets += "\x00\x00"; - } - - var format314 = "\x00\x00" + string16(2 * segCount) + string16(searchParams.range) + string16(searchParams.entry) + string16(searchParams.rangeShift) + endCount + "\x00\x00" + startCount + idDeltas + idRangeOffsets + glyphsIds; - var format31012 = ""; - var header31012 = ""; - - if (numTables > 1) { - cmap += "\x00\x03" + "\x00\x0A" + (0, _util.string32)(4 + numTables * 8 + 4 + format314.length); - format31012 = ""; - - for (i = 0, ii = ranges.length; i < ii; i++) { - range = ranges[i]; - start = range[0]; - codes = range[2]; - var code = codes[0]; - - for (j = 1, jj = codes.length; j < jj; ++j) { - if (codes[j] !== codes[j - 1] + 1) { - end = range[0] + j - 1; - format31012 += (0, _util.string32)(start) + (0, _util.string32)(end) + (0, _util.string32)(code); - start = end + 1; - code = codes[j]; - } - } - - format31012 += (0, _util.string32)(start) + (0, _util.string32)(range[1]) + (0, _util.string32)(code); - } - - header31012 = "\x00\x0C" + "\x00\x00" + (0, _util.string32)(format31012.length + 16) + "\x00\x00\x00\x00" + (0, _util.string32)(format31012.length / 12); - } - - return cmap + "\x00\x04" + string16(format314.length + 4) + format314 + header31012 + format31012; - } - - function validateOS2Table(os2, file) { - file.pos = (file.start || 0) + os2.offset; - var version = file.getUint16(); - file.skip(60); - var selection = file.getUint16(); - - if (version < 4 && selection & 0x0300) { - return false; - } - - var firstChar = file.getUint16(); - var lastChar = file.getUint16(); - - if (firstChar > lastChar) { - return false; - } - - file.skip(6); - var usWinAscent = file.getUint16(); - - if (usWinAscent === 0) { - return false; - } - - os2.data[8] = os2.data[9] = 0; - return true; - } - - function createOS2Table(properties, charstrings, override) { - override = override || { - unitsPerEm: 0, - yMax: 0, - yMin: 0, - ascent: 0, - descent: 0 - }; - var ulUnicodeRange1 = 0; - var ulUnicodeRange2 = 0; - var ulUnicodeRange3 = 0; - var ulUnicodeRange4 = 0; - var firstCharIndex = null; - var lastCharIndex = 0; - - if (charstrings) { - for (var code in charstrings) { - code |= 0; - - if (firstCharIndex > code || !firstCharIndex) { - firstCharIndex = code; - } - - if (lastCharIndex < code) { - lastCharIndex = code; - } - - var position = (0, _unicode.getUnicodeRangeFor)(code); - - if (position < 32) { - ulUnicodeRange1 |= 1 << position; - } else if (position < 64) { - ulUnicodeRange2 |= 1 << position - 32; - } else if (position < 96) { - ulUnicodeRange3 |= 1 << position - 64; - } else if (position < 123) { - ulUnicodeRange4 |= 1 << position - 96; - } else { - throw new _util.FormatError("Unicode ranges Bits > 123 are reserved for internal usage"); - } - } - - if (lastCharIndex > 0xffff) { - lastCharIndex = 0xffff; - } - } else { - firstCharIndex = 0; - lastCharIndex = 255; - } - - var bbox = properties.bbox || [0, 0, 0, 0]; - var unitsPerEm = override.unitsPerEm || 1 / (properties.fontMatrix || _util.FONT_IDENTITY_MATRIX)[0]; - var scale = properties.ascentScaled ? 1.0 : unitsPerEm / PDF_GLYPH_SPACE_UNITS; - var typoAscent = override.ascent || Math.round(scale * (properties.ascent || bbox[3])); - var typoDescent = override.descent || Math.round(scale * (properties.descent || bbox[1])); - - if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) { - typoDescent = -typoDescent; - } - - var winAscent = override.yMax || typoAscent; - var winDescent = -override.yMin || -typoDescent; - return "\x00\x03" + "\x02\x24" + "\x01\xF4" + "\x00\x05" + "\x00\x00" + "\x02\x8A" + "\x02\xBB" + "\x00\x00" + "\x00\x8C" + "\x02\x8A" + "\x02\xBB" + "\x00\x00" + "\x01\xDF" + "\x00\x31" + "\x01\x02" + "\x00\x00" + "\x00\x00\x06" + String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) + "\x00\x00\x00\x00\x00\x00" + (0, _util.string32)(ulUnicodeRange1) + (0, _util.string32)(ulUnicodeRange2) + (0, _util.string32)(ulUnicodeRange3) + (0, _util.string32)(ulUnicodeRange4) + "\x2A\x32\x31\x2A" + string16(properties.italicAngle ? 1 : 0) + string16(firstCharIndex || properties.firstChar) + string16(lastCharIndex || properties.lastChar) + string16(typoAscent) + string16(typoDescent) + "\x00\x64" + string16(winAscent) + string16(winDescent) + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + string16(properties.xHeight) + string16(properties.capHeight) + string16(0) + string16(firstCharIndex || properties.firstChar) + "\x00\x03"; - } - - function createPostTable(properties) { - var angle = Math.floor(properties.italicAngle * 2 ** 16); - return "\x00\x03\x00\x00" + (0, _util.string32)(angle) + "\x00\x00" + "\x00\x00" + (0, _util.string32)(properties.fixedPitch) + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00"; - } - - function createNameTable(name, proto) { - if (!proto) { - proto = [[], []]; - } - - var strings = [proto[0][0] || "Original licence", proto[0][1] || name, proto[0][2] || "Unknown", proto[0][3] || "uniqueID", proto[0][4] || name, proto[0][5] || "Version 0.11", proto[0][6] || "", proto[0][7] || "Unknown", proto[0][8] || "Unknown", proto[0][9] || "Unknown"]; - var stringsUnicode = []; - var i, ii, j, jj, str; - - for (i = 0, ii = strings.length; i < ii; i++) { - str = proto[1][i] || strings[i]; - var strBufUnicode = []; - - for (j = 0, jj = str.length; j < jj; j++) { - strBufUnicode.push(string16(str.charCodeAt(j))); - } - - stringsUnicode.push(strBufUnicode.join("")); - } - - var names = [strings, stringsUnicode]; - var platforms = ["\x00\x01", "\x00\x03"]; - var encodings = ["\x00\x00", "\x00\x01"]; - var languages = ["\x00\x00", "\x04\x09"]; - var namesRecordCount = strings.length * platforms.length; - var nameTable = "\x00\x00" + string16(namesRecordCount) + string16(namesRecordCount * 12 + 6); - var strOffset = 0; - - for (i = 0, ii = platforms.length; i < ii; i++) { - var strs = names[i]; - - for (j = 0, jj = strs.length; j < jj; j++) { - str = strs[j]; - var nameRecord = platforms[i] + encodings[i] + languages[i] + string16(j) + string16(str.length) + string16(strOffset); - nameTable += nameRecord; - strOffset += str.length; - } - } - - nameTable += strings.join("") + stringsUnicode.join(""); - return nameTable; - } - - Font.prototype = { - name: null, - font: null, - mimetype: null, - disableFontFace: false, - - get renderer() { - var renderer = _font_renderer.FontRendererFactory.create(this, SEAC_ANALYSIS_ENABLED); - - return (0, _util.shadow)(this, "renderer", renderer); - }, - - exportData(extraProperties = false) { - const exportDataProperties = extraProperties ? [...EXPORT_DATA_PROPERTIES, ...EXPORT_DATA_EXTRA_PROPERTIES] : EXPORT_DATA_PROPERTIES; - const data = Object.create(null); - let property, value; - - for (property of exportDataProperties) { - value = this[property]; - - if (value !== undefined) { - data[property] = value; - } - } - - return data; - }, - - fallbackToSystemFont: function Font_fallbackToSystemFont() { - this.missingFile = true; - var name = this.name; - var type = this.type; - var subtype = this.subtype; - let fontName = name.replace(/[,_]/g, "-").replace(/\s/g, ""); - var stdFontMap = (0, _standard_fonts.getStdFontMap)(), + fallbackToSystemFont(properties) { + this.missingFile = true; + const name = this.name; + const type = this.type; + const subtype = this.subtype; + let fontName = (0, _fonts_utils.normalizeFontName)(name); + const stdFontMap = (0, _standard_fonts.getStdFontMap)(), nonStdFontMap = (0, _standard_fonts.getNonStdFontMap)(); - var isStandardFont = !!stdFontMap[fontName] || !!(nonStdFontMap[fontName] && stdFontMap[nonStdFontMap[fontName]]); - fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName; - this.bold = fontName.search(/bold/gi) !== -1; - this.italic = fontName.search(/oblique/gi) !== -1 || fontName.search(/italic/gi) !== -1; - this.black = name.search(/Black/g) !== -1; - this.remeasure = Object.keys(this.widths).length > 0; + const isStandardFont = !!stdFontMap[fontName]; + const isMappedToStandardFont = !!(nonStdFontMap[fontName] && stdFontMap[nonStdFontMap[fontName]]); + fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName; + const fontBasicMetricsMap = (0, _metrics.getFontBasicMetrics)(); + const metrics = fontBasicMetricsMap[fontName]; - if (isStandardFont && type === "CIDFontType2" && this.cidEncoding.startsWith("Identity-")) { - const GlyphMapForStandardFonts = (0, _standard_fonts.getGlyphMapForStandardFonts)(); - const map = []; + if (metrics) { + if (isNaN(this.ascent)) { + this.ascent = metrics.ascent / PDF_GLYPH_SPACE_UNITS; + } - for (const charCode in GlyphMapForStandardFonts) { - map[+charCode] = GlyphMapForStandardFonts[charCode]; - } + if (isNaN(this.descent)) { + this.descent = metrics.descent / PDF_GLYPH_SPACE_UNITS; + } - if (/Arial-?Black/i.test(name)) { - var SupplementalGlyphMapForArialBlack = (0, _standard_fonts.getSupplementalGlyphMapForArialBlack)(); + if (isNaN(this.capHeight)) { + this.capHeight = metrics.capHeight / PDF_GLYPH_SPACE_UNITS; + } + } - for (const charCode in SupplementalGlyphMapForArialBlack) { - map[+charCode] = SupplementalGlyphMapForArialBlack[charCode]; - } - } else if (/Calibri/i.test(name)) { - const SupplementalGlyphMapForCalibri = (0, _standard_fonts.getSupplementalGlyphMapForCalibri)(); + this.bold = fontName.search(/bold/gi) !== -1; + this.italic = fontName.search(/oblique/gi) !== -1 || fontName.search(/italic/gi) !== -1; + this.black = name.search(/Black/g) !== -1; + const isNarrow = name.search(/Narrow/g) !== -1; + this.remeasure = (!isStandardFont || isNarrow) && Object.keys(this.widths).length > 0; - for (const charCode in SupplementalGlyphMapForCalibri) { - map[+charCode] = SupplementalGlyphMapForCalibri[charCode]; + if ((isStandardFont || isMappedToStandardFont) && type === "CIDFontType2" && this.cidEncoding.startsWith("Identity-")) { + const cidToGidMap = properties.cidToGidMap; + const map = []; + applyStandardFontGlyphMap(map, (0, _standard_fonts.getGlyphMapForStandardFonts)()); + + if (/Arial-?Black/i.test(name)) { + applyStandardFontGlyphMap(map, (0, _standard_fonts.getSupplementalGlyphMapForArialBlack)()); + } else if (/Calibri/i.test(name)) { + applyStandardFontGlyphMap(map, (0, _standard_fonts.getSupplementalGlyphMapForCalibri)()); + } + + if (cidToGidMap) { + for (const charCode in map) { + const cid = map[charCode]; + + if (cidToGidMap[cid] !== undefined) { + map[+charCode] = cidToGidMap[cid]; } } - var isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap; - - if (!isIdentityUnicode) { + if (cidToGidMap.length !== this.toUnicode.length && properties.hasIncludedToUnicodeMap && this.toUnicode instanceof _to_unicode_map.IdentityToUnicodeMap) { this.toUnicode.forEach(function (charCode, unicodeCharCode) { - map[+charCode] = unicodeCharCode; + const cid = map[charCode]; + + if (cidToGidMap[cid] === undefined) { + map[+charCode] = unicodeCharCode; + } }); } + } - this.toFontChar = map; - this.toUnicode = new ToUnicodeMap(map); - } else if (/Symbol/i.test(fontName)) { - this.toFontChar = buildToFontChar(_encodings.SymbolSetEncoding, (0, _glyphlist.getGlyphsUnicode)(), this.differences); - } else if (/Dingbats/i.test(fontName)) { - if (/Wingdings/i.test(name)) { - (0, _util.warn)("Non-embedded Wingdings font, falling back to ZapfDingbats."); - } - - this.toFontChar = buildToFontChar(_encodings.ZapfDingbatsEncoding, (0, _glyphlist.getDingbatsGlyphsUnicode)(), this.differences); - } else if (isStandardFont) { - this.toFontChar = buildToFontChar(this.defaultEncoding, (0, _glyphlist.getGlyphsUnicode)(), this.differences); - } else { - const glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); - const map = []; - this.toUnicode.forEach((charCode, unicodeCharCode) => { - if (!this.composite) { - var glyphName = this.differences[charCode] || this.defaultEncoding[charCode]; - const unicode = (0, _unicode.getUnicodeForGlyph)(glyphName, glyphsUnicodeMap); - - if (unicode !== -1) { - unicodeCharCode = unicode; - } - } - + if (!(this.toUnicode instanceof _to_unicode_map.IdentityToUnicodeMap)) { + this.toUnicode.forEach(function (charCode, unicodeCharCode) { map[+charCode] = unicodeCharCode; }); + } - if (this.composite && this.toUnicode instanceof IdentityToUnicodeMap) { - if (/Verdana/i.test(name)) { - const GlyphMapForStandardFonts = (0, _standard_fonts.getGlyphMapForStandardFonts)(); + this.toFontChar = map; + this.toUnicode = new _to_unicode_map.ToUnicodeMap(map); + } else if (/Symbol/i.test(fontName)) { + this.toFontChar = buildToFontChar(_encodings.SymbolSetEncoding, (0, _glyphlist.getGlyphsUnicode)(), this.differences); + } else if (/Dingbats/i.test(fontName)) { + if (/Wingdings/i.test(name)) { + (0, _util.warn)("Non-embedded Wingdings font, falling back to ZapfDingbats."); + } - for (const charCode in GlyphMapForStandardFonts) { - map[+charCode] = GlyphMapForStandardFonts[charCode]; + this.toFontChar = buildToFontChar(_encodings.ZapfDingbatsEncoding, (0, _glyphlist.getDingbatsGlyphsUnicode)(), this.differences); + } else if (isStandardFont) { + const map = buildToFontChar(this.defaultEncoding, (0, _glyphlist.getGlyphsUnicode)(), this.differences); + + if (type === "CIDFontType2" && !this.cidEncoding.startsWith("Identity-") && !(this.toUnicode instanceof _to_unicode_map.IdentityToUnicodeMap)) { + this.toUnicode.forEach(function (charCode, unicodeCharCode) { + map[+charCode] = unicodeCharCode; + }); + } + + this.toFontChar = map; + } else { + const glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + const map = []; + this.toUnicode.forEach((charCode, unicodeCharCode) => { + if (!this.composite) { + const glyphName = this.differences[charCode] || this.defaultEncoding[charCode]; + const unicode = (0, _unicode.getUnicodeForGlyph)(glyphName, glyphsUnicodeMap); + + if (unicode !== -1) { + unicodeCharCode = unicode; + } + } + + map[+charCode] = unicodeCharCode; + }); + + if (this.composite && this.toUnicode instanceof _to_unicode_map.IdentityToUnicodeMap) { + if (/Verdana/i.test(name)) { + applyStandardFontGlyphMap(map, (0, _standard_fonts.getGlyphMapForStandardFonts)()); + } + } + + this.toFontChar = map; + } + + amendFallbackToUnicode(properties); + this.loadedName = fontName.split("-")[0]; + this.fontType = (0, _fonts_utils.getFontType)(type, subtype, properties.isStandardFont); + } + + checkAndRepair(name, font, properties) { + const VALID_TABLES = ["OS/2", "cmap", "head", "hhea", "hmtx", "maxp", "name", "post", "loca", "glyf", "fpgm", "prep", "cvt ", "CFF "]; + + function readTables(file, numTables) { + const tables = Object.create(null); + tables["OS/2"] = null; + tables.cmap = null; + tables.head = null; + tables.hhea = null; + tables.hmtx = null; + tables.maxp = null; + tables.name = null; + tables.post = null; + + for (let i = 0; i < numTables; i++) { + const table = readTableEntry(file); + + if (!VALID_TABLES.includes(table.tag)) { + continue; + } + + if (table.length === 0) { + continue; + } + + tables[table.tag] = table; + } + + return tables; + } + + function readTableEntry(file) { + const tag = file.getString(4); + const checksum = file.getInt32() >>> 0; + const offset = file.getInt32() >>> 0; + const length = file.getInt32() >>> 0; + const previousPosition = file.pos; + file.pos = file.start || 0; + file.skip(offset); + const data = file.getBytes(length); + file.pos = previousPosition; + + if (tag === "head") { + data[8] = data[9] = data[10] = data[11] = 0; + data[17] |= 0x20; + } + + return { + tag, + checksum, + length, + offset, + data + }; + } + + function readOpenTypeHeader(ttf) { + return { + version: ttf.getString(4), + numTables: ttf.getUint16(), + searchRange: ttf.getUint16(), + entrySelector: ttf.getUint16(), + rangeShift: ttf.getUint16() + }; + } + + function readTrueTypeCollectionHeader(ttc) { + const ttcTag = ttc.getString(4); + (0, _util.assert)(ttcTag === "ttcf", "Must be a TrueType Collection font."); + const majorVersion = ttc.getUint16(); + const minorVersion = ttc.getUint16(); + const numFonts = ttc.getInt32() >>> 0; + const offsetTable = []; + + for (let i = 0; i < numFonts; i++) { + offsetTable.push(ttc.getInt32() >>> 0); + } + + const header = { + ttcTag, + majorVersion, + minorVersion, + numFonts, + offsetTable + }; + + switch (majorVersion) { + case 1: + return header; + + case 2: + header.dsigTag = ttc.getInt32() >>> 0; + header.dsigLength = ttc.getInt32() >>> 0; + header.dsigOffset = ttc.getInt32() >>> 0; + return header; + } + + throw new _util.FormatError(`Invalid TrueType Collection majorVersion: ${majorVersion}.`); + } + + function readTrueTypeCollectionData(ttc, fontName) { + const { + numFonts, + offsetTable + } = readTrueTypeCollectionHeader(ttc); + const fontNameParts = fontName.split("+"); + let fallbackData; + + for (let i = 0; i < numFonts; i++) { + ttc.pos = (ttc.start || 0) + offsetTable[i]; + const potentialHeader = readOpenTypeHeader(ttc); + const potentialTables = readTables(ttc, potentialHeader.numTables); + + if (!potentialTables.name) { + throw new _util.FormatError('TrueType Collection font must contain a "name" table.'); + } + + const nameTable = readNameTable(potentialTables.name); + + for (let j = 0, jj = nameTable.length; j < jj; j++) { + for (let k = 0, kk = nameTable[j].length; k < kk; k++) { + const nameEntry = nameTable[j][k] && nameTable[j][k].replace(/\s/g, ""); + + if (!nameEntry) { + continue; } - } - } - this.toFontChar = map; - } + if (nameEntry === fontName) { + return { + header: potentialHeader, + tables: potentialTables + }; + } - this.loadedName = fontName.split("-")[0]; - this.fontType = getFontType(type, subtype); - }, - checkAndRepair: function Font_checkAndRepair(name, font, properties) { - const VALID_TABLES = ["OS/2", "cmap", "head", "hhea", "hmtx", "maxp", "name", "post", "loca", "glyf", "fpgm", "prep", "cvt ", "CFF "]; + if (fontNameParts.length < 2) { + continue; + } - function readTables(file, numTables) { - const tables = Object.create(null); - tables["OS/2"] = null; - tables.cmap = null; - tables.head = null; - tables.hhea = null; - tables.hmtx = null; - tables.maxp = null; - tables.name = null; - tables.post = null; - - for (let i = 0; i < numTables; i++) { - const table = readTableEntry(file); - - if (!VALID_TABLES.includes(table.tag)) { - continue; - } - - if (table.length === 0) { - continue; - } - - tables[table.tag] = table; - } - - return tables; - } - - function readTableEntry(file) { - var tag = (0, _util.bytesToString)(file.getBytes(4)); - var checksum = file.getInt32() >>> 0; - var offset = file.getInt32() >>> 0; - var length = file.getInt32() >>> 0; - var previousPosition = file.pos; - file.pos = file.start ? file.start : 0; - file.skip(offset); - var data = file.getBytes(length); - file.pos = previousPosition; - - if (tag === "head") { - data[8] = data[9] = data[10] = data[11] = 0; - data[17] |= 0x20; - } - - return { - tag, - checksum, - length, - offset, - data - }; - } - - function readOpenTypeHeader(ttf) { - return { - version: (0, _util.bytesToString)(ttf.getBytes(4)), - numTables: ttf.getUint16(), - searchRange: ttf.getUint16(), - entrySelector: ttf.getUint16(), - rangeShift: ttf.getUint16() - }; - } - - function readTrueTypeCollectionHeader(ttc) { - const ttcTag = (0, _util.bytesToString)(ttc.getBytes(4)); - (0, _util.assert)(ttcTag === "ttcf", "Must be a TrueType Collection font."); - const majorVersion = ttc.getUint16(); - const minorVersion = ttc.getUint16(); - const numFonts = ttc.getInt32() >>> 0; - const offsetTable = []; - - for (let i = 0; i < numFonts; i++) { - offsetTable.push(ttc.getInt32() >>> 0); - } - - const header = { - ttcTag, - majorVersion, - minorVersion, - numFonts, - offsetTable - }; - - switch (majorVersion) { - case 1: - return header; - - case 2: - header.dsigTag = ttc.getInt32() >>> 0; - header.dsigLength = ttc.getInt32() >>> 0; - header.dsigOffset = ttc.getInt32() >>> 0; - return header; - } - - throw new _util.FormatError(`Invalid TrueType Collection majorVersion: ${majorVersion}.`); - } - - function readTrueTypeCollectionData(ttc, fontName) { - const { - numFonts, - offsetTable - } = readTrueTypeCollectionHeader(ttc); - - for (let i = 0; i < numFonts; i++) { - ttc.pos = (ttc.start || 0) + offsetTable[i]; - const potentialHeader = readOpenTypeHeader(ttc); - const potentialTables = readTables(ttc, potentialHeader.numTables); - - if (!potentialTables.name) { - throw new _util.FormatError('TrueType Collection font must contain a "name" table.'); - } - - const nameTable = readNameTable(potentialTables.name); - - for (let j = 0, jj = nameTable.length; j < jj; j++) { - for (let k = 0, kk = nameTable[j].length; k < kk; k++) { - const nameEntry = nameTable[j][k]; - - if (nameEntry && nameEntry.replace(/\s/g, "") === fontName) { - return { + for (const part of fontNameParts) { + if (nameEntry === part) { + fallbackData = { + name: part, header: potentialHeader, tables: potentialTables }; @@ -27427,1206 +26107,1403 @@ var Font = function FontClosure() { } } } - - throw new _util.FormatError(`TrueType Collection does not contain "${fontName}" font.`); } - function readCmapTable(cmap, file, isSymbolicFont, hasEncoding) { - if (!cmap) { - (0, _util.warn)("No cmap table available."); - return { - platformId: -1, - encodingId: -1, - mappings: [], - hasShortCmap: false + if (fallbackData) { + (0, _util.warn)(`TrueType Collection does not contain "${fontName}" font, ` + `falling back to "${fallbackData.name}" font instead.`); + return { + header: fallbackData.header, + tables: fallbackData.tables + }; + } + + throw new _util.FormatError(`TrueType Collection does not contain "${fontName}" font.`); + } + + function readCmapTable(cmap, file, isSymbolicFont, hasEncoding) { + if (!cmap) { + (0, _util.warn)("No cmap table available."); + return { + platformId: -1, + encodingId: -1, + mappings: [], + hasShortCmap: false + }; + } + + let segment; + let start = (file.start || 0) + cmap.offset; + file.pos = start; + file.skip(2); + const numTables = file.getUint16(); + let potentialTable; + let canBreak = false; + + for (let i = 0; i < numTables; i++) { + const platformId = file.getUint16(); + const encodingId = file.getUint16(); + const offset = file.getInt32() >>> 0; + let useTable = false; + + if (potentialTable && potentialTable.platformId === platformId && potentialTable.encodingId === encodingId) { + continue; + } + + if (platformId === 0 && (encodingId === 0 || encodingId === 1 || encodingId === 3)) { + useTable = true; + } else if (platformId === 1 && encodingId === 0) { + useTable = true; + } else if (platformId === 3 && encodingId === 1 && (hasEncoding || !potentialTable)) { + useTable = true; + + if (!isSymbolicFont) { + canBreak = true; + } + } else if (isSymbolicFont && platformId === 3 && encodingId === 0) { + useTable = true; + let correctlySorted = true; + + if (i < numTables - 1) { + const nextBytes = file.peekBytes(2), + nextPlatformId = int16(nextBytes[0], nextBytes[1]); + + if (nextPlatformId < platformId) { + correctlySorted = false; + } + } + + if (correctlySorted) { + canBreak = true; + } + } + + if (useTable) { + potentialTable = { + platformId, + encodingId, + offset }; } - var segment; - var start = (file.start ? file.start : 0) + cmap.offset; - file.pos = start; - file.skip(2); - var numTables = file.getUint16(); - var potentialTable; - var canBreak = false; + if (canBreak) { + break; + } + } - for (var i = 0; i < numTables; i++) { - var platformId = file.getUint16(); - var encodingId = file.getUint16(); - var offset = file.getInt32() >>> 0; - var useTable = false; + if (potentialTable) { + file.pos = start + potentialTable.offset; + } - if (potentialTable && potentialTable.platformId === platformId && potentialTable.encodingId === encodingId) { + if (!potentialTable || file.peekByte() === -1) { + (0, _util.warn)("Could not find a preferred cmap table."); + return { + platformId: -1, + encodingId: -1, + mappings: [], + hasShortCmap: false + }; + } + + const format = file.getUint16(); + let hasShortCmap = false; + const mappings = []; + let j, glyphId; + + if (format === 0) { + file.skip(2 + 2); + + for (j = 0; j < 256; j++) { + const index = file.getByte(); + + if (!index) { continue; } - if (platformId === 0 && (encodingId === 0 || encodingId === 1 || encodingId === 3)) { - useTable = true; - } else if (platformId === 1 && encodingId === 0) { - useTable = true; - } else if (platformId === 3 && encodingId === 1 && (hasEncoding || !potentialTable)) { - useTable = true; - - if (!isSymbolicFont) { - canBreak = true; - } - } else if (isSymbolicFont && platformId === 3 && encodingId === 0) { - useTable = true; - canBreak = true; - } - - if (useTable) { - potentialTable = { - platformId, - encodingId, - offset - }; - } - - if (canBreak) { - break; - } + mappings.push({ + charCode: j, + glyphId: index + }); } - if (potentialTable) { - file.pos = start + potentialTable.offset; - } - - if (!potentialTable || file.peekByte() === -1) { - (0, _util.warn)("Could not find a preferred cmap table."); - return { - platformId: -1, - encodingId: -1, - mappings: [], - hasShortCmap: false - }; - } - - var format = file.getUint16(); + hasShortCmap = true; + } else if (format === 2) { file.skip(2 + 2); - var hasShortCmap = false; - var mappings = []; - var j, glyphId; + const subHeaderKeys = []; + let maxSubHeaderKey = 0; - if (format === 0) { - for (j = 0; j < 256; j++) { - var index = file.getByte(); + for (let i = 0; i < 256; i++) { + const subHeaderKey = file.getUint16() >> 3; + subHeaderKeys.push(subHeaderKey); + maxSubHeaderKey = Math.max(subHeaderKey, maxSubHeaderKey); + } - if (!index) { - continue; - } + const subHeaders = []; + for (let i = 0; i <= maxSubHeaderKey; i++) { + subHeaders.push({ + firstCode: file.getUint16(), + entryCount: file.getUint16(), + idDelta: signedInt16(file.getByte(), file.getByte()), + idRangePos: file.pos + file.getUint16() + }); + } + + for (let i = 0; i < 256; i++) { + if (subHeaderKeys[i] === 0) { + file.pos = subHeaders[0].idRangePos + 2 * i; + glyphId = file.getUint16(); mappings.push({ - charCode: j, - glyphId: index + charCode: i, + glyphId }); - } + } else { + const s = subHeaders[subHeaderKeys[i]]; - hasShortCmap = true; - } else if (format === 4) { - var segCount = file.getUint16() >> 1; - file.skip(6); - var segIndex, - segments = []; + for (j = 0; j < s.entryCount; j++) { + const charCode = (i << 8) + j + s.firstCode; + file.pos = s.idRangePos + 2 * j; + glyphId = file.getUint16(); - for (segIndex = 0; segIndex < segCount; segIndex++) { - segments.push({ - end: file.getUint16() - }); - } - - file.skip(2); - - for (segIndex = 0; segIndex < segCount; segIndex++) { - segments[segIndex].start = file.getUint16(); - } - - for (segIndex = 0; segIndex < segCount; segIndex++) { - segments[segIndex].delta = file.getUint16(); - } - - var offsetsCount = 0; - - for (segIndex = 0; segIndex < segCount; segIndex++) { - segment = segments[segIndex]; - var rangeOffset = file.getUint16(); - - if (!rangeOffset) { - segment.offsetIndex = -1; - continue; - } - - var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex); - segment.offsetIndex = offsetIndex; - offsetsCount = Math.max(offsetsCount, offsetIndex + segment.end - segment.start + 1); - } - - var offsets = []; - - for (j = 0; j < offsetsCount; j++) { - offsets.push(file.getUint16()); - } - - for (segIndex = 0; segIndex < segCount; segIndex++) { - segment = segments[segIndex]; - start = segment.start; - var end = segment.end; - var delta = segment.delta; - offsetIndex = segment.offsetIndex; - - for (j = start; j <= end; j++) { - if (j === 0xffff) { - continue; + if (glyphId !== 0) { + glyphId = (glyphId + s.idDelta) % 65536; } - glyphId = offsetIndex < 0 ? j : offsets[offsetIndex + j - start]; - glyphId = glyphId + delta & 0xffff; mappings.push({ - charCode: j, + charCode, glyphId }); } } - } else if (format === 6) { - var firstCode = file.getUint16(); - var entryCount = file.getUint16(); + } + } else if (format === 4) { + file.skip(2 + 2); + const segCount = file.getUint16() >> 1; + file.skip(6); + const segments = []; + let segIndex; - for (j = 0; j < entryCount; j++) { - glyphId = file.getUint16(); - var charCode = firstCode + j; + for (segIndex = 0; segIndex < segCount; segIndex++) { + segments.push({ + end: file.getUint16() + }); + } + + file.skip(2); + + for (segIndex = 0; segIndex < segCount; segIndex++) { + segments[segIndex].start = file.getUint16(); + } + + for (segIndex = 0; segIndex < segCount; segIndex++) { + segments[segIndex].delta = file.getUint16(); + } + + let offsetsCount = 0, + offsetIndex; + + for (segIndex = 0; segIndex < segCount; segIndex++) { + segment = segments[segIndex]; + const rangeOffset = file.getUint16(); + + if (!rangeOffset) { + segment.offsetIndex = -1; + continue; + } + + offsetIndex = (rangeOffset >> 1) - (segCount - segIndex); + segment.offsetIndex = offsetIndex; + offsetsCount = Math.max(offsetsCount, offsetIndex + segment.end - segment.start + 1); + } + + const offsets = []; + + for (j = 0; j < offsetsCount; j++) { + offsets.push(file.getUint16()); + } + + for (segIndex = 0; segIndex < segCount; segIndex++) { + segment = segments[segIndex]; + start = segment.start; + const end = segment.end; + const delta = segment.delta; + offsetIndex = segment.offsetIndex; + + for (j = start; j <= end; j++) { + if (j === 0xffff) { + continue; + } + + glyphId = offsetIndex < 0 ? j : offsets[offsetIndex + j - start]; + glyphId = glyphId + delta & 0xffff; mappings.push({ - charCode, + charCode: j, glyphId }); } - } else { - (0, _util.warn)("cmap table has unsupported format: " + format); - return { - platformId: -1, - encodingId: -1, - mappings: [], - hasShortCmap: false - }; } + } else if (format === 6) { + file.skip(2 + 2); + const firstCode = file.getUint16(); + const entryCount = file.getUint16(); - mappings.sort(function (a, b) { - return a.charCode - b.charCode; - }); + for (j = 0; j < entryCount; j++) { + glyphId = file.getUint16(); + const charCode = firstCode + j; + mappings.push({ + charCode, + glyphId + }); + } + } else if (format === 12) { + file.skip(2 + 4 + 4); + const nGroups = file.getInt32() >>> 0; - for (i = 1; i < mappings.length; i++) { - if (mappings[i - 1].charCode === mappings[i].charCode) { - mappings.splice(i, 1); - i--; + for (j = 0; j < nGroups; j++) { + const startCharCode = file.getInt32() >>> 0; + const endCharCode = file.getInt32() >>> 0; + let glyphCode = file.getInt32() >>> 0; + + for (let charCode = startCharCode; charCode <= endCharCode; charCode++) { + mappings.push({ + charCode, + glyphId: glyphCode++ + }); } } - + } else { + (0, _util.warn)("cmap table has unsupported format: " + format); return { - platformId: potentialTable.platformId, - encodingId: potentialTable.encodingId, - mappings, - hasShortCmap + platformId: -1, + encodingId: -1, + mappings: [], + hasShortCmap: false }; } - function sanitizeMetrics(file, header, metrics, numGlyphs, dupFirstEntry) { - if (!header) { - if (metrics) { - metrics.data = null; - } + mappings.sort(function (a, b) { + return a.charCode - b.charCode; + }); - return; - } - - file.pos = (file.start ? file.start : 0) + header.offset; - file.pos += 4; - file.pos += 2; - file.pos += 2; - file.pos += 2; - file.pos += 2; - file.pos += 2; - file.pos += 2; - file.pos += 2; - file.pos += 2; - file.pos += 2; - file.pos += 2; - file.pos += 8; - file.pos += 2; - var numOfMetrics = file.getUint16(); - - if (numOfMetrics > numGlyphs) { - (0, _util.info)("The numOfMetrics (" + numOfMetrics + ") should not be " + "greater than the numGlyphs (" + numGlyphs + ")"); - numOfMetrics = numGlyphs; - header.data[34] = (numOfMetrics & 0xff00) >> 8; - header.data[35] = numOfMetrics & 0x00ff; - } - - var numOfSidebearings = numGlyphs - numOfMetrics; - var numMissing = numOfSidebearings - (metrics.length - numOfMetrics * 4 >> 1); - - if (numMissing > 0) { - var entries = new Uint8Array(metrics.length + numMissing * 2); - entries.set(metrics.data); - - if (dupFirstEntry) { - entries[metrics.length] = metrics.data[2]; - entries[metrics.length + 1] = metrics.data[3]; - } - - metrics.data = entries; + for (let i = 1; i < mappings.length; i++) { + if (mappings[i - 1].charCode === mappings[i].charCode) { + mappings.splice(i, 1); + i--; } } - function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart, hintsValid) { - var glyphProfile = { - length: 0, - sizeOfInstructions: 0 - }; + return { + platformId: potentialTable.platformId, + encodingId: potentialTable.encodingId, + mappings, + hasShortCmap + }; + } - if (sourceEnd - sourceStart <= 12) { - return glyphProfile; + function sanitizeMetrics(file, header, metrics, headTable, numGlyphs, dupFirstEntry) { + if (!header) { + if (metrics) { + metrics.data = null; } - var glyf = source.subarray(sourceStart, sourceEnd); - var contoursCount = signedInt16(glyf[0], glyf[1]); + return; + } - if (contoursCount < 0) { - contoursCount = -1; - writeSignedInt16(glyf, 0, contoursCount); - dest.set(glyf, destStart); - glyphProfile.length = glyf.length; - return glyphProfile; + file.pos = (file.start || 0) + header.offset; + file.pos += 4; + file.pos += 2; + file.pos += 2; + file.pos += 2; + file.pos += 2; + file.pos += 2; + file.pos += 2; + file.pos += 2; + file.pos += 2; + file.pos += 2; + const caretOffset = file.getUint16(); + file.pos += 8; + file.pos += 2; + let numOfMetrics = file.getUint16(); + + if (caretOffset !== 0) { + const macStyle = int16(headTable.data[44], headTable.data[45]); + + if (!(macStyle & 2)) { + header.data[22] = 0; + header.data[23] = 0; + } + } + + if (numOfMetrics > numGlyphs) { + (0, _util.info)(`The numOfMetrics (${numOfMetrics}) should not be ` + `greater than the numGlyphs (${numGlyphs}).`); + numOfMetrics = numGlyphs; + header.data[34] = (numOfMetrics & 0xff00) >> 8; + header.data[35] = numOfMetrics & 0x00ff; + } + + const numOfSidebearings = numGlyphs - numOfMetrics; + const numMissing = numOfSidebearings - (metrics.length - numOfMetrics * 4 >> 1); + + if (numMissing > 0) { + const entries = new Uint8Array(metrics.length + numMissing * 2); + entries.set(metrics.data); + + if (dupFirstEntry) { + entries[metrics.length] = metrics.data[2]; + entries[metrics.length + 1] = metrics.data[3]; } - var i, - j = 10, - flagsCount = 0; + metrics.data = entries; + } + } - for (i = 0; i < contoursCount; i++) { - var endPoint = glyf[j] << 8 | glyf[j + 1]; - flagsCount = endPoint + 1; - j += 2; - } + function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart, hintsValid) { + const glyphProfile = { + length: 0, + sizeOfInstructions: 0 + }; - var instructionsStart = j; - var instructionsLength = glyf[j] << 8 | glyf[j + 1]; - glyphProfile.sizeOfInstructions = instructionsLength; - j += 2 + instructionsLength; - var instructionsEnd = j; - var coordinatesLength = 0; + if (sourceEnd - sourceStart <= 12) { + return glyphProfile; + } - for (i = 0; i < flagsCount; i++) { - var flag = glyf[j++]; - - if (flag & 0xc0) { - glyf[j - 1] = flag & 0x3f; - } - - let xLength = 2; - - if (flag & 2) { - xLength = 1; - } else if (flag & 16) { - xLength = 0; - } - - let yLength = 2; - - if (flag & 4) { - yLength = 1; - } else if (flag & 32) { - yLength = 0; - } - - const xyLength = xLength + yLength; - coordinatesLength += xyLength; - - if (flag & 8) { - var repeat = glyf[j++]; - i += repeat; - coordinatesLength += repeat * xyLength; - } - } - - if (coordinatesLength === 0) { - return glyphProfile; - } - - var glyphDataLength = j + coordinatesLength; - - if (glyphDataLength > glyf.length) { - return glyphProfile; - } - - if (!hintsValid && instructionsLength > 0) { - dest.set(glyf.subarray(0, instructionsStart), destStart); - dest.set([0, 0], destStart + instructionsStart); - dest.set(glyf.subarray(instructionsEnd, glyphDataLength), destStart + instructionsStart + 2); - glyphDataLength -= instructionsLength; - - if (glyf.length - glyphDataLength > 3) { - glyphDataLength = glyphDataLength + 3 & ~3; - } - - glyphProfile.length = glyphDataLength; - return glyphProfile; - } - - if (glyf.length - glyphDataLength > 3) { - glyphDataLength = glyphDataLength + 3 & ~3; - dest.set(glyf.subarray(0, glyphDataLength), destStart); - glyphProfile.length = glyphDataLength; - return glyphProfile; - } + const glyf = source.subarray(sourceStart, sourceEnd); + let contoursCount = signedInt16(glyf[0], glyf[1]); + if (contoursCount < 0) { + contoursCount = -1; + writeSignedInt16(glyf, 0, contoursCount); dest.set(glyf, destStart); glyphProfile.length = glyf.length; return glyphProfile; } - function sanitizeHead(head, numGlyphs, locaLength) { - var data = head.data; - var version = int32(data[0], data[1], data[2], data[3]); + let i, + j = 10, + flagsCount = 0; - if (version >> 16 !== 1) { - (0, _util.info)("Attempting to fix invalid version in head table: " + version); - data[0] = 0; - data[1] = 1; - data[2] = 0; - data[3] = 0; + for (i = 0; i < contoursCount; i++) { + const endPoint = glyf[j] << 8 | glyf[j + 1]; + flagsCount = endPoint + 1; + j += 2; + } + + const instructionsStart = j; + const instructionsLength = glyf[j] << 8 | glyf[j + 1]; + glyphProfile.sizeOfInstructions = instructionsLength; + j += 2 + instructionsLength; + const instructionsEnd = j; + let coordinatesLength = 0; + + for (i = 0; i < flagsCount; i++) { + const flag = glyf[j++]; + + if (flag & 0xc0) { + glyf[j - 1] = flag & 0x3f; } - var indexToLocFormat = int16(data[50], data[51]); + let xLength = 2; - if (indexToLocFormat < 0 || indexToLocFormat > 1) { - (0, _util.info)("Attempting to fix invalid indexToLocFormat in head table: " + indexToLocFormat); - var numGlyphsPlusOne = numGlyphs + 1; + if (flag & 2) { + xLength = 1; + } else if (flag & 16) { + xLength = 0; + } - if (locaLength === numGlyphsPlusOne << 1) { - data[50] = 0; - data[51] = 0; - } else if (locaLength === numGlyphsPlusOne << 2) { - data[50] = 0; - data[51] = 1; - } else { - throw new _util.FormatError("Could not fix indexToLocFormat: " + indexToLocFormat); - } + let yLength = 2; + + if (flag & 4) { + yLength = 1; + } else if (flag & 32) { + yLength = 0; + } + + const xyLength = xLength + yLength; + coordinatesLength += xyLength; + + if (flag & 8) { + const repeat = glyf[j++]; + i += repeat; + coordinatesLength += repeat * xyLength; } } - function sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry, maxSizeOfInstructions) { - var itemSize, itemDecode, itemEncode; + if (coordinatesLength === 0) { + return glyphProfile; + } - if (isGlyphLocationsLong) { - itemSize = 4; + let glyphDataLength = j + coordinatesLength; - itemDecode = function fontItemDecodeLong(data, offset) { - return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; - }; + if (glyphDataLength > glyf.length) { + return glyphProfile; + } - itemEncode = function fontItemEncodeLong(data, offset, value) { - data[offset] = value >>> 24 & 0xff; - data[offset + 1] = value >> 16 & 0xff; - data[offset + 2] = value >> 8 & 0xff; - data[offset + 3] = value & 0xff; - }; + if (!hintsValid && instructionsLength > 0) { + dest.set(glyf.subarray(0, instructionsStart), destStart); + dest.set([0, 0], destStart + instructionsStart); + dest.set(glyf.subarray(instructionsEnd, glyphDataLength), destStart + instructionsStart + 2); + glyphDataLength -= instructionsLength; + + if (glyf.length - glyphDataLength > 3) { + glyphDataLength = glyphDataLength + 3 & ~3; + } + + glyphProfile.length = glyphDataLength; + return glyphProfile; + } + + if (glyf.length - glyphDataLength > 3) { + glyphDataLength = glyphDataLength + 3 & ~3; + dest.set(glyf.subarray(0, glyphDataLength), destStart); + glyphProfile.length = glyphDataLength; + return glyphProfile; + } + + dest.set(glyf, destStart); + glyphProfile.length = glyf.length; + return glyphProfile; + } + + function sanitizeHead(head, numGlyphs, locaLength) { + const data = head.data; + const version = int32(data[0], data[1], data[2], data[3]); + + if (version >> 16 !== 1) { + (0, _util.info)("Attempting to fix invalid version in head table: " + version); + data[0] = 0; + data[1] = 1; + data[2] = 0; + data[3] = 0; + } + + const indexToLocFormat = int16(data[50], data[51]); + + if (indexToLocFormat < 0 || indexToLocFormat > 1) { + (0, _util.info)("Attempting to fix invalid indexToLocFormat in head table: " + indexToLocFormat); + const numGlyphsPlusOne = numGlyphs + 1; + + if (locaLength === numGlyphsPlusOne << 1) { + data[50] = 0; + data[51] = 0; + } else if (locaLength === numGlyphsPlusOne << 2) { + data[50] = 0; + data[51] = 1; } else { - itemSize = 2; - - itemDecode = function fontItemDecode(data, offset) { - return data[offset] << 9 | data[offset + 1] << 1; - }; - - itemEncode = function fontItemEncode(data, offset, value) { - data[offset] = value >> 9 & 0xff; - data[offset + 1] = value >> 1 & 0xff; - }; + throw new _util.FormatError("Could not fix indexToLocFormat: " + indexToLocFormat); } + } + } - var numGlyphsOut = dupFirstEntry ? numGlyphs + 1 : numGlyphs; - var locaDataSize = itemSize * (1 + numGlyphsOut); - var locaData = new Uint8Array(locaDataSize); - locaData.set(loca.data.subarray(0, locaDataSize)); - loca.data = locaData; - var oldGlyfData = glyf.data; - var oldGlyfDataLength = oldGlyfData.length; - var newGlyfData = new Uint8Array(oldGlyfDataLength); - var i, j; - const locaEntries = []; + function sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry, maxSizeOfInstructions) { + let itemSize, itemDecode, itemEncode; - for (i = 0, j = 0; i < numGlyphs + 1; i++, j += itemSize) { - let offset = itemDecode(locaData, j); + if (isGlyphLocationsLong) { + itemSize = 4; - if (offset > oldGlyfDataLength) { - offset = oldGlyfDataLength; - } + itemDecode = function fontItemDecodeLong(data, offset) { + return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; + }; - locaEntries.push({ - index: i, - offset, - endOffset: 0 - }); - } + itemEncode = function fontItemEncodeLong(data, offset, value) { + data[offset] = value >>> 24 & 0xff; + data[offset + 1] = value >> 16 & 0xff; + data[offset + 2] = value >> 8 & 0xff; + data[offset + 3] = value & 0xff; + }; + } else { + itemSize = 2; - locaEntries.sort((a, b) => { - return a.offset - b.offset; - }); + itemDecode = function fontItemDecode(data, offset) { + return data[offset] << 9 | data[offset + 1] << 1; + }; - for (i = 0; i < numGlyphs; i++) { - locaEntries[i].endOffset = locaEntries[i + 1].offset; - } - - locaEntries.sort((a, b) => { - return a.index - b.index; - }); - var missingGlyphs = Object.create(null); - var writeOffset = 0; - itemEncode(locaData, 0, writeOffset); - - for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) { - var glyphProfile = sanitizeGlyph(oldGlyfData, locaEntries[i].offset, locaEntries[i].endOffset, newGlyfData, writeOffset, hintsValid); - var newLength = glyphProfile.length; - - if (newLength === 0) { - missingGlyphs[i] = true; - } - - if (glyphProfile.sizeOfInstructions > maxSizeOfInstructions) { - maxSizeOfInstructions = glyphProfile.sizeOfInstructions; - } - - writeOffset += newLength; - itemEncode(locaData, j, writeOffset); - } - - if (writeOffset === 0) { - var simpleGlyph = new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]); - - for (i = 0, j = itemSize; i < numGlyphsOut; i++, j += itemSize) { - itemEncode(locaData, j, simpleGlyph.length); - } - - glyf.data = simpleGlyph; - } else if (dupFirstEntry) { - var firstEntryLength = itemDecode(locaData, itemSize); - - if (newGlyfData.length > firstEntryLength + writeOffset) { - glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset); - } else { - glyf.data = new Uint8Array(firstEntryLength + writeOffset); - glyf.data.set(newGlyfData.subarray(0, writeOffset)); - } - - glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset); - itemEncode(loca.data, locaData.length - itemSize, writeOffset + firstEntryLength); - } else { - glyf.data = newGlyfData.subarray(0, writeOffset); - } - - return { - missingGlyphs, - maxSizeOfInstructions + itemEncode = function fontItemEncode(data, offset, value) { + data[offset] = value >> 9 & 0xff; + data[offset + 1] = value >> 1 & 0xff; }; } - function readPostScriptTable(post, propertiesObj, maxpNumGlyphs) { - var start = (font.start ? font.start : 0) + post.offset; - font.pos = start; - var length = post.length, + const numGlyphsOut = dupFirstEntry ? numGlyphs + 1 : numGlyphs; + const locaDataSize = itemSize * (1 + numGlyphsOut); + const locaData = new Uint8Array(locaDataSize); + locaData.set(loca.data.subarray(0, locaDataSize)); + loca.data = locaData; + const oldGlyfData = glyf.data; + const oldGlyfDataLength = oldGlyfData.length; + const newGlyfData = new Uint8Array(oldGlyfDataLength); + let i, j; + const locaEntries = []; + + for (i = 0, j = 0; i < numGlyphs + 1; i++, j += itemSize) { + let offset = itemDecode(locaData, j); + + if (offset > oldGlyfDataLength) { + offset = oldGlyfDataLength; + } + + locaEntries.push({ + index: i, + offset, + endOffset: 0 + }); + } + + locaEntries.sort((a, b) => { + return a.offset - b.offset; + }); + + for (i = 0; i < numGlyphs; i++) { + locaEntries[i].endOffset = locaEntries[i + 1].offset; + } + + locaEntries.sort((a, b) => { + return a.index - b.index; + }); + + for (i = 0; i < numGlyphs; i++) { + const { + offset, + endOffset + } = locaEntries[i]; + + if (offset !== 0 || endOffset !== 0) { + break; + } + + const nextOffset = locaEntries[i + 1].offset; + + if (nextOffset === 0) { + continue; + } + + locaEntries[i].endOffset = nextOffset; + break; + } + + const missingGlyphs = Object.create(null); + let writeOffset = 0; + itemEncode(locaData, 0, writeOffset); + + for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) { + const glyphProfile = sanitizeGlyph(oldGlyfData, locaEntries[i].offset, locaEntries[i].endOffset, newGlyfData, writeOffset, hintsValid); + const newLength = glyphProfile.length; + + if (newLength === 0) { + missingGlyphs[i] = true; + } + + if (glyphProfile.sizeOfInstructions > maxSizeOfInstructions) { + maxSizeOfInstructions = glyphProfile.sizeOfInstructions; + } + + writeOffset += newLength; + itemEncode(locaData, j, writeOffset); + } + + if (writeOffset === 0) { + const simpleGlyph = new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]); + + for (i = 0, j = itemSize; i < numGlyphsOut; i++, j += itemSize) { + itemEncode(locaData, j, simpleGlyph.length); + } + + glyf.data = simpleGlyph; + } else if (dupFirstEntry) { + const firstEntryLength = itemDecode(locaData, itemSize); + + if (newGlyfData.length > firstEntryLength + writeOffset) { + glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset); + } else { + glyf.data = new Uint8Array(firstEntryLength + writeOffset); + glyf.data.set(newGlyfData.subarray(0, writeOffset)); + } + + glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset); + itemEncode(loca.data, locaData.length - itemSize, writeOffset + firstEntryLength); + } else { + glyf.data = newGlyfData.subarray(0, writeOffset); + } + + return { + missingGlyphs, + maxSizeOfInstructions + }; + } + + function readPostScriptTable(post, propertiesObj, maxpNumGlyphs) { + const start = (font.start || 0) + post.offset; + font.pos = start; + const length = post.length, end = start + length; - var version = font.getInt32(); - font.skip(28); - var glyphNames; - var valid = true; - var i; + const version = font.getInt32(); + font.skip(28); + let glyphNames; + let valid = true; + let i; - switch (version) { - case 0x00010000: - glyphNames = MacStandardGlyphOrdering; + switch (version) { + case 0x00010000: + glyphNames = _fonts_utils.MacStandardGlyphOrdering; + break; + + case 0x00020000: + const numGlyphs = font.getUint16(); + + if (numGlyphs !== maxpNumGlyphs) { + valid = false; break; + } - case 0x00020000: - var numGlyphs = font.getUint16(); + const glyphNameIndexes = []; - if (numGlyphs !== maxpNumGlyphs) { + for (i = 0; i < numGlyphs; ++i) { + const index = font.getUint16(); + + if (index >= 32768) { valid = false; break; } - var glyphNameIndexes = []; - - for (i = 0; i < numGlyphs; ++i) { - var index = font.getUint16(); - - if (index >= 32768) { - valid = false; - break; - } - - glyphNameIndexes.push(index); - } - - if (!valid) { - break; - } - - var customNames = []; - var strBuf = []; - - while (font.pos < end) { - var stringLength = font.getByte(); - strBuf.length = stringLength; - - for (i = 0; i < stringLength; ++i) { - strBuf[i] = String.fromCharCode(font.getByte()); - } - - customNames.push(strBuf.join("")); - } - - glyphNames = []; - - for (i = 0; i < numGlyphs; ++i) { - var j = glyphNameIndexes[i]; - - if (j < 258) { - glyphNames.push(MacStandardGlyphOrdering[j]); - continue; - } - - glyphNames.push(customNames[j - 258]); - } + glyphNameIndexes.push(index); + } + if (!valid) { break; + } - case 0x00030000: - break; + const customNames = [], + strBuf = []; - default: - (0, _util.warn)("Unknown/unsupported post table version " + version); - valid = false; + while (font.pos < end) { + const stringLength = font.getByte(); + strBuf.length = stringLength; - if (propertiesObj.defaultEncoding) { - glyphNames = propertiesObj.defaultEncoding; + for (i = 0; i < stringLength; ++i) { + strBuf[i] = String.fromCharCode(font.getByte()); } - break; - } + customNames.push(strBuf.join("")); + } - propertiesObj.glyphNames = glyphNames; - return valid; + glyphNames = []; + + for (i = 0; i < numGlyphs; ++i) { + const j = glyphNameIndexes[i]; + + if (j < 258) { + glyphNames.push(_fonts_utils.MacStandardGlyphOrdering[j]); + continue; + } + + glyphNames.push(customNames[j - 258]); + } + + break; + + case 0x00030000: + break; + + default: + (0, _util.warn)("Unknown/unsupported post table version " + version); + valid = false; + + if (propertiesObj.defaultEncoding) { + glyphNames = propertiesObj.defaultEncoding; + } + + break; } - function readNameTable(nameTable) { - var start = (font.start ? font.start : 0) + nameTable.offset; - font.pos = start; - var names = [[], []]; - var length = nameTable.length, + propertiesObj.glyphNames = glyphNames; + return valid; + } + + function readNameTable(nameTable) { + const start = (font.start || 0) + nameTable.offset; + font.pos = start; + const names = [[], []]; + const length = nameTable.length, end = start + length; - var format = font.getUint16(); - var FORMAT_0_HEADER_LENGTH = 6; - - if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) { - return names; - } - - var numRecords = font.getUint16(); - var stringsStart = font.getUint16(); - var records = []; - var NAME_RECORD_LENGTH = 12; - var i, ii; - - for (i = 0; i < numRecords && font.pos + NAME_RECORD_LENGTH <= end; i++) { - var r = { - platform: font.getUint16(), - encoding: font.getUint16(), - language: font.getUint16(), - name: font.getUint16(), - length: font.getUint16(), - offset: font.getUint16() - }; - - if (r.platform === 1 && r.encoding === 0 && r.language === 0 || r.platform === 3 && r.encoding === 1 && r.language === 0x409) { - records.push(r); - } - } - - for (i = 0, ii = records.length; i < ii; i++) { - var record = records[i]; - - if (record.length <= 0) { - continue; - } - - var pos = start + stringsStart + record.offset; - - if (pos + record.length > end) { - continue; - } - - font.pos = pos; - var nameIndex = record.name; - - if (record.encoding) { - var str = ""; - - for (var j = 0, jj = record.length; j < jj; j += 2) { - str += String.fromCharCode(font.getUint16()); - } - - names[1][nameIndex] = str; - } else { - names[0][nameIndex] = (0, _util.bytesToString)(font.getBytes(record.length)); - } - } + const format = font.getUint16(); + const FORMAT_0_HEADER_LENGTH = 6; + if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) { return names; } - var TTOpsStackDeltas = [0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1, 1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1, 0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2, 0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1, -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2]; + const numRecords = font.getUint16(); + const stringsStart = font.getUint16(); + const records = []; + const NAME_RECORD_LENGTH = 12; + let i, ii; - function sanitizeTTProgram(table, ttContext) { - var data = table.data; - var i = 0, - j, - n, - b, - funcId, - pc, - lastEndf = 0, - lastDeff = 0; - var stack = []; - var callstack = []; - var functionsCalled = []; - var tooComplexToFollowFunctions = ttContext.tooComplexToFollowFunctions; - var inFDEF = false, - ifLevel = 0, - inELSE = 0; + for (i = 0; i < numRecords && font.pos + NAME_RECORD_LENGTH <= end; i++) { + const r = { + platform: font.getUint16(), + encoding: font.getUint16(), + language: font.getUint16(), + name: font.getUint16(), + length: font.getUint16(), + offset: font.getUint16() + }; - for (var ii = data.length; i < ii;) { - var op = data[i++]; - - if (op === 0x40) { - n = data[i++]; - - if (inFDEF || inELSE) { - i += n; - } else { - for (j = 0; j < n; j++) { - stack.push(data[i++]); - } - } - } else if (op === 0x41) { - n = data[i++]; - - if (inFDEF || inELSE) { - i += n * 2; - } else { - for (j = 0; j < n; j++) { - b = data[i++]; - stack.push(b << 8 | data[i++]); - } - } - } else if ((op & 0xf8) === 0xb0) { - n = op - 0xb0 + 1; - - if (inFDEF || inELSE) { - i += n; - } else { - for (j = 0; j < n; j++) { - stack.push(data[i++]); - } - } - } else if ((op & 0xf8) === 0xb8) { - n = op - 0xb8 + 1; - - if (inFDEF || inELSE) { - i += n * 2; - } else { - for (j = 0; j < n; j++) { - b = data[i++]; - stack.push(b << 8 | data[i++]); - } - } - } else if (op === 0x2b && !tooComplexToFollowFunctions) { - if (!inFDEF && !inELSE) { - funcId = stack[stack.length - 1]; - - if (isNaN(funcId)) { - (0, _util.info)("TT: CALL empty stack (or invalid entry)."); - } else { - ttContext.functionsUsed[funcId] = true; - - if (funcId in ttContext.functionsStackDeltas) { - const newStackLength = stack.length + ttContext.functionsStackDeltas[funcId]; - - if (newStackLength < 0) { - (0, _util.warn)("TT: CALL invalid functions stack delta."); - ttContext.hintsValid = false; - return; - } - - stack.length = newStackLength; - } else if (funcId in ttContext.functionsDefined && !functionsCalled.includes(funcId)) { - callstack.push({ - data, - i, - stackTop: stack.length - 1 - }); - functionsCalled.push(funcId); - pc = ttContext.functionsDefined[funcId]; - - if (!pc) { - (0, _util.warn)("TT: CALL non-existent function"); - ttContext.hintsValid = false; - return; - } - - data = pc.data; - i = pc.i; - } - } - } - } else if (op === 0x2c && !tooComplexToFollowFunctions) { - if (inFDEF || inELSE) { - (0, _util.warn)("TT: nested FDEFs not allowed"); - tooComplexToFollowFunctions = true; - } - - inFDEF = true; - lastDeff = i; - funcId = stack.pop(); - ttContext.functionsDefined[funcId] = { - data, - i - }; - } else if (op === 0x2d) { - if (inFDEF) { - inFDEF = false; - lastEndf = i; - } else { - pc = callstack.pop(); - - if (!pc) { - (0, _util.warn)("TT: ENDF bad stack"); - ttContext.hintsValid = false; - return; - } - - funcId = functionsCalled.pop(); - data = pc.data; - i = pc.i; - ttContext.functionsStackDeltas[funcId] = stack.length - pc.stackTop; - } - } else if (op === 0x89) { - if (inFDEF || inELSE) { - (0, _util.warn)("TT: nested IDEFs not allowed"); - tooComplexToFollowFunctions = true; - } - - inFDEF = true; - lastDeff = i; - } else if (op === 0x58) { - ++ifLevel; - } else if (op === 0x1b) { - inELSE = ifLevel; - } else if (op === 0x59) { - if (inELSE === ifLevel) { - inELSE = 0; - } - - --ifLevel; - } else if (op === 0x1c) { - if (!inFDEF && !inELSE) { - var offset = stack[stack.length - 1]; - - if (offset > 0) { - i += offset - 1; - } - } - } - - if (!inFDEF && !inELSE) { - let stackDelta = 0; - - if (op <= 0x8e) { - stackDelta = TTOpsStackDeltas[op]; - } else if (op >= 0xc0 && op <= 0xdf) { - stackDelta = -1; - } else if (op >= 0xe0) { - stackDelta = -2; - } - - if (op >= 0x71 && op <= 0x75) { - n = stack.pop(); - - if (!isNaN(n)) { - stackDelta = -n * 2; - } - } - - while (stackDelta < 0 && stack.length > 0) { - stack.pop(); - stackDelta++; - } - - while (stackDelta > 0) { - stack.push(NaN); - stackDelta--; - } - } + if (r.platform === 1 && r.encoding === 0 && r.language === 0 || r.platform === 3 && r.encoding === 1 && r.language === 0x409) { + records.push(r); } - - ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions; - var content = [data]; - - if (i > data.length) { - content.push(new Uint8Array(i - data.length)); - } - - if (lastDeff > lastEndf) { - (0, _util.warn)("TT: complementing a missing function tail"); - content.push(new Uint8Array([0x22, 0x2d])); - } - - foldTTTable(table, content); } - function checkInvalidFunctions(ttContext, maxFunctionDefs) { - if (ttContext.tooComplexToFollowFunctions) { - return; + for (i = 0, ii = records.length; i < ii; i++) { + const record = records[i]; + + if (record.length <= 0) { + continue; } - if (ttContext.functionsDefined.length > maxFunctionDefs) { - (0, _util.warn)("TT: more functions defined than expected"); + const pos = start + stringsStart + record.offset; + + if (pos + record.length > end) { + continue; + } + + font.pos = pos; + const nameIndex = record.name; + + if (record.encoding) { + let str = ""; + + for (let j = 0, jj = record.length; j < jj; j += 2) { + str += String.fromCharCode(font.getUint16()); + } + + names[1][nameIndex] = str; + } else { + names[0][nameIndex] = font.getString(record.length); + } + } + + return names; + } + + const TTOpsStackDeltas = [0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1, 1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1, 0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2, 0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1, -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2]; + + function sanitizeTTProgram(table, ttContext) { + let data = table.data; + let i = 0, + j, + n, + b, + funcId, + pc, + lastEndf = 0, + lastDeff = 0; + const stack = []; + const callstack = []; + const functionsCalled = []; + let tooComplexToFollowFunctions = ttContext.tooComplexToFollowFunctions; + let inFDEF = false, + ifLevel = 0, + inELSE = 0; + + for (let ii = data.length; i < ii;) { + const op = data[i++]; + + if (op === 0x40) { + n = data[i++]; + + if (inFDEF || inELSE) { + i += n; + } else { + for (j = 0; j < n; j++) { + stack.push(data[i++]); + } + } + } else if (op === 0x41) { + n = data[i++]; + + if (inFDEF || inELSE) { + i += n * 2; + } else { + for (j = 0; j < n; j++) { + b = data[i++]; + stack.push(b << 8 | data[i++]); + } + } + } else if ((op & 0xf8) === 0xb0) { + n = op - 0xb0 + 1; + + if (inFDEF || inELSE) { + i += n; + } else { + for (j = 0; j < n; j++) { + stack.push(data[i++]); + } + } + } else if ((op & 0xf8) === 0xb8) { + n = op - 0xb8 + 1; + + if (inFDEF || inELSE) { + i += n * 2; + } else { + for (j = 0; j < n; j++) { + b = data[i++]; + stack.push(b << 8 | data[i++]); + } + } + } else if (op === 0x2b && !tooComplexToFollowFunctions) { + if (!inFDEF && !inELSE) { + funcId = stack.at(-1); + + if (isNaN(funcId)) { + (0, _util.info)("TT: CALL empty stack (or invalid entry)."); + } else { + ttContext.functionsUsed[funcId] = true; + + if (funcId in ttContext.functionsStackDeltas) { + const newStackLength = stack.length + ttContext.functionsStackDeltas[funcId]; + + if (newStackLength < 0) { + (0, _util.warn)("TT: CALL invalid functions stack delta."); + ttContext.hintsValid = false; + return; + } + + stack.length = newStackLength; + } else if (funcId in ttContext.functionsDefined && !functionsCalled.includes(funcId)) { + callstack.push({ + data, + i, + stackTop: stack.length - 1 + }); + functionsCalled.push(funcId); + pc = ttContext.functionsDefined[funcId]; + + if (!pc) { + (0, _util.warn)("TT: CALL non-existent function"); + ttContext.hintsValid = false; + return; + } + + data = pc.data; + i = pc.i; + } + } + } + } else if (op === 0x2c && !tooComplexToFollowFunctions) { + if (inFDEF || inELSE) { + (0, _util.warn)("TT: nested FDEFs not allowed"); + tooComplexToFollowFunctions = true; + } + + inFDEF = true; + lastDeff = i; + funcId = stack.pop(); + ttContext.functionsDefined[funcId] = { + data, + i + }; + } else if (op === 0x2d) { + if (inFDEF) { + inFDEF = false; + lastEndf = i; + } else { + pc = callstack.pop(); + + if (!pc) { + (0, _util.warn)("TT: ENDF bad stack"); + ttContext.hintsValid = false; + return; + } + + funcId = functionsCalled.pop(); + data = pc.data; + i = pc.i; + ttContext.functionsStackDeltas[funcId] = stack.length - pc.stackTop; + } + } else if (op === 0x89) { + if (inFDEF || inELSE) { + (0, _util.warn)("TT: nested IDEFs not allowed"); + tooComplexToFollowFunctions = true; + } + + inFDEF = true; + lastDeff = i; + } else if (op === 0x58) { + ++ifLevel; + } else if (op === 0x1b) { + inELSE = ifLevel; + } else if (op === 0x59) { + if (inELSE === ifLevel) { + inELSE = 0; + } + + --ifLevel; + } else if (op === 0x1c) { + if (!inFDEF && !inELSE) { + const offset = stack.at(-1); + + if (offset > 0) { + i += offset - 1; + } + } + } + + if (!inFDEF && !inELSE) { + let stackDelta = 0; + + if (op <= 0x8e) { + stackDelta = TTOpsStackDeltas[op]; + } else if (op >= 0xc0 && op <= 0xdf) { + stackDelta = -1; + } else if (op >= 0xe0) { + stackDelta = -2; + } + + if (op >= 0x71 && op <= 0x75) { + n = stack.pop(); + + if (!isNaN(n)) { + stackDelta = -n * 2; + } + } + + while (stackDelta < 0 && stack.length > 0) { + stack.pop(); + stackDelta++; + } + + while (stackDelta > 0) { + stack.push(NaN); + stackDelta--; + } + } + } + + ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions; + const content = [data]; + + if (i > data.length) { + content.push(new Uint8Array(i - data.length)); + } + + if (lastDeff > lastEndf) { + (0, _util.warn)("TT: complementing a missing function tail"); + content.push(new Uint8Array([0x22, 0x2d])); + } + + foldTTTable(table, content); + } + + function checkInvalidFunctions(ttContext, maxFunctionDefs) { + if (ttContext.tooComplexToFollowFunctions) { + return; + } + + if (ttContext.functionsDefined.length > maxFunctionDefs) { + (0, _util.warn)("TT: more functions defined than expected"); + ttContext.hintsValid = false; + return; + } + + for (let j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) { + if (j > maxFunctionDefs) { + (0, _util.warn)("TT: invalid function id: " + j); ttContext.hintsValid = false; return; } - for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) { - if (j > maxFunctionDefs) { - (0, _util.warn)("TT: invalid function id: " + j); - ttContext.hintsValid = false; - return; - } - - if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) { - (0, _util.warn)("TT: undefined function: " + j); - ttContext.hintsValid = false; - return; - } + if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) { + (0, _util.warn)("TT: undefined function: " + j); + ttContext.hintsValid = false; + return; } } + } - function foldTTTable(table, content) { - if (content.length > 1) { - var newLength = 0; - var j, jj; + function foldTTTable(table, content) { + if (content.length > 1) { + let newLength = 0; + let j, jj; - for (j = 0, jj = content.length; j < jj; j++) { - newLength += content[j].length; - } - - newLength = newLength + 3 & ~3; - var result = new Uint8Array(newLength); - var pos = 0; - - for (j = 0, jj = content.length; j < jj; j++) { - result.set(content[j], pos); - pos += content[j].length; - } - - table.data = result; - table.length = newLength; + for (j = 0, jj = content.length; j < jj; j++) { + newLength += content[j].length; } + + newLength = newLength + 3 & ~3; + const result = new Uint8Array(newLength); + let pos = 0; + + for (j = 0, jj = content.length; j < jj; j++) { + result.set(content[j], pos); + pos += content[j].length; + } + + table.data = result; + table.length = newLength; + } + } + + function sanitizeTTPrograms(fpgm, prep, cvt, maxFunctionDefs) { + const ttContext = { + functionsDefined: [], + functionsUsed: [], + functionsStackDeltas: [], + tooComplexToFollowFunctions: false, + hintsValid: true + }; + + if (fpgm) { + sanitizeTTProgram(fpgm, ttContext); } - function sanitizeTTPrograms(fpgm, prep, cvt, maxFunctionDefs) { - var ttContext = { - functionsDefined: [], - functionsUsed: [], - functionsStackDeltas: [], - tooComplexToFollowFunctions: false, - hintsValid: true + if (prep) { + sanitizeTTProgram(prep, ttContext); + } + + if (fpgm) { + checkInvalidFunctions(ttContext, maxFunctionDefs); + } + + if (cvt && cvt.length & 1) { + const cvtData = new Uint8Array(cvt.length + 1); + cvtData.set(cvt.data); + cvt.data = cvtData; + } + + return ttContext.hintsValid; + } + + font = new _stream.Stream(new Uint8Array(font.getBytes())); + let header, tables; + + if (isTrueTypeCollectionFile(font)) { + const ttcData = readTrueTypeCollectionData(font, this.name); + header = ttcData.header; + tables = ttcData.tables; + } else { + header = readOpenTypeHeader(font); + tables = readTables(font, header.numTables); + } + + let cff, cffFile; + const isTrueType = !tables["CFF "]; + + if (!isTrueType) { + const isComposite = properties.composite && ((properties.cidToGidMap || []).length > 0 || !(properties.cMap instanceof _cmap.IdentityCMap)); + + if (header.version === "OTTO" && !isComposite || !tables.head || !tables.hhea || !tables.maxp || !tables.post) { + cffFile = new _stream.Stream(tables["CFF "].data); + cff = new _cff_font.CFFFont(cffFile, properties); + adjustWidths(properties); + return this.convert(name, cff, properties); + } + + delete tables.glyf; + delete tables.loca; + delete tables.fpgm; + delete tables.prep; + delete tables["cvt "]; + this.isOpenType = true; + } else { + if (!tables.loca) { + throw new _util.FormatError('Required "loca" table is not found'); + } + + if (!tables.glyf) { + (0, _util.warn)('Required "glyf" table is not found -- trying to recover.'); + tables.glyf = { + tag: "glyf", + data: new Uint8Array(0) }; - - if (fpgm) { - sanitizeTTProgram(fpgm, ttContext); - } - - if (prep) { - sanitizeTTProgram(prep, ttContext); - } - - if (fpgm) { - checkInvalidFunctions(ttContext, maxFunctionDefs); - } - - if (cvt && cvt.length & 1) { - var cvtData = new Uint8Array(cvt.length + 1); - cvtData.set(cvt.data); - cvt.data = cvtData; - } - - return ttContext.hintsValid; } - font = new _stream.Stream(new Uint8Array(font.getBytes())); - let header, tables; + this.isOpenType = false; + } - if (isTrueTypeCollectionFile(font)) { - const ttcData = readTrueTypeCollectionData(font, this.name); - header = ttcData.header; - tables = ttcData.tables; - } else { - header = readOpenTypeHeader(font); - tables = readTables(font, header.numTables); + if (!tables.maxp) { + throw new _util.FormatError('Required "maxp" table is not found'); + } + + font.pos = (font.start || 0) + tables.maxp.offset; + const version = font.getInt32(); + const numGlyphs = font.getUint16(); + + if (properties.scaleFactors && properties.scaleFactors.length === numGlyphs && isTrueType) { + const { + scaleFactors + } = properties; + const isGlyphLocationsLong = int16(tables.head.data[50], tables.head.data[51]); + const glyphs = new _glyf.GlyfTable({ + glyfTable: tables.glyf.data, + isGlyphLocationsLong, + locaTable: tables.loca.data, + numGlyphs + }); + glyphs.scale(scaleFactors); + const { + glyf, + loca, + isLocationLong + } = glyphs.write(); + tables.glyf.data = glyf; + tables.loca.data = loca; + + if (isLocationLong !== !!isGlyphLocationsLong) { + tables.head.data[50] = 0; + tables.head.data[51] = isLocationLong ? 1 : 0; } - let cff, cffFile; - var isTrueType = !tables["CFF "]; + const metrics = tables.hmtx.data; - if (!isTrueType) { - const isComposite = properties.composite && ((properties.cidToGidMap || []).length > 0 || !(properties.cMap instanceof _cmap.IdentityCMap)); + for (let i = 0; i < numGlyphs; i++) { + const j = 4 * i; + const advanceWidth = Math.round(scaleFactors[i] * int16(metrics[j], metrics[j + 1])); + metrics[j] = advanceWidth >> 8 & 0xff; + metrics[j + 1] = advanceWidth & 0xff; + const lsb = Math.round(scaleFactors[i] * signedInt16(metrics[j + 2], metrics[j + 3])); + writeSignedInt16(metrics, j + 2, lsb); + } + } - if (header.version === "OTTO" && !isComposite || !tables.head || !tables.hhea || !tables.maxp || !tables.post) { - cffFile = new _stream.Stream(tables["CFF "].data); - cff = new CFFFont(cffFile, properties); - adjustWidths(properties); - return this.convert(name, cff, properties); - } + let numGlyphsOut = numGlyphs + 1; + let dupFirstEntry = true; - delete tables.glyf; - delete tables.loca; - delete tables.fpgm; - delete tables.prep; - delete tables["cvt "]; - this.isOpenType = true; - } else { - if (!tables.loca) { - throw new _util.FormatError('Required "loca" table is not found'); - } + if (numGlyphsOut > 0xffff) { + dupFirstEntry = false; + numGlyphsOut = numGlyphs; + (0, _util.warn)("Not enough space in glyfs to duplicate first glyph."); + } - if (!tables.glyf) { - (0, _util.warn)('Required "glyf" table is not found -- trying to recover.'); - tables.glyf = { - tag: "glyf", - data: new Uint8Array(0) - }; - } + let maxFunctionDefs = 0; + let maxSizeOfInstructions = 0; - this.isOpenType = false; + if (version >= 0x00010000 && tables.maxp.length >= 22) { + font.pos += 8; + const maxZones = font.getUint16(); + + if (maxZones > 2) { + tables.maxp.data[14] = 0; + tables.maxp.data[15] = 2; } - if (!tables.maxp) { - throw new _util.FormatError('Required "maxp" table is not found'); - } + font.pos += 4; + maxFunctionDefs = font.getUint16(); + font.pos += 4; + maxSizeOfInstructions = font.getUint16(); + } - font.pos = (font.start || 0) + tables.maxp.offset; - var version = font.getInt32(); - const numGlyphs = font.getUint16(); - let numGlyphsOut = numGlyphs + 1; - let dupFirstEntry = true; + tables.maxp.data[4] = numGlyphsOut >> 8; + tables.maxp.data[5] = numGlyphsOut & 255; + const hintsValid = sanitizeTTPrograms(tables.fpgm, tables.prep, tables["cvt "], maxFunctionDefs); - if (numGlyphsOut > 0xffff) { - dupFirstEntry = false; - numGlyphsOut = numGlyphs; - (0, _util.warn)("Not enough space in glyfs to duplicate first glyph."); - } + if (!hintsValid) { + delete tables.fpgm; + delete tables.prep; + delete tables["cvt "]; + } - var maxFunctionDefs = 0; - var maxSizeOfInstructions = 0; + sanitizeMetrics(font, tables.hhea, tables.hmtx, tables.head, numGlyphsOut, dupFirstEntry); + + if (!tables.head) { + throw new _util.FormatError('Required "head" table is not found'); + } + + sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0); + let missingGlyphs = Object.create(null); + + if (isTrueType) { + const isGlyphLocationsLong = int16(tables.head.data[50], tables.head.data[51]); + const glyphsInfo = sanitizeGlyphLocations(tables.loca, tables.glyf, numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry, maxSizeOfInstructions); + missingGlyphs = glyphsInfo.missingGlyphs; if (version >= 0x00010000 && tables.maxp.length >= 22) { - font.pos += 8; - var maxZones = font.getUint16(); + tables.maxp.data[26] = glyphsInfo.maxSizeOfInstructions >> 8; + tables.maxp.data[27] = glyphsInfo.maxSizeOfInstructions & 255; + } + } - if (maxZones > 2) { - tables.maxp.data[14] = 0; - tables.maxp.data[15] = 2; + if (!tables.hhea) { + throw new _util.FormatError('Required "hhea" table is not found'); + } + + if (tables.hhea.data[10] === 0 && tables.hhea.data[11] === 0) { + tables.hhea.data[10] = 0xff; + tables.hhea.data[11] = 0xff; + } + + const metricsOverride = { + unitsPerEm: int16(tables.head.data[18], tables.head.data[19]), + yMax: int16(tables.head.data[42], tables.head.data[43]), + yMin: signedInt16(tables.head.data[38], tables.head.data[39]), + ascent: signedInt16(tables.hhea.data[4], tables.hhea.data[5]), + descent: signedInt16(tables.hhea.data[6], tables.hhea.data[7]), + lineGap: signedInt16(tables.hhea.data[8], tables.hhea.data[9]) + }; + this.ascent = metricsOverride.ascent / metricsOverride.unitsPerEm; + this.descent = metricsOverride.descent / metricsOverride.unitsPerEm; + this.lineGap = metricsOverride.lineGap / metricsOverride.unitsPerEm; + + if (this.cssFontInfo && this.cssFontInfo.lineHeight) { + this.lineHeight = this.cssFontInfo.metrics.lineHeight; + this.lineGap = this.cssFontInfo.metrics.lineGap; + } else { + this.lineHeight = this.ascent - this.descent + this.lineGap; + } + + if (tables.post) { + readPostScriptTable(tables.post, properties, numGlyphs); + } + + tables.post = { + tag: "post", + data: createPostTable(properties) + }; + const charCodeToGlyphId = []; + + function hasGlyph(glyphId) { + return !missingGlyphs[glyphId]; + } + + if (properties.composite) { + const cidToGidMap = properties.cidToGidMap || []; + const isCidToGidMapEmpty = cidToGidMap.length === 0; + properties.cMap.forEach(function (charCode, cid) { + if (typeof cid === "string") { + cid = convertCidString(charCode, cid, true); } - font.pos += 4; - maxFunctionDefs = font.getUint16(); - font.pos += 4; - maxSizeOfInstructions = font.getUint16(); - } - - tables.maxp.data[4] = numGlyphsOut >> 8; - tables.maxp.data[5] = numGlyphsOut & 255; - var hintsValid = sanitizeTTPrograms(tables.fpgm, tables.prep, tables["cvt "], maxFunctionDefs); - - if (!hintsValid) { - delete tables.fpgm; - delete tables.prep; - delete tables["cvt "]; - } - - sanitizeMetrics(font, tables.hhea, tables.hmtx, numGlyphsOut, dupFirstEntry); - - if (!tables.head) { - throw new _util.FormatError('Required "head" table is not found'); - } - - sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0); - var missingGlyphs = Object.create(null); - - if (isTrueType) { - var isGlyphLocationsLong = int16(tables.head.data[50], tables.head.data[51]); - var glyphsInfo = sanitizeGlyphLocations(tables.loca, tables.glyf, numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry, maxSizeOfInstructions); - missingGlyphs = glyphsInfo.missingGlyphs; - - if (version >= 0x00010000 && tables.maxp.length >= 22) { - tables.maxp.data[26] = glyphsInfo.maxSizeOfInstructions >> 8; - tables.maxp.data[27] = glyphsInfo.maxSizeOfInstructions & 255; - } - } - - if (!tables.hhea) { - throw new _util.FormatError('Required "hhea" table is not found'); - } - - if (tables.hhea.data[10] === 0 && tables.hhea.data[11] === 0) { - tables.hhea.data[10] = 0xff; - tables.hhea.data[11] = 0xff; - } - - var metricsOverride = { - unitsPerEm: int16(tables.head.data[18], tables.head.data[19]), - yMax: int16(tables.head.data[42], tables.head.data[43]), - yMin: signedInt16(tables.head.data[38], tables.head.data[39]), - ascent: int16(tables.hhea.data[4], tables.hhea.data[5]), - descent: signedInt16(tables.hhea.data[6], tables.hhea.data[7]) - }; - this.ascent = metricsOverride.ascent / metricsOverride.unitsPerEm; - this.descent = metricsOverride.descent / metricsOverride.unitsPerEm; - - if (tables.post) { - readPostScriptTable(tables.post, properties, numGlyphs); - } - - tables.post = { - tag: "post", - data: createPostTable(properties) - }; - const charCodeToGlyphId = []; - - function hasGlyph(glyphId) { - return !missingGlyphs[glyphId]; - } - - if (properties.composite) { - var cidToGidMap = properties.cidToGidMap || []; - var isCidToGidMapEmpty = cidToGidMap.length === 0; - properties.cMap.forEach(function (charCode, cid) { - if (cid > 0xffff) { - throw new _util.FormatError("Max size of CID is 65,535"); - } - - var glyphId = -1; - - if (isCidToGidMapEmpty) { - glyphId = cid; - } else if (cidToGidMap[cid] !== undefined) { - glyphId = cidToGidMap[cid]; - } - - if (glyphId >= 0 && glyphId < numGlyphs && hasGlyph(glyphId)) { - charCodeToGlyphId[charCode] = glyphId; - } - }); - } else { - var cmapTable = readCmapTable(tables.cmap, font, this.isSymbolicFont, properties.hasEncoding); - var cmapPlatformId = cmapTable.platformId; - var cmapEncodingId = cmapTable.encodingId; - var cmapMappings = cmapTable.mappings; - var cmapMappingsLength = cmapMappings.length; - let baseEncoding = []; - - if (properties.hasEncoding && (properties.baseEncodingName === "MacRomanEncoding" || properties.baseEncodingName === "WinAnsiEncoding")) { - baseEncoding = (0, _encodings.getEncoding)(properties.baseEncodingName); + if (cid > 0xffff) { + throw new _util.FormatError("Max size of CID is 65,535"); } - if (properties.hasEncoding && !this.isSymbolicFont && (cmapPlatformId === 3 && cmapEncodingId === 1 || cmapPlatformId === 1 && cmapEncodingId === 0)) { - var glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + let glyphId = -1; - for (let charCode = 0; charCode < 256; charCode++) { - var glyphName, standardGlyphName; + if (isCidToGidMapEmpty) { + glyphId = cid; + } else if (cidToGidMap[cid] !== undefined) { + glyphId = cidToGidMap[cid]; + } - if (this.differences && charCode in this.differences) { - glyphName = this.differences[charCode]; - } else if (charCode in baseEncoding && baseEncoding[charCode] !== "") { - glyphName = baseEncoding[charCode]; - } else { - glyphName = _encodings.StandardEncoding[charCode]; + if (glyphId >= 0 && glyphId < numGlyphs && hasGlyph(glyphId)) { + charCodeToGlyphId[charCode] = glyphId; + } + }); + } else { + const cmapTable = readCmapTable(tables.cmap, font, this.isSymbolicFont, properties.hasEncoding); + const cmapPlatformId = cmapTable.platformId; + const cmapEncodingId = cmapTable.encodingId; + const cmapMappings = cmapTable.mappings; + const cmapMappingsLength = cmapMappings.length; + let baseEncoding = [], + forcePostTable = false; + + if (properties.hasEncoding && (properties.baseEncodingName === "MacRomanEncoding" || properties.baseEncodingName === "WinAnsiEncoding")) { + baseEncoding = (0, _encodings.getEncoding)(properties.baseEncodingName); + } + + if (properties.hasEncoding && !this.isSymbolicFont && (cmapPlatformId === 3 && cmapEncodingId === 1 || cmapPlatformId === 1 && cmapEncodingId === 0)) { + const glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + + for (let charCode = 0; charCode < 256; charCode++) { + let glyphName; + + if (this.differences[charCode] !== undefined) { + glyphName = this.differences[charCode]; + } else if (baseEncoding.length && baseEncoding[charCode] !== "") { + glyphName = baseEncoding[charCode]; + } else { + glyphName = _encodings.StandardEncoding[charCode]; + } + + if (!glyphName) { + continue; + } + + const standardGlyphName = (0, _fonts_utils.recoverGlyphName)(glyphName, glyphsUnicodeMap); + let unicodeOrCharCode; + + if (cmapPlatformId === 3 && cmapEncodingId === 1) { + unicodeOrCharCode = glyphsUnicodeMap[standardGlyphName]; + } else if (cmapPlatformId === 1 && cmapEncodingId === 0) { + unicodeOrCharCode = _encodings.MacRomanEncoding.indexOf(standardGlyphName); + } + + if (unicodeOrCharCode === undefined) { + if (!properties.glyphNames && properties.hasIncludedToUnicodeMap && !(this.toUnicode instanceof _to_unicode_map.IdentityToUnicodeMap)) { + const unicode = this.toUnicode.get(charCode); + + if (unicode) { + unicodeOrCharCode = unicode.codePointAt(0); + } } - if (!glyphName) { + if (unicodeOrCharCode === undefined) { + continue; + } + } + + for (let i = 0; i < cmapMappingsLength; ++i) { + if (cmapMappings[i].charCode !== unicodeOrCharCode) { continue; } - standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap); - var unicodeOrCharCode; - - if (cmapPlatformId === 3 && cmapEncodingId === 1) { - unicodeOrCharCode = glyphsUnicodeMap[standardGlyphName]; - } else if (cmapPlatformId === 1 && cmapEncodingId === 0) { - unicodeOrCharCode = _encodings.MacRomanEncoding.indexOf(standardGlyphName); - } - - for (let i = 0; i < cmapMappingsLength; ++i) { - if (cmapMappings[i].charCode !== unicodeOrCharCode) { - continue; - } - - charCodeToGlyphId[charCode] = cmapMappings[i].glyphId; - break; - } - } - } else if (cmapPlatformId === 0) { - for (let i = 0; i < cmapMappingsLength; ++i) { - charCodeToGlyphId[cmapMappings[i].charCode] = cmapMappings[i].glyphId; - } - } else { - for (let i = 0; i < cmapMappingsLength; ++i) { - let charCode = cmapMappings[i].charCode; - - if (cmapPlatformId === 3 && charCode >= 0xf000 && charCode <= 0xf0ff) { - charCode &= 0xff; - } - charCodeToGlyphId[charCode] = cmapMappings[i].glyphId; + break; } } + } else if (cmapPlatformId === 0) { + for (let i = 0; i < cmapMappingsLength; ++i) { + charCodeToGlyphId[cmapMappings[i].charCode] = cmapMappings[i].glyphId; + } - if (properties.glyphNames && baseEncoding.length) { - for (let i = 0; i < 256; ++i) { - if (charCodeToGlyphId[i] === undefined && baseEncoding[i]) { - glyphName = baseEncoding[i]; - const glyphId = properties.glyphNames.indexOf(glyphName); + forcePostTable = true; + } else { + for (let i = 0; i < cmapMappingsLength; ++i) { + let charCode = cmapMappings[i].charCode; - if (glyphId > 0 && hasGlyph(glyphId)) { - charCodeToGlyphId[i] = glyphId; - } - } + if (cmapPlatformId === 3 && charCode >= 0xf000 && charCode <= 0xf0ff) { + charCode &= 0xff; } + + charCodeToGlyphId[charCode] = cmapMappings[i].glyphId; } } - if (charCodeToGlyphId.length === 0) { - charCodeToGlyphId[0] = 0; + if (properties.glyphNames && (baseEncoding.length || this.differences.length)) { + for (let i = 0; i < 256; ++i) { + if (!forcePostTable && charCodeToGlyphId[i] !== undefined) { + continue; + } + + const glyphName = this.differences[i] || baseEncoding[i]; + + if (!glyphName) { + continue; + } + + const glyphId = properties.glyphNames.indexOf(glyphName); + + if (glyphId > 0 && hasGlyph(glyphId)) { + charCodeToGlyphId[i] = glyphId; + } + } } + } - let glyphZeroId = numGlyphsOut - 1; + if (charCodeToGlyphId.length === 0) { + charCodeToGlyphId[0] = 0; + } - if (!dupFirstEntry) { - glyphZeroId = 0; - } + let glyphZeroId = numGlyphsOut - 1; - var newMapping = adjustMapping(charCodeToGlyphId, hasGlyph, glyphZeroId); + if (!dupFirstEntry) { + glyphZeroId = 0; + } + + if (!properties.cssFontInfo) { + const newMapping = adjustMapping(charCodeToGlyphId, hasGlyph, glyphZeroId, this.toUnicode); this.toFontChar = newMapping.toFontChar; tables.cmap = { tag: "cmap", - data: createCmapTable(newMapping.charCodeToGlyphId, numGlyphsOut) + data: createCmapTable(newMapping.charCodeToGlyphId, newMapping.toUnicodeExtraMap, numGlyphsOut) }; if (!tables["OS/2"] || !validateOS2Table(tables["OS/2"], font)) { @@ -28635,1782 +27512,1411 @@ var Font = function FontClosure() { data: createOS2Table(properties, newMapping.charCodeToGlyphId, metricsOverride) }; } - - if (!isTrueType) { - try { - cffFile = new _stream.Stream(tables["CFF "].data); - var parser = new _cff_parser.CFFParser(cffFile, properties, SEAC_ANALYSIS_ENABLED); - cff = parser.parse(); - cff.duplicateFirstGlyph(); - var compiler = new _cff_parser.CFFCompiler(cff); - tables["CFF "].data = compiler.compile(); - } catch (e) { - (0, _util.warn)("Failed to compile font " + properties.loadedName); - } - } - - if (!tables.name) { - tables.name = { - tag: "name", - data: createNameTable(this.name) - }; - } else { - var namePrototype = readNameTable(tables.name); - tables.name.data = createNameTable(name, namePrototype); - } - - var builder = new OpenTypeFileBuilder(header.version); - - for (var tableTag in tables) { - builder.addTable(tableTag, tables[tableTag].data); - } - - return builder.toArray(); - }, - convert: function Font_convert(fontName, font, properties) { - properties.fixedPitch = false; - - if (properties.builtInEncoding) { - adjustToUnicode(properties, properties.builtInEncoding); - } - - let glyphZeroId = 1; - - if (font instanceof CFFFont) { - glyphZeroId = font.numGlyphs - 1; - } - - var mapping = font.getGlyphMapping(properties); - var newMapping = adjustMapping(mapping, font.hasGlyphId.bind(font), glyphZeroId); - this.toFontChar = newMapping.toFontChar; - var numGlyphs = font.numGlyphs; - - function getCharCodes(charCodeToGlyphId, glyphId) { - var charCodes = null; - - for (var charCode in charCodeToGlyphId) { - if (glyphId === charCodeToGlyphId[charCode]) { - if (!charCodes) { - charCodes = []; - } - - charCodes.push(charCode | 0); - } - } - - return charCodes; - } - - function createCharCode(charCodeToGlyphId, glyphId) { - for (var charCode in charCodeToGlyphId) { - if (glyphId === charCodeToGlyphId[charCode]) { - return charCode | 0; - } - } - - newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] = glyphId; - return newMapping.nextAvailableFontCharCode++; - } - - var seacs = font.seacs; - - if (SEAC_ANALYSIS_ENABLED && seacs && seacs.length) { - var matrix = properties.fontMatrix || _util.FONT_IDENTITY_MATRIX; - var charset = font.getCharset(); - var seacMap = Object.create(null); - - for (var glyphId in seacs) { - glyphId |= 0; - var seac = seacs[glyphId]; - var baseGlyphName = _encodings.StandardEncoding[seac[2]]; - var accentGlyphName = _encodings.StandardEncoding[seac[3]]; - var baseGlyphId = charset.indexOf(baseGlyphName); - var accentGlyphId = charset.indexOf(accentGlyphName); - - if (baseGlyphId < 0 || accentGlyphId < 0) { - continue; - } - - var accentOffset = { - x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4], - y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5] - }; - var charCodes = getCharCodes(mapping, glyphId); - - if (!charCodes) { - continue; - } - - for (let i = 0, ii = charCodes.length; i < ii; i++) { - var charCode = charCodes[i]; - var charCodeToGlyphId = newMapping.charCodeToGlyphId; - var baseFontCharCode = createCharCode(charCodeToGlyphId, baseGlyphId); - var accentFontCharCode = createCharCode(charCodeToGlyphId, accentGlyphId); - seacMap[charCode] = { - baseFontCharCode, - accentFontCharCode, - accentOffset - }; - } - } - - properties.seacMap = seacMap; - } - - var unitsPerEm = 1 / (properties.fontMatrix || _util.FONT_IDENTITY_MATRIX)[0]; - var builder = new OpenTypeFileBuilder("\x4F\x54\x54\x4F"); - builder.addTable("CFF ", font.data); - builder.addTable("OS/2", createOS2Table(properties, newMapping.charCodeToGlyphId)); - builder.addTable("cmap", createCmapTable(newMapping.charCodeToGlyphId, numGlyphs)); - builder.addTable("head", "\x00\x01\x00\x00" + "\x00\x00\x10\x00" + "\x00\x00\x00\x00" + "\x5F\x0F\x3C\xF5" + "\x00\x00" + safeString16(unitsPerEm) + "\x00\x00\x00\x00\x9e\x0b\x7e\x27" + "\x00\x00\x00\x00\x9e\x0b\x7e\x27" + "\x00\x00" + safeString16(properties.descent) + "\x0F\xFF" + safeString16(properties.ascent) + string16(properties.italicAngle ? 2 : 0) + "\x00\x11" + "\x00\x00" + "\x00\x00" + "\x00\x00"); - builder.addTable("hhea", "\x00\x01\x00\x00" + safeString16(properties.ascent) + safeString16(properties.descent) + "\x00\x00" + "\xFF\xFF" + "\x00\x00" + "\x00\x00" + "\x00\x00" + safeString16(properties.capHeight) + safeString16(Math.tan(properties.italicAngle) * properties.xHeight) + "\x00\x00" + "\x00\x00" + "\x00\x00" + "\x00\x00" + "\x00\x00" + "\x00\x00" + string16(numGlyphs)); - builder.addTable("hmtx", function fontFieldsHmtx() { - var charstrings = font.charstrings; - var cffWidths = font.cff ? font.cff.widths : null; - var hmtx = "\x00\x00\x00\x00"; - - for (let i = 1, ii = numGlyphs; i < ii; i++) { - var width = 0; - - if (charstrings) { - var charstring = charstrings[i - 1]; - width = "width" in charstring ? charstring.width : 0; - } else if (cffWidths) { - width = Math.ceil(cffWidths[i] || 0); - } - - hmtx += string16(width) + string16(0); - } - - return hmtx; - }()); - builder.addTable("maxp", "\x00\x00\x50\x00" + string16(numGlyphs)); - builder.addTable("name", createNameTable(fontName)); - builder.addTable("post", createPostTable(properties)); - return builder.toArray(); - }, - - get spaceWidth() { - var possibleSpaceReplacements = ["space", "minus", "one", "i", "I"]; - var width; - - for (var i = 0, ii = possibleSpaceReplacements.length; i < ii; i++) { - var glyphName = possibleSpaceReplacements[i]; - - if (glyphName in this.widths) { - width = this.widths[glyphName]; - break; - } - - var glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); - var glyphUnicode = glyphsUnicodeMap[glyphName]; - var charcode = 0; - - if (this.composite && this.cMap.contains(glyphUnicode)) { - charcode = this.cMap.lookup(glyphUnicode); - } - - if (!charcode && this.toUnicode) { - charcode = this.toUnicode.charCodeOf(glyphUnicode); - } - - if (charcode <= 0) { - charcode = glyphUnicode; - } - - width = this.widths[charcode]; - - if (width) { - break; - } - } - - width = width || this.defaultWidth; - return (0, _util.shadow)(this, "spaceWidth", width); - }, - - charToGlyph: function Font_charToGlyph(charcode, isSpace) { - var fontCharCode, width, operatorListId; - var widthCode = charcode; - - if (this.cMap && this.cMap.contains(charcode)) { - widthCode = this.cMap.lookup(charcode); - } - - width = this.widths[widthCode]; - width = (0, _util.isNum)(width) ? width : this.defaultWidth; - var vmetric = this.vmetrics && this.vmetrics[widthCode]; - let unicode = this.toUnicode.get(charcode) || this.fallbackToUnicode.get(charcode) || charcode; - - if (typeof unicode === "number") { - unicode = String.fromCharCode(unicode); - } - - var isInFont = (charcode in this.toFontChar); - fontCharCode = this.toFontChar[charcode] || charcode; - - if (this.missingFile) { - const glyphName = this.differences[charcode] || this.defaultEncoding[charcode]; - - if ((glyphName === ".notdef" || glyphName === "") && this.type === "Type1") { - fontCharCode = 0x20; - } - - fontCharCode = (0, _unicode.mapSpecialUnicodeValues)(fontCharCode); - } - - if (this.isType3Font) { - operatorListId = fontCharCode; - } - - var accent = null; - - if (this.seacMap && this.seacMap[charcode]) { - isInFont = true; - var seac = this.seacMap[charcode]; - fontCharCode = seac.baseFontCharCode; - accent = { - fontChar: String.fromCodePoint(seac.accentFontCharCode), - offset: seac.accentOffset - }; - } - - let fontChar = ""; - - if (typeof fontCharCode === "number") { - if (fontCharCode <= 0x10ffff) { - fontChar = String.fromCodePoint(fontCharCode); - } else { - (0, _util.warn)(`charToGlyph - invalid fontCharCode: ${fontCharCode}`); - } - } - - var glyph = this.glyphCache[charcode]; - - if (!glyph || !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont)) { - glyph = new Glyph(fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont); - this.glyphCache[charcode] = glyph; - } - - return glyph; - }, - charsToGlyphs: function Font_charsToGlyphs(chars) { - var charsCache = this.charsCache; - var glyphs, glyph, charcode; - - if (charsCache) { - glyphs = charsCache[chars]; - - if (glyphs) { - return glyphs; - } - } - - if (!charsCache) { - charsCache = this.charsCache = Object.create(null); - } - - glyphs = []; - var charsCacheKey = chars; - var i = 0, - ii; - - if (this.cMap) { - var c = Object.create(null); - - while (i < chars.length) { - this.cMap.readCharCode(chars, i, c); - charcode = c.charcode; - var length = c.length; - i += length; - var isSpace = length === 1 && chars.charCodeAt(i - 1) === 0x20; - glyph = this.charToGlyph(charcode, isSpace); - glyphs.push(glyph); - } - } else { - for (i = 0, ii = chars.length; i < ii; ++i) { - charcode = chars.charCodeAt(i); - glyph = this.charToGlyph(charcode, charcode === 0x20); - glyphs.push(glyph); - } - } - - return charsCache[charsCacheKey] = glyphs; - }, - - get glyphCacheValues() { - return Object.values(this.glyphCache); } - }; - return Font; -}(); + if (!isTrueType) { + try { + cffFile = new _stream.Stream(tables["CFF "].data); + const parser = new _cff_parser.CFFParser(cffFile, properties, _fonts_utils.SEAC_ANALYSIS_ENABLED); + cff = parser.parse(); + cff.duplicateFirstGlyph(); + const compiler = new _cff_parser.CFFCompiler(cff); + tables["CFF "].data = compiler.compile(); + } catch (e) { + (0, _util.warn)("Failed to compile font " + properties.loadedName); + } + } + + if (!tables.name) { + tables.name = { + tag: "name", + data: createNameTable(this.name) + }; + } else { + const namePrototype = readNameTable(tables.name); + tables.name.data = createNameTable(name, namePrototype); + this.psName = namePrototype[0][6] || null; + } + + const builder = new _opentype_file_builder.OpenTypeFileBuilder(header.version); + + for (const tableTag in tables) { + builder.addTable(tableTag, tables[tableTag].data); + } + + return builder.toArray(); + } + + convert(fontName, font, properties) { + properties.fixedPitch = false; + + if (properties.builtInEncoding) { + adjustToUnicode(properties, properties.builtInEncoding); + } + + let glyphZeroId = 1; + + if (font instanceof _cff_font.CFFFont) { + glyphZeroId = font.numGlyphs - 1; + } + + const mapping = font.getGlyphMapping(properties); + let newMapping = null; + let newCharCodeToGlyphId = mapping; + let toUnicodeExtraMap = null; + + if (!properties.cssFontInfo) { + newMapping = adjustMapping(mapping, font.hasGlyphId.bind(font), glyphZeroId, this.toUnicode); + this.toFontChar = newMapping.toFontChar; + newCharCodeToGlyphId = newMapping.charCodeToGlyphId; + toUnicodeExtraMap = newMapping.toUnicodeExtraMap; + } + + const numGlyphs = font.numGlyphs; + + function getCharCodes(charCodeToGlyphId, glyphId) { + let charCodes = null; + + for (const charCode in charCodeToGlyphId) { + if (glyphId === charCodeToGlyphId[charCode]) { + if (!charCodes) { + charCodes = []; + } + + charCodes.push(charCode | 0); + } + } + + return charCodes; + } + + function createCharCode(charCodeToGlyphId, glyphId) { + for (const charCode in charCodeToGlyphId) { + if (glyphId === charCodeToGlyphId[charCode]) { + return charCode | 0; + } + } + + newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] = glyphId; + return newMapping.nextAvailableFontCharCode++; + } + + const seacs = font.seacs; + + if (newMapping && _fonts_utils.SEAC_ANALYSIS_ENABLED && seacs && seacs.length) { + const matrix = properties.fontMatrix || _util.FONT_IDENTITY_MATRIX; + const charset = font.getCharset(); + const seacMap = Object.create(null); + + for (let glyphId in seacs) { + glyphId |= 0; + const seac = seacs[glyphId]; + const baseGlyphName = _encodings.StandardEncoding[seac[2]]; + const accentGlyphName = _encodings.StandardEncoding[seac[3]]; + const baseGlyphId = charset.indexOf(baseGlyphName); + const accentGlyphId = charset.indexOf(accentGlyphName); + + if (baseGlyphId < 0 || accentGlyphId < 0) { + continue; + } + + const accentOffset = { + x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4], + y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5] + }; + const charCodes = getCharCodes(mapping, glyphId); + + if (!charCodes) { + continue; + } + + for (let i = 0, ii = charCodes.length; i < ii; i++) { + const charCode = charCodes[i]; + const charCodeToGlyphId = newMapping.charCodeToGlyphId; + const baseFontCharCode = createCharCode(charCodeToGlyphId, baseGlyphId); + const accentFontCharCode = createCharCode(charCodeToGlyphId, accentGlyphId); + seacMap[charCode] = { + baseFontCharCode, + accentFontCharCode, + accentOffset + }; + } + } + + properties.seacMap = seacMap; + } + + const unitsPerEm = 1 / (properties.fontMatrix || _util.FONT_IDENTITY_MATRIX)[0]; + const builder = new _opentype_file_builder.OpenTypeFileBuilder("\x4F\x54\x54\x4F"); + builder.addTable("CFF ", font.data); + builder.addTable("OS/2", createOS2Table(properties, newCharCodeToGlyphId)); + builder.addTable("cmap", createCmapTable(newCharCodeToGlyphId, toUnicodeExtraMap, numGlyphs)); + builder.addTable("head", "\x00\x01\x00\x00" + "\x00\x00\x10\x00" + "\x00\x00\x00\x00" + "\x5F\x0F\x3C\xF5" + "\x00\x00" + safeString16(unitsPerEm) + "\x00\x00\x00\x00\x9e\x0b\x7e\x27" + "\x00\x00\x00\x00\x9e\x0b\x7e\x27" + "\x00\x00" + safeString16(properties.descent) + "\x0F\xFF" + safeString16(properties.ascent) + string16(properties.italicAngle ? 2 : 0) + "\x00\x11" + "\x00\x00" + "\x00\x00" + "\x00\x00"); + builder.addTable("hhea", "\x00\x01\x00\x00" + safeString16(properties.ascent) + safeString16(properties.descent) + "\x00\x00" + "\xFF\xFF" + "\x00\x00" + "\x00\x00" + "\x00\x00" + safeString16(properties.capHeight) + safeString16(Math.tan(properties.italicAngle) * properties.xHeight) + "\x00\x00" + "\x00\x00" + "\x00\x00" + "\x00\x00" + "\x00\x00" + "\x00\x00" + string16(numGlyphs)); + builder.addTable("hmtx", function fontFieldsHmtx() { + const charstrings = font.charstrings; + const cffWidths = font.cff ? font.cff.widths : null; + let hmtx = "\x00\x00\x00\x00"; + + for (let i = 1, ii = numGlyphs; i < ii; i++) { + let width = 0; + + if (charstrings) { + const charstring = charstrings[i - 1]; + width = "width" in charstring ? charstring.width : 0; + } else if (cffWidths) { + width = Math.ceil(cffWidths[i] || 0); + } + + hmtx += string16(width) + string16(0); + } + + return hmtx; + }()); + builder.addTable("maxp", "\x00\x00\x50\x00" + string16(numGlyphs)); + builder.addTable("name", createNameTable(fontName)); + builder.addTable("post", createPostTable(properties)); + return builder.toArray(); + } + + get spaceWidth() { + const possibleSpaceReplacements = ["space", "minus", "one", "i", "I"]; + let width; + + for (let i = 0, ii = possibleSpaceReplacements.length; i < ii; i++) { + const glyphName = possibleSpaceReplacements[i]; + + if (glyphName in this.widths) { + width = this.widths[glyphName]; + break; + } + + const glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + const glyphUnicode = glyphsUnicodeMap[glyphName]; + let charcode = 0; + + if (this.composite && this.cMap.contains(glyphUnicode)) { + charcode = this.cMap.lookup(glyphUnicode); + + if (typeof charcode === "string") { + charcode = convertCidString(glyphUnicode, charcode); + } + } + + if (!charcode && this.toUnicode) { + charcode = this.toUnicode.charCodeOf(glyphUnicode); + } + + if (charcode <= 0) { + charcode = glyphUnicode; + } + + width = this.widths[charcode]; + + if (width) { + break; + } + } + + width = width || this.defaultWidth; + return (0, _util.shadow)(this, "spaceWidth", width); + } + + _charToGlyph(charcode, isSpace = false) { + let fontCharCode, width, operatorListId; + let widthCode = charcode; + + if (this.cMap && this.cMap.contains(charcode)) { + widthCode = this.cMap.lookup(charcode); + + if (typeof widthCode === "string") { + widthCode = convertCidString(charcode, widthCode); + } + } + + width = this.widths[widthCode]; + + if (typeof width !== "number") { + width = this.defaultWidth; + } + + const vmetric = this.vmetrics && this.vmetrics[widthCode]; + let unicode = this.toUnicode.get(charcode) || charcode; + + if (typeof unicode === "number") { + unicode = String.fromCharCode(unicode); + } + + let isInFont = this.toFontChar[charcode] !== undefined; + fontCharCode = this.toFontChar[charcode] || charcode; + + if (this.missingFile) { + const glyphName = this.differences[charcode] || this.defaultEncoding[charcode]; + + if ((glyphName === ".notdef" || glyphName === "") && this.type === "Type1") { + fontCharCode = 0x20; + } + + fontCharCode = (0, _unicode.mapSpecialUnicodeValues)(fontCharCode); + } + + if (this.isType3Font) { + operatorListId = fontCharCode; + } + + let accent = null; + + if (this.seacMap && this.seacMap[charcode]) { + isInFont = true; + const seac = this.seacMap[charcode]; + fontCharCode = seac.baseFontCharCode; + accent = { + fontChar: String.fromCodePoint(seac.accentFontCharCode), + offset: seac.accentOffset + }; + } + + let fontChar = ""; + + if (typeof fontCharCode === "number") { + if (fontCharCode <= 0x10ffff) { + fontChar = String.fromCodePoint(fontCharCode); + } else { + (0, _util.warn)(`charToGlyph - invalid fontCharCode: ${fontCharCode}`); + } + } + + let glyph = this._glyphCache[charcode]; + + if (!glyph || !glyph.matchesForCache(charcode, fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont)) { + glyph = new Glyph(charcode, fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont); + this._glyphCache[charcode] = glyph; + } + + return glyph; + } + + charsToGlyphs(chars) { + let glyphs = this._charsCache[chars]; + + if (glyphs) { + return glyphs; + } + + glyphs = []; + + if (this.cMap) { + const c = Object.create(null), + ii = chars.length; + let i = 0; + + while (i < ii) { + this.cMap.readCharCode(chars, i, c); + const { + charcode, + length + } = c; + i += length; + + const glyph = this._charToGlyph(charcode, length === 1 && chars.charCodeAt(i - 1) === 0x20); + + glyphs.push(glyph); + } + } else { + for (let i = 0, ii = chars.length; i < ii; ++i) { + const charcode = chars.charCodeAt(i); + + const glyph = this._charToGlyph(charcode, charcode === 0x20); + + glyphs.push(glyph); + } + } + + return this._charsCache[chars] = glyphs; + } + + getCharPositions(chars) { + const positions = []; + + if (this.cMap) { + const c = Object.create(null); + let i = 0; + + while (i < chars.length) { + this.cMap.readCharCode(chars, i, c); + const length = c.length; + positions.push([i, i + length]); + i += length; + } + } else { + for (let i = 0, ii = chars.length; i < ii; ++i) { + positions.push([i, i + 1]); + } + } + + return positions; + } + + get glyphCacheValues() { + return Object.values(this._glyphCache); + } + + encodeString(str) { + const buffers = []; + const currentBuf = []; + + const hasCurrentBufErrors = () => buffers.length % 2 === 1; + + const getCharCode = this.toUnicode instanceof _to_unicode_map.IdentityToUnicodeMap ? unicode => this.toUnicode.charCodeOf(unicode) : unicode => this.toUnicode.charCodeOf(String.fromCodePoint(unicode)); + + for (let i = 0, ii = str.length; i < ii; i++) { + const unicode = str.codePointAt(i); + + if (unicode > 0xd7ff && (unicode < 0xe000 || unicode > 0xfffd)) { + i++; + } + + if (this.toUnicode) { + const charCode = getCharCode(unicode); + + if (charCode !== -1) { + if (hasCurrentBufErrors()) { + buffers.push(currentBuf.join("")); + currentBuf.length = 0; + } + + const charCodeLength = this.cMap ? this.cMap.getCharCodeLength(charCode) : 1; + + for (let j = charCodeLength - 1; j >= 0; j--) { + currentBuf.push(String.fromCharCode(charCode >> 8 * j & 0xff)); + } + + continue; + } + } + + if (!hasCurrentBufErrors()) { + buffers.push(currentBuf.join("")); + currentBuf.length = 0; + } + + currentBuf.push(String.fromCodePoint(unicode)); + } + + buffers.push(currentBuf.join("")); + return buffers; + } + +} exports.Font = Font; -var ErrorFont = function ErrorFontClosure() { - function ErrorFont(error) { +class ErrorFont { + constructor(error) { this.error = error; this.loadedName = "g_font_error"; this.missingFile = true; } - ErrorFont.prototype = { - charsToGlyphs: function ErrorFont_charsToGlyphs() { - return []; - }, + charsToGlyphs() { + return []; + } - exportData(extraProperties = false) { - return { - error: this.error - }; - } + encodeString(chars) { + return [chars]; + } - }; - return ErrorFont; -}(); + exportData(extraProperties = false) { + return { + error: this.error + }; + } + +} exports.ErrorFont = ErrorFont; -function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) { - var charCodeToGlyphId = Object.create(null); - var glyphId, charCode, baseEncoding; - var isSymbolicFont = !!(properties.flags & FontFlags.Symbolic); - - if (properties.baseEncodingName) { - baseEncoding = (0, _encodings.getEncoding)(properties.baseEncodingName); - - for (charCode = 0; charCode < baseEncoding.length; charCode++) { - glyphId = glyphNames.indexOf(baseEncoding[charCode]); - - if (glyphId >= 0) { - charCodeToGlyphId[charCode] = glyphId; - } else { - charCodeToGlyphId[charCode] = 0; - } - } - } else if (isSymbolicFont) { - for (charCode in builtInEncoding) { - charCodeToGlyphId[charCode] = builtInEncoding[charCode]; - } - } else { - baseEncoding = _encodings.StandardEncoding; - - for (charCode = 0; charCode < baseEncoding.length; charCode++) { - glyphId = glyphNames.indexOf(baseEncoding[charCode]); - - if (glyphId >= 0) { - charCodeToGlyphId[charCode] = glyphId; - } else { - charCodeToGlyphId[charCode] = 0; - } - } - } - - var differences = properties.differences, - glyphsUnicodeMap; - - if (differences) { - for (charCode in differences) { - var glyphName = differences[charCode]; - glyphId = glyphNames.indexOf(glyphName); - - if (glyphId === -1) { - if (!glyphsUnicodeMap) { - glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); - } - - var standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap); - - if (standardGlyphName !== glyphName) { - glyphId = glyphNames.indexOf(standardGlyphName); - } - } - - if (glyphId >= 0) { - charCodeToGlyphId[charCode] = glyphId; - } else { - charCodeToGlyphId[charCode] = 0; - } - } - } - - return charCodeToGlyphId; -} - -var Type1Font = function Type1FontClosure() { - function findBlock(streamBytes, signature, startIndex) { - var streamBytesLength = streamBytes.length; - var signatureLength = signature.length; - var scanLength = streamBytesLength - signatureLength; - var i = startIndex, - j, - found = false; - - while (i < scanLength) { - j = 0; - - while (j < signatureLength && streamBytes[i + j] === signature[j]) { - j++; - } - - if (j >= signatureLength) { - i += j; - - while (i < streamBytesLength && (0, _core_utils.isWhiteSpace)(streamBytes[i])) { - i++; - } - - found = true; - break; - } - - i++; - } - - return { - found, - length: i - }; - } - - function getHeaderBlock(stream, suggestedLength) { - var EEXEC_SIGNATURE = [0x65, 0x65, 0x78, 0x65, 0x63]; - var streamStartPos = stream.pos; - var headerBytes, headerBytesLength, block; - - try { - headerBytes = stream.getBytes(suggestedLength); - headerBytesLength = headerBytes.length; - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - } - - if (headerBytesLength === suggestedLength) { - block = findBlock(headerBytes, EEXEC_SIGNATURE, suggestedLength - 2 * EEXEC_SIGNATURE.length); - - if (block.found && block.length === suggestedLength) { - return { - stream: new _stream.Stream(headerBytes), - length: suggestedLength - }; - } - } - - (0, _util.warn)('Invalid "Length1" property in Type1 font -- trying to recover.'); - stream.pos = streamStartPos; - var SCAN_BLOCK_LENGTH = 2048; - var actualLength; - - while (true) { - var scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH); - block = findBlock(scanBytes, EEXEC_SIGNATURE, 0); - - if (block.length === 0) { - break; - } - - stream.pos += block.length; - - if (block.found) { - actualLength = stream.pos - streamStartPos; - break; - } - } - - stream.pos = streamStartPos; - - if (actualLength) { - return { - stream: new _stream.Stream(stream.getBytes(actualLength)), - length: actualLength - }; - } - - (0, _util.warn)('Unable to recover "Length1" property in Type1 font -- using as is.'); - return { - stream: new _stream.Stream(stream.getBytes(suggestedLength)), - length: suggestedLength - }; - } - - function getEexecBlock(stream, suggestedLength) { - var eexecBytes = stream.getBytes(); - return { - stream: new _stream.Stream(eexecBytes), - length: eexecBytes.length - }; - } - - function Type1Font(name, file, properties) { - var PFB_HEADER_SIZE = 6; - var headerBlockLength = properties.length1; - var eexecBlockLength = properties.length2; - var pfbHeader = file.peekBytes(PFB_HEADER_SIZE); - var pfbHeaderPresent = pfbHeader[0] === 0x80 && pfbHeader[1] === 0x01; - - if (pfbHeaderPresent) { - file.skip(PFB_HEADER_SIZE); - headerBlockLength = pfbHeader[5] << 24 | pfbHeader[4] << 16 | pfbHeader[3] << 8 | pfbHeader[2]; - } - - var headerBlock = getHeaderBlock(file, headerBlockLength); - var headerBlockParser = new _type1_parser.Type1Parser(headerBlock.stream, false, SEAC_ANALYSIS_ENABLED); - headerBlockParser.extractFontHeader(properties); - - if (pfbHeaderPresent) { - pfbHeader = file.getBytes(PFB_HEADER_SIZE); - eexecBlockLength = pfbHeader[5] << 24 | pfbHeader[4] << 16 | pfbHeader[3] << 8 | pfbHeader[2]; - } - - var eexecBlock = getEexecBlock(file, eexecBlockLength); - var eexecBlockParser = new _type1_parser.Type1Parser(eexecBlock.stream, true, SEAC_ANALYSIS_ENABLED); - var data = eexecBlockParser.extractFontProgram(properties); - - for (const key in data.properties) { - properties[key] = data.properties[key]; - } - - var charstrings = data.charstrings; - var type2Charstrings = this.getType2Charstrings(charstrings); - var subrs = this.getType2Subrs(data.subrs); - this.charstrings = charstrings; - this.data = this.wrap(name, type2Charstrings, this.charstrings, subrs, properties); - this.seacs = this.getSeacs(data.charstrings); - } - - Type1Font.prototype = { - get numGlyphs() { - return this.charstrings.length + 1; - }, - - getCharset: function Type1Font_getCharset() { - var charset = [".notdef"]; - var charstrings = this.charstrings; - - for (var glyphId = 0; glyphId < charstrings.length; glyphId++) { - charset.push(charstrings[glyphId].glyphName); - } - - return charset; - }, - getGlyphMapping: function Type1Font_getGlyphMapping(properties) { - var charstrings = this.charstrings; - - if (properties.composite) { - const charCodeToGlyphId = Object.create(null); - - for (let glyphId = 0, charstringsLen = charstrings.length; glyphId < charstringsLen; glyphId++) { - const charCode = properties.cMap.charCodeOf(glyphId); - charCodeToGlyphId[charCode] = glyphId + 1; - } - - return charCodeToGlyphId; - } - - var glyphNames = [".notdef"], - glyphId; - - for (glyphId = 0; glyphId < charstrings.length; glyphId++) { - glyphNames.push(charstrings[glyphId].glyphName); - } - - var encoding = properties.builtInEncoding; - - if (encoding) { - var builtInEncoding = Object.create(null); - - for (var charCode in encoding) { - glyphId = glyphNames.indexOf(encoding[charCode]); - - if (glyphId >= 0) { - builtInEncoding[charCode] = glyphId; - } - } - } - - return type1FontGlyphMapping(properties, builtInEncoding, glyphNames); - }, - hasGlyphId: function Type1Font_hasGlyphID(id) { - if (id < 0 || id >= this.numGlyphs) { - return false; - } - - if (id === 0) { - return true; - } - - var glyph = this.charstrings[id - 1]; - return glyph.charstring.length > 0; - }, - getSeacs: function Type1Font_getSeacs(charstrings) { - var i, ii; - var seacMap = []; - - for (i = 0, ii = charstrings.length; i < ii; i++) { - var charstring = charstrings[i]; - - if (charstring.seac) { - seacMap[i + 1] = charstring.seac; - } - } - - return seacMap; - }, - getType2Charstrings: function Type1Font_getType2Charstrings(type1Charstrings) { - var type2Charstrings = []; - - for (var i = 0, ii = type1Charstrings.length; i < ii; i++) { - type2Charstrings.push(type1Charstrings[i].charstring); - } - - return type2Charstrings; - }, - getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) { - var bias = 0; - var count = type1Subrs.length; - - if (count < 1133) { - bias = 107; - } else if (count < 33769) { - bias = 1131; - } else { - bias = 32768; - } - - var type2Subrs = []; - var i; - - for (i = 0; i < bias; i++) { - type2Subrs.push([0x0b]); - } - - for (i = 0; i < count; i++) { - type2Subrs.push(type1Subrs[i]); - } - - return type2Subrs; - }, - wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) { - var cff = new _cff_parser.CFF(); - cff.header = new _cff_parser.CFFHeader(1, 0, 4, 4); - cff.names = [name]; - var topDict = new _cff_parser.CFFTopDict(); - topDict.setByName("version", 391); - topDict.setByName("Notice", 392); - topDict.setByName("FullName", 393); - topDict.setByName("FamilyName", 394); - topDict.setByName("Weight", 395); - topDict.setByName("Encoding", null); - topDict.setByName("FontMatrix", properties.fontMatrix); - topDict.setByName("FontBBox", properties.bbox); - topDict.setByName("charset", null); - topDict.setByName("CharStrings", null); - topDict.setByName("Private", null); - cff.topDict = topDict; - var strings = new _cff_parser.CFFStrings(); - strings.add("Version 0.11"); - strings.add("See original notice"); - strings.add(name); - strings.add(name); - strings.add("Medium"); - cff.strings = strings; - cff.globalSubrIndex = new _cff_parser.CFFIndex(); - var count = glyphs.length; - var charsetArray = [".notdef"]; - var i, ii; - - for (i = 0; i < count; i++) { - const glyphName = charstrings[i].glyphName; - - const index = _cff_parser.CFFStandardStrings.indexOf(glyphName); - - if (index === -1) { - strings.add(glyphName); - } - - charsetArray.push(glyphName); - } - - cff.charset = new _cff_parser.CFFCharset(false, 0, charsetArray); - var charStringsIndex = new _cff_parser.CFFIndex(); - charStringsIndex.add([0x8b, 0x0e]); - - for (i = 0; i < count; i++) { - charStringsIndex.add(glyphs[i]); - } - - cff.charStrings = charStringsIndex; - var privateDict = new _cff_parser.CFFPrivateDict(); - privateDict.setByName("Subrs", null); - var fields = ["BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StemSnapH", "StemSnapV", "BlueShift", "BlueFuzz", "BlueScale", "LanguageGroup", "ExpansionFactor", "ForceBold", "StdHW", "StdVW"]; - - for (i = 0, ii = fields.length; i < ii; i++) { - var field = fields[i]; - - if (!(field in properties.privateData)) { - continue; - } - - var value = properties.privateData[field]; - - if (Array.isArray(value)) { - for (var j = value.length - 1; j > 0; j--) { - value[j] -= value[j - 1]; - } - } - - privateDict.setByName(field, value); - } - - cff.topDict.privateDict = privateDict; - var subrIndex = new _cff_parser.CFFIndex(); - - for (i = 0, ii = subrs.length; i < ii; i++) { - subrIndex.add(subrs[i]); - } - - privateDict.subrsIndex = subrIndex; - var compiler = new _cff_parser.CFFCompiler(cff); - return compiler.compile(); - } - }; - return Type1Font; -}(); - -var CFFFont = function CFFFontClosure() { - function CFFFont(file, properties) { - this.properties = properties; - var parser = new _cff_parser.CFFParser(file, properties, SEAC_ANALYSIS_ENABLED); - this.cff = parser.parse(); - this.cff.duplicateFirstGlyph(); - var compiler = new _cff_parser.CFFCompiler(this.cff); - this.seacs = this.cff.seacs; - - try { - this.data = compiler.compile(); - } catch (e) { - (0, _util.warn)("Failed to compile font " + properties.loadedName); - this.data = file; - } - } - - CFFFont.prototype = { - get numGlyphs() { - return this.cff.charStrings.count; - }, - - getCharset: function CFFFont_getCharset() { - return this.cff.charset.charset; - }, - getGlyphMapping: function CFFFont_getGlyphMapping() { - var cff = this.cff; - var properties = this.properties; - var charsets = cff.charset.charset; - var charCodeToGlyphId; - var glyphId; - - if (properties.composite) { - charCodeToGlyphId = Object.create(null); - let charCode; - - if (cff.isCIDFont) { - for (glyphId = 0; glyphId < charsets.length; glyphId++) { - var cid = charsets[glyphId]; - charCode = properties.cMap.charCodeOf(cid); - charCodeToGlyphId[charCode] = glyphId; - } - } else { - for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) { - charCode = properties.cMap.charCodeOf(glyphId); - charCodeToGlyphId[charCode] = glyphId; - } - } - - return charCodeToGlyphId; - } - - var encoding = cff.encoding ? cff.encoding.encoding : null; - charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets); - return charCodeToGlyphId; - }, - hasGlyphId: function CFFFont_hasGlyphID(id) { - return this.cff.hasGlyphId(id); - } - }; - return CFFFont; -}(); - /***/ }), -/* 31 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 35 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.CFFFDSelect = exports.CFFCompiler = exports.CFFPrivateDict = exports.CFFTopDict = exports.CFFCharset = exports.CFFIndex = exports.CFFStrings = exports.CFFHeader = exports.CFF = exports.CFFParser = exports.CFFStandardStrings = void 0; +})); +exports.CFFTopDict = exports.CFFStrings = exports.CFFStandardStrings = exports.CFFPrivateDict = exports.CFFParser = exports.CFFIndex = exports.CFFHeader = exports.CFFFDSelect = exports.CFFCompiler = exports.CFFCharset = exports.CFF = void 0; var _util = __w_pdfjs_require__(2); -var _charsets = __w_pdfjs_require__(32); +var _charsets = __w_pdfjs_require__(36); -var _encodings = __w_pdfjs_require__(33); +var _encodings = __w_pdfjs_require__(37); -var MAX_SUBR_NESTING = 10; -var CFFStandardStrings = [".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"]; +const MAX_SUBR_NESTING = 10; +const CFFStandardStrings = [".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"]; exports.CFFStandardStrings = CFFStandardStrings; const NUM_STANDARD_CFF_STRINGS = 391; +const CharstringValidationData = [null, { + id: "hstem", + min: 2, + stackClearing: true, + stem: true +}, null, { + id: "vstem", + min: 2, + stackClearing: true, + stem: true +}, { + id: "vmoveto", + min: 1, + stackClearing: true +}, { + id: "rlineto", + min: 2, + resetStack: true +}, { + id: "hlineto", + min: 1, + resetStack: true +}, { + id: "vlineto", + min: 1, + resetStack: true +}, { + id: "rrcurveto", + min: 6, + resetStack: true +}, null, { + id: "callsubr", + min: 1, + undefStack: true +}, { + id: "return", + min: 0, + undefStack: true +}, null, null, { + id: "endchar", + min: 0, + stackClearing: true +}, null, null, null, { + id: "hstemhm", + min: 2, + stackClearing: true, + stem: true +}, { + id: "hintmask", + min: 0, + stackClearing: true +}, { + id: "cntrmask", + min: 0, + stackClearing: true +}, { + id: "rmoveto", + min: 2, + stackClearing: true +}, { + id: "hmoveto", + min: 1, + stackClearing: true +}, { + id: "vstemhm", + min: 2, + stackClearing: true, + stem: true +}, { + id: "rcurveline", + min: 8, + resetStack: true +}, { + id: "rlinecurve", + min: 8, + resetStack: true +}, { + id: "vvcurveto", + min: 4, + resetStack: true +}, { + id: "hhcurveto", + min: 4, + resetStack: true +}, null, { + id: "callgsubr", + min: 1, + undefStack: true +}, { + id: "vhcurveto", + min: 4, + resetStack: true +}, { + id: "hvcurveto", + min: 4, + resetStack: true +}]; +const CharstringValidationData12 = [null, null, null, { + id: "and", + min: 2, + stackDelta: -1 +}, { + id: "or", + min: 2, + stackDelta: -1 +}, { + id: "not", + min: 1, + stackDelta: 0 +}, null, null, null, { + id: "abs", + min: 1, + stackDelta: 0 +}, { + id: "add", + min: 2, + stackDelta: -1, -var CFFParser = function CFFParserClosure() { - var CharstringValidationData = [null, { - id: "hstem", - min: 2, - stackClearing: true, - stem: true - }, null, { - id: "vstem", - min: 2, - stackClearing: true, - stem: true - }, { - id: "vmoveto", - min: 1, - stackClearing: true - }, { - id: "rlineto", - min: 2, - resetStack: true - }, { - id: "hlineto", - min: 1, - resetStack: true - }, { - id: "vlineto", - min: 1, - resetStack: true - }, { - id: "rrcurveto", - min: 6, - resetStack: true - }, null, { - id: "callsubr", - min: 1, - undefStack: true - }, { - id: "return", - min: 0, - undefStack: true - }, null, null, { - id: "endchar", - min: 0, - stackClearing: true - }, null, null, null, { - id: "hstemhm", - min: 2, - stackClearing: true, - stem: true - }, { - id: "hintmask", - min: 0, - stackClearing: true - }, { - id: "cntrmask", - min: 0, - stackClearing: true - }, { - id: "rmoveto", - min: 2, - stackClearing: true - }, { - id: "hmoveto", - min: 1, - stackClearing: true - }, { - id: "vstemhm", - min: 2, - stackClearing: true, - stem: true - }, { - id: "rcurveline", - min: 8, - resetStack: true - }, { - id: "rlinecurve", - min: 8, - resetStack: true - }, { - id: "vvcurveto", - min: 4, - resetStack: true - }, { - id: "hhcurveto", - min: 4, - resetStack: true - }, null, { - id: "callgsubr", - min: 1, - undefStack: true - }, { - id: "vhcurveto", - min: 4, - resetStack: true - }, { - id: "hvcurveto", - min: 4, - resetStack: true - }]; - var CharstringValidationData12 = [null, null, null, { - id: "and", - min: 2, - stackDelta: -1 - }, { - id: "or", - min: 2, - stackDelta: -1 - }, { - id: "not", - min: 1, - stackDelta: 0 - }, null, null, null, { - id: "abs", - min: 1, - stackDelta: 0 - }, { - id: "add", - min: 2, - stackDelta: -1, - stackFn: function stack_div(stack, index) { - stack[index - 2] = stack[index - 2] + stack[index - 1]; - } - }, { - id: "sub", - min: 2, - stackDelta: -1, - stackFn: function stack_div(stack, index) { - stack[index - 2] = stack[index - 2] - stack[index - 1]; - } - }, { - id: "div", - min: 2, - stackDelta: -1, - stackFn: function stack_div(stack, index) { - stack[index - 2] = stack[index - 2] / stack[index - 1]; - } - }, null, { - id: "neg", - min: 1, - stackDelta: 0, - stackFn: function stack_div(stack, index) { - stack[index - 1] = -stack[index - 1]; - } - }, { - id: "eq", - min: 2, - stackDelta: -1 - }, null, null, { - id: "drop", - min: 1, - stackDelta: -1 - }, null, { - id: "put", - min: 2, - stackDelta: -2 - }, { - id: "get", - min: 1, - stackDelta: 0 - }, { - id: "ifelse", - min: 4, - stackDelta: -3 - }, { - id: "random", - min: 0, - stackDelta: 1 - }, { - id: "mul", - min: 2, - stackDelta: -1, - stackFn: function stack_div(stack, index) { - stack[index - 2] = stack[index - 2] * stack[index - 1]; - } - }, null, { - id: "sqrt", - min: 1, - stackDelta: 0 - }, { - id: "dup", - min: 1, - stackDelta: 1 - }, { - id: "exch", - min: 2, - stackDelta: 0 - }, { - id: "index", - min: 2, - stackDelta: 0 - }, { - id: "roll", - min: 3, - stackDelta: -2 - }, null, null, null, { - id: "hflex", - min: 7, - resetStack: true - }, { - id: "flex", - min: 13, - resetStack: true - }, { - id: "hflex1", - min: 9, - resetStack: true - }, { - id: "flex1", - min: 11, - resetStack: true - }]; + stackFn(stack, index) { + stack[index - 2] = stack[index - 2] + stack[index - 1]; + } - class CFFParser { - constructor(file, properties, seacAnalysisEnabled) { - this.bytes = file.getBytes(); - this.properties = properties; - this.seacAnalysisEnabled = !!seacAnalysisEnabled; +}, { + id: "sub", + min: 2, + stackDelta: -1, + + stackFn(stack, index) { + stack[index - 2] = stack[index - 2] - stack[index - 1]; + } + +}, { + id: "div", + min: 2, + stackDelta: -1, + + stackFn(stack, index) { + stack[index - 2] = stack[index - 2] / stack[index - 1]; + } + +}, null, { + id: "neg", + min: 1, + stackDelta: 0, + + stackFn(stack, index) { + stack[index - 1] = -stack[index - 1]; + } + +}, { + id: "eq", + min: 2, + stackDelta: -1 +}, null, null, { + id: "drop", + min: 1, + stackDelta: -1 +}, null, { + id: "put", + min: 2, + stackDelta: -2 +}, { + id: "get", + min: 1, + stackDelta: 0 +}, { + id: "ifelse", + min: 4, + stackDelta: -3 +}, { + id: "random", + min: 0, + stackDelta: 1 +}, { + id: "mul", + min: 2, + stackDelta: -1, + + stackFn(stack, index) { + stack[index - 2] = stack[index - 2] * stack[index - 1]; + } + +}, null, { + id: "sqrt", + min: 1, + stackDelta: 0 +}, { + id: "dup", + min: 1, + stackDelta: 1 +}, { + id: "exch", + min: 2, + stackDelta: 0 +}, { + id: "index", + min: 2, + stackDelta: 0 +}, { + id: "roll", + min: 3, + stackDelta: -2 +}, null, null, null, { + id: "hflex", + min: 7, + resetStack: true +}, { + id: "flex", + min: 13, + resetStack: true +}, { + id: "hflex1", + min: 9, + resetStack: true +}, { + id: "flex1", + min: 11, + resetStack: true +}]; + +class CFFParser { + constructor(file, properties, seacAnalysisEnabled) { + this.bytes = file.getBytes(); + this.properties = properties; + this.seacAnalysisEnabled = !!seacAnalysisEnabled; + } + + parse() { + const properties = this.properties; + const cff = new CFF(); + this.cff = cff; + const header = this.parseHeader(); + const nameIndex = this.parseIndex(header.endPos); + const topDictIndex = this.parseIndex(nameIndex.endPos); + const stringIndex = this.parseIndex(topDictIndex.endPos); + const globalSubrIndex = this.parseIndex(stringIndex.endPos); + const topDictParsed = this.parseDict(topDictIndex.obj.get(0)); + const topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings); + cff.header = header.obj; + cff.names = this.parseNameIndex(nameIndex.obj); + cff.strings = this.parseStringIndex(stringIndex.obj); + cff.topDict = topDict; + cff.globalSubrIndex = globalSubrIndex.obj; + this.parsePrivateDict(cff.topDict); + cff.isCIDFont = topDict.hasName("ROS"); + const charStringOffset = topDict.getByName("CharStrings"); + const charStringIndex = this.parseIndex(charStringOffset).obj; + const fontMatrix = topDict.getByName("FontMatrix"); + + if (fontMatrix) { + properties.fontMatrix = fontMatrix; } - parse() { - var properties = this.properties; - var cff = new CFF(); - this.cff = cff; - var header = this.parseHeader(); - var nameIndex = this.parseIndex(header.endPos); - var topDictIndex = this.parseIndex(nameIndex.endPos); - var stringIndex = this.parseIndex(topDictIndex.endPos); - var globalSubrIndex = this.parseIndex(stringIndex.endPos); - var topDictParsed = this.parseDict(topDictIndex.obj.get(0)); - var topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings); - cff.header = header.obj; - cff.names = this.parseNameIndex(nameIndex.obj); - cff.strings = this.parseStringIndex(stringIndex.obj); - cff.topDict = topDict; - cff.globalSubrIndex = globalSubrIndex.obj; - this.parsePrivateDict(cff.topDict); - cff.isCIDFont = topDict.hasName("ROS"); - var charStringOffset = topDict.getByName("CharStrings"); - var charStringIndex = this.parseIndex(charStringOffset).obj; - var fontMatrix = topDict.getByName("FontMatrix"); + const fontBBox = topDict.getByName("FontBBox"); - if (fontMatrix) { - properties.fontMatrix = fontMatrix; + if (fontBBox) { + properties.ascent = Math.max(fontBBox[3], fontBBox[1]); + properties.descent = Math.min(fontBBox[1], fontBBox[3]); + properties.ascentScaled = true; + } + + let charset, encoding; + + if (cff.isCIDFont) { + const fdArrayIndex = this.parseIndex(topDict.getByName("FDArray")).obj; + + for (let i = 0, ii = fdArrayIndex.count; i < ii; ++i) { + const dictRaw = fdArrayIndex.get(i); + const fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw), cff.strings); + this.parsePrivateDict(fontDict); + cff.fdArray.push(fontDict); } - var fontBBox = topDict.getByName("FontBBox"); + encoding = null; + charset = this.parseCharsets(topDict.getByName("charset"), charStringIndex.count, cff.strings, true); + cff.fdSelect = this.parseFDSelect(topDict.getByName("FDSelect"), charStringIndex.count); + } else { + charset = this.parseCharsets(topDict.getByName("charset"), charStringIndex.count, cff.strings, false); + encoding = this.parseEncoding(topDict.getByName("Encoding"), properties, cff.strings, charset.charset); + } - if (fontBBox) { - properties.ascent = Math.max(fontBBox[3], fontBBox[1]); - properties.descent = Math.min(fontBBox[1], fontBBox[3]); - properties.ascentScaled = true; + cff.charset = charset; + cff.encoding = encoding; + const charStringsAndSeacs = this.parseCharStrings({ + charStrings: charStringIndex, + localSubrIndex: topDict.privateDict.subrsIndex, + globalSubrIndex: globalSubrIndex.obj, + fdSelect: cff.fdSelect, + fdArray: cff.fdArray, + privateDict: topDict.privateDict + }); + cff.charStrings = charStringsAndSeacs.charStrings; + cff.seacs = charStringsAndSeacs.seacs; + cff.widths = charStringsAndSeacs.widths; + return cff; + } + + parseHeader() { + let bytes = this.bytes; + const bytesLength = bytes.length; + let offset = 0; + + while (offset < bytesLength && bytes[offset] !== 1) { + ++offset; + } + + if (offset >= bytesLength) { + throw new _util.FormatError("Invalid CFF header"); + } + + if (offset !== 0) { + (0, _util.info)("cff data is shifted"); + bytes = bytes.subarray(offset); + this.bytes = bytes; + } + + const major = bytes[0]; + const minor = bytes[1]; + const hdrSize = bytes[2]; + const offSize = bytes[3]; + const header = new CFFHeader(major, minor, hdrSize, offSize); + return { + obj: header, + endPos: hdrSize + }; + } + + parseDict(dict) { + let pos = 0; + + function parseOperand() { + let value = dict[pos++]; + + if (value === 30) { + return parseFloatOperand(); + } else if (value === 28) { + value = dict[pos++]; + value = (value << 24 | dict[pos++] << 16) >> 16; + return value; + } else if (value === 29) { + value = dict[pos++]; + value = value << 8 | dict[pos++]; + value = value << 8 | dict[pos++]; + value = value << 8 | dict[pos++]; + return value; + } else if (value >= 32 && value <= 246) { + return value - 139; + } else if (value >= 247 && value <= 250) { + return (value - 247) * 256 + dict[pos++] + 108; + } else if (value >= 251 && value <= 254) { + return -((value - 251) * 256) - dict[pos++] - 108; } - var charset, encoding; + (0, _util.warn)('CFFParser_parseDict: "' + value + '" is a reserved command.'); + return NaN; + } - if (cff.isCIDFont) { - var fdArrayIndex = this.parseIndex(topDict.getByName("FDArray")).obj; + function parseFloatOperand() { + let str = ""; + const eof = 15; + const lookup = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "E", "E-", null, "-"]; + const length = dict.length; - for (var i = 0, ii = fdArrayIndex.count; i < ii; ++i) { - var dictRaw = fdArrayIndex.get(i); - var fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw), cff.strings); - this.parsePrivateDict(fontDict); - cff.fdArray.push(fontDict); + while (pos < length) { + const b = dict[pos++]; + const b1 = b >> 4; + const b2 = b & 15; + + if (b1 === eof) { + break; } - encoding = null; - charset = this.parseCharsets(topDict.getByName("charset"), charStringIndex.count, cff.strings, true); - cff.fdSelect = this.parseFDSelect(topDict.getByName("FDSelect"), charStringIndex.count); + str += lookup[b1]; + + if (b2 === eof) { + break; + } + + str += lookup[b2]; + } + + return parseFloat(str); + } + + let operands = []; + const entries = []; + pos = 0; + const end = dict.length; + + while (pos < end) { + let b = dict[pos]; + + if (b <= 21) { + if (b === 12) { + b = b << 8 | dict[++pos]; + } + + entries.push([b, operands]); + operands = []; + ++pos; } else { - charset = this.parseCharsets(topDict.getByName("charset"), charStringIndex.count, cff.strings, false); - encoding = this.parseEncoding(topDict.getByName("Encoding"), properties, cff.strings, charset.charset); + operands.push(parseOperand()); } - - cff.charset = charset; - cff.encoding = encoding; - var charStringsAndSeacs = this.parseCharStrings({ - charStrings: charStringIndex, - localSubrIndex: topDict.privateDict.subrsIndex, - globalSubrIndex: globalSubrIndex.obj, - fdSelect: cff.fdSelect, - fdArray: cff.fdArray, - privateDict: topDict.privateDict - }); - cff.charStrings = charStringsAndSeacs.charStrings; - cff.seacs = charStringsAndSeacs.seacs; - cff.widths = charStringsAndSeacs.widths; - return cff; } - parseHeader() { - var bytes = this.bytes; - var bytesLength = bytes.length; - var offset = 0; + return entries; + } - while (offset < bytesLength && bytes[offset] !== 1) { - ++offset; + parseIndex(pos) { + const cffIndex = new CFFIndex(); + const bytes = this.bytes; + const count = bytes[pos++] << 8 | bytes[pos++]; + const offsets = []; + let end = pos; + let i, ii; + + if (count !== 0) { + const offsetSize = bytes[pos++]; + const startPos = pos + (count + 1) * offsetSize - 1; + + for (i = 0, ii = count + 1; i < ii; ++i) { + let offset = 0; + + for (let j = 0; j < offsetSize; ++j) { + offset <<= 8; + offset += bytes[pos++]; + } + + offsets.push(startPos + offset); } - if (offset >= bytesLength) { - throw new _util.FormatError("Invalid CFF header"); - } - - if (offset !== 0) { - (0, _util.info)("cff data is shifted"); - bytes = bytes.subarray(offset); - this.bytes = bytes; - } - - var major = bytes[0]; - var minor = bytes[1]; - var hdrSize = bytes[2]; - var offSize = bytes[3]; - var header = new CFFHeader(major, minor, hdrSize, offSize); - return { - obj: header, - endPos: hdrSize - }; + end = offsets[count]; } - parseDict(dict) { - var pos = 0; + for (i = 0, ii = offsets.length - 1; i < ii; ++i) { + const offsetStart = offsets[i]; + const offsetEnd = offsets[i + 1]; + cffIndex.add(bytes.subarray(offsetStart, offsetEnd)); + } - function parseOperand() { - var value = dict[pos++]; + return { + obj: cffIndex, + endPos: end + }; + } - if (value === 30) { - return parseFloatOperand(); - } else if (value === 28) { - value = dict[pos++]; - value = (value << 24 | dict[pos++] << 16) >> 16; - return value; - } else if (value === 29) { - value = dict[pos++]; - value = value << 8 | dict[pos++]; - value = value << 8 | dict[pos++]; - value = value << 8 | dict[pos++]; - return value; - } else if (value >= 32 && value <= 246) { - return value - 139; - } else if (value >= 247 && value <= 250) { - return (value - 247) * 256 + dict[pos++] + 108; - } else if (value >= 251 && value <= 254) { - return -((value - 251) * 256) - dict[pos++] - 108; - } + parseNameIndex(index) { + const names = []; - (0, _util.warn)('CFFParser_parseDict: "' + value + '" is a reserved command.'); - return NaN; - } + for (let i = 0, ii = index.count; i < ii; ++i) { + const name = index.get(i); + names.push((0, _util.bytesToString)(name)); + } - function parseFloatOperand() { - var str = ""; - var eof = 15; - const lookup = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "E", "E-", null, "-"]; - var length = dict.length; + return names; + } - while (pos < length) { - var b = dict[pos++]; - var b1 = b >> 4; - var b2 = b & 15; + parseStringIndex(index) { + const strings = new CFFStrings(); - if (b1 === eof) { - break; - } + for (let i = 0, ii = index.count; i < ii; ++i) { + const data = index.get(i); + strings.add((0, _util.bytesToString)(data)); + } - str += lookup[b1]; + return strings; + } - if (b2 === eof) { - break; - } + createDict(Type, dict, strings) { + const cffDict = new Type(strings); - str += lookup[b2]; - } + for (let i = 0, ii = dict.length; i < ii; ++i) { + const pair = dict[i]; + const key = pair[0]; + const value = pair[1]; + cffDict.setByKey(key, value); + } - return parseFloat(str); - } + return cffDict; + } - var operands = []; - var entries = []; - pos = 0; - var end = dict.length; + parseCharString(state, data, localSubrIndex, globalSubrIndex) { + if (!data || state.callDepth > MAX_SUBR_NESTING) { + return false; + } - while (pos < end) { - var b = dict[pos]; + let stackSize = state.stackSize; + const stack = state.stack; + const length = data.length; - if (b <= 21) { - if (b === 12) { - b = b << 8 | dict[++pos]; - } + for (let j = 0; j < length;) { + const value = data[j++]; + let validationCommand = null; - entries.push([b, operands]); - operands = []; - ++pos; + if (value === 12) { + const q = data[j++]; + + if (q === 0) { + data[j - 2] = 139; + data[j - 1] = 22; + stackSize = 0; } else { - operands.push(parseOperand()); + validationCommand = CharstringValidationData12[q]; } - } + } else if (value === 28) { + stack[stackSize] = (data[j] << 24 | data[j + 1] << 16) >> 16; + j += 2; + stackSize++; + } else if (value === 14) { + if (stackSize >= 4) { + stackSize -= 4; - return entries; - } - - parseIndex(pos) { - var cffIndex = new CFFIndex(); - var bytes = this.bytes; - var count = bytes[pos++] << 8 | bytes[pos++]; - var offsets = []; - var end = pos; - var i, ii; - - if (count !== 0) { - var offsetSize = bytes[pos++]; - var startPos = pos + (count + 1) * offsetSize - 1; - - for (i = 0, ii = count + 1; i < ii; ++i) { - var offset = 0; - - for (var j = 0; j < offsetSize; ++j) { - offset <<= 8; - offset += bytes[pos++]; + if (this.seacAnalysisEnabled) { + state.seac = stack.slice(stackSize, stackSize + 4); + return false; } - - offsets.push(startPos + offset); } - end = offsets[count]; - } + validationCommand = CharstringValidationData[value]; + } else if (value >= 32 && value <= 246) { + stack[stackSize] = value - 139; + stackSize++; + } else if (value >= 247 && value <= 254) { + stack[stackSize] = value < 251 ? (value - 247 << 8) + data[j] + 108 : -(value - 251 << 8) - data[j] - 108; + j++; + stackSize++; + } else if (value === 255) { + stack[stackSize] = (data[j] << 24 | data[j + 1] << 16 | data[j + 2] << 8 | data[j + 3]) / 65536; + j += 4; + stackSize++; + } else if (value === 19 || value === 20) { + state.hints += stackSize >> 1; + j += state.hints + 7 >> 3; + stackSize %= 2; + validationCommand = CharstringValidationData[value]; + } else if (value === 10 || value === 29) { + let subrsIndex; - for (i = 0, ii = offsets.length - 1; i < ii; ++i) { - var offsetStart = offsets[i]; - var offsetEnd = offsets[i + 1]; - cffIndex.add(bytes.subarray(offsetStart, offsetEnd)); - } - - return { - obj: cffIndex, - endPos: end - }; - } - - parseNameIndex(index) { - var names = []; - - for (var i = 0, ii = index.count; i < ii; ++i) { - var name = index.get(i); - names.push((0, _util.bytesToString)(name)); - } - - return names; - } - - parseStringIndex(index) { - var strings = new CFFStrings(); - - for (var i = 0, ii = index.count; i < ii; ++i) { - var data = index.get(i); - strings.add((0, _util.bytesToString)(data)); - } - - return strings; - } - - createDict(Type, dict, strings) { - var cffDict = new Type(strings); - - for (var i = 0, ii = dict.length; i < ii; ++i) { - var pair = dict[i]; - var key = pair[0]; - var value = pair[1]; - cffDict.setByKey(key, value); - } - - return cffDict; - } - - parseCharString(state, data, localSubrIndex, globalSubrIndex) { - if (!data || state.callDepth > MAX_SUBR_NESTING) { - return false; - } - - var stackSize = state.stackSize; - var stack = state.stack; - var length = data.length; - - for (var j = 0; j < length;) { - var value = data[j++]; - var validationCommand = null; - - if (value === 12) { - var q = data[j++]; - - if (q === 0) { - data[j - 2] = 139; - data[j - 1] = 22; - stackSize = 0; - } else { - validationCommand = CharstringValidationData12[q]; - } - } else if (value === 28) { - stack[stackSize] = (data[j] << 24 | data[j + 1] << 16) >> 16; - j += 2; - stackSize++; - } else if (value === 14) { - if (stackSize >= 4) { - stackSize -= 4; - - if (this.seacAnalysisEnabled) { - state.seac = stack.slice(stackSize, stackSize + 4); - return false; - } - } + if (value === 10) { + subrsIndex = localSubrIndex; + } else { + subrsIndex = globalSubrIndex; + } + if (!subrsIndex) { validationCommand = CharstringValidationData[value]; - } else if (value >= 32 && value <= 246) { - stack[stackSize] = value - 139; - stackSize++; - } else if (value >= 247 && value <= 254) { - stack[stackSize] = value < 251 ? (value - 247 << 8) + data[j] + 108 : -(value - 251 << 8) - data[j] - 108; - j++; - stackSize++; - } else if (value === 255) { - stack[stackSize] = (data[j] << 24 | data[j + 1] << 16 | data[j + 2] << 8 | data[j + 3]) / 65536; - j += 4; - stackSize++; - } else if (value === 19 || value === 20) { + (0, _util.warn)("Missing subrsIndex for " + validationCommand.id); + return false; + } + + let bias = 32768; + + if (subrsIndex.count < 1240) { + bias = 107; + } else if (subrsIndex.count < 33900) { + bias = 1131; + } + + const subrNumber = stack[--stackSize] + bias; + + if (subrNumber < 0 || subrNumber >= subrsIndex.count || isNaN(subrNumber)) { + validationCommand = CharstringValidationData[value]; + (0, _util.warn)("Out of bounds subrIndex for " + validationCommand.id); + return false; + } + + state.stackSize = stackSize; + state.callDepth++; + const valid = this.parseCharString(state, subrsIndex.get(subrNumber), localSubrIndex, globalSubrIndex); + + if (!valid) { + return false; + } + + state.callDepth--; + stackSize = state.stackSize; + continue; + } else if (value === 11) { + state.stackSize = stackSize; + return true; + } else if (value === 0 && j === data.length) { + data[j - 1] = 14; + validationCommand = CharstringValidationData[14]; + } else { + validationCommand = CharstringValidationData[value]; + } + + if (validationCommand) { + if (validationCommand.stem) { state.hints += stackSize >> 1; - j += state.hints + 7 >> 3; - stackSize %= 2; - validationCommand = CharstringValidationData[value]; - } else if (value === 10 || value === 29) { - var subrsIndex; - if (value === 10) { - subrsIndex = localSubrIndex; - } else { - subrsIndex = globalSubrIndex; + if (value === 3 || value === 23) { + state.hasVStems = true; + } else if (state.hasVStems && (value === 1 || value === 18)) { + (0, _util.warn)("CFF stem hints are in wrong order"); + data[j - 1] = value === 1 ? 3 : 23; } - - if (!subrsIndex) { - validationCommand = CharstringValidationData[value]; - (0, _util.warn)("Missing subrsIndex for " + validationCommand.id); - return false; - } - - var bias = 32768; - - if (subrsIndex.count < 1240) { - bias = 107; - } else if (subrsIndex.count < 33900) { - bias = 1131; - } - - var subrNumber = stack[--stackSize] + bias; - - if (subrNumber < 0 || subrNumber >= subrsIndex.count || isNaN(subrNumber)) { - validationCommand = CharstringValidationData[value]; - (0, _util.warn)("Out of bounds subrIndex for " + validationCommand.id); - return false; - } - - state.stackSize = stackSize; - state.callDepth++; - var valid = this.parseCharString(state, subrsIndex.get(subrNumber), localSubrIndex, globalSubrIndex); - - if (!valid) { - return false; - } - - state.callDepth--; - stackSize = state.stackSize; - continue; - } else if (value === 11) { - state.stackSize = stackSize; - return true; - } else { - validationCommand = CharstringValidationData[value]; } - if (validationCommand) { - if (validationCommand.stem) { - state.hints += stackSize >> 1; + if ("min" in validationCommand) { + if (!state.undefStack && stackSize < validationCommand.min) { + (0, _util.warn)("Not enough parameters for " + validationCommand.id + "; actual: " + stackSize + ", expected: " + validationCommand.min); - if (value === 3 || value === 23) { - state.hasVStems = true; - } else if (state.hasVStems && (value === 1 || value === 18)) { - (0, _util.warn)("CFF stem hints are in wrong order"); - data[j - 1] = value === 1 ? 3 : 23; + if (stackSize === 0) { + data[j - 1] = 14; + return true; } + + return false; + } + } + + if (state.firstStackClearing && validationCommand.stackClearing) { + state.firstStackClearing = false; + stackSize -= validationCommand.min; + + if (stackSize >= 2 && validationCommand.stem) { + stackSize %= 2; + } else if (stackSize > 1) { + (0, _util.warn)("Found too many parameters for stack-clearing command"); } - if ("min" in validationCommand) { - if (!state.undefStack && stackSize < validationCommand.min) { - (0, _util.warn)("Not enough parameters for " + validationCommand.id + "; actual: " + stackSize + ", expected: " + validationCommand.min); - return false; - } + if (stackSize > 0) { + state.width = stack[stackSize - 1]; + } + } + + if ("stackDelta" in validationCommand) { + if ("stackFn" in validationCommand) { + validationCommand.stackFn(stack, stackSize); } - if (state.firstStackClearing && validationCommand.stackClearing) { - state.firstStackClearing = false; - stackSize -= validationCommand.min; - - if (stackSize >= 2 && validationCommand.stem) { - stackSize %= 2; - } else if (stackSize > 1) { - (0, _util.warn)("Found too many parameters for stack-clearing command"); - } - - if (stackSize > 0 && stack[stackSize - 1] >= 0) { - state.width = stack[stackSize - 1]; - } - } - - if ("stackDelta" in validationCommand) { - if ("stackFn" in validationCommand) { - validationCommand.stackFn(stack, stackSize); - } - - stackSize += validationCommand.stackDelta; - } else if (validationCommand.stackClearing) { - stackSize = 0; - } else if (validationCommand.resetStack) { - stackSize = 0; - state.undefStack = false; - } else if (validationCommand.undefStack) { - stackSize = 0; - state.undefStack = true; - state.firstStackClearing = false; - } + stackSize += validationCommand.stackDelta; + } else if (validationCommand.stackClearing) { + stackSize = 0; + } else if (validationCommand.resetStack) { + stackSize = 0; + state.undefStack = false; + } else if (validationCommand.undefStack) { + stackSize = 0; + state.undefStack = true; + state.firstStackClearing = false; } } - - state.stackSize = stackSize; - return true; } - parseCharStrings({ - charStrings, - localSubrIndex, - globalSubrIndex, - fdSelect, - fdArray, - privateDict - }) { - var seacs = []; - var widths = []; - var count = charStrings.count; + state.stackSize = stackSize; + return true; + } - for (var i = 0; i < count; i++) { - var charstring = charStrings.get(i); - var state = { - callDepth: 0, - stackSize: 0, - stack: [], - undefStack: true, - hints: 0, - firstStackClearing: true, - seac: null, - width: null, - hasVStems: false - }; - var valid = true; - var localSubrToUse = null; - var privateDictToUse = privateDict; + parseCharStrings({ + charStrings, + localSubrIndex, + globalSubrIndex, + fdSelect, + fdArray, + privateDict + }) { + const seacs = []; + const widths = []; + const count = charStrings.count; - if (fdSelect && fdArray.length) { - var fdIndex = fdSelect.getFDIndex(i); + for (let i = 0; i < count; i++) { + const charstring = charStrings.get(i); + const state = { + callDepth: 0, + stackSize: 0, + stack: [], + undefStack: true, + hints: 0, + firstStackClearing: true, + seac: null, + width: null, + hasVStems: false + }; + let valid = true; + let localSubrToUse = null; + let privateDictToUse = privateDict; - if (fdIndex === -1) { - (0, _util.warn)("Glyph index is not in fd select."); - valid = false; - } + if (fdSelect && fdArray.length) { + const fdIndex = fdSelect.getFDIndex(i); - if (fdIndex >= fdArray.length) { - (0, _util.warn)("Invalid fd index for glyph index."); - valid = false; - } + if (fdIndex === -1) { + (0, _util.warn)("Glyph index is not in fd select."); + valid = false; + } - if (valid) { - privateDictToUse = fdArray[fdIndex].privateDict; - localSubrToUse = privateDictToUse.subrsIndex; - } - } else if (localSubrIndex) { - localSubrToUse = localSubrIndex; + if (fdIndex >= fdArray.length) { + (0, _util.warn)("Invalid fd index for glyph index."); + valid = false; } if (valid) { - valid = this.parseCharString(state, charstring, localSubrToUse, globalSubrIndex); - } - - if (state.width !== null) { - const nominalWidth = privateDictToUse.getByName("nominalWidthX"); - widths[i] = nominalWidth + state.width; - } else { - const defaultWidth = privateDictToUse.getByName("defaultWidthX"); - widths[i] = defaultWidth; - } - - if (state.seac !== null) { - seacs[i] = state.seac; - } - - if (!valid) { - charStrings.set(i, new Uint8Array([14])); + privateDictToUse = fdArray[fdIndex].privateDict; + localSubrToUse = privateDictToUse.subrsIndex; } + } else if (localSubrIndex) { + localSubrToUse = localSubrIndex; } - return { - charStrings, - seacs, - widths - }; + if (valid) { + valid = this.parseCharString(state, charstring, localSubrToUse, globalSubrIndex); + } + + if (state.width !== null) { + const nominalWidth = privateDictToUse.getByName("nominalWidthX"); + widths[i] = nominalWidth + state.width; + } else { + const defaultWidth = privateDictToUse.getByName("defaultWidthX"); + widths[i] = defaultWidth; + } + + if (state.seac !== null) { + seacs[i] = state.seac; + } + + if (!valid) { + charStrings.set(i, new Uint8Array([14])); + } } - emptyPrivateDictionary(parentDict) { - var privateDict = this.createDict(CFFPrivateDict, [], parentDict.strings); - parentDict.setByKey(18, [0, 0]); - parentDict.privateDict = privateDict; + return { + charStrings, + seacs, + widths + }; + } + + emptyPrivateDictionary(parentDict) { + const privateDict = this.createDict(CFFPrivateDict, [], parentDict.strings); + parentDict.setByKey(18, [0, 0]); + parentDict.privateDict = privateDict; + } + + parsePrivateDict(parentDict) { + if (!parentDict.hasName("Private")) { + this.emptyPrivateDictionary(parentDict); + return; } - parsePrivateDict(parentDict) { - if (!parentDict.hasName("Private")) { - this.emptyPrivateDictionary(parentDict); - return; - } + const privateOffset = parentDict.getByName("Private"); - var privateOffset = parentDict.getByName("Private"); - - if (!Array.isArray(privateOffset) || privateOffset.length !== 2) { - parentDict.removeByName("Private"); - return; - } - - var size = privateOffset[0]; - var offset = privateOffset[1]; - - if (size === 0 || offset >= this.bytes.length) { - this.emptyPrivateDictionary(parentDict); - return; - } - - var privateDictEnd = offset + size; - var dictData = this.bytes.subarray(offset, privateDictEnd); - var dict = this.parseDict(dictData); - var privateDict = this.createDict(CFFPrivateDict, dict, parentDict.strings); - parentDict.privateDict = privateDict; - - if (!privateDict.getByName("Subrs")) { - return; - } - - var subrsOffset = privateDict.getByName("Subrs"); - var relativeOffset = offset + subrsOffset; - - if (subrsOffset === 0 || relativeOffset >= this.bytes.length) { - this.emptyPrivateDictionary(parentDict); - return; - } - - var subrsIndex = this.parseIndex(relativeOffset); - privateDict.subrsIndex = subrsIndex.obj; + if (!Array.isArray(privateOffset) || privateOffset.length !== 2) { + parentDict.removeByName("Private"); + return; } - parseCharsets(pos, length, strings, cid) { - if (pos === 0) { - return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE, _charsets.ISOAdobeCharset); - } else if (pos === 1) { - return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT, _charsets.ExpertCharset); - } else if (pos === 2) { - return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET, _charsets.ExpertSubsetCharset); + const size = privateOffset[0]; + const offset = privateOffset[1]; + + if (size === 0 || offset >= this.bytes.length) { + this.emptyPrivateDictionary(parentDict); + return; + } + + const privateDictEnd = offset + size; + const dictData = this.bytes.subarray(offset, privateDictEnd); + const dict = this.parseDict(dictData); + const privateDict = this.createDict(CFFPrivateDict, dict, parentDict.strings); + parentDict.privateDict = privateDict; + + if (!privateDict.getByName("Subrs")) { + return; + } + + const subrsOffset = privateDict.getByName("Subrs"); + const relativeOffset = offset + subrsOffset; + + if (subrsOffset === 0 || relativeOffset >= this.bytes.length) { + this.emptyPrivateDictionary(parentDict); + return; + } + + const subrsIndex = this.parseIndex(relativeOffset); + privateDict.subrsIndex = subrsIndex.obj; + } + + parseCharsets(pos, length, strings, cid) { + if (pos === 0) { + return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE, _charsets.ISOAdobeCharset); + } else if (pos === 1) { + return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT, _charsets.ExpertCharset); + } else if (pos === 2) { + return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET, _charsets.ExpertSubsetCharset); + } + + const bytes = this.bytes; + const start = pos; + const format = bytes[pos++]; + const charset = [cid ? 0 : ".notdef"]; + let id, count, i; + length -= 1; + + switch (format) { + case 0: + for (i = 0; i < length; i++) { + id = bytes[pos++] << 8 | bytes[pos++]; + charset.push(cid ? id : strings.get(id)); + } + + break; + + case 1: + while (charset.length <= length) { + id = bytes[pos++] << 8 | bytes[pos++]; + count = bytes[pos++]; + + for (i = 0; i <= count; i++) { + charset.push(cid ? id++ : strings.get(id++)); + } + } + + break; + + case 2: + while (charset.length <= length) { + id = bytes[pos++] << 8 | bytes[pos++]; + count = bytes[pos++] << 8 | bytes[pos++]; + + for (i = 0; i <= count; i++) { + charset.push(cid ? id++ : strings.get(id++)); + } + } + + break; + + default: + throw new _util.FormatError("Unknown charset format"); + } + + const end = pos; + const raw = bytes.subarray(start, end); + return new CFFCharset(false, format, charset, raw); + } + + parseEncoding(pos, properties, strings, charset) { + const encoding = Object.create(null); + const bytes = this.bytes; + let predefined = false; + let format, i, ii; + let raw = null; + + function readSupplement() { + const supplementsCount = bytes[pos++]; + + for (i = 0; i < supplementsCount; i++) { + const code = bytes[pos++]; + const sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff); + encoding[code] = charset.indexOf(strings.get(sid)); } + } - var bytes = this.bytes; - var start = pos; - var format = bytes[pos++]; - const charset = [cid ? 0 : ".notdef"]; - var id, count, i; - length -= 1; + if (pos === 0 || pos === 1) { + predefined = true; + format = pos; + const baseEncoding = pos ? _encodings.ExpertEncoding : _encodings.StandardEncoding; - switch (format) { + for (i = 0, ii = charset.length; i < ii; i++) { + const index = baseEncoding.indexOf(charset[i]); + + if (index !== -1) { + encoding[index] = i; + } + } + } else { + const dataStart = pos; + format = bytes[pos++]; + + switch (format & 0x7f) { case 0: - for (i = 0; i < length; i++) { - id = bytes[pos++] << 8 | bytes[pos++]; - charset.push(cid ? id : strings.get(id)); + const glyphsCount = bytes[pos++]; + + for (i = 1; i <= glyphsCount; i++) { + encoding[bytes[pos++]] = i; } break; case 1: - while (charset.length <= length) { - id = bytes[pos++] << 8 | bytes[pos++]; - count = bytes[pos++]; + const rangesCount = bytes[pos++]; + let gid = 1; - for (i = 0; i <= count; i++) { - charset.push(cid ? id++ : strings.get(id++)); - } - } + for (i = 0; i < rangesCount; i++) { + const start = bytes[pos++]; + const left = bytes[pos++]; - break; - - case 2: - while (charset.length <= length) { - id = bytes[pos++] << 8 | bytes[pos++]; - count = bytes[pos++] << 8 | bytes[pos++]; - - for (i = 0; i <= count; i++) { - charset.push(cid ? id++ : strings.get(id++)); + for (let j = start; j <= start + left; j++) { + encoding[j] = gid++; } } break; default: - throw new _util.FormatError("Unknown charset format"); + throw new _util.FormatError(`Unknown encoding format: ${format} in CFF`); } - var end = pos; - var raw = bytes.subarray(start, end); - return new CFFCharset(false, format, charset, raw); - } - - parseEncoding(pos, properties, strings, charset) { - var encoding = Object.create(null); - var bytes = this.bytes; - var predefined = false; - var format, i, ii; - var raw = null; - - function readSupplement() { - var supplementsCount = bytes[pos++]; - - for (i = 0; i < supplementsCount; i++) { - var code = bytes[pos++]; - var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff); - encoding[code] = charset.indexOf(strings.get(sid)); - } - } - - if (pos === 0 || pos === 1) { - predefined = true; - format = pos; - var baseEncoding = pos ? _encodings.ExpertEncoding : _encodings.StandardEncoding; - - for (i = 0, ii = charset.length; i < ii; i++) { - var index = baseEncoding.indexOf(charset[i]); - - if (index !== -1) { - encoding[index] = i; - } - } - } else { - var dataStart = pos; - format = bytes[pos++]; - - switch (format & 0x7f) { - case 0: - var glyphsCount = bytes[pos++]; - - for (i = 1; i <= glyphsCount; i++) { - encoding[bytes[pos++]] = i; - } - - break; - - case 1: - var rangesCount = bytes[pos++]; - var gid = 1; - - for (i = 0; i < rangesCount; i++) { - var start = bytes[pos++]; - var left = bytes[pos++]; - - for (var j = start; j <= start + left; j++) { - encoding[j] = gid++; - } - } - - break; - - default: - throw new _util.FormatError(`Unknown encoding format: ${format} in CFF`); - } - - var dataEnd = pos; - - if (format & 0x80) { - bytes[dataStart] &= 0x7f; - readSupplement(); - } - - raw = bytes.subarray(dataStart, dataEnd); - } - - format = format & 0x7f; - return new CFFEncoding(predefined, format, encoding, raw); - } - - parseFDSelect(pos, length) { - var bytes = this.bytes; - var format = bytes[pos++]; - var fdSelect = []; - var i; - - switch (format) { - case 0: - for (i = 0; i < length; ++i) { - var id = bytes[pos++]; - fdSelect.push(id); - } - - break; - - case 3: - var rangesCount = bytes[pos++] << 8 | bytes[pos++]; - - for (i = 0; i < rangesCount; ++i) { - var first = bytes[pos++] << 8 | bytes[pos++]; - - if (i === 0 && first !== 0) { - (0, _util.warn)("parseFDSelect: The first range must have a first GID of 0" + " -- trying to recover."); - first = 0; - } - - var fdIndex = bytes[pos++]; - var next = bytes[pos] << 8 | bytes[pos + 1]; - - for (var j = first; j < next; ++j) { - fdSelect.push(fdIndex); - } - } - - pos += 2; - break; - - default: - throw new _util.FormatError(`parseFDSelect: Unknown format "${format}".`); - } - - if (fdSelect.length !== length) { - throw new _util.FormatError("parseFDSelect: Invalid font data."); - } - - return new CFFFDSelect(format, fdSelect); + const dataEnd = pos; + + if (format & 0x80) { + bytes[dataStart] &= 0x7f; + readSupplement(); + } + + raw = bytes.subarray(dataStart, dataEnd); } + format &= 0x7f; + return new CFFEncoding(predefined, format, encoding, raw); } - return CFFParser; -}(); + parseFDSelect(pos, length) { + const bytes = this.bytes; + const format = bytes[pos++]; + const fdSelect = []; + let i; + + switch (format) { + case 0: + for (i = 0; i < length; ++i) { + const id = bytes[pos++]; + fdSelect.push(id); + } + + break; + + case 3: + const rangesCount = bytes[pos++] << 8 | bytes[pos++]; + + for (i = 0; i < rangesCount; ++i) { + let first = bytes[pos++] << 8 | bytes[pos++]; + + if (i === 0 && first !== 0) { + (0, _util.warn)("parseFDSelect: The first range must have a first GID of 0" + " -- trying to recover."); + first = 0; + } + + const fdIndex = bytes[pos++]; + const next = bytes[pos] << 8 | bytes[pos + 1]; + + for (let j = first; j < next; ++j) { + fdSelect.push(fdIndex); + } + } + + pos += 2; + break; + + default: + throw new _util.FormatError(`parseFDSelect: Unknown format "${format}".`); + } + + if (fdSelect.length !== length) { + throw new _util.FormatError("parseFDSelect: Invalid font data."); + } + + return new CFFFDSelect(format, fdSelect); + } + +} exports.CFFParser = CFFParser; @@ -30435,7 +28941,7 @@ class CFF { return; } - var glyphZero = this.charStrings.get(0); + const glyphZero = this.charStrings.get(0); this.charStrings.add(glyphZero); if (this.isCIDFont) { @@ -30448,7 +28954,7 @@ class CFF { return false; } - var glyph = this.charStrings.get(id); + const glyph = this.charStrings.get(id); return glyph.length > 0; } @@ -30558,20 +29064,20 @@ class CFFDict { return false; } - var valueLength = value.length; + const valueLength = value.length; if (valueLength === 0) { return true; } - for (var i = 0; i < valueLength; i++) { + for (let i = 0; i < valueLength; i++) { if (isNaN(value[i])) { (0, _util.warn)('Invalid CFFDict value: "' + value + '" for key "' + key + '".'); return true; } } - var type = this.types[key]; + const type = this.types[key]; if (type === "num" || type === "sid" || type === "offset") { value = value[0]; @@ -30598,7 +29104,7 @@ class CFFDict { throw new _util.FormatError(`Invalid dictionary name ${name}"`); } - var key = this.nameToKeyMap[name]; + const key = this.nameToKeyMap[name]; if (!(key in this.values)) { return this.defaults[key]; @@ -30612,7 +29118,7 @@ class CFFDict { } static createTables(layout) { - var tables = { + const tables = { keyToNameMap: {}, nameToKeyMap: {}, defaults: {}, @@ -30621,9 +29127,9 @@ class CFFDict { order: [] }; - for (var i = 0, ii = layout.length; i < ii; ++i) { - var entry = layout[i]; - var key = Array.isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0]; + for (let i = 0, ii = layout.length; i < ii; ++i) { + const entry = layout[i]; + const key = Array.isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0]; tables.keyToNameMap[key] = entry[1]; tables.nameToKeyMap[entry[1]] = key; tables.types[key] = entry[2]; @@ -30637,48 +29143,37 @@ class CFFDict { } -var CFFTopDict = function CFFTopDictClosure() { - var layout = [[[12, 30], "ROS", ["sid", "sid", "num"], null], [[12, 20], "SyntheticBase", "num", null], [0, "version", "sid", null], [1, "Notice", "sid", null], [[12, 0], "Copyright", "sid", null], [2, "FullName", "sid", null], [3, "FamilyName", "sid", null], [4, "Weight", "sid", null], [[12, 1], "isFixedPitch", "num", 0], [[12, 2], "ItalicAngle", "num", 0], [[12, 3], "UnderlinePosition", "num", -100], [[12, 4], "UnderlineThickness", "num", 50], [[12, 5], "PaintType", "num", 0], [[12, 6], "CharstringType", "num", 2], [[12, 7], "FontMatrix", ["num", "num", "num", "num", "num", "num"], [0.001, 0, 0, 0.001, 0, 0]], [13, "UniqueID", "num", null], [5, "FontBBox", ["num", "num", "num", "num"], [0, 0, 0, 0]], [[12, 8], "StrokeWidth", "num", 0], [14, "XUID", "array", null], [15, "charset", "offset", 0], [16, "Encoding", "offset", 0], [17, "CharStrings", "offset", 0], [18, "Private", ["offset", "offset"], null], [[12, 21], "PostScript", "sid", null], [[12, 22], "BaseFontName", "sid", null], [[12, 23], "BaseFontBlend", "delta", null], [[12, 31], "CIDFontVersion", "num", 0], [[12, 32], "CIDFontRevision", "num", 0], [[12, 33], "CIDFontType", "num", 0], [[12, 34], "CIDCount", "num", 8720], [[12, 35], "UIDBase", "num", null], [[12, 37], "FDSelect", "offset", null], [[12, 36], "FDArray", "offset", null], [[12, 38], "FontName", "sid", null]]; - var tables = null; - - class CFFTopDict extends CFFDict { - constructor(strings) { - if (tables === null) { - tables = CFFDict.createTables(layout); - } - - super(tables, strings); - this.privateDict = null; - } +const CFFTopDictLayout = [[[12, 30], "ROS", ["sid", "sid", "num"], null], [[12, 20], "SyntheticBase", "num", null], [0, "version", "sid", null], [1, "Notice", "sid", null], [[12, 0], "Copyright", "sid", null], [2, "FullName", "sid", null], [3, "FamilyName", "sid", null], [4, "Weight", "sid", null], [[12, 1], "isFixedPitch", "num", 0], [[12, 2], "ItalicAngle", "num", 0], [[12, 3], "UnderlinePosition", "num", -100], [[12, 4], "UnderlineThickness", "num", 50], [[12, 5], "PaintType", "num", 0], [[12, 6], "CharstringType", "num", 2], [[12, 7], "FontMatrix", ["num", "num", "num", "num", "num", "num"], [0.001, 0, 0, 0.001, 0, 0]], [13, "UniqueID", "num", null], [5, "FontBBox", ["num", "num", "num", "num"], [0, 0, 0, 0]], [[12, 8], "StrokeWidth", "num", 0], [14, "XUID", "array", null], [15, "charset", "offset", 0], [16, "Encoding", "offset", 0], [17, "CharStrings", "offset", 0], [18, "Private", ["offset", "offset"], null], [[12, 21], "PostScript", "sid", null], [[12, 22], "BaseFontName", "sid", null], [[12, 23], "BaseFontBlend", "delta", null], [[12, 31], "CIDFontVersion", "num", 0], [[12, 32], "CIDFontRevision", "num", 0], [[12, 33], "CIDFontType", "num", 0], [[12, 34], "CIDCount", "num", 8720], [[12, 35], "UIDBase", "num", null], [[12, 37], "FDSelect", "offset", null], [[12, 36], "FDArray", "offset", null], [[12, 38], "FontName", "sid", null]]; +class CFFTopDict extends CFFDict { + static get tables() { + return (0, _util.shadow)(this, "tables", this.createTables(CFFTopDictLayout)); } - return CFFTopDict; -}(); + constructor(strings) { + super(CFFTopDict.tables, strings); + this.privateDict = null; + } + +} exports.CFFTopDict = CFFTopDict; +const CFFPrivateDictLayout = [[6, "BlueValues", "delta", null], [7, "OtherBlues", "delta", null], [8, "FamilyBlues", "delta", null], [9, "FamilyOtherBlues", "delta", null], [[12, 9], "BlueScale", "num", 0.039625], [[12, 10], "BlueShift", "num", 7], [[12, 11], "BlueFuzz", "num", 1], [10, "StdHW", "num", null], [11, "StdVW", "num", null], [[12, 12], "StemSnapH", "delta", null], [[12, 13], "StemSnapV", "delta", null], [[12, 14], "ForceBold", "num", 0], [[12, 17], "LanguageGroup", "num", 0], [[12, 18], "ExpansionFactor", "num", 0.06], [[12, 19], "initialRandomSeed", "num", 0], [20, "defaultWidthX", "num", 0], [21, "nominalWidthX", "num", 0], [19, "Subrs", "offset", null]]; -var CFFPrivateDict = function CFFPrivateDictClosure() { - var layout = [[6, "BlueValues", "delta", null], [7, "OtherBlues", "delta", null], [8, "FamilyBlues", "delta", null], [9, "FamilyOtherBlues", "delta", null], [[12, 9], "BlueScale", "num", 0.039625], [[12, 10], "BlueShift", "num", 7], [[12, 11], "BlueFuzz", "num", 1], [10, "StdHW", "num", null], [11, "StdVW", "num", null], [[12, 12], "StemSnapH", "delta", null], [[12, 13], "StemSnapV", "delta", null], [[12, 14], "ForceBold", "num", 0], [[12, 17], "LanguageGroup", "num", 0], [[12, 18], "ExpansionFactor", "num", 0.06], [[12, 19], "initialRandomSeed", "num", 0], [20, "defaultWidthX", "num", 0], [21, "nominalWidthX", "num", 0], [19, "Subrs", "offset", null]]; - var tables = null; - - class CFFPrivateDict extends CFFDict { - constructor(strings) { - if (tables === null) { - tables = CFFDict.createTables(layout); - } - - super(tables, strings); - this.subrsIndex = null; - } - +class CFFPrivateDict extends CFFDict { + static get tables() { + return (0, _util.shadow)(this, "tables", this.createTables(CFFPrivateDictLayout)); } - return CFFPrivateDict; -}(); + constructor(strings) { + super(CFFPrivateDict.tables, strings); + this.subrsIndex = null; + } + +} exports.CFFPrivateDict = CFFPrivateDict; -var CFFCharsetPredefinedTypes = { +const CFFCharsetPredefinedTypes = { ISO_ADOBE: 0, EXPERT: 1, EXPERT_SUBSET: 2 @@ -30742,7 +29237,7 @@ class CFFOffsetTracker { } offset(value) { - for (var key in this.offsets) { + for (const key in this.offsets) { this.offsets[key] += value; } } @@ -30752,22 +29247,22 @@ class CFFOffsetTracker { throw new _util.FormatError(`Not tracking location of ${key}`); } - var data = output.data; - var dataOffset = this.offsets[key]; - var size = 5; + const data = output.data; + const dataOffset = this.offsets[key]; + const size = 5; - for (var i = 0, ii = values.length; i < ii; ++i) { - var offset0 = i * size + dataOffset; - var offset1 = offset0 + 1; - var offset2 = offset0 + 2; - var offset3 = offset0 + 3; - var offset4 = offset0 + 4; + for (let i = 0, ii = values.length; i < ii; ++i) { + const offset0 = i * size + dataOffset; + const offset1 = offset0 + 1; + const offset2 = offset0 + 2; + const offset3 = offset0 + 3; + const offset4 = offset0 + 4; if (data[offset0] !== 0x1d || data[offset1] !== 0 || data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0) { throw new _util.FormatError("writing to an offset that is not empty"); } - var value = values[i]; + const value = values[i]; data[offset0] = 0x1d; data[offset1] = value >> 24 & 0xff; data[offset2] = value >> 16 & 0xff; @@ -30784,28 +29279,30 @@ class CFFCompiler { } compile() { - var cff = this.cff; - var output = { + const cff = this.cff; + const output = { data: [], length: 0, - add: function CFFCompiler_add(data) { + + add(data) { this.data = this.data.concat(data); this.length = this.data.length; } + }; - var header = this.compileHeader(cff.header); + const header = this.compileHeader(cff.header); output.add(header); - var nameIndex = this.compileNameIndex(cff.names); + const nameIndex = this.compileNameIndex(cff.names); output.add(nameIndex); if (cff.isCIDFont) { if (cff.topDict.hasName("FontMatrix")) { - var base = cff.topDict.getByName("FontMatrix"); + const base = cff.topDict.getByName("FontMatrix"); cff.topDict.removeByName("FontMatrix"); - for (var i = 0, ii = cff.fdArray.length; i < ii; i++) { - var subDict = cff.fdArray[i]; - var matrix = base.slice(0); + for (let i = 0, ii = cff.fdArray.length; i < ii; i++) { + const subDict = cff.fdArray[i]; + let matrix = base.slice(0); if (subDict.hasName("FontMatrix")) { matrix = _util.Util.transform(matrix, subDict.getByName("FontMatrix")); @@ -30816,40 +29313,46 @@ class CFFCompiler { } } + const xuid = cff.topDict.getByName("XUID"); + + if (xuid && xuid.length > 16) { + cff.topDict.removeByName("XUID"); + } + cff.topDict.setByName("charset", 0); - var compiled = this.compileTopDicts([cff.topDict], output.length, cff.isCIDFont); + let compiled = this.compileTopDicts([cff.topDict], output.length, cff.isCIDFont); output.add(compiled.output); - var topDictTracker = compiled.trackers[0]; - var stringIndex = this.compileStringIndex(cff.strings.strings); + const topDictTracker = compiled.trackers[0]; + const stringIndex = this.compileStringIndex(cff.strings.strings); output.add(stringIndex); - var globalSubrIndex = this.compileIndex(cff.globalSubrIndex); + const globalSubrIndex = this.compileIndex(cff.globalSubrIndex); output.add(globalSubrIndex); if (cff.encoding && cff.topDict.hasName("Encoding")) { if (cff.encoding.predefined) { topDictTracker.setEntryLocation("Encoding", [cff.encoding.format], output); } else { - var encoding = this.compileEncoding(cff.encoding); + const encoding = this.compileEncoding(cff.encoding); topDictTracker.setEntryLocation("Encoding", [output.length], output); output.add(encoding); } } - var charset = this.compileCharset(cff.charset, cff.charStrings.count, cff.strings, cff.isCIDFont); + const charset = this.compileCharset(cff.charset, cff.charStrings.count, cff.strings, cff.isCIDFont); topDictTracker.setEntryLocation("charset", [output.length], output); output.add(charset); - var charStrings = this.compileCharStrings(cff.charStrings); + const charStrings = this.compileCharStrings(cff.charStrings); topDictTracker.setEntryLocation("CharStrings", [output.length], output); output.add(charStrings); if (cff.isCIDFont) { topDictTracker.setEntryLocation("FDSelect", [output.length], output); - var fdSelect = this.compileFDSelect(cff.fdSelect); + const fdSelect = this.compileFDSelect(cff.fdSelect); output.add(fdSelect); compiled = this.compileTopDicts(cff.fdArray, output.length, true); topDictTracker.setEntryLocation("FDArray", [output.length], output); output.add(compiled.output); - var fontDictTrackers = compiled.trackers; + const fontDictTrackers = compiled.trackers; this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output); } @@ -30871,19 +29374,19 @@ class CFFCompiler { } encodeFloat(num) { - var value = num.toString(); - var m = CFFCompiler.EncodeFloatRegExp.exec(value); + let value = num.toString(); + const m = CFFCompiler.EncodeFloatRegExp.exec(value); if (m) { - var epsilon = parseFloat("1e" + ((m[2] ? +m[2] : 0) + m[1].length)); + const epsilon = parseFloat("1e" + ((m[2] ? +m[2] : 0) + m[1].length)); value = (Math.round(num * epsilon) / epsilon).toString(); } - var nibbles = ""; - var i, ii; + let nibbles = ""; + let i, ii; for (i = 0, ii = value.length; i < ii; ++i) { - var a = value[i]; + const a = value[i]; if (a === "e") { nibbles += value[++i] === "-" ? "c" : "b"; @@ -30897,7 +29400,7 @@ class CFFCompiler { } nibbles += nibbles.length & 1 ? "f" : "ff"; - var out = [30]; + const out = [30]; for (i = 0, ii = nibbles.length; i < ii; i += 2) { out.push(parseInt(nibbles.substring(i, i + 2), 16)); @@ -30907,12 +29410,12 @@ class CFFCompiler { } encodeInteger(value) { - var code; + let code; if (value >= -107 && value <= 107) { code = [value + 139]; } else if (value >= 108 && value <= 1131) { - value = value - 108; + value -= 108; code = [(value >> 8) + 247, value & 0xff]; } else if (value >= -1131 && value <= -108) { value = -value - 108; @@ -30927,19 +29430,19 @@ class CFFCompiler { } compileHeader(header) { - return [header.major, header.minor, header.hdrSize, header.offSize]; + return [header.major, header.minor, 4, header.offSize]; } compileNameIndex(names) { - var nameIndex = new CFFIndex(); + const nameIndex = new CFFIndex(); - for (var i = 0, ii = names.length; i < ii; ++i) { - var name = names[i]; - var length = Math.min(name.length, 127); - var sanitizedName = new Array(length); + for (let i = 0, ii = names.length; i < ii; ++i) { + const name = names[i]; + const length = Math.min(name.length, 127); + let sanitizedName = new Array(length); - for (var j = 0; j < length; j++) { - var char = name[j]; + for (let j = 0; j < length; j++) { + let char = name[j]; if (char < "!" || char > "~" || char === "[" || char === "]" || char === "(" || char === ")" || char === "{" || char === "}" || char === "<" || char === ">" || char === "/" || char === "%") { char = "_"; @@ -30961,11 +29464,11 @@ class CFFCompiler { } compileTopDicts(dicts, length, removeCidKeys) { - var fontDictTrackers = []; - var fdArrayIndex = new CFFIndex(); + const fontDictTrackers = []; + let fdArrayIndex = new CFFIndex(); - for (var i = 0, ii = dicts.length; i < ii; ++i) { - var fontDict = dicts[i]; + for (let i = 0, ii = dicts.length; i < ii; ++i) { + const fontDict = dicts[i]; if (removeCidKeys) { fontDict.removeByName("CIDFontVersion"); @@ -30975,8 +29478,8 @@ class CFFCompiler { fontDict.removeByName("UIDBase"); } - var fontDictTracker = new CFFOffsetTracker(); - var fontDictData = this.compileDict(fontDict, fontDictTracker); + const fontDictTracker = new CFFOffsetTracker(); + const fontDictData = this.compileDict(fontDict, fontDictTracker); fontDictTrackers.push(fontDictTracker); fdArrayIndex.add(fontDictData); fontDictTracker.offset(length); @@ -30990,17 +29493,17 @@ class CFFCompiler { } compilePrivateDicts(dicts, trackers, output) { - for (var i = 0, ii = dicts.length; i < ii; ++i) { - var fontDict = dicts[i]; - var privateDict = fontDict.privateDict; + for (let i = 0, ii = dicts.length; i < ii; ++i) { + const fontDict = dicts[i]; + const privateDict = fontDict.privateDict; if (!privateDict || !fontDict.hasName("Private")) { throw new _util.FormatError("There must be a private dictionary."); } - var privateDictTracker = new CFFOffsetTracker(); - var privateDictData = this.compileDict(privateDict, privateDictTracker); - var outputLength = output.length; + const privateDictTracker = new CFFOffsetTracker(); + const privateDictData = this.compileDict(privateDict, privateDictTracker); + let outputLength = output.length; privateDictTracker.offset(outputLength); if (!privateDictData.length) { @@ -31011,7 +29514,7 @@ class CFFCompiler { output.add(privateDictData); if (privateDict.subrsIndex && privateDict.hasName("Subrs")) { - var subrs = this.compileIndex(privateDict.subrsIndex); + const subrs = this.compileIndex(privateDict.subrsIndex); privateDictTracker.setEntryLocation("Subrs", [privateDictData.length], output); output.add(subrs); } @@ -31019,18 +29522,15 @@ class CFFCompiler { } compileDict(dict, offsetTracker) { - var out = []; - var order = dict.order; - - for (var i = 0; i < order.length; ++i) { - var key = order[i]; + const out = []; + for (const key of dict.order) { if (!(key in dict.values)) { continue; } - var values = dict.values[key]; - var types = dict.types[key]; + let values = dict.values[key]; + let types = dict.types[key]; if (!Array.isArray(types)) { types = [types]; @@ -31044,32 +29544,32 @@ class CFFCompiler { continue; } - for (var j = 0, jj = types.length; j < jj; ++j) { - var type = types[j]; - var value = values[j]; + for (let j = 0, jj = types.length; j < jj; ++j) { + const type = types[j]; + const value = values[j]; switch (type) { case "num": case "sid": - out = out.concat(this.encodeNumber(value)); + out.push(...this.encodeNumber(value)); break; case "offset": - var name = dict.keyToNameMap[key]; + const name = dict.keyToNameMap[key]; if (!offsetTracker.isTracking(name)) { offsetTracker.track(name, out.length); } - out = out.concat([0x1d, 0, 0, 0, 0]); + out.push(0x1d, 0, 0, 0, 0); break; case "array": case "delta": - out = out.concat(this.encodeNumber(value)); + out.push(...this.encodeNumber(value)); - for (var k = 1, kk = values.length; k < kk; ++k) { - out = out.concat(this.encodeNumber(values[k])); + for (let k = 1, kk = values.length; k < kk; ++k) { + out.push(...this.encodeNumber(values[k])); } break; @@ -31079,16 +29579,16 @@ class CFFCompiler { } } - out = out.concat(dict.opcodes[key]); + out.push(...dict.opcodes[key]); } return out; } compileStringIndex(strings) { - var stringIndex = new CFFIndex(); + const stringIndex = new CFFIndex(); - for (var i = 0, ii = strings.length; i < ii; ++i) { + for (let i = 0, ii = strings.length; i < ii; ++i) { stringIndex.add((0, _util.stringToBytes)(strings[i])); } @@ -31096,15 +29596,15 @@ class CFFCompiler { } compileGlobalSubrIndex() { - var globalSubrIndex = this.cff.globalSubrIndex; + const globalSubrIndex = this.cff.globalSubrIndex; this.out.writeByteArray(this.compileIndex(globalSubrIndex)); } compileCharStrings(charStrings) { - var charStringsIndex = new CFFIndex(); + const charStringsIndex = new CFFIndex(); - for (var i = 0; i < charStrings.count; i++) { - var glyph = charStrings.get(i); + for (let i = 0; i < charStrings.count; i++) { + const glyph = charStrings.get(i); if (glyph.length === 0) { charStringsIndex.add(new Uint8Array([0x8b, 0x0e])); @@ -31201,9 +29701,9 @@ class CFFCompiler { } compileTypedArray(data) { - var out = []; + const out = []; - for (var i = 0, ii = data.length; i < ii; ++i) { + for (let i = 0, ii = data.length; i < ii; ++i) { out[i] = data[i]; } @@ -31211,22 +29711,22 @@ class CFFCompiler { } compileIndex(index, trackers = []) { - var objects = index.objects; - var count = objects.length; + const objects = index.objects; + const count = objects.length; if (count === 0) { - return [0, 0, 0]; + return [0, 0]; } - var data = [count >> 8 & 0xff, count & 0xff]; - var lastOffset = 1, + const data = [count >> 8 & 0xff, count & 0xff]; + let lastOffset = 1, i; for (i = 0; i < count; ++i) { lastOffset += objects[i].length; } - var offsetSize; + let offsetSize; if (lastOffset < 0x100) { offsetSize = 1; @@ -31239,7 +29739,7 @@ class CFFCompiler { } data.push(offsetSize); - var relativeOffset = 1; + let relativeOffset = 1; for (i = 0; i < count + 1; i++) { if (offsetSize === 1) { @@ -31262,7 +29762,7 @@ class CFFCompiler { trackers[i].offset(data.length); } - for (var j = 0, jj = objects[i].length; j < jj; j++) { + for (let j = 0, jj = objects[i].length; j < jj; j++) { data.push(objects[i][j]); } } @@ -31275,16 +29775,15 @@ class CFFCompiler { exports.CFFCompiler = CFFCompiler; /***/ }), -/* 32 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 36 */ +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.ExpertSubsetCharset = exports.ExpertCharset = exports.ISOAdobeCharset = void 0; +})); +exports.ISOAdobeCharset = exports.ExpertSubsetCharset = exports.ExpertCharset = void 0; const ISOAdobeCharset = [".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron"]; exports.ISOAdobeCharset = ISOAdobeCharset; const ExpertCharset = [".notdef", "space", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "onequarter", "onehalf", "threequarters", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall"]; @@ -31293,17 +29792,16 @@ const ExpertSubsetCharset = [".notdef", "space", "dollaroldstyle", "dollarsuperi exports.ExpertSubsetCharset = ExpertSubsetCharset; /***/ }), -/* 33 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 37 */ +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.ZapfDingbatsEncoding = exports.WinAnsiEncoding = exports.SymbolSetEncoding = exports.StandardEncoding = exports.MacRomanEncoding = exports.ExpertEncoding = void 0; exports.getEncoding = getEncoding; -exports.ExpertEncoding = exports.ZapfDingbatsEncoding = exports.SymbolSetEncoding = exports.MacRomanEncoding = exports.StandardEncoding = exports.WinAnsiEncoding = void 0; const ExpertEncoding = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "space", "exclamsmall", "Hungarumlautsmall", "", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "", "", "", "isuperior", "", "", "lsuperior", "msuperior", "nsuperior", "osuperior", "", "", "rsuperior", "ssuperior", "tsuperior", "", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", "", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "exclamdownsmall", "centoldstyle", "Lslashsmall", "", "", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "", "Dotaccentsmall", "", "", "Macronsmall", "", "", "figuredash", "hypheninferior", "", "", "Ogoneksmall", "Ringsmall", "Cedillasmall", "", "", "", "onequarter", "onehalf", "threequarters", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "", "", "zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall"]; exports.ExpertEncoding = ExpertEncoding; const MacExpertEncoding = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "space", "exclamsmall", "Hungarumlautsmall", "centoldstyle", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", "", "threequartersemdash", "", "questionsmall", "", "", "", "", "Ethsmall", "", "", "onequarter", "onehalf", "threequarters", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "", "", "", "", "", "", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", "", "parenrightinferior", "Circumflexsmall", "hypheninferior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "", "", "asuperior", "centsuperior", "", "", "", "", "Aacutesmall", "Agravesmall", "Acircumflexsmall", "Adieresissmall", "Atildesmall", "Aringsmall", "Ccedillasmall", "Eacutesmall", "Egravesmall", "Ecircumflexsmall", "Edieresissmall", "Iacutesmall", "Igravesmall", "Icircumflexsmall", "Idieresissmall", "Ntildesmall", "Oacutesmall", "Ogravesmall", "Ocircumflexsmall", "Odieresissmall", "Otildesmall", "Uacutesmall", "Ugravesmall", "Ucircumflexsmall", "Udieresissmall", "", "eightsuperior", "fourinferior", "threeinferior", "sixinferior", "eightinferior", "seveninferior", "Scaronsmall", "", "centinferior", "twoinferior", "", "Dieresissmall", "", "Caronsmall", "osuperior", "fiveinferior", "", "commainferior", "periodinferior", "Yacutesmall", "", "dollarinferior", "", "", "Thornsmall", "", "nineinferior", "zeroinferior", "Zcaronsmall", "AEsmall", "Oslashsmall", "questiondownsmall", "oneinferior", "Lslashsmall", "", "", "", "", "", "", "Cedillasmall", "", "", "", "", "", "OEsmall", "figuredash", "hyphensuperior", "", "", "", "", "exclamdownsmall", "", "Ydieresissmall", "", "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "ninesuperior", "zerosuperior", "", "esuperior", "rsuperior", "tsuperior", "", "", "isuperior", "ssuperior", "dsuperior", "", "", "", "", "", "lsuperior", "Ogoneksmall", "Brevesmall", "Macronsmall", "bsuperior", "nsuperior", "msuperior", "commasuperior", "periodsuperior", "Dotaccentsmall", "Ringsmall", "", "", "", ""]; @@ -31347,5292 +29845,9266 @@ function getEncoding(encodingName) { } /***/ }), -/* 34 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -var getLookupTableFactory = __w_pdfjs_require__(8).getLookupTableFactory; -var getGlyphsUnicode = getLookupTableFactory(function (t) { - t.A = 0x0041; - t.AE = 0x00c6; - t.AEacute = 0x01fc; - t.AEmacron = 0x01e2; - t.AEsmall = 0xf7e6; - t.Aacute = 0x00c1; - t.Aacutesmall = 0xf7e1; - t.Abreve = 0x0102; - t.Abreveacute = 0x1eae; - t.Abrevecyrillic = 0x04d0; - t.Abrevedotbelow = 0x1eb6; - t.Abrevegrave = 0x1eb0; - t.Abrevehookabove = 0x1eb2; - t.Abrevetilde = 0x1eb4; - t.Acaron = 0x01cd; - t.Acircle = 0x24b6; - t.Acircumflex = 0x00c2; - t.Acircumflexacute = 0x1ea4; - t.Acircumflexdotbelow = 0x1eac; - t.Acircumflexgrave = 0x1ea6; - t.Acircumflexhookabove = 0x1ea8; - t.Acircumflexsmall = 0xf7e2; - t.Acircumflextilde = 0x1eaa; - t.Acute = 0xf6c9; - t.Acutesmall = 0xf7b4; - t.Acyrillic = 0x0410; - t.Adblgrave = 0x0200; - t.Adieresis = 0x00c4; - t.Adieresiscyrillic = 0x04d2; - t.Adieresismacron = 0x01de; - t.Adieresissmall = 0xf7e4; - t.Adotbelow = 0x1ea0; - t.Adotmacron = 0x01e0; - t.Agrave = 0x00c0; - t.Agravesmall = 0xf7e0; - t.Ahookabove = 0x1ea2; - t.Aiecyrillic = 0x04d4; - t.Ainvertedbreve = 0x0202; - t.Alpha = 0x0391; - t.Alphatonos = 0x0386; - t.Amacron = 0x0100; - t.Amonospace = 0xff21; - t.Aogonek = 0x0104; - t.Aring = 0x00c5; - t.Aringacute = 0x01fa; - t.Aringbelow = 0x1e00; - t.Aringsmall = 0xf7e5; - t.Asmall = 0xf761; - t.Atilde = 0x00c3; - t.Atildesmall = 0xf7e3; - t.Aybarmenian = 0x0531; - t.B = 0x0042; - t.Bcircle = 0x24b7; - t.Bdotaccent = 0x1e02; - t.Bdotbelow = 0x1e04; - t.Becyrillic = 0x0411; - t.Benarmenian = 0x0532; - t.Beta = 0x0392; - t.Bhook = 0x0181; - t.Blinebelow = 0x1e06; - t.Bmonospace = 0xff22; - t.Brevesmall = 0xf6f4; - t.Bsmall = 0xf762; - t.Btopbar = 0x0182; - t.C = 0x0043; - t.Caarmenian = 0x053e; - t.Cacute = 0x0106; - t.Caron = 0xf6ca; - t.Caronsmall = 0xf6f5; - t.Ccaron = 0x010c; - t.Ccedilla = 0x00c7; - t.Ccedillaacute = 0x1e08; - t.Ccedillasmall = 0xf7e7; - t.Ccircle = 0x24b8; - t.Ccircumflex = 0x0108; - t.Cdot = 0x010a; - t.Cdotaccent = 0x010a; - t.Cedillasmall = 0xf7b8; - t.Chaarmenian = 0x0549; - t.Cheabkhasiancyrillic = 0x04bc; - t.Checyrillic = 0x0427; - t.Chedescenderabkhasiancyrillic = 0x04be; - t.Chedescendercyrillic = 0x04b6; - t.Chedieresiscyrillic = 0x04f4; - t.Cheharmenian = 0x0543; - t.Chekhakassiancyrillic = 0x04cb; - t.Cheverticalstrokecyrillic = 0x04b8; - t.Chi = 0x03a7; - t.Chook = 0x0187; - t.Circumflexsmall = 0xf6f6; - t.Cmonospace = 0xff23; - t.Coarmenian = 0x0551; - t.Csmall = 0xf763; - t.D = 0x0044; - t.DZ = 0x01f1; - t.DZcaron = 0x01c4; - t.Daarmenian = 0x0534; - t.Dafrican = 0x0189; - t.Dcaron = 0x010e; - t.Dcedilla = 0x1e10; - t.Dcircle = 0x24b9; - t.Dcircumflexbelow = 0x1e12; - t.Dcroat = 0x0110; - t.Ddotaccent = 0x1e0a; - t.Ddotbelow = 0x1e0c; - t.Decyrillic = 0x0414; - t.Deicoptic = 0x03ee; - t.Delta = 0x2206; - t.Deltagreek = 0x0394; - t.Dhook = 0x018a; - t.Dieresis = 0xf6cb; - t.DieresisAcute = 0xf6cc; - t.DieresisGrave = 0xf6cd; - t.Dieresissmall = 0xf7a8; - t.Digammagreek = 0x03dc; - t.Djecyrillic = 0x0402; - t.Dlinebelow = 0x1e0e; - t.Dmonospace = 0xff24; - t.Dotaccentsmall = 0xf6f7; - t.Dslash = 0x0110; - t.Dsmall = 0xf764; - t.Dtopbar = 0x018b; - t.Dz = 0x01f2; - t.Dzcaron = 0x01c5; - t.Dzeabkhasiancyrillic = 0x04e0; - t.Dzecyrillic = 0x0405; - t.Dzhecyrillic = 0x040f; - t.E = 0x0045; - t.Eacute = 0x00c9; - t.Eacutesmall = 0xf7e9; - t.Ebreve = 0x0114; - t.Ecaron = 0x011a; - t.Ecedillabreve = 0x1e1c; - t.Echarmenian = 0x0535; - t.Ecircle = 0x24ba; - t.Ecircumflex = 0x00ca; - t.Ecircumflexacute = 0x1ebe; - t.Ecircumflexbelow = 0x1e18; - t.Ecircumflexdotbelow = 0x1ec6; - t.Ecircumflexgrave = 0x1ec0; - t.Ecircumflexhookabove = 0x1ec2; - t.Ecircumflexsmall = 0xf7ea; - t.Ecircumflextilde = 0x1ec4; - t.Ecyrillic = 0x0404; - t.Edblgrave = 0x0204; - t.Edieresis = 0x00cb; - t.Edieresissmall = 0xf7eb; - t.Edot = 0x0116; - t.Edotaccent = 0x0116; - t.Edotbelow = 0x1eb8; - t.Efcyrillic = 0x0424; - t.Egrave = 0x00c8; - t.Egravesmall = 0xf7e8; - t.Eharmenian = 0x0537; - t.Ehookabove = 0x1eba; - t.Eightroman = 0x2167; - t.Einvertedbreve = 0x0206; - t.Eiotifiedcyrillic = 0x0464; - t.Elcyrillic = 0x041b; - t.Elevenroman = 0x216a; - t.Emacron = 0x0112; - t.Emacronacute = 0x1e16; - t.Emacrongrave = 0x1e14; - t.Emcyrillic = 0x041c; - t.Emonospace = 0xff25; - t.Encyrillic = 0x041d; - t.Endescendercyrillic = 0x04a2; - t.Eng = 0x014a; - t.Enghecyrillic = 0x04a4; - t.Enhookcyrillic = 0x04c7; - t.Eogonek = 0x0118; - t.Eopen = 0x0190; - t.Epsilon = 0x0395; - t.Epsilontonos = 0x0388; - t.Ercyrillic = 0x0420; - t.Ereversed = 0x018e; - t.Ereversedcyrillic = 0x042d; - t.Escyrillic = 0x0421; - t.Esdescendercyrillic = 0x04aa; - t.Esh = 0x01a9; - t.Esmall = 0xf765; - t.Eta = 0x0397; - t.Etarmenian = 0x0538; - t.Etatonos = 0x0389; - t.Eth = 0x00d0; - t.Ethsmall = 0xf7f0; - t.Etilde = 0x1ebc; - t.Etildebelow = 0x1e1a; - t.Euro = 0x20ac; - t.Ezh = 0x01b7; - t.Ezhcaron = 0x01ee; - t.Ezhreversed = 0x01b8; - t.F = 0x0046; - t.Fcircle = 0x24bb; - t.Fdotaccent = 0x1e1e; - t.Feharmenian = 0x0556; - t.Feicoptic = 0x03e4; - t.Fhook = 0x0191; - t.Fitacyrillic = 0x0472; - t.Fiveroman = 0x2164; - t.Fmonospace = 0xff26; - t.Fourroman = 0x2163; - t.Fsmall = 0xf766; - t.G = 0x0047; - t.GBsquare = 0x3387; - t.Gacute = 0x01f4; - t.Gamma = 0x0393; - t.Gammaafrican = 0x0194; - t.Gangiacoptic = 0x03ea; - t.Gbreve = 0x011e; - t.Gcaron = 0x01e6; - t.Gcedilla = 0x0122; - t.Gcircle = 0x24bc; - t.Gcircumflex = 0x011c; - t.Gcommaaccent = 0x0122; - t.Gdot = 0x0120; - t.Gdotaccent = 0x0120; - t.Gecyrillic = 0x0413; - t.Ghadarmenian = 0x0542; - t.Ghemiddlehookcyrillic = 0x0494; - t.Ghestrokecyrillic = 0x0492; - t.Gheupturncyrillic = 0x0490; - t.Ghook = 0x0193; - t.Gimarmenian = 0x0533; - t.Gjecyrillic = 0x0403; - t.Gmacron = 0x1e20; - t.Gmonospace = 0xff27; - t.Grave = 0xf6ce; - t.Gravesmall = 0xf760; - t.Gsmall = 0xf767; - t.Gsmallhook = 0x029b; - t.Gstroke = 0x01e4; - t.H = 0x0048; - t.H18533 = 0x25cf; - t.H18543 = 0x25aa; - t.H18551 = 0x25ab; - t.H22073 = 0x25a1; - t.HPsquare = 0x33cb; - t.Haabkhasiancyrillic = 0x04a8; - t.Hadescendercyrillic = 0x04b2; - t.Hardsigncyrillic = 0x042a; - t.Hbar = 0x0126; - t.Hbrevebelow = 0x1e2a; - t.Hcedilla = 0x1e28; - t.Hcircle = 0x24bd; - t.Hcircumflex = 0x0124; - t.Hdieresis = 0x1e26; - t.Hdotaccent = 0x1e22; - t.Hdotbelow = 0x1e24; - t.Hmonospace = 0xff28; - t.Hoarmenian = 0x0540; - t.Horicoptic = 0x03e8; - t.Hsmall = 0xf768; - t.Hungarumlaut = 0xf6cf; - t.Hungarumlautsmall = 0xf6f8; - t.Hzsquare = 0x3390; - t.I = 0x0049; - t.IAcyrillic = 0x042f; - t.IJ = 0x0132; - t.IUcyrillic = 0x042e; - t.Iacute = 0x00cd; - t.Iacutesmall = 0xf7ed; - t.Ibreve = 0x012c; - t.Icaron = 0x01cf; - t.Icircle = 0x24be; - t.Icircumflex = 0x00ce; - t.Icircumflexsmall = 0xf7ee; - t.Icyrillic = 0x0406; - t.Idblgrave = 0x0208; - t.Idieresis = 0x00cf; - t.Idieresisacute = 0x1e2e; - t.Idieresiscyrillic = 0x04e4; - t.Idieresissmall = 0xf7ef; - t.Idot = 0x0130; - t.Idotaccent = 0x0130; - t.Idotbelow = 0x1eca; - t.Iebrevecyrillic = 0x04d6; - t.Iecyrillic = 0x0415; - t.Ifraktur = 0x2111; - t.Igrave = 0x00cc; - t.Igravesmall = 0xf7ec; - t.Ihookabove = 0x1ec8; - t.Iicyrillic = 0x0418; - t.Iinvertedbreve = 0x020a; - t.Iishortcyrillic = 0x0419; - t.Imacron = 0x012a; - t.Imacroncyrillic = 0x04e2; - t.Imonospace = 0xff29; - t.Iniarmenian = 0x053b; - t.Iocyrillic = 0x0401; - t.Iogonek = 0x012e; - t.Iota = 0x0399; - t.Iotaafrican = 0x0196; - t.Iotadieresis = 0x03aa; - t.Iotatonos = 0x038a; - t.Ismall = 0xf769; - t.Istroke = 0x0197; - t.Itilde = 0x0128; - t.Itildebelow = 0x1e2c; - t.Izhitsacyrillic = 0x0474; - t.Izhitsadblgravecyrillic = 0x0476; - t.J = 0x004a; - t.Jaarmenian = 0x0541; - t.Jcircle = 0x24bf; - t.Jcircumflex = 0x0134; - t.Jecyrillic = 0x0408; - t.Jheharmenian = 0x054b; - t.Jmonospace = 0xff2a; - t.Jsmall = 0xf76a; - t.K = 0x004b; - t.KBsquare = 0x3385; - t.KKsquare = 0x33cd; - t.Kabashkircyrillic = 0x04a0; - t.Kacute = 0x1e30; - t.Kacyrillic = 0x041a; - t.Kadescendercyrillic = 0x049a; - t.Kahookcyrillic = 0x04c3; - t.Kappa = 0x039a; - t.Kastrokecyrillic = 0x049e; - t.Kaverticalstrokecyrillic = 0x049c; - t.Kcaron = 0x01e8; - t.Kcedilla = 0x0136; - t.Kcircle = 0x24c0; - t.Kcommaaccent = 0x0136; - t.Kdotbelow = 0x1e32; - t.Keharmenian = 0x0554; - t.Kenarmenian = 0x053f; - t.Khacyrillic = 0x0425; - t.Kheicoptic = 0x03e6; - t.Khook = 0x0198; - t.Kjecyrillic = 0x040c; - t.Klinebelow = 0x1e34; - t.Kmonospace = 0xff2b; - t.Koppacyrillic = 0x0480; - t.Koppagreek = 0x03de; - t.Ksicyrillic = 0x046e; - t.Ksmall = 0xf76b; - t.L = 0x004c; - t.LJ = 0x01c7; - t.LL = 0xf6bf; - t.Lacute = 0x0139; - t.Lambda = 0x039b; - t.Lcaron = 0x013d; - t.Lcedilla = 0x013b; - t.Lcircle = 0x24c1; - t.Lcircumflexbelow = 0x1e3c; - t.Lcommaaccent = 0x013b; - t.Ldot = 0x013f; - t.Ldotaccent = 0x013f; - t.Ldotbelow = 0x1e36; - t.Ldotbelowmacron = 0x1e38; - t.Liwnarmenian = 0x053c; - t.Lj = 0x01c8; - t.Ljecyrillic = 0x0409; - t.Llinebelow = 0x1e3a; - t.Lmonospace = 0xff2c; - t.Lslash = 0x0141; - t.Lslashsmall = 0xf6f9; - t.Lsmall = 0xf76c; - t.M = 0x004d; - t.MBsquare = 0x3386; - t.Macron = 0xf6d0; - t.Macronsmall = 0xf7af; - t.Macute = 0x1e3e; - t.Mcircle = 0x24c2; - t.Mdotaccent = 0x1e40; - t.Mdotbelow = 0x1e42; - t.Menarmenian = 0x0544; - t.Mmonospace = 0xff2d; - t.Msmall = 0xf76d; - t.Mturned = 0x019c; - t.Mu = 0x039c; - t.N = 0x004e; - t.NJ = 0x01ca; - t.Nacute = 0x0143; - t.Ncaron = 0x0147; - t.Ncedilla = 0x0145; - t.Ncircle = 0x24c3; - t.Ncircumflexbelow = 0x1e4a; - t.Ncommaaccent = 0x0145; - t.Ndotaccent = 0x1e44; - t.Ndotbelow = 0x1e46; - t.Nhookleft = 0x019d; - t.Nineroman = 0x2168; - t.Nj = 0x01cb; - t.Njecyrillic = 0x040a; - t.Nlinebelow = 0x1e48; - t.Nmonospace = 0xff2e; - t.Nowarmenian = 0x0546; - t.Nsmall = 0xf76e; - t.Ntilde = 0x00d1; - t.Ntildesmall = 0xf7f1; - t.Nu = 0x039d; - t.O = 0x004f; - t.OE = 0x0152; - t.OEsmall = 0xf6fa; - t.Oacute = 0x00d3; - t.Oacutesmall = 0xf7f3; - t.Obarredcyrillic = 0x04e8; - t.Obarreddieresiscyrillic = 0x04ea; - t.Obreve = 0x014e; - t.Ocaron = 0x01d1; - t.Ocenteredtilde = 0x019f; - t.Ocircle = 0x24c4; - t.Ocircumflex = 0x00d4; - t.Ocircumflexacute = 0x1ed0; - t.Ocircumflexdotbelow = 0x1ed8; - t.Ocircumflexgrave = 0x1ed2; - t.Ocircumflexhookabove = 0x1ed4; - t.Ocircumflexsmall = 0xf7f4; - t.Ocircumflextilde = 0x1ed6; - t.Ocyrillic = 0x041e; - t.Odblacute = 0x0150; - t.Odblgrave = 0x020c; - t.Odieresis = 0x00d6; - t.Odieresiscyrillic = 0x04e6; - t.Odieresissmall = 0xf7f6; - t.Odotbelow = 0x1ecc; - t.Ogoneksmall = 0xf6fb; - t.Ograve = 0x00d2; - t.Ogravesmall = 0xf7f2; - t.Oharmenian = 0x0555; - t.Ohm = 0x2126; - t.Ohookabove = 0x1ece; - t.Ohorn = 0x01a0; - t.Ohornacute = 0x1eda; - t.Ohorndotbelow = 0x1ee2; - t.Ohorngrave = 0x1edc; - t.Ohornhookabove = 0x1ede; - t.Ohorntilde = 0x1ee0; - t.Ohungarumlaut = 0x0150; - t.Oi = 0x01a2; - t.Oinvertedbreve = 0x020e; - t.Omacron = 0x014c; - t.Omacronacute = 0x1e52; - t.Omacrongrave = 0x1e50; - t.Omega = 0x2126; - t.Omegacyrillic = 0x0460; - t.Omegagreek = 0x03a9; - t.Omegaroundcyrillic = 0x047a; - t.Omegatitlocyrillic = 0x047c; - t.Omegatonos = 0x038f; - t.Omicron = 0x039f; - t.Omicrontonos = 0x038c; - t.Omonospace = 0xff2f; - t.Oneroman = 0x2160; - t.Oogonek = 0x01ea; - t.Oogonekmacron = 0x01ec; - t.Oopen = 0x0186; - t.Oslash = 0x00d8; - t.Oslashacute = 0x01fe; - t.Oslashsmall = 0xf7f8; - t.Osmall = 0xf76f; - t.Ostrokeacute = 0x01fe; - t.Otcyrillic = 0x047e; - t.Otilde = 0x00d5; - t.Otildeacute = 0x1e4c; - t.Otildedieresis = 0x1e4e; - t.Otildesmall = 0xf7f5; - t.P = 0x0050; - t.Pacute = 0x1e54; - t.Pcircle = 0x24c5; - t.Pdotaccent = 0x1e56; - t.Pecyrillic = 0x041f; - t.Peharmenian = 0x054a; - t.Pemiddlehookcyrillic = 0x04a6; - t.Phi = 0x03a6; - t.Phook = 0x01a4; - t.Pi = 0x03a0; - t.Piwrarmenian = 0x0553; - t.Pmonospace = 0xff30; - t.Psi = 0x03a8; - t.Psicyrillic = 0x0470; - t.Psmall = 0xf770; - t.Q = 0x0051; - t.Qcircle = 0x24c6; - t.Qmonospace = 0xff31; - t.Qsmall = 0xf771; - t.R = 0x0052; - t.Raarmenian = 0x054c; - t.Racute = 0x0154; - t.Rcaron = 0x0158; - t.Rcedilla = 0x0156; - t.Rcircle = 0x24c7; - t.Rcommaaccent = 0x0156; - t.Rdblgrave = 0x0210; - t.Rdotaccent = 0x1e58; - t.Rdotbelow = 0x1e5a; - t.Rdotbelowmacron = 0x1e5c; - t.Reharmenian = 0x0550; - t.Rfraktur = 0x211c; - t.Rho = 0x03a1; - t.Ringsmall = 0xf6fc; - t.Rinvertedbreve = 0x0212; - t.Rlinebelow = 0x1e5e; - t.Rmonospace = 0xff32; - t.Rsmall = 0xf772; - t.Rsmallinverted = 0x0281; - t.Rsmallinvertedsuperior = 0x02b6; - t.S = 0x0053; - t.SF010000 = 0x250c; - t.SF020000 = 0x2514; - t.SF030000 = 0x2510; - t.SF040000 = 0x2518; - t.SF050000 = 0x253c; - t.SF060000 = 0x252c; - t.SF070000 = 0x2534; - t.SF080000 = 0x251c; - t.SF090000 = 0x2524; - t.SF100000 = 0x2500; - t.SF110000 = 0x2502; - t.SF190000 = 0x2561; - t.SF200000 = 0x2562; - t.SF210000 = 0x2556; - t.SF220000 = 0x2555; - t.SF230000 = 0x2563; - t.SF240000 = 0x2551; - t.SF250000 = 0x2557; - t.SF260000 = 0x255d; - t.SF270000 = 0x255c; - t.SF280000 = 0x255b; - t.SF360000 = 0x255e; - t.SF370000 = 0x255f; - t.SF380000 = 0x255a; - t.SF390000 = 0x2554; - t.SF400000 = 0x2569; - t.SF410000 = 0x2566; - t.SF420000 = 0x2560; - t.SF430000 = 0x2550; - t.SF440000 = 0x256c; - t.SF450000 = 0x2567; - t.SF460000 = 0x2568; - t.SF470000 = 0x2564; - t.SF480000 = 0x2565; - t.SF490000 = 0x2559; - t.SF500000 = 0x2558; - t.SF510000 = 0x2552; - t.SF520000 = 0x2553; - t.SF530000 = 0x256b; - t.SF540000 = 0x256a; - t.Sacute = 0x015a; - t.Sacutedotaccent = 0x1e64; - t.Sampigreek = 0x03e0; - t.Scaron = 0x0160; - t.Scarondotaccent = 0x1e66; - t.Scaronsmall = 0xf6fd; - t.Scedilla = 0x015e; - t.Schwa = 0x018f; - t.Schwacyrillic = 0x04d8; - t.Schwadieresiscyrillic = 0x04da; - t.Scircle = 0x24c8; - t.Scircumflex = 0x015c; - t.Scommaaccent = 0x0218; - t.Sdotaccent = 0x1e60; - t.Sdotbelow = 0x1e62; - t.Sdotbelowdotaccent = 0x1e68; - t.Seharmenian = 0x054d; - t.Sevenroman = 0x2166; - t.Shaarmenian = 0x0547; - t.Shacyrillic = 0x0428; - t.Shchacyrillic = 0x0429; - t.Sheicoptic = 0x03e2; - t.Shhacyrillic = 0x04ba; - t.Shimacoptic = 0x03ec; - t.Sigma = 0x03a3; - t.Sixroman = 0x2165; - t.Smonospace = 0xff33; - t.Softsigncyrillic = 0x042c; - t.Ssmall = 0xf773; - t.Stigmagreek = 0x03da; - t.T = 0x0054; - t.Tau = 0x03a4; - t.Tbar = 0x0166; - t.Tcaron = 0x0164; - t.Tcedilla = 0x0162; - t.Tcircle = 0x24c9; - t.Tcircumflexbelow = 0x1e70; - t.Tcommaaccent = 0x0162; - t.Tdotaccent = 0x1e6a; - t.Tdotbelow = 0x1e6c; - t.Tecyrillic = 0x0422; - t.Tedescendercyrillic = 0x04ac; - t.Tenroman = 0x2169; - t.Tetsecyrillic = 0x04b4; - t.Theta = 0x0398; - t.Thook = 0x01ac; - t.Thorn = 0x00de; - t.Thornsmall = 0xf7fe; - t.Threeroman = 0x2162; - t.Tildesmall = 0xf6fe; - t.Tiwnarmenian = 0x054f; - t.Tlinebelow = 0x1e6e; - t.Tmonospace = 0xff34; - t.Toarmenian = 0x0539; - t.Tonefive = 0x01bc; - t.Tonesix = 0x0184; - t.Tonetwo = 0x01a7; - t.Tretroflexhook = 0x01ae; - t.Tsecyrillic = 0x0426; - t.Tshecyrillic = 0x040b; - t.Tsmall = 0xf774; - t.Twelveroman = 0x216b; - t.Tworoman = 0x2161; - t.U = 0x0055; - t.Uacute = 0x00da; - t.Uacutesmall = 0xf7fa; - t.Ubreve = 0x016c; - t.Ucaron = 0x01d3; - t.Ucircle = 0x24ca; - t.Ucircumflex = 0x00db; - t.Ucircumflexbelow = 0x1e76; - t.Ucircumflexsmall = 0xf7fb; - t.Ucyrillic = 0x0423; - t.Udblacute = 0x0170; - t.Udblgrave = 0x0214; - t.Udieresis = 0x00dc; - t.Udieresisacute = 0x01d7; - t.Udieresisbelow = 0x1e72; - t.Udieresiscaron = 0x01d9; - t.Udieresiscyrillic = 0x04f0; - t.Udieresisgrave = 0x01db; - t.Udieresismacron = 0x01d5; - t.Udieresissmall = 0xf7fc; - t.Udotbelow = 0x1ee4; - t.Ugrave = 0x00d9; - t.Ugravesmall = 0xf7f9; - t.Uhookabove = 0x1ee6; - t.Uhorn = 0x01af; - t.Uhornacute = 0x1ee8; - t.Uhorndotbelow = 0x1ef0; - t.Uhorngrave = 0x1eea; - t.Uhornhookabove = 0x1eec; - t.Uhorntilde = 0x1eee; - t.Uhungarumlaut = 0x0170; - t.Uhungarumlautcyrillic = 0x04f2; - t.Uinvertedbreve = 0x0216; - t.Ukcyrillic = 0x0478; - t.Umacron = 0x016a; - t.Umacroncyrillic = 0x04ee; - t.Umacrondieresis = 0x1e7a; - t.Umonospace = 0xff35; - t.Uogonek = 0x0172; - t.Upsilon = 0x03a5; - t.Upsilon1 = 0x03d2; - t.Upsilonacutehooksymbolgreek = 0x03d3; - t.Upsilonafrican = 0x01b1; - t.Upsilondieresis = 0x03ab; - t.Upsilondieresishooksymbolgreek = 0x03d4; - t.Upsilonhooksymbol = 0x03d2; - t.Upsilontonos = 0x038e; - t.Uring = 0x016e; - t.Ushortcyrillic = 0x040e; - t.Usmall = 0xf775; - t.Ustraightcyrillic = 0x04ae; - t.Ustraightstrokecyrillic = 0x04b0; - t.Utilde = 0x0168; - t.Utildeacute = 0x1e78; - t.Utildebelow = 0x1e74; - t.V = 0x0056; - t.Vcircle = 0x24cb; - t.Vdotbelow = 0x1e7e; - t.Vecyrillic = 0x0412; - t.Vewarmenian = 0x054e; - t.Vhook = 0x01b2; - t.Vmonospace = 0xff36; - t.Voarmenian = 0x0548; - t.Vsmall = 0xf776; - t.Vtilde = 0x1e7c; - t.W = 0x0057; - t.Wacute = 0x1e82; - t.Wcircle = 0x24cc; - t.Wcircumflex = 0x0174; - t.Wdieresis = 0x1e84; - t.Wdotaccent = 0x1e86; - t.Wdotbelow = 0x1e88; - t.Wgrave = 0x1e80; - t.Wmonospace = 0xff37; - t.Wsmall = 0xf777; - t.X = 0x0058; - t.Xcircle = 0x24cd; - t.Xdieresis = 0x1e8c; - t.Xdotaccent = 0x1e8a; - t.Xeharmenian = 0x053d; - t.Xi = 0x039e; - t.Xmonospace = 0xff38; - t.Xsmall = 0xf778; - t.Y = 0x0059; - t.Yacute = 0x00dd; - t.Yacutesmall = 0xf7fd; - t.Yatcyrillic = 0x0462; - t.Ycircle = 0x24ce; - t.Ycircumflex = 0x0176; - t.Ydieresis = 0x0178; - t.Ydieresissmall = 0xf7ff; - t.Ydotaccent = 0x1e8e; - t.Ydotbelow = 0x1ef4; - t.Yericyrillic = 0x042b; - t.Yerudieresiscyrillic = 0x04f8; - t.Ygrave = 0x1ef2; - t.Yhook = 0x01b3; - t.Yhookabove = 0x1ef6; - t.Yiarmenian = 0x0545; - t.Yicyrillic = 0x0407; - t.Yiwnarmenian = 0x0552; - t.Ymonospace = 0xff39; - t.Ysmall = 0xf779; - t.Ytilde = 0x1ef8; - t.Yusbigcyrillic = 0x046a; - t.Yusbigiotifiedcyrillic = 0x046c; - t.Yuslittlecyrillic = 0x0466; - t.Yuslittleiotifiedcyrillic = 0x0468; - t.Z = 0x005a; - t.Zaarmenian = 0x0536; - t.Zacute = 0x0179; - t.Zcaron = 0x017d; - t.Zcaronsmall = 0xf6ff; - t.Zcircle = 0x24cf; - t.Zcircumflex = 0x1e90; - t.Zdot = 0x017b; - t.Zdotaccent = 0x017b; - t.Zdotbelow = 0x1e92; - t.Zecyrillic = 0x0417; - t.Zedescendercyrillic = 0x0498; - t.Zedieresiscyrillic = 0x04de; - t.Zeta = 0x0396; - t.Zhearmenian = 0x053a; - t.Zhebrevecyrillic = 0x04c1; - t.Zhecyrillic = 0x0416; - t.Zhedescendercyrillic = 0x0496; - t.Zhedieresiscyrillic = 0x04dc; - t.Zlinebelow = 0x1e94; - t.Zmonospace = 0xff3a; - t.Zsmall = 0xf77a; - t.Zstroke = 0x01b5; - t.a = 0x0061; - t.aabengali = 0x0986; - t.aacute = 0x00e1; - t.aadeva = 0x0906; - t.aagujarati = 0x0a86; - t.aagurmukhi = 0x0a06; - t.aamatragurmukhi = 0x0a3e; - t.aarusquare = 0x3303; - t.aavowelsignbengali = 0x09be; - t.aavowelsigndeva = 0x093e; - t.aavowelsigngujarati = 0x0abe; - t.abbreviationmarkarmenian = 0x055f; - t.abbreviationsigndeva = 0x0970; - t.abengali = 0x0985; - t.abopomofo = 0x311a; - t.abreve = 0x0103; - t.abreveacute = 0x1eaf; - t.abrevecyrillic = 0x04d1; - t.abrevedotbelow = 0x1eb7; - t.abrevegrave = 0x1eb1; - t.abrevehookabove = 0x1eb3; - t.abrevetilde = 0x1eb5; - t.acaron = 0x01ce; - t.acircle = 0x24d0; - t.acircumflex = 0x00e2; - t.acircumflexacute = 0x1ea5; - t.acircumflexdotbelow = 0x1ead; - t.acircumflexgrave = 0x1ea7; - t.acircumflexhookabove = 0x1ea9; - t.acircumflextilde = 0x1eab; - t.acute = 0x00b4; - t.acutebelowcmb = 0x0317; - t.acutecmb = 0x0301; - t.acutecomb = 0x0301; - t.acutedeva = 0x0954; - t.acutelowmod = 0x02cf; - t.acutetonecmb = 0x0341; - t.acyrillic = 0x0430; - t.adblgrave = 0x0201; - t.addakgurmukhi = 0x0a71; - t.adeva = 0x0905; - t.adieresis = 0x00e4; - t.adieresiscyrillic = 0x04d3; - t.adieresismacron = 0x01df; - t.adotbelow = 0x1ea1; - t.adotmacron = 0x01e1; - t.ae = 0x00e6; - t.aeacute = 0x01fd; - t.aekorean = 0x3150; - t.aemacron = 0x01e3; - t.afii00208 = 0x2015; - t.afii08941 = 0x20a4; - t.afii10017 = 0x0410; - t.afii10018 = 0x0411; - t.afii10019 = 0x0412; - t.afii10020 = 0x0413; - t.afii10021 = 0x0414; - t.afii10022 = 0x0415; - t.afii10023 = 0x0401; - t.afii10024 = 0x0416; - t.afii10025 = 0x0417; - t.afii10026 = 0x0418; - t.afii10027 = 0x0419; - t.afii10028 = 0x041a; - t.afii10029 = 0x041b; - t.afii10030 = 0x041c; - t.afii10031 = 0x041d; - t.afii10032 = 0x041e; - t.afii10033 = 0x041f; - t.afii10034 = 0x0420; - t.afii10035 = 0x0421; - t.afii10036 = 0x0422; - t.afii10037 = 0x0423; - t.afii10038 = 0x0424; - t.afii10039 = 0x0425; - t.afii10040 = 0x0426; - t.afii10041 = 0x0427; - t.afii10042 = 0x0428; - t.afii10043 = 0x0429; - t.afii10044 = 0x042a; - t.afii10045 = 0x042b; - t.afii10046 = 0x042c; - t.afii10047 = 0x042d; - t.afii10048 = 0x042e; - t.afii10049 = 0x042f; - t.afii10050 = 0x0490; - t.afii10051 = 0x0402; - t.afii10052 = 0x0403; - t.afii10053 = 0x0404; - t.afii10054 = 0x0405; - t.afii10055 = 0x0406; - t.afii10056 = 0x0407; - t.afii10057 = 0x0408; - t.afii10058 = 0x0409; - t.afii10059 = 0x040a; - t.afii10060 = 0x040b; - t.afii10061 = 0x040c; - t.afii10062 = 0x040e; - t.afii10063 = 0xf6c4; - t.afii10064 = 0xf6c5; - t.afii10065 = 0x0430; - t.afii10066 = 0x0431; - t.afii10067 = 0x0432; - t.afii10068 = 0x0433; - t.afii10069 = 0x0434; - t.afii10070 = 0x0435; - t.afii10071 = 0x0451; - t.afii10072 = 0x0436; - t.afii10073 = 0x0437; - t.afii10074 = 0x0438; - t.afii10075 = 0x0439; - t.afii10076 = 0x043a; - t.afii10077 = 0x043b; - t.afii10078 = 0x043c; - t.afii10079 = 0x043d; - t.afii10080 = 0x043e; - t.afii10081 = 0x043f; - t.afii10082 = 0x0440; - t.afii10083 = 0x0441; - t.afii10084 = 0x0442; - t.afii10085 = 0x0443; - t.afii10086 = 0x0444; - t.afii10087 = 0x0445; - t.afii10088 = 0x0446; - t.afii10089 = 0x0447; - t.afii10090 = 0x0448; - t.afii10091 = 0x0449; - t.afii10092 = 0x044a; - t.afii10093 = 0x044b; - t.afii10094 = 0x044c; - t.afii10095 = 0x044d; - t.afii10096 = 0x044e; - t.afii10097 = 0x044f; - t.afii10098 = 0x0491; - t.afii10099 = 0x0452; - t.afii10100 = 0x0453; - t.afii10101 = 0x0454; - t.afii10102 = 0x0455; - t.afii10103 = 0x0456; - t.afii10104 = 0x0457; - t.afii10105 = 0x0458; - t.afii10106 = 0x0459; - t.afii10107 = 0x045a; - t.afii10108 = 0x045b; - t.afii10109 = 0x045c; - t.afii10110 = 0x045e; - t.afii10145 = 0x040f; - t.afii10146 = 0x0462; - t.afii10147 = 0x0472; - t.afii10148 = 0x0474; - t.afii10192 = 0xf6c6; - t.afii10193 = 0x045f; - t.afii10194 = 0x0463; - t.afii10195 = 0x0473; - t.afii10196 = 0x0475; - t.afii10831 = 0xf6c7; - t.afii10832 = 0xf6c8; - t.afii10846 = 0x04d9; - t.afii299 = 0x200e; - t.afii300 = 0x200f; - t.afii301 = 0x200d; - t.afii57381 = 0x066a; - t.afii57388 = 0x060c; - t.afii57392 = 0x0660; - t.afii57393 = 0x0661; - t.afii57394 = 0x0662; - t.afii57395 = 0x0663; - t.afii57396 = 0x0664; - t.afii57397 = 0x0665; - t.afii57398 = 0x0666; - t.afii57399 = 0x0667; - t.afii57400 = 0x0668; - t.afii57401 = 0x0669; - t.afii57403 = 0x061b; - t.afii57407 = 0x061f; - t.afii57409 = 0x0621; - t.afii57410 = 0x0622; - t.afii57411 = 0x0623; - t.afii57412 = 0x0624; - t.afii57413 = 0x0625; - t.afii57414 = 0x0626; - t.afii57415 = 0x0627; - t.afii57416 = 0x0628; - t.afii57417 = 0x0629; - t.afii57418 = 0x062a; - t.afii57419 = 0x062b; - t.afii57420 = 0x062c; - t.afii57421 = 0x062d; - t.afii57422 = 0x062e; - t.afii57423 = 0x062f; - t.afii57424 = 0x0630; - t.afii57425 = 0x0631; - t.afii57426 = 0x0632; - t.afii57427 = 0x0633; - t.afii57428 = 0x0634; - t.afii57429 = 0x0635; - t.afii57430 = 0x0636; - t.afii57431 = 0x0637; - t.afii57432 = 0x0638; - t.afii57433 = 0x0639; - t.afii57434 = 0x063a; - t.afii57440 = 0x0640; - t.afii57441 = 0x0641; - t.afii57442 = 0x0642; - t.afii57443 = 0x0643; - t.afii57444 = 0x0644; - t.afii57445 = 0x0645; - t.afii57446 = 0x0646; - t.afii57448 = 0x0648; - t.afii57449 = 0x0649; - t.afii57450 = 0x064a; - t.afii57451 = 0x064b; - t.afii57452 = 0x064c; - t.afii57453 = 0x064d; - t.afii57454 = 0x064e; - t.afii57455 = 0x064f; - t.afii57456 = 0x0650; - t.afii57457 = 0x0651; - t.afii57458 = 0x0652; - t.afii57470 = 0x0647; - t.afii57505 = 0x06a4; - t.afii57506 = 0x067e; - t.afii57507 = 0x0686; - t.afii57508 = 0x0698; - t.afii57509 = 0x06af; - t.afii57511 = 0x0679; - t.afii57512 = 0x0688; - t.afii57513 = 0x0691; - t.afii57514 = 0x06ba; - t.afii57519 = 0x06d2; - t.afii57534 = 0x06d5; - t.afii57636 = 0x20aa; - t.afii57645 = 0x05be; - t.afii57658 = 0x05c3; - t.afii57664 = 0x05d0; - t.afii57665 = 0x05d1; - t.afii57666 = 0x05d2; - t.afii57667 = 0x05d3; - t.afii57668 = 0x05d4; - t.afii57669 = 0x05d5; - t.afii57670 = 0x05d6; - t.afii57671 = 0x05d7; - t.afii57672 = 0x05d8; - t.afii57673 = 0x05d9; - t.afii57674 = 0x05da; - t.afii57675 = 0x05db; - t.afii57676 = 0x05dc; - t.afii57677 = 0x05dd; - t.afii57678 = 0x05de; - t.afii57679 = 0x05df; - t.afii57680 = 0x05e0; - t.afii57681 = 0x05e1; - t.afii57682 = 0x05e2; - t.afii57683 = 0x05e3; - t.afii57684 = 0x05e4; - t.afii57685 = 0x05e5; - t.afii57686 = 0x05e6; - t.afii57687 = 0x05e7; - t.afii57688 = 0x05e8; - t.afii57689 = 0x05e9; - t.afii57690 = 0x05ea; - t.afii57694 = 0xfb2a; - t.afii57695 = 0xfb2b; - t.afii57700 = 0xfb4b; - t.afii57705 = 0xfb1f; - t.afii57716 = 0x05f0; - t.afii57717 = 0x05f1; - t.afii57718 = 0x05f2; - t.afii57723 = 0xfb35; - t.afii57793 = 0x05b4; - t.afii57794 = 0x05b5; - t.afii57795 = 0x05b6; - t.afii57796 = 0x05bb; - t.afii57797 = 0x05b8; - t.afii57798 = 0x05b7; - t.afii57799 = 0x05b0; - t.afii57800 = 0x05b2; - t.afii57801 = 0x05b1; - t.afii57802 = 0x05b3; - t.afii57803 = 0x05c2; - t.afii57804 = 0x05c1; - t.afii57806 = 0x05b9; - t.afii57807 = 0x05bc; - t.afii57839 = 0x05bd; - t.afii57841 = 0x05bf; - t.afii57842 = 0x05c0; - t.afii57929 = 0x02bc; - t.afii61248 = 0x2105; - t.afii61289 = 0x2113; - t.afii61352 = 0x2116; - t.afii61573 = 0x202c; - t.afii61574 = 0x202d; - t.afii61575 = 0x202e; - t.afii61664 = 0x200c; - t.afii63167 = 0x066d; - t.afii64937 = 0x02bd; - t.agrave = 0x00e0; - t.agujarati = 0x0a85; - t.agurmukhi = 0x0a05; - t.ahiragana = 0x3042; - t.ahookabove = 0x1ea3; - t.aibengali = 0x0990; - t.aibopomofo = 0x311e; - t.aideva = 0x0910; - t.aiecyrillic = 0x04d5; - t.aigujarati = 0x0a90; - t.aigurmukhi = 0x0a10; - t.aimatragurmukhi = 0x0a48; - t.ainarabic = 0x0639; - t.ainfinalarabic = 0xfeca; - t.aininitialarabic = 0xfecb; - t.ainmedialarabic = 0xfecc; - t.ainvertedbreve = 0x0203; - t.aivowelsignbengali = 0x09c8; - t.aivowelsigndeva = 0x0948; - t.aivowelsigngujarati = 0x0ac8; - t.akatakana = 0x30a2; - t.akatakanahalfwidth = 0xff71; - t.akorean = 0x314f; - t.alef = 0x05d0; - t.alefarabic = 0x0627; - t.alefdageshhebrew = 0xfb30; - t.aleffinalarabic = 0xfe8e; - t.alefhamzaabovearabic = 0x0623; - t.alefhamzaabovefinalarabic = 0xfe84; - t.alefhamzabelowarabic = 0x0625; - t.alefhamzabelowfinalarabic = 0xfe88; - t.alefhebrew = 0x05d0; - t.aleflamedhebrew = 0xfb4f; - t.alefmaddaabovearabic = 0x0622; - t.alefmaddaabovefinalarabic = 0xfe82; - t.alefmaksuraarabic = 0x0649; - t.alefmaksurafinalarabic = 0xfef0; - t.alefmaksurainitialarabic = 0xfef3; - t.alefmaksuramedialarabic = 0xfef4; - t.alefpatahhebrew = 0xfb2e; - t.alefqamatshebrew = 0xfb2f; - t.aleph = 0x2135; - t.allequal = 0x224c; - t.alpha = 0x03b1; - t.alphatonos = 0x03ac; - t.amacron = 0x0101; - t.amonospace = 0xff41; - t.ampersand = 0x0026; - t.ampersandmonospace = 0xff06; - t.ampersandsmall = 0xf726; - t.amsquare = 0x33c2; - t.anbopomofo = 0x3122; - t.angbopomofo = 0x3124; - t.angbracketleft = 0x3008; - t.angbracketright = 0x3009; - t.angkhankhuthai = 0x0e5a; - t.angle = 0x2220; - t.anglebracketleft = 0x3008; - t.anglebracketleftvertical = 0xfe3f; - t.anglebracketright = 0x3009; - t.anglebracketrightvertical = 0xfe40; - t.angleleft = 0x2329; - t.angleright = 0x232a; - t.angstrom = 0x212b; - t.anoteleia = 0x0387; - t.anudattadeva = 0x0952; - t.anusvarabengali = 0x0982; - t.anusvaradeva = 0x0902; - t.anusvaragujarati = 0x0a82; - t.aogonek = 0x0105; - t.apaatosquare = 0x3300; - t.aparen = 0x249c; - t.apostrophearmenian = 0x055a; - t.apostrophemod = 0x02bc; - t.apple = 0xf8ff; - t.approaches = 0x2250; - t.approxequal = 0x2248; - t.approxequalorimage = 0x2252; - t.approximatelyequal = 0x2245; - t.araeaekorean = 0x318e; - t.araeakorean = 0x318d; - t.arc = 0x2312; - t.arighthalfring = 0x1e9a; - t.aring = 0x00e5; - t.aringacute = 0x01fb; - t.aringbelow = 0x1e01; - t.arrowboth = 0x2194; - t.arrowdashdown = 0x21e3; - t.arrowdashleft = 0x21e0; - t.arrowdashright = 0x21e2; - t.arrowdashup = 0x21e1; - t.arrowdblboth = 0x21d4; - t.arrowdbldown = 0x21d3; - t.arrowdblleft = 0x21d0; - t.arrowdblright = 0x21d2; - t.arrowdblup = 0x21d1; - t.arrowdown = 0x2193; - t.arrowdownleft = 0x2199; - t.arrowdownright = 0x2198; - t.arrowdownwhite = 0x21e9; - t.arrowheaddownmod = 0x02c5; - t.arrowheadleftmod = 0x02c2; - t.arrowheadrightmod = 0x02c3; - t.arrowheadupmod = 0x02c4; - t.arrowhorizex = 0xf8e7; - t.arrowleft = 0x2190; - t.arrowleftdbl = 0x21d0; - t.arrowleftdblstroke = 0x21cd; - t.arrowleftoverright = 0x21c6; - t.arrowleftwhite = 0x21e6; - t.arrowright = 0x2192; - t.arrowrightdblstroke = 0x21cf; - t.arrowrightheavy = 0x279e; - t.arrowrightoverleft = 0x21c4; - t.arrowrightwhite = 0x21e8; - t.arrowtableft = 0x21e4; - t.arrowtabright = 0x21e5; - t.arrowup = 0x2191; - t.arrowupdn = 0x2195; - t.arrowupdnbse = 0x21a8; - t.arrowupdownbase = 0x21a8; - t.arrowupleft = 0x2196; - t.arrowupleftofdown = 0x21c5; - t.arrowupright = 0x2197; - t.arrowupwhite = 0x21e7; - t.arrowvertex = 0xf8e6; - t.asciicircum = 0x005e; - t.asciicircummonospace = 0xff3e; - t.asciitilde = 0x007e; - t.asciitildemonospace = 0xff5e; - t.ascript = 0x0251; - t.ascriptturned = 0x0252; - t.asmallhiragana = 0x3041; - t.asmallkatakana = 0x30a1; - t.asmallkatakanahalfwidth = 0xff67; - t.asterisk = 0x002a; - t.asteriskaltonearabic = 0x066d; - t.asteriskarabic = 0x066d; - t.asteriskmath = 0x2217; - t.asteriskmonospace = 0xff0a; - t.asterisksmall = 0xfe61; - t.asterism = 0x2042; - t.asuperior = 0xf6e9; - t.asymptoticallyequal = 0x2243; - t.at = 0x0040; - t.atilde = 0x00e3; - t.atmonospace = 0xff20; - t.atsmall = 0xfe6b; - t.aturned = 0x0250; - t.aubengali = 0x0994; - t.aubopomofo = 0x3120; - t.audeva = 0x0914; - t.augujarati = 0x0a94; - t.augurmukhi = 0x0a14; - t.aulengthmarkbengali = 0x09d7; - t.aumatragurmukhi = 0x0a4c; - t.auvowelsignbengali = 0x09cc; - t.auvowelsigndeva = 0x094c; - t.auvowelsigngujarati = 0x0acc; - t.avagrahadeva = 0x093d; - t.aybarmenian = 0x0561; - t.ayin = 0x05e2; - t.ayinaltonehebrew = 0xfb20; - t.ayinhebrew = 0x05e2; - t.b = 0x0062; - t.babengali = 0x09ac; - t.backslash = 0x005c; - t.backslashmonospace = 0xff3c; - t.badeva = 0x092c; - t.bagujarati = 0x0aac; - t.bagurmukhi = 0x0a2c; - t.bahiragana = 0x3070; - t.bahtthai = 0x0e3f; - t.bakatakana = 0x30d0; - t.bar = 0x007c; - t.barmonospace = 0xff5c; - t.bbopomofo = 0x3105; - t.bcircle = 0x24d1; - t.bdotaccent = 0x1e03; - t.bdotbelow = 0x1e05; - t.beamedsixteenthnotes = 0x266c; - t.because = 0x2235; - t.becyrillic = 0x0431; - t.beharabic = 0x0628; - t.behfinalarabic = 0xfe90; - t.behinitialarabic = 0xfe91; - t.behiragana = 0x3079; - t.behmedialarabic = 0xfe92; - t.behmeeminitialarabic = 0xfc9f; - t.behmeemisolatedarabic = 0xfc08; - t.behnoonfinalarabic = 0xfc6d; - t.bekatakana = 0x30d9; - t.benarmenian = 0x0562; - t.bet = 0x05d1; - t.beta = 0x03b2; - t.betasymbolgreek = 0x03d0; - t.betdagesh = 0xfb31; - t.betdageshhebrew = 0xfb31; - t.bethebrew = 0x05d1; - t.betrafehebrew = 0xfb4c; - t.bhabengali = 0x09ad; - t.bhadeva = 0x092d; - t.bhagujarati = 0x0aad; - t.bhagurmukhi = 0x0a2d; - t.bhook = 0x0253; - t.bihiragana = 0x3073; - t.bikatakana = 0x30d3; - t.bilabialclick = 0x0298; - t.bindigurmukhi = 0x0a02; - t.birusquare = 0x3331; - t.blackcircle = 0x25cf; - t.blackdiamond = 0x25c6; - t.blackdownpointingtriangle = 0x25bc; - t.blackleftpointingpointer = 0x25c4; - t.blackleftpointingtriangle = 0x25c0; - t.blacklenticularbracketleft = 0x3010; - t.blacklenticularbracketleftvertical = 0xfe3b; - t.blacklenticularbracketright = 0x3011; - t.blacklenticularbracketrightvertical = 0xfe3c; - t.blacklowerlefttriangle = 0x25e3; - t.blacklowerrighttriangle = 0x25e2; - t.blackrectangle = 0x25ac; - t.blackrightpointingpointer = 0x25ba; - t.blackrightpointingtriangle = 0x25b6; - t.blacksmallsquare = 0x25aa; - t.blacksmilingface = 0x263b; - t.blacksquare = 0x25a0; - t.blackstar = 0x2605; - t.blackupperlefttriangle = 0x25e4; - t.blackupperrighttriangle = 0x25e5; - t.blackuppointingsmalltriangle = 0x25b4; - t.blackuppointingtriangle = 0x25b2; - t.blank = 0x2423; - t.blinebelow = 0x1e07; - t.block = 0x2588; - t.bmonospace = 0xff42; - t.bobaimaithai = 0x0e1a; - t.bohiragana = 0x307c; - t.bokatakana = 0x30dc; - t.bparen = 0x249d; - t.bqsquare = 0x33c3; - t.braceex = 0xf8f4; - t.braceleft = 0x007b; - t.braceleftbt = 0xf8f3; - t.braceleftmid = 0xf8f2; - t.braceleftmonospace = 0xff5b; - t.braceleftsmall = 0xfe5b; - t.bracelefttp = 0xf8f1; - t.braceleftvertical = 0xfe37; - t.braceright = 0x007d; - t.bracerightbt = 0xf8fe; - t.bracerightmid = 0xf8fd; - t.bracerightmonospace = 0xff5d; - t.bracerightsmall = 0xfe5c; - t.bracerighttp = 0xf8fc; - t.bracerightvertical = 0xfe38; - t.bracketleft = 0x005b; - t.bracketleftbt = 0xf8f0; - t.bracketleftex = 0xf8ef; - t.bracketleftmonospace = 0xff3b; - t.bracketlefttp = 0xf8ee; - t.bracketright = 0x005d; - t.bracketrightbt = 0xf8fb; - t.bracketrightex = 0xf8fa; - t.bracketrightmonospace = 0xff3d; - t.bracketrighttp = 0xf8f9; - t.breve = 0x02d8; - t.brevebelowcmb = 0x032e; - t.brevecmb = 0x0306; - t.breveinvertedbelowcmb = 0x032f; - t.breveinvertedcmb = 0x0311; - t.breveinverteddoublecmb = 0x0361; - t.bridgebelowcmb = 0x032a; - t.bridgeinvertedbelowcmb = 0x033a; - t.brokenbar = 0x00a6; - t.bstroke = 0x0180; - t.bsuperior = 0xf6ea; - t.btopbar = 0x0183; - t.buhiragana = 0x3076; - t.bukatakana = 0x30d6; - t.bullet = 0x2022; - t.bulletinverse = 0x25d8; - t.bulletoperator = 0x2219; - t.bullseye = 0x25ce; - t.c = 0x0063; - t.caarmenian = 0x056e; - t.cabengali = 0x099a; - t.cacute = 0x0107; - t.cadeva = 0x091a; - t.cagujarati = 0x0a9a; - t.cagurmukhi = 0x0a1a; - t.calsquare = 0x3388; - t.candrabindubengali = 0x0981; - t.candrabinducmb = 0x0310; - t.candrabindudeva = 0x0901; - t.candrabindugujarati = 0x0a81; - t.capslock = 0x21ea; - t.careof = 0x2105; - t.caron = 0x02c7; - t.caronbelowcmb = 0x032c; - t.caroncmb = 0x030c; - t.carriagereturn = 0x21b5; - t.cbopomofo = 0x3118; - t.ccaron = 0x010d; - t.ccedilla = 0x00e7; - t.ccedillaacute = 0x1e09; - t.ccircle = 0x24d2; - t.ccircumflex = 0x0109; - t.ccurl = 0x0255; - t.cdot = 0x010b; - t.cdotaccent = 0x010b; - t.cdsquare = 0x33c5; - t.cedilla = 0x00b8; - t.cedillacmb = 0x0327; - t.cent = 0x00a2; - t.centigrade = 0x2103; - t.centinferior = 0xf6df; - t.centmonospace = 0xffe0; - t.centoldstyle = 0xf7a2; - t.centsuperior = 0xf6e0; - t.chaarmenian = 0x0579; - t.chabengali = 0x099b; - t.chadeva = 0x091b; - t.chagujarati = 0x0a9b; - t.chagurmukhi = 0x0a1b; - t.chbopomofo = 0x3114; - t.cheabkhasiancyrillic = 0x04bd; - t.checkmark = 0x2713; - t.checyrillic = 0x0447; - t.chedescenderabkhasiancyrillic = 0x04bf; - t.chedescendercyrillic = 0x04b7; - t.chedieresiscyrillic = 0x04f5; - t.cheharmenian = 0x0573; - t.chekhakassiancyrillic = 0x04cc; - t.cheverticalstrokecyrillic = 0x04b9; - t.chi = 0x03c7; - t.chieuchacirclekorean = 0x3277; - t.chieuchaparenkorean = 0x3217; - t.chieuchcirclekorean = 0x3269; - t.chieuchkorean = 0x314a; - t.chieuchparenkorean = 0x3209; - t.chochangthai = 0x0e0a; - t.chochanthai = 0x0e08; - t.chochingthai = 0x0e09; - t.chochoethai = 0x0e0c; - t.chook = 0x0188; - t.cieucacirclekorean = 0x3276; - t.cieucaparenkorean = 0x3216; - t.cieuccirclekorean = 0x3268; - t.cieuckorean = 0x3148; - t.cieucparenkorean = 0x3208; - t.cieucuparenkorean = 0x321c; - t.circle = 0x25cb; - t.circlecopyrt = 0x00a9; - t.circlemultiply = 0x2297; - t.circleot = 0x2299; - t.circleplus = 0x2295; - t.circlepostalmark = 0x3036; - t.circlewithlefthalfblack = 0x25d0; - t.circlewithrighthalfblack = 0x25d1; - t.circumflex = 0x02c6; - t.circumflexbelowcmb = 0x032d; - t.circumflexcmb = 0x0302; - t.clear = 0x2327; - t.clickalveolar = 0x01c2; - t.clickdental = 0x01c0; - t.clicklateral = 0x01c1; - t.clickretroflex = 0x01c3; - t.club = 0x2663; - t.clubsuitblack = 0x2663; - t.clubsuitwhite = 0x2667; - t.cmcubedsquare = 0x33a4; - t.cmonospace = 0xff43; - t.cmsquaredsquare = 0x33a0; - t.coarmenian = 0x0581; - t.colon = 0x003a; - t.colonmonetary = 0x20a1; - t.colonmonospace = 0xff1a; - t.colonsign = 0x20a1; - t.colonsmall = 0xfe55; - t.colontriangularhalfmod = 0x02d1; - t.colontriangularmod = 0x02d0; - t.comma = 0x002c; - t.commaabovecmb = 0x0313; - t.commaaboverightcmb = 0x0315; - t.commaaccent = 0xf6c3; - t.commaarabic = 0x060c; - t.commaarmenian = 0x055d; - t.commainferior = 0xf6e1; - t.commamonospace = 0xff0c; - t.commareversedabovecmb = 0x0314; - t.commareversedmod = 0x02bd; - t.commasmall = 0xfe50; - t.commasuperior = 0xf6e2; - t.commaturnedabovecmb = 0x0312; - t.commaturnedmod = 0x02bb; - t.compass = 0x263c; - t.congruent = 0x2245; - t.contourintegral = 0x222e; - t.control = 0x2303; - t.controlACK = 0x0006; - t.controlBEL = 0x0007; - t.controlBS = 0x0008; - t.controlCAN = 0x0018; - t.controlCR = 0x000d; - t.controlDC1 = 0x0011; - t.controlDC2 = 0x0012; - t.controlDC3 = 0x0013; - t.controlDC4 = 0x0014; - t.controlDEL = 0x007f; - t.controlDLE = 0x0010; - t.controlEM = 0x0019; - t.controlENQ = 0x0005; - t.controlEOT = 0x0004; - t.controlESC = 0x001b; - t.controlETB = 0x0017; - t.controlETX = 0x0003; - t.controlFF = 0x000c; - t.controlFS = 0x001c; - t.controlGS = 0x001d; - t.controlHT = 0x0009; - t.controlLF = 0x000a; - t.controlNAK = 0x0015; - t.controlNULL = 0x0000; - t.controlRS = 0x001e; - t.controlSI = 0x000f; - t.controlSO = 0x000e; - t.controlSOT = 0x0002; - t.controlSTX = 0x0001; - t.controlSUB = 0x001a; - t.controlSYN = 0x0016; - t.controlUS = 0x001f; - t.controlVT = 0x000b; - t.copyright = 0x00a9; - t.copyrightsans = 0xf8e9; - t.copyrightserif = 0xf6d9; - t.cornerbracketleft = 0x300c; - t.cornerbracketlefthalfwidth = 0xff62; - t.cornerbracketleftvertical = 0xfe41; - t.cornerbracketright = 0x300d; - t.cornerbracketrighthalfwidth = 0xff63; - t.cornerbracketrightvertical = 0xfe42; - t.corporationsquare = 0x337f; - t.cosquare = 0x33c7; - t.coverkgsquare = 0x33c6; - t.cparen = 0x249e; - t.cruzeiro = 0x20a2; - t.cstretched = 0x0297; - t.curlyand = 0x22cf; - t.curlyor = 0x22ce; - t.currency = 0x00a4; - t.cyrBreve = 0xf6d1; - t.cyrFlex = 0xf6d2; - t.cyrbreve = 0xf6d4; - t.cyrflex = 0xf6d5; - t.d = 0x0064; - t.daarmenian = 0x0564; - t.dabengali = 0x09a6; - t.dadarabic = 0x0636; - t.dadeva = 0x0926; - t.dadfinalarabic = 0xfebe; - t.dadinitialarabic = 0xfebf; - t.dadmedialarabic = 0xfec0; - t.dagesh = 0x05bc; - t.dageshhebrew = 0x05bc; - t.dagger = 0x2020; - t.daggerdbl = 0x2021; - t.dagujarati = 0x0aa6; - t.dagurmukhi = 0x0a26; - t.dahiragana = 0x3060; - t.dakatakana = 0x30c0; - t.dalarabic = 0x062f; - t.dalet = 0x05d3; - t.daletdagesh = 0xfb33; - t.daletdageshhebrew = 0xfb33; - t.dalethebrew = 0x05d3; - t.dalfinalarabic = 0xfeaa; - t.dammaarabic = 0x064f; - t.dammalowarabic = 0x064f; - t.dammatanaltonearabic = 0x064c; - t.dammatanarabic = 0x064c; - t.danda = 0x0964; - t.dargahebrew = 0x05a7; - t.dargalefthebrew = 0x05a7; - t.dasiapneumatacyrilliccmb = 0x0485; - t.dblGrave = 0xf6d3; - t.dblanglebracketleft = 0x300a; - t.dblanglebracketleftvertical = 0xfe3d; - t.dblanglebracketright = 0x300b; - t.dblanglebracketrightvertical = 0xfe3e; - t.dblarchinvertedbelowcmb = 0x032b; - t.dblarrowleft = 0x21d4; - t.dblarrowright = 0x21d2; - t.dbldanda = 0x0965; - t.dblgrave = 0xf6d6; - t.dblgravecmb = 0x030f; - t.dblintegral = 0x222c; - t.dbllowline = 0x2017; - t.dbllowlinecmb = 0x0333; - t.dbloverlinecmb = 0x033f; - t.dblprimemod = 0x02ba; - t.dblverticalbar = 0x2016; - t.dblverticallineabovecmb = 0x030e; - t.dbopomofo = 0x3109; - t.dbsquare = 0x33c8; - t.dcaron = 0x010f; - t.dcedilla = 0x1e11; - t.dcircle = 0x24d3; - t.dcircumflexbelow = 0x1e13; - t.dcroat = 0x0111; - t.ddabengali = 0x09a1; - t.ddadeva = 0x0921; - t.ddagujarati = 0x0aa1; - t.ddagurmukhi = 0x0a21; - t.ddalarabic = 0x0688; - t.ddalfinalarabic = 0xfb89; - t.dddhadeva = 0x095c; - t.ddhabengali = 0x09a2; - t.ddhadeva = 0x0922; - t.ddhagujarati = 0x0aa2; - t.ddhagurmukhi = 0x0a22; - t.ddotaccent = 0x1e0b; - t.ddotbelow = 0x1e0d; - t.decimalseparatorarabic = 0x066b; - t.decimalseparatorpersian = 0x066b; - t.decyrillic = 0x0434; - t.degree = 0x00b0; - t.dehihebrew = 0x05ad; - t.dehiragana = 0x3067; - t.deicoptic = 0x03ef; - t.dekatakana = 0x30c7; - t.deleteleft = 0x232b; - t.deleteright = 0x2326; - t.delta = 0x03b4; - t.deltaturned = 0x018d; - t.denominatorminusonenumeratorbengali = 0x09f8; - t.dezh = 0x02a4; - t.dhabengali = 0x09a7; - t.dhadeva = 0x0927; - t.dhagujarati = 0x0aa7; - t.dhagurmukhi = 0x0a27; - t.dhook = 0x0257; - t.dialytikatonos = 0x0385; - t.dialytikatonoscmb = 0x0344; - t.diamond = 0x2666; - t.diamondsuitwhite = 0x2662; - t.dieresis = 0x00a8; - t.dieresisacute = 0xf6d7; - t.dieresisbelowcmb = 0x0324; - t.dieresiscmb = 0x0308; - t.dieresisgrave = 0xf6d8; - t.dieresistonos = 0x0385; - t.dihiragana = 0x3062; - t.dikatakana = 0x30c2; - t.dittomark = 0x3003; - t.divide = 0x00f7; - t.divides = 0x2223; - t.divisionslash = 0x2215; - t.djecyrillic = 0x0452; - t.dkshade = 0x2593; - t.dlinebelow = 0x1e0f; - t.dlsquare = 0x3397; - t.dmacron = 0x0111; - t.dmonospace = 0xff44; - t.dnblock = 0x2584; - t.dochadathai = 0x0e0e; - t.dodekthai = 0x0e14; - t.dohiragana = 0x3069; - t.dokatakana = 0x30c9; - t.dollar = 0x0024; - t.dollarinferior = 0xf6e3; - t.dollarmonospace = 0xff04; - t.dollaroldstyle = 0xf724; - t.dollarsmall = 0xfe69; - t.dollarsuperior = 0xf6e4; - t.dong = 0x20ab; - t.dorusquare = 0x3326; - t.dotaccent = 0x02d9; - t.dotaccentcmb = 0x0307; - t.dotbelowcmb = 0x0323; - t.dotbelowcomb = 0x0323; - t.dotkatakana = 0x30fb; - t.dotlessi = 0x0131; - t.dotlessj = 0xf6be; - t.dotlessjstrokehook = 0x0284; - t.dotmath = 0x22c5; - t.dottedcircle = 0x25cc; - t.doubleyodpatah = 0xfb1f; - t.doubleyodpatahhebrew = 0xfb1f; - t.downtackbelowcmb = 0x031e; - t.downtackmod = 0x02d5; - t.dparen = 0x249f; - t.dsuperior = 0xf6eb; - t.dtail = 0x0256; - t.dtopbar = 0x018c; - t.duhiragana = 0x3065; - t.dukatakana = 0x30c5; - t.dz = 0x01f3; - t.dzaltone = 0x02a3; - t.dzcaron = 0x01c6; - t.dzcurl = 0x02a5; - t.dzeabkhasiancyrillic = 0x04e1; - t.dzecyrillic = 0x0455; - t.dzhecyrillic = 0x045f; - t.e = 0x0065; - t.eacute = 0x00e9; - t.earth = 0x2641; - t.ebengali = 0x098f; - t.ebopomofo = 0x311c; - t.ebreve = 0x0115; - t.ecandradeva = 0x090d; - t.ecandragujarati = 0x0a8d; - t.ecandravowelsigndeva = 0x0945; - t.ecandravowelsigngujarati = 0x0ac5; - t.ecaron = 0x011b; - t.ecedillabreve = 0x1e1d; - t.echarmenian = 0x0565; - t.echyiwnarmenian = 0x0587; - t.ecircle = 0x24d4; - t.ecircumflex = 0x00ea; - t.ecircumflexacute = 0x1ebf; - t.ecircumflexbelow = 0x1e19; - t.ecircumflexdotbelow = 0x1ec7; - t.ecircumflexgrave = 0x1ec1; - t.ecircumflexhookabove = 0x1ec3; - t.ecircumflextilde = 0x1ec5; - t.ecyrillic = 0x0454; - t.edblgrave = 0x0205; - t.edeva = 0x090f; - t.edieresis = 0x00eb; - t.edot = 0x0117; - t.edotaccent = 0x0117; - t.edotbelow = 0x1eb9; - t.eegurmukhi = 0x0a0f; - t.eematragurmukhi = 0x0a47; - t.efcyrillic = 0x0444; - t.egrave = 0x00e8; - t.egujarati = 0x0a8f; - t.eharmenian = 0x0567; - t.ehbopomofo = 0x311d; - t.ehiragana = 0x3048; - t.ehookabove = 0x1ebb; - t.eibopomofo = 0x311f; - t.eight = 0x0038; - t.eightarabic = 0x0668; - t.eightbengali = 0x09ee; - t.eightcircle = 0x2467; - t.eightcircleinversesansserif = 0x2791; - t.eightdeva = 0x096e; - t.eighteencircle = 0x2471; - t.eighteenparen = 0x2485; - t.eighteenperiod = 0x2499; - t.eightgujarati = 0x0aee; - t.eightgurmukhi = 0x0a6e; - t.eighthackarabic = 0x0668; - t.eighthangzhou = 0x3028; - t.eighthnotebeamed = 0x266b; - t.eightideographicparen = 0x3227; - t.eightinferior = 0x2088; - t.eightmonospace = 0xff18; - t.eightoldstyle = 0xf738; - t.eightparen = 0x247b; - t.eightperiod = 0x248f; - t.eightpersian = 0x06f8; - t.eightroman = 0x2177; - t.eightsuperior = 0x2078; - t.eightthai = 0x0e58; - t.einvertedbreve = 0x0207; - t.eiotifiedcyrillic = 0x0465; - t.ekatakana = 0x30a8; - t.ekatakanahalfwidth = 0xff74; - t.ekonkargurmukhi = 0x0a74; - t.ekorean = 0x3154; - t.elcyrillic = 0x043b; - t.element = 0x2208; - t.elevencircle = 0x246a; - t.elevenparen = 0x247e; - t.elevenperiod = 0x2492; - t.elevenroman = 0x217a; - t.ellipsis = 0x2026; - t.ellipsisvertical = 0x22ee; - t.emacron = 0x0113; - t.emacronacute = 0x1e17; - t.emacrongrave = 0x1e15; - t.emcyrillic = 0x043c; - t.emdash = 0x2014; - t.emdashvertical = 0xfe31; - t.emonospace = 0xff45; - t.emphasismarkarmenian = 0x055b; - t.emptyset = 0x2205; - t.enbopomofo = 0x3123; - t.encyrillic = 0x043d; - t.endash = 0x2013; - t.endashvertical = 0xfe32; - t.endescendercyrillic = 0x04a3; - t.eng = 0x014b; - t.engbopomofo = 0x3125; - t.enghecyrillic = 0x04a5; - t.enhookcyrillic = 0x04c8; - t.enspace = 0x2002; - t.eogonek = 0x0119; - t.eokorean = 0x3153; - t.eopen = 0x025b; - t.eopenclosed = 0x029a; - t.eopenreversed = 0x025c; - t.eopenreversedclosed = 0x025e; - t.eopenreversedhook = 0x025d; - t.eparen = 0x24a0; - t.epsilon = 0x03b5; - t.epsilontonos = 0x03ad; - t.equal = 0x003d; - t.equalmonospace = 0xff1d; - t.equalsmall = 0xfe66; - t.equalsuperior = 0x207c; - t.equivalence = 0x2261; - t.erbopomofo = 0x3126; - t.ercyrillic = 0x0440; - t.ereversed = 0x0258; - t.ereversedcyrillic = 0x044d; - t.escyrillic = 0x0441; - t.esdescendercyrillic = 0x04ab; - t.esh = 0x0283; - t.eshcurl = 0x0286; - t.eshortdeva = 0x090e; - t.eshortvowelsigndeva = 0x0946; - t.eshreversedloop = 0x01aa; - t.eshsquatreversed = 0x0285; - t.esmallhiragana = 0x3047; - t.esmallkatakana = 0x30a7; - t.esmallkatakanahalfwidth = 0xff6a; - t.estimated = 0x212e; - t.esuperior = 0xf6ec; - t.eta = 0x03b7; - t.etarmenian = 0x0568; - t.etatonos = 0x03ae; - t.eth = 0x00f0; - t.etilde = 0x1ebd; - t.etildebelow = 0x1e1b; - t.etnahtafoukhhebrew = 0x0591; - t.etnahtafoukhlefthebrew = 0x0591; - t.etnahtahebrew = 0x0591; - t.etnahtalefthebrew = 0x0591; - t.eturned = 0x01dd; - t.eukorean = 0x3161; - t.euro = 0x20ac; - t.evowelsignbengali = 0x09c7; - t.evowelsigndeva = 0x0947; - t.evowelsigngujarati = 0x0ac7; - t.exclam = 0x0021; - t.exclamarmenian = 0x055c; - t.exclamdbl = 0x203c; - t.exclamdown = 0x00a1; - t.exclamdownsmall = 0xf7a1; - t.exclammonospace = 0xff01; - t.exclamsmall = 0xf721; - t.existential = 0x2203; - t.ezh = 0x0292; - t.ezhcaron = 0x01ef; - t.ezhcurl = 0x0293; - t.ezhreversed = 0x01b9; - t.ezhtail = 0x01ba; - t.f = 0x0066; - t.fadeva = 0x095e; - t.fagurmukhi = 0x0a5e; - t.fahrenheit = 0x2109; - t.fathaarabic = 0x064e; - t.fathalowarabic = 0x064e; - t.fathatanarabic = 0x064b; - t.fbopomofo = 0x3108; - t.fcircle = 0x24d5; - t.fdotaccent = 0x1e1f; - t.feharabic = 0x0641; - t.feharmenian = 0x0586; - t.fehfinalarabic = 0xfed2; - t.fehinitialarabic = 0xfed3; - t.fehmedialarabic = 0xfed4; - t.feicoptic = 0x03e5; - t.female = 0x2640; - t.ff = 0xfb00; - t.f_f = 0xfb00; - t.ffi = 0xfb03; - t.ffl = 0xfb04; - t.fi = 0xfb01; - t.fifteencircle = 0x246e; - t.fifteenparen = 0x2482; - t.fifteenperiod = 0x2496; - t.figuredash = 0x2012; - t.filledbox = 0x25a0; - t.filledrect = 0x25ac; - t.finalkaf = 0x05da; - t.finalkafdagesh = 0xfb3a; - t.finalkafdageshhebrew = 0xfb3a; - t.finalkafhebrew = 0x05da; - t.finalmem = 0x05dd; - t.finalmemhebrew = 0x05dd; - t.finalnun = 0x05df; - t.finalnunhebrew = 0x05df; - t.finalpe = 0x05e3; - t.finalpehebrew = 0x05e3; - t.finaltsadi = 0x05e5; - t.finaltsadihebrew = 0x05e5; - t.firsttonechinese = 0x02c9; - t.fisheye = 0x25c9; - t.fitacyrillic = 0x0473; - t.five = 0x0035; - t.fivearabic = 0x0665; - t.fivebengali = 0x09eb; - t.fivecircle = 0x2464; - t.fivecircleinversesansserif = 0x278e; - t.fivedeva = 0x096b; - t.fiveeighths = 0x215d; - t.fivegujarati = 0x0aeb; - t.fivegurmukhi = 0x0a6b; - t.fivehackarabic = 0x0665; - t.fivehangzhou = 0x3025; - t.fiveideographicparen = 0x3224; - t.fiveinferior = 0x2085; - t.fivemonospace = 0xff15; - t.fiveoldstyle = 0xf735; - t.fiveparen = 0x2478; - t.fiveperiod = 0x248c; - t.fivepersian = 0x06f5; - t.fiveroman = 0x2174; - t.fivesuperior = 0x2075; - t.fivethai = 0x0e55; - t.fl = 0xfb02; - t.florin = 0x0192; - t.fmonospace = 0xff46; - t.fmsquare = 0x3399; - t.fofanthai = 0x0e1f; - t.fofathai = 0x0e1d; - t.fongmanthai = 0x0e4f; - t.forall = 0x2200; - t.four = 0x0034; - t.fourarabic = 0x0664; - t.fourbengali = 0x09ea; - t.fourcircle = 0x2463; - t.fourcircleinversesansserif = 0x278d; - t.fourdeva = 0x096a; - t.fourgujarati = 0x0aea; - t.fourgurmukhi = 0x0a6a; - t.fourhackarabic = 0x0664; - t.fourhangzhou = 0x3024; - t.fourideographicparen = 0x3223; - t.fourinferior = 0x2084; - t.fourmonospace = 0xff14; - t.fournumeratorbengali = 0x09f7; - t.fouroldstyle = 0xf734; - t.fourparen = 0x2477; - t.fourperiod = 0x248b; - t.fourpersian = 0x06f4; - t.fourroman = 0x2173; - t.foursuperior = 0x2074; - t.fourteencircle = 0x246d; - t.fourteenparen = 0x2481; - t.fourteenperiod = 0x2495; - t.fourthai = 0x0e54; - t.fourthtonechinese = 0x02cb; - t.fparen = 0x24a1; - t.fraction = 0x2044; - t.franc = 0x20a3; - t.g = 0x0067; - t.gabengali = 0x0997; - t.gacute = 0x01f5; - t.gadeva = 0x0917; - t.gafarabic = 0x06af; - t.gaffinalarabic = 0xfb93; - t.gafinitialarabic = 0xfb94; - t.gafmedialarabic = 0xfb95; - t.gagujarati = 0x0a97; - t.gagurmukhi = 0x0a17; - t.gahiragana = 0x304c; - t.gakatakana = 0x30ac; - t.gamma = 0x03b3; - t.gammalatinsmall = 0x0263; - t.gammasuperior = 0x02e0; - t.gangiacoptic = 0x03eb; - t.gbopomofo = 0x310d; - t.gbreve = 0x011f; - t.gcaron = 0x01e7; - t.gcedilla = 0x0123; - t.gcircle = 0x24d6; - t.gcircumflex = 0x011d; - t.gcommaaccent = 0x0123; - t.gdot = 0x0121; - t.gdotaccent = 0x0121; - t.gecyrillic = 0x0433; - t.gehiragana = 0x3052; - t.gekatakana = 0x30b2; - t.geometricallyequal = 0x2251; - t.gereshaccenthebrew = 0x059c; - t.gereshhebrew = 0x05f3; - t.gereshmuqdamhebrew = 0x059d; - t.germandbls = 0x00df; - t.gershayimaccenthebrew = 0x059e; - t.gershayimhebrew = 0x05f4; - t.getamark = 0x3013; - t.ghabengali = 0x0998; - t.ghadarmenian = 0x0572; - t.ghadeva = 0x0918; - t.ghagujarati = 0x0a98; - t.ghagurmukhi = 0x0a18; - t.ghainarabic = 0x063a; - t.ghainfinalarabic = 0xfece; - t.ghaininitialarabic = 0xfecf; - t.ghainmedialarabic = 0xfed0; - t.ghemiddlehookcyrillic = 0x0495; - t.ghestrokecyrillic = 0x0493; - t.gheupturncyrillic = 0x0491; - t.ghhadeva = 0x095a; - t.ghhagurmukhi = 0x0a5a; - t.ghook = 0x0260; - t.ghzsquare = 0x3393; - t.gihiragana = 0x304e; - t.gikatakana = 0x30ae; - t.gimarmenian = 0x0563; - t.gimel = 0x05d2; - t.gimeldagesh = 0xfb32; - t.gimeldageshhebrew = 0xfb32; - t.gimelhebrew = 0x05d2; - t.gjecyrillic = 0x0453; - t.glottalinvertedstroke = 0x01be; - t.glottalstop = 0x0294; - t.glottalstopinverted = 0x0296; - t.glottalstopmod = 0x02c0; - t.glottalstopreversed = 0x0295; - t.glottalstopreversedmod = 0x02c1; - t.glottalstopreversedsuperior = 0x02e4; - t.glottalstopstroke = 0x02a1; - t.glottalstopstrokereversed = 0x02a2; - t.gmacron = 0x1e21; - t.gmonospace = 0xff47; - t.gohiragana = 0x3054; - t.gokatakana = 0x30b4; - t.gparen = 0x24a2; - t.gpasquare = 0x33ac; - t.gradient = 0x2207; - t.grave = 0x0060; - t.gravebelowcmb = 0x0316; - t.gravecmb = 0x0300; - t.gravecomb = 0x0300; - t.gravedeva = 0x0953; - t.gravelowmod = 0x02ce; - t.gravemonospace = 0xff40; - t.gravetonecmb = 0x0340; - t.greater = 0x003e; - t.greaterequal = 0x2265; - t.greaterequalorless = 0x22db; - t.greatermonospace = 0xff1e; - t.greaterorequivalent = 0x2273; - t.greaterorless = 0x2277; - t.greateroverequal = 0x2267; - t.greatersmall = 0xfe65; - t.gscript = 0x0261; - t.gstroke = 0x01e5; - t.guhiragana = 0x3050; - t.guillemotleft = 0x00ab; - t.guillemotright = 0x00bb; - t.guilsinglleft = 0x2039; - t.guilsinglright = 0x203a; - t.gukatakana = 0x30b0; - t.guramusquare = 0x3318; - t.gysquare = 0x33c9; - t.h = 0x0068; - t.haabkhasiancyrillic = 0x04a9; - t.haaltonearabic = 0x06c1; - t.habengali = 0x09b9; - t.hadescendercyrillic = 0x04b3; - t.hadeva = 0x0939; - t.hagujarati = 0x0ab9; - t.hagurmukhi = 0x0a39; - t.haharabic = 0x062d; - t.hahfinalarabic = 0xfea2; - t.hahinitialarabic = 0xfea3; - t.hahiragana = 0x306f; - t.hahmedialarabic = 0xfea4; - t.haitusquare = 0x332a; - t.hakatakana = 0x30cf; - t.hakatakanahalfwidth = 0xff8a; - t.halantgurmukhi = 0x0a4d; - t.hamzaarabic = 0x0621; - t.hamzalowarabic = 0x0621; - t.hangulfiller = 0x3164; - t.hardsigncyrillic = 0x044a; - t.harpoonleftbarbup = 0x21bc; - t.harpoonrightbarbup = 0x21c0; - t.hasquare = 0x33ca; - t.hatafpatah = 0x05b2; - t.hatafpatah16 = 0x05b2; - t.hatafpatah23 = 0x05b2; - t.hatafpatah2f = 0x05b2; - t.hatafpatahhebrew = 0x05b2; - t.hatafpatahnarrowhebrew = 0x05b2; - t.hatafpatahquarterhebrew = 0x05b2; - t.hatafpatahwidehebrew = 0x05b2; - t.hatafqamats = 0x05b3; - t.hatafqamats1b = 0x05b3; - t.hatafqamats28 = 0x05b3; - t.hatafqamats34 = 0x05b3; - t.hatafqamatshebrew = 0x05b3; - t.hatafqamatsnarrowhebrew = 0x05b3; - t.hatafqamatsquarterhebrew = 0x05b3; - t.hatafqamatswidehebrew = 0x05b3; - t.hatafsegol = 0x05b1; - t.hatafsegol17 = 0x05b1; - t.hatafsegol24 = 0x05b1; - t.hatafsegol30 = 0x05b1; - t.hatafsegolhebrew = 0x05b1; - t.hatafsegolnarrowhebrew = 0x05b1; - t.hatafsegolquarterhebrew = 0x05b1; - t.hatafsegolwidehebrew = 0x05b1; - t.hbar = 0x0127; - t.hbopomofo = 0x310f; - t.hbrevebelow = 0x1e2b; - t.hcedilla = 0x1e29; - t.hcircle = 0x24d7; - t.hcircumflex = 0x0125; - t.hdieresis = 0x1e27; - t.hdotaccent = 0x1e23; - t.hdotbelow = 0x1e25; - t.he = 0x05d4; - t.heart = 0x2665; - t.heartsuitblack = 0x2665; - t.heartsuitwhite = 0x2661; - t.hedagesh = 0xfb34; - t.hedageshhebrew = 0xfb34; - t.hehaltonearabic = 0x06c1; - t.heharabic = 0x0647; - t.hehebrew = 0x05d4; - t.hehfinalaltonearabic = 0xfba7; - t.hehfinalalttwoarabic = 0xfeea; - t.hehfinalarabic = 0xfeea; - t.hehhamzaabovefinalarabic = 0xfba5; - t.hehhamzaaboveisolatedarabic = 0xfba4; - t.hehinitialaltonearabic = 0xfba8; - t.hehinitialarabic = 0xfeeb; - t.hehiragana = 0x3078; - t.hehmedialaltonearabic = 0xfba9; - t.hehmedialarabic = 0xfeec; - t.heiseierasquare = 0x337b; - t.hekatakana = 0x30d8; - t.hekatakanahalfwidth = 0xff8d; - t.hekutaarusquare = 0x3336; - t.henghook = 0x0267; - t.herutusquare = 0x3339; - t.het = 0x05d7; - t.hethebrew = 0x05d7; - t.hhook = 0x0266; - t.hhooksuperior = 0x02b1; - t.hieuhacirclekorean = 0x327b; - t.hieuhaparenkorean = 0x321b; - t.hieuhcirclekorean = 0x326d; - t.hieuhkorean = 0x314e; - t.hieuhparenkorean = 0x320d; - t.hihiragana = 0x3072; - t.hikatakana = 0x30d2; - t.hikatakanahalfwidth = 0xff8b; - t.hiriq = 0x05b4; - t.hiriq14 = 0x05b4; - t.hiriq21 = 0x05b4; - t.hiriq2d = 0x05b4; - t.hiriqhebrew = 0x05b4; - t.hiriqnarrowhebrew = 0x05b4; - t.hiriqquarterhebrew = 0x05b4; - t.hiriqwidehebrew = 0x05b4; - t.hlinebelow = 0x1e96; - t.hmonospace = 0xff48; - t.hoarmenian = 0x0570; - t.hohipthai = 0x0e2b; - t.hohiragana = 0x307b; - t.hokatakana = 0x30db; - t.hokatakanahalfwidth = 0xff8e; - t.holam = 0x05b9; - t.holam19 = 0x05b9; - t.holam26 = 0x05b9; - t.holam32 = 0x05b9; - t.holamhebrew = 0x05b9; - t.holamnarrowhebrew = 0x05b9; - t.holamquarterhebrew = 0x05b9; - t.holamwidehebrew = 0x05b9; - t.honokhukthai = 0x0e2e; - t.hookabovecomb = 0x0309; - t.hookcmb = 0x0309; - t.hookpalatalizedbelowcmb = 0x0321; - t.hookretroflexbelowcmb = 0x0322; - t.hoonsquare = 0x3342; - t.horicoptic = 0x03e9; - t.horizontalbar = 0x2015; - t.horncmb = 0x031b; - t.hotsprings = 0x2668; - t.house = 0x2302; - t.hparen = 0x24a3; - t.hsuperior = 0x02b0; - t.hturned = 0x0265; - t.huhiragana = 0x3075; - t.huiitosquare = 0x3333; - t.hukatakana = 0x30d5; - t.hukatakanahalfwidth = 0xff8c; - t.hungarumlaut = 0x02dd; - t.hungarumlautcmb = 0x030b; - t.hv = 0x0195; - t.hyphen = 0x002d; - t.hypheninferior = 0xf6e5; - t.hyphenmonospace = 0xff0d; - t.hyphensmall = 0xfe63; - t.hyphensuperior = 0xf6e6; - t.hyphentwo = 0x2010; - t.i = 0x0069; - t.iacute = 0x00ed; - t.iacyrillic = 0x044f; - t.ibengali = 0x0987; - t.ibopomofo = 0x3127; - t.ibreve = 0x012d; - t.icaron = 0x01d0; - t.icircle = 0x24d8; - t.icircumflex = 0x00ee; - t.icyrillic = 0x0456; - t.idblgrave = 0x0209; - t.ideographearthcircle = 0x328f; - t.ideographfirecircle = 0x328b; - t.ideographicallianceparen = 0x323f; - t.ideographiccallparen = 0x323a; - t.ideographiccentrecircle = 0x32a5; - t.ideographicclose = 0x3006; - t.ideographiccomma = 0x3001; - t.ideographiccommaleft = 0xff64; - t.ideographiccongratulationparen = 0x3237; - t.ideographiccorrectcircle = 0x32a3; - t.ideographicearthparen = 0x322f; - t.ideographicenterpriseparen = 0x323d; - t.ideographicexcellentcircle = 0x329d; - t.ideographicfestivalparen = 0x3240; - t.ideographicfinancialcircle = 0x3296; - t.ideographicfinancialparen = 0x3236; - t.ideographicfireparen = 0x322b; - t.ideographichaveparen = 0x3232; - t.ideographichighcircle = 0x32a4; - t.ideographiciterationmark = 0x3005; - t.ideographiclaborcircle = 0x3298; - t.ideographiclaborparen = 0x3238; - t.ideographicleftcircle = 0x32a7; - t.ideographiclowcircle = 0x32a6; - t.ideographicmedicinecircle = 0x32a9; - t.ideographicmetalparen = 0x322e; - t.ideographicmoonparen = 0x322a; - t.ideographicnameparen = 0x3234; - t.ideographicperiod = 0x3002; - t.ideographicprintcircle = 0x329e; - t.ideographicreachparen = 0x3243; - t.ideographicrepresentparen = 0x3239; - t.ideographicresourceparen = 0x323e; - t.ideographicrightcircle = 0x32a8; - t.ideographicsecretcircle = 0x3299; - t.ideographicselfparen = 0x3242; - t.ideographicsocietyparen = 0x3233; - t.ideographicspace = 0x3000; - t.ideographicspecialparen = 0x3235; - t.ideographicstockparen = 0x3231; - t.ideographicstudyparen = 0x323b; - t.ideographicsunparen = 0x3230; - t.ideographicsuperviseparen = 0x323c; - t.ideographicwaterparen = 0x322c; - t.ideographicwoodparen = 0x322d; - t.ideographiczero = 0x3007; - t.ideographmetalcircle = 0x328e; - t.ideographmooncircle = 0x328a; - t.ideographnamecircle = 0x3294; - t.ideographsuncircle = 0x3290; - t.ideographwatercircle = 0x328c; - t.ideographwoodcircle = 0x328d; - t.ideva = 0x0907; - t.idieresis = 0x00ef; - t.idieresisacute = 0x1e2f; - t.idieresiscyrillic = 0x04e5; - t.idotbelow = 0x1ecb; - t.iebrevecyrillic = 0x04d7; - t.iecyrillic = 0x0435; - t.ieungacirclekorean = 0x3275; - t.ieungaparenkorean = 0x3215; - t.ieungcirclekorean = 0x3267; - t.ieungkorean = 0x3147; - t.ieungparenkorean = 0x3207; - t.igrave = 0x00ec; - t.igujarati = 0x0a87; - t.igurmukhi = 0x0a07; - t.ihiragana = 0x3044; - t.ihookabove = 0x1ec9; - t.iibengali = 0x0988; - t.iicyrillic = 0x0438; - t.iideva = 0x0908; - t.iigujarati = 0x0a88; - t.iigurmukhi = 0x0a08; - t.iimatragurmukhi = 0x0a40; - t.iinvertedbreve = 0x020b; - t.iishortcyrillic = 0x0439; - t.iivowelsignbengali = 0x09c0; - t.iivowelsigndeva = 0x0940; - t.iivowelsigngujarati = 0x0ac0; - t.ij = 0x0133; - t.ikatakana = 0x30a4; - t.ikatakanahalfwidth = 0xff72; - t.ikorean = 0x3163; - t.ilde = 0x02dc; - t.iluyhebrew = 0x05ac; - t.imacron = 0x012b; - t.imacroncyrillic = 0x04e3; - t.imageorapproximatelyequal = 0x2253; - t.imatragurmukhi = 0x0a3f; - t.imonospace = 0xff49; - t.increment = 0x2206; - t.infinity = 0x221e; - t.iniarmenian = 0x056b; - t.integral = 0x222b; - t.integralbottom = 0x2321; - t.integralbt = 0x2321; - t.integralex = 0xf8f5; - t.integraltop = 0x2320; - t.integraltp = 0x2320; - t.intersection = 0x2229; - t.intisquare = 0x3305; - t.invbullet = 0x25d8; - t.invcircle = 0x25d9; - t.invsmileface = 0x263b; - t.iocyrillic = 0x0451; - t.iogonek = 0x012f; - t.iota = 0x03b9; - t.iotadieresis = 0x03ca; - t.iotadieresistonos = 0x0390; - t.iotalatin = 0x0269; - t.iotatonos = 0x03af; - t.iparen = 0x24a4; - t.irigurmukhi = 0x0a72; - t.ismallhiragana = 0x3043; - t.ismallkatakana = 0x30a3; - t.ismallkatakanahalfwidth = 0xff68; - t.issharbengali = 0x09fa; - t.istroke = 0x0268; - t.isuperior = 0xf6ed; - t.iterationhiragana = 0x309d; - t.iterationkatakana = 0x30fd; - t.itilde = 0x0129; - t.itildebelow = 0x1e2d; - t.iubopomofo = 0x3129; - t.iucyrillic = 0x044e; - t.ivowelsignbengali = 0x09bf; - t.ivowelsigndeva = 0x093f; - t.ivowelsigngujarati = 0x0abf; - t.izhitsacyrillic = 0x0475; - t.izhitsadblgravecyrillic = 0x0477; - t.j = 0x006a; - t.jaarmenian = 0x0571; - t.jabengali = 0x099c; - t.jadeva = 0x091c; - t.jagujarati = 0x0a9c; - t.jagurmukhi = 0x0a1c; - t.jbopomofo = 0x3110; - t.jcaron = 0x01f0; - t.jcircle = 0x24d9; - t.jcircumflex = 0x0135; - t.jcrossedtail = 0x029d; - t.jdotlessstroke = 0x025f; - t.jecyrillic = 0x0458; - t.jeemarabic = 0x062c; - t.jeemfinalarabic = 0xfe9e; - t.jeeminitialarabic = 0xfe9f; - t.jeemmedialarabic = 0xfea0; - t.jeharabic = 0x0698; - t.jehfinalarabic = 0xfb8b; - t.jhabengali = 0x099d; - t.jhadeva = 0x091d; - t.jhagujarati = 0x0a9d; - t.jhagurmukhi = 0x0a1d; - t.jheharmenian = 0x057b; - t.jis = 0x3004; - t.jmonospace = 0xff4a; - t.jparen = 0x24a5; - t.jsuperior = 0x02b2; - t.k = 0x006b; - t.kabashkircyrillic = 0x04a1; - t.kabengali = 0x0995; - t.kacute = 0x1e31; - t.kacyrillic = 0x043a; - t.kadescendercyrillic = 0x049b; - t.kadeva = 0x0915; - t.kaf = 0x05db; - t.kafarabic = 0x0643; - t.kafdagesh = 0xfb3b; - t.kafdageshhebrew = 0xfb3b; - t.kaffinalarabic = 0xfeda; - t.kafhebrew = 0x05db; - t.kafinitialarabic = 0xfedb; - t.kafmedialarabic = 0xfedc; - t.kafrafehebrew = 0xfb4d; - t.kagujarati = 0x0a95; - t.kagurmukhi = 0x0a15; - t.kahiragana = 0x304b; - t.kahookcyrillic = 0x04c4; - t.kakatakana = 0x30ab; - t.kakatakanahalfwidth = 0xff76; - t.kappa = 0x03ba; - t.kappasymbolgreek = 0x03f0; - t.kapyeounmieumkorean = 0x3171; - t.kapyeounphieuphkorean = 0x3184; - t.kapyeounpieupkorean = 0x3178; - t.kapyeounssangpieupkorean = 0x3179; - t.karoriisquare = 0x330d; - t.kashidaautoarabic = 0x0640; - t.kashidaautonosidebearingarabic = 0x0640; - t.kasmallkatakana = 0x30f5; - t.kasquare = 0x3384; - t.kasraarabic = 0x0650; - t.kasratanarabic = 0x064d; - t.kastrokecyrillic = 0x049f; - t.katahiraprolongmarkhalfwidth = 0xff70; - t.kaverticalstrokecyrillic = 0x049d; - t.kbopomofo = 0x310e; - t.kcalsquare = 0x3389; - t.kcaron = 0x01e9; - t.kcedilla = 0x0137; - t.kcircle = 0x24da; - t.kcommaaccent = 0x0137; - t.kdotbelow = 0x1e33; - t.keharmenian = 0x0584; - t.kehiragana = 0x3051; - t.kekatakana = 0x30b1; - t.kekatakanahalfwidth = 0xff79; - t.kenarmenian = 0x056f; - t.kesmallkatakana = 0x30f6; - t.kgreenlandic = 0x0138; - t.khabengali = 0x0996; - t.khacyrillic = 0x0445; - t.khadeva = 0x0916; - t.khagujarati = 0x0a96; - t.khagurmukhi = 0x0a16; - t.khaharabic = 0x062e; - t.khahfinalarabic = 0xfea6; - t.khahinitialarabic = 0xfea7; - t.khahmedialarabic = 0xfea8; - t.kheicoptic = 0x03e7; - t.khhadeva = 0x0959; - t.khhagurmukhi = 0x0a59; - t.khieukhacirclekorean = 0x3278; - t.khieukhaparenkorean = 0x3218; - t.khieukhcirclekorean = 0x326a; - t.khieukhkorean = 0x314b; - t.khieukhparenkorean = 0x320a; - t.khokhaithai = 0x0e02; - t.khokhonthai = 0x0e05; - t.khokhuatthai = 0x0e03; - t.khokhwaithai = 0x0e04; - t.khomutthai = 0x0e5b; - t.khook = 0x0199; - t.khorakhangthai = 0x0e06; - t.khzsquare = 0x3391; - t.kihiragana = 0x304d; - t.kikatakana = 0x30ad; - t.kikatakanahalfwidth = 0xff77; - t.kiroguramusquare = 0x3315; - t.kiromeetorusquare = 0x3316; - t.kirosquare = 0x3314; - t.kiyeokacirclekorean = 0x326e; - t.kiyeokaparenkorean = 0x320e; - t.kiyeokcirclekorean = 0x3260; - t.kiyeokkorean = 0x3131; - t.kiyeokparenkorean = 0x3200; - t.kiyeoksioskorean = 0x3133; - t.kjecyrillic = 0x045c; - t.klinebelow = 0x1e35; - t.klsquare = 0x3398; - t.kmcubedsquare = 0x33a6; - t.kmonospace = 0xff4b; - t.kmsquaredsquare = 0x33a2; - t.kohiragana = 0x3053; - t.kohmsquare = 0x33c0; - t.kokaithai = 0x0e01; - t.kokatakana = 0x30b3; - t.kokatakanahalfwidth = 0xff7a; - t.kooposquare = 0x331e; - t.koppacyrillic = 0x0481; - t.koreanstandardsymbol = 0x327f; - t.koroniscmb = 0x0343; - t.kparen = 0x24a6; - t.kpasquare = 0x33aa; - t.ksicyrillic = 0x046f; - t.ktsquare = 0x33cf; - t.kturned = 0x029e; - t.kuhiragana = 0x304f; - t.kukatakana = 0x30af; - t.kukatakanahalfwidth = 0xff78; - t.kvsquare = 0x33b8; - t.kwsquare = 0x33be; - t.l = 0x006c; - t.labengali = 0x09b2; - t.lacute = 0x013a; - t.ladeva = 0x0932; - t.lagujarati = 0x0ab2; - t.lagurmukhi = 0x0a32; - t.lakkhangyaothai = 0x0e45; - t.lamaleffinalarabic = 0xfefc; - t.lamalefhamzaabovefinalarabic = 0xfef8; - t.lamalefhamzaaboveisolatedarabic = 0xfef7; - t.lamalefhamzabelowfinalarabic = 0xfefa; - t.lamalefhamzabelowisolatedarabic = 0xfef9; - t.lamalefisolatedarabic = 0xfefb; - t.lamalefmaddaabovefinalarabic = 0xfef6; - t.lamalefmaddaaboveisolatedarabic = 0xfef5; - t.lamarabic = 0x0644; - t.lambda = 0x03bb; - t.lambdastroke = 0x019b; - t.lamed = 0x05dc; - t.lameddagesh = 0xfb3c; - t.lameddageshhebrew = 0xfb3c; - t.lamedhebrew = 0x05dc; - t.lamfinalarabic = 0xfede; - t.lamhahinitialarabic = 0xfcca; - t.laminitialarabic = 0xfedf; - t.lamjeeminitialarabic = 0xfcc9; - t.lamkhahinitialarabic = 0xfccb; - t.lamlamhehisolatedarabic = 0xfdf2; - t.lammedialarabic = 0xfee0; - t.lammeemhahinitialarabic = 0xfd88; - t.lammeeminitialarabic = 0xfccc; - t.largecircle = 0x25ef; - t.lbar = 0x019a; - t.lbelt = 0x026c; - t.lbopomofo = 0x310c; - t.lcaron = 0x013e; - t.lcedilla = 0x013c; - t.lcircle = 0x24db; - t.lcircumflexbelow = 0x1e3d; - t.lcommaaccent = 0x013c; - t.ldot = 0x0140; - t.ldotaccent = 0x0140; - t.ldotbelow = 0x1e37; - t.ldotbelowmacron = 0x1e39; - t.leftangleabovecmb = 0x031a; - t.lefttackbelowcmb = 0x0318; - t.less = 0x003c; - t.lessequal = 0x2264; - t.lessequalorgreater = 0x22da; - t.lessmonospace = 0xff1c; - t.lessorequivalent = 0x2272; - t.lessorgreater = 0x2276; - t.lessoverequal = 0x2266; - t.lesssmall = 0xfe64; - t.lezh = 0x026e; - t.lfblock = 0x258c; - t.lhookretroflex = 0x026d; - t.lira = 0x20a4; - t.liwnarmenian = 0x056c; - t.lj = 0x01c9; - t.ljecyrillic = 0x0459; - t.ll = 0xf6c0; - t.lladeva = 0x0933; - t.llagujarati = 0x0ab3; - t.llinebelow = 0x1e3b; - t.llladeva = 0x0934; - t.llvocalicbengali = 0x09e1; - t.llvocalicdeva = 0x0961; - t.llvocalicvowelsignbengali = 0x09e3; - t.llvocalicvowelsigndeva = 0x0963; - t.lmiddletilde = 0x026b; - t.lmonospace = 0xff4c; - t.lmsquare = 0x33d0; - t.lochulathai = 0x0e2c; - t.logicaland = 0x2227; - t.logicalnot = 0x00ac; - t.logicalnotreversed = 0x2310; - t.logicalor = 0x2228; - t.lolingthai = 0x0e25; - t.longs = 0x017f; - t.lowlinecenterline = 0xfe4e; - t.lowlinecmb = 0x0332; - t.lowlinedashed = 0xfe4d; - t.lozenge = 0x25ca; - t.lparen = 0x24a7; - t.lslash = 0x0142; - t.lsquare = 0x2113; - t.lsuperior = 0xf6ee; - t.ltshade = 0x2591; - t.luthai = 0x0e26; - t.lvocalicbengali = 0x098c; - t.lvocalicdeva = 0x090c; - t.lvocalicvowelsignbengali = 0x09e2; - t.lvocalicvowelsigndeva = 0x0962; - t.lxsquare = 0x33d3; - t.m = 0x006d; - t.mabengali = 0x09ae; - t.macron = 0x00af; - t.macronbelowcmb = 0x0331; - t.macroncmb = 0x0304; - t.macronlowmod = 0x02cd; - t.macronmonospace = 0xffe3; - t.macute = 0x1e3f; - t.madeva = 0x092e; - t.magujarati = 0x0aae; - t.magurmukhi = 0x0a2e; - t.mahapakhhebrew = 0x05a4; - t.mahapakhlefthebrew = 0x05a4; - t.mahiragana = 0x307e; - t.maichattawalowleftthai = 0xf895; - t.maichattawalowrightthai = 0xf894; - t.maichattawathai = 0x0e4b; - t.maichattawaupperleftthai = 0xf893; - t.maieklowleftthai = 0xf88c; - t.maieklowrightthai = 0xf88b; - t.maiekthai = 0x0e48; - t.maiekupperleftthai = 0xf88a; - t.maihanakatleftthai = 0xf884; - t.maihanakatthai = 0x0e31; - t.maitaikhuleftthai = 0xf889; - t.maitaikhuthai = 0x0e47; - t.maitholowleftthai = 0xf88f; - t.maitholowrightthai = 0xf88e; - t.maithothai = 0x0e49; - t.maithoupperleftthai = 0xf88d; - t.maitrilowleftthai = 0xf892; - t.maitrilowrightthai = 0xf891; - t.maitrithai = 0x0e4a; - t.maitriupperleftthai = 0xf890; - t.maiyamokthai = 0x0e46; - t.makatakana = 0x30de; - t.makatakanahalfwidth = 0xff8f; - t.male = 0x2642; - t.mansyonsquare = 0x3347; - t.maqafhebrew = 0x05be; - t.mars = 0x2642; - t.masoracirclehebrew = 0x05af; - t.masquare = 0x3383; - t.mbopomofo = 0x3107; - t.mbsquare = 0x33d4; - t.mcircle = 0x24dc; - t.mcubedsquare = 0x33a5; - t.mdotaccent = 0x1e41; - t.mdotbelow = 0x1e43; - t.meemarabic = 0x0645; - t.meemfinalarabic = 0xfee2; - t.meeminitialarabic = 0xfee3; - t.meemmedialarabic = 0xfee4; - t.meemmeeminitialarabic = 0xfcd1; - t.meemmeemisolatedarabic = 0xfc48; - t.meetorusquare = 0x334d; - t.mehiragana = 0x3081; - t.meizierasquare = 0x337e; - t.mekatakana = 0x30e1; - t.mekatakanahalfwidth = 0xff92; - t.mem = 0x05de; - t.memdagesh = 0xfb3e; - t.memdageshhebrew = 0xfb3e; - t.memhebrew = 0x05de; - t.menarmenian = 0x0574; - t.merkhahebrew = 0x05a5; - t.merkhakefulahebrew = 0x05a6; - t.merkhakefulalefthebrew = 0x05a6; - t.merkhalefthebrew = 0x05a5; - t.mhook = 0x0271; - t.mhzsquare = 0x3392; - t.middledotkatakanahalfwidth = 0xff65; - t.middot = 0x00b7; - t.mieumacirclekorean = 0x3272; - t.mieumaparenkorean = 0x3212; - t.mieumcirclekorean = 0x3264; - t.mieumkorean = 0x3141; - t.mieumpansioskorean = 0x3170; - t.mieumparenkorean = 0x3204; - t.mieumpieupkorean = 0x316e; - t.mieumsioskorean = 0x316f; - t.mihiragana = 0x307f; - t.mikatakana = 0x30df; - t.mikatakanahalfwidth = 0xff90; - t.minus = 0x2212; - t.minusbelowcmb = 0x0320; - t.minuscircle = 0x2296; - t.minusmod = 0x02d7; - t.minusplus = 0x2213; - t.minute = 0x2032; - t.miribaarusquare = 0x334a; - t.mirisquare = 0x3349; - t.mlonglegturned = 0x0270; - t.mlsquare = 0x3396; - t.mmcubedsquare = 0x33a3; - t.mmonospace = 0xff4d; - t.mmsquaredsquare = 0x339f; - t.mohiragana = 0x3082; - t.mohmsquare = 0x33c1; - t.mokatakana = 0x30e2; - t.mokatakanahalfwidth = 0xff93; - t.molsquare = 0x33d6; - t.momathai = 0x0e21; - t.moverssquare = 0x33a7; - t.moverssquaredsquare = 0x33a8; - t.mparen = 0x24a8; - t.mpasquare = 0x33ab; - t.mssquare = 0x33b3; - t.msuperior = 0xf6ef; - t.mturned = 0x026f; - t.mu = 0x00b5; - t.mu1 = 0x00b5; - t.muasquare = 0x3382; - t.muchgreater = 0x226b; - t.muchless = 0x226a; - t.mufsquare = 0x338c; - t.mugreek = 0x03bc; - t.mugsquare = 0x338d; - t.muhiragana = 0x3080; - t.mukatakana = 0x30e0; - t.mukatakanahalfwidth = 0xff91; - t.mulsquare = 0x3395; - t.multiply = 0x00d7; - t.mumsquare = 0x339b; - t.munahhebrew = 0x05a3; - t.munahlefthebrew = 0x05a3; - t.musicalnote = 0x266a; - t.musicalnotedbl = 0x266b; - t.musicflatsign = 0x266d; - t.musicsharpsign = 0x266f; - t.mussquare = 0x33b2; - t.muvsquare = 0x33b6; - t.muwsquare = 0x33bc; - t.mvmegasquare = 0x33b9; - t.mvsquare = 0x33b7; - t.mwmegasquare = 0x33bf; - t.mwsquare = 0x33bd; - t.n = 0x006e; - t.nabengali = 0x09a8; - t.nabla = 0x2207; - t.nacute = 0x0144; - t.nadeva = 0x0928; - t.nagujarati = 0x0aa8; - t.nagurmukhi = 0x0a28; - t.nahiragana = 0x306a; - t.nakatakana = 0x30ca; - t.nakatakanahalfwidth = 0xff85; - t.napostrophe = 0x0149; - t.nasquare = 0x3381; - t.nbopomofo = 0x310b; - t.nbspace = 0x00a0; - t.ncaron = 0x0148; - t.ncedilla = 0x0146; - t.ncircle = 0x24dd; - t.ncircumflexbelow = 0x1e4b; - t.ncommaaccent = 0x0146; - t.ndotaccent = 0x1e45; - t.ndotbelow = 0x1e47; - t.nehiragana = 0x306d; - t.nekatakana = 0x30cd; - t.nekatakanahalfwidth = 0xff88; - t.newsheqelsign = 0x20aa; - t.nfsquare = 0x338b; - t.ngabengali = 0x0999; - t.ngadeva = 0x0919; - t.ngagujarati = 0x0a99; - t.ngagurmukhi = 0x0a19; - t.ngonguthai = 0x0e07; - t.nhiragana = 0x3093; - t.nhookleft = 0x0272; - t.nhookretroflex = 0x0273; - t.nieunacirclekorean = 0x326f; - t.nieunaparenkorean = 0x320f; - t.nieuncieuckorean = 0x3135; - t.nieuncirclekorean = 0x3261; - t.nieunhieuhkorean = 0x3136; - t.nieunkorean = 0x3134; - t.nieunpansioskorean = 0x3168; - t.nieunparenkorean = 0x3201; - t.nieunsioskorean = 0x3167; - t.nieuntikeutkorean = 0x3166; - t.nihiragana = 0x306b; - t.nikatakana = 0x30cb; - t.nikatakanahalfwidth = 0xff86; - t.nikhahitleftthai = 0xf899; - t.nikhahitthai = 0x0e4d; - t.nine = 0x0039; - t.ninearabic = 0x0669; - t.ninebengali = 0x09ef; - t.ninecircle = 0x2468; - t.ninecircleinversesansserif = 0x2792; - t.ninedeva = 0x096f; - t.ninegujarati = 0x0aef; - t.ninegurmukhi = 0x0a6f; - t.ninehackarabic = 0x0669; - t.ninehangzhou = 0x3029; - t.nineideographicparen = 0x3228; - t.nineinferior = 0x2089; - t.ninemonospace = 0xff19; - t.nineoldstyle = 0xf739; - t.nineparen = 0x247c; - t.nineperiod = 0x2490; - t.ninepersian = 0x06f9; - t.nineroman = 0x2178; - t.ninesuperior = 0x2079; - t.nineteencircle = 0x2472; - t.nineteenparen = 0x2486; - t.nineteenperiod = 0x249a; - t.ninethai = 0x0e59; - t.nj = 0x01cc; - t.njecyrillic = 0x045a; - t.nkatakana = 0x30f3; - t.nkatakanahalfwidth = 0xff9d; - t.nlegrightlong = 0x019e; - t.nlinebelow = 0x1e49; - t.nmonospace = 0xff4e; - t.nmsquare = 0x339a; - t.nnabengali = 0x09a3; - t.nnadeva = 0x0923; - t.nnagujarati = 0x0aa3; - t.nnagurmukhi = 0x0a23; - t.nnnadeva = 0x0929; - t.nohiragana = 0x306e; - t.nokatakana = 0x30ce; - t.nokatakanahalfwidth = 0xff89; - t.nonbreakingspace = 0x00a0; - t.nonenthai = 0x0e13; - t.nonuthai = 0x0e19; - t.noonarabic = 0x0646; - t.noonfinalarabic = 0xfee6; - t.noonghunnaarabic = 0x06ba; - t.noonghunnafinalarabic = 0xfb9f; - t.nooninitialarabic = 0xfee7; - t.noonjeeminitialarabic = 0xfcd2; - t.noonjeemisolatedarabic = 0xfc4b; - t.noonmedialarabic = 0xfee8; - t.noonmeeminitialarabic = 0xfcd5; - t.noonmeemisolatedarabic = 0xfc4e; - t.noonnoonfinalarabic = 0xfc8d; - t.notcontains = 0x220c; - t.notelement = 0x2209; - t.notelementof = 0x2209; - t.notequal = 0x2260; - t.notgreater = 0x226f; - t.notgreaternorequal = 0x2271; - t.notgreaternorless = 0x2279; - t.notidentical = 0x2262; - t.notless = 0x226e; - t.notlessnorequal = 0x2270; - t.notparallel = 0x2226; - t.notprecedes = 0x2280; - t.notsubset = 0x2284; - t.notsucceeds = 0x2281; - t.notsuperset = 0x2285; - t.nowarmenian = 0x0576; - t.nparen = 0x24a9; - t.nssquare = 0x33b1; - t.nsuperior = 0x207f; - t.ntilde = 0x00f1; - t.nu = 0x03bd; - t.nuhiragana = 0x306c; - t.nukatakana = 0x30cc; - t.nukatakanahalfwidth = 0xff87; - t.nuktabengali = 0x09bc; - t.nuktadeva = 0x093c; - t.nuktagujarati = 0x0abc; - t.nuktagurmukhi = 0x0a3c; - t.numbersign = 0x0023; - t.numbersignmonospace = 0xff03; - t.numbersignsmall = 0xfe5f; - t.numeralsigngreek = 0x0374; - t.numeralsignlowergreek = 0x0375; - t.numero = 0x2116; - t.nun = 0x05e0; - t.nundagesh = 0xfb40; - t.nundageshhebrew = 0xfb40; - t.nunhebrew = 0x05e0; - t.nvsquare = 0x33b5; - t.nwsquare = 0x33bb; - t.nyabengali = 0x099e; - t.nyadeva = 0x091e; - t.nyagujarati = 0x0a9e; - t.nyagurmukhi = 0x0a1e; - t.o = 0x006f; - t.oacute = 0x00f3; - t.oangthai = 0x0e2d; - t.obarred = 0x0275; - t.obarredcyrillic = 0x04e9; - t.obarreddieresiscyrillic = 0x04eb; - t.obengali = 0x0993; - t.obopomofo = 0x311b; - t.obreve = 0x014f; - t.ocandradeva = 0x0911; - t.ocandragujarati = 0x0a91; - t.ocandravowelsigndeva = 0x0949; - t.ocandravowelsigngujarati = 0x0ac9; - t.ocaron = 0x01d2; - t.ocircle = 0x24de; - t.ocircumflex = 0x00f4; - t.ocircumflexacute = 0x1ed1; - t.ocircumflexdotbelow = 0x1ed9; - t.ocircumflexgrave = 0x1ed3; - t.ocircumflexhookabove = 0x1ed5; - t.ocircumflextilde = 0x1ed7; - t.ocyrillic = 0x043e; - t.odblacute = 0x0151; - t.odblgrave = 0x020d; - t.odeva = 0x0913; - t.odieresis = 0x00f6; - t.odieresiscyrillic = 0x04e7; - t.odotbelow = 0x1ecd; - t.oe = 0x0153; - t.oekorean = 0x315a; - t.ogonek = 0x02db; - t.ogonekcmb = 0x0328; - t.ograve = 0x00f2; - t.ogujarati = 0x0a93; - t.oharmenian = 0x0585; - t.ohiragana = 0x304a; - t.ohookabove = 0x1ecf; - t.ohorn = 0x01a1; - t.ohornacute = 0x1edb; - t.ohorndotbelow = 0x1ee3; - t.ohorngrave = 0x1edd; - t.ohornhookabove = 0x1edf; - t.ohorntilde = 0x1ee1; - t.ohungarumlaut = 0x0151; - t.oi = 0x01a3; - t.oinvertedbreve = 0x020f; - t.okatakana = 0x30aa; - t.okatakanahalfwidth = 0xff75; - t.okorean = 0x3157; - t.olehebrew = 0x05ab; - t.omacron = 0x014d; - t.omacronacute = 0x1e53; - t.omacrongrave = 0x1e51; - t.omdeva = 0x0950; - t.omega = 0x03c9; - t.omega1 = 0x03d6; - t.omegacyrillic = 0x0461; - t.omegalatinclosed = 0x0277; - t.omegaroundcyrillic = 0x047b; - t.omegatitlocyrillic = 0x047d; - t.omegatonos = 0x03ce; - t.omgujarati = 0x0ad0; - t.omicron = 0x03bf; - t.omicrontonos = 0x03cc; - t.omonospace = 0xff4f; - t.one = 0x0031; - t.onearabic = 0x0661; - t.onebengali = 0x09e7; - t.onecircle = 0x2460; - t.onecircleinversesansserif = 0x278a; - t.onedeva = 0x0967; - t.onedotenleader = 0x2024; - t.oneeighth = 0x215b; - t.onefitted = 0xf6dc; - t.onegujarati = 0x0ae7; - t.onegurmukhi = 0x0a67; - t.onehackarabic = 0x0661; - t.onehalf = 0x00bd; - t.onehangzhou = 0x3021; - t.oneideographicparen = 0x3220; - t.oneinferior = 0x2081; - t.onemonospace = 0xff11; - t.onenumeratorbengali = 0x09f4; - t.oneoldstyle = 0xf731; - t.oneparen = 0x2474; - t.oneperiod = 0x2488; - t.onepersian = 0x06f1; - t.onequarter = 0x00bc; - t.oneroman = 0x2170; - t.onesuperior = 0x00b9; - t.onethai = 0x0e51; - t.onethird = 0x2153; - t.oogonek = 0x01eb; - t.oogonekmacron = 0x01ed; - t.oogurmukhi = 0x0a13; - t.oomatragurmukhi = 0x0a4b; - t.oopen = 0x0254; - t.oparen = 0x24aa; - t.openbullet = 0x25e6; - t.option = 0x2325; - t.ordfeminine = 0x00aa; - t.ordmasculine = 0x00ba; - t.orthogonal = 0x221f; - t.oshortdeva = 0x0912; - t.oshortvowelsigndeva = 0x094a; - t.oslash = 0x00f8; - t.oslashacute = 0x01ff; - t.osmallhiragana = 0x3049; - t.osmallkatakana = 0x30a9; - t.osmallkatakanahalfwidth = 0xff6b; - t.ostrokeacute = 0x01ff; - t.osuperior = 0xf6f0; - t.otcyrillic = 0x047f; - t.otilde = 0x00f5; - t.otildeacute = 0x1e4d; - t.otildedieresis = 0x1e4f; - t.oubopomofo = 0x3121; - t.overline = 0x203e; - t.overlinecenterline = 0xfe4a; - t.overlinecmb = 0x0305; - t.overlinedashed = 0xfe49; - t.overlinedblwavy = 0xfe4c; - t.overlinewavy = 0xfe4b; - t.overscore = 0x00af; - t.ovowelsignbengali = 0x09cb; - t.ovowelsigndeva = 0x094b; - t.ovowelsigngujarati = 0x0acb; - t.p = 0x0070; - t.paampssquare = 0x3380; - t.paasentosquare = 0x332b; - t.pabengali = 0x09aa; - t.pacute = 0x1e55; - t.padeva = 0x092a; - t.pagedown = 0x21df; - t.pageup = 0x21de; - t.pagujarati = 0x0aaa; - t.pagurmukhi = 0x0a2a; - t.pahiragana = 0x3071; - t.paiyannoithai = 0x0e2f; - t.pakatakana = 0x30d1; - t.palatalizationcyrilliccmb = 0x0484; - t.palochkacyrillic = 0x04c0; - t.pansioskorean = 0x317f; - t.paragraph = 0x00b6; - t.parallel = 0x2225; - t.parenleft = 0x0028; - t.parenleftaltonearabic = 0xfd3e; - t.parenleftbt = 0xf8ed; - t.parenleftex = 0xf8ec; - t.parenleftinferior = 0x208d; - t.parenleftmonospace = 0xff08; - t.parenleftsmall = 0xfe59; - t.parenleftsuperior = 0x207d; - t.parenlefttp = 0xf8eb; - t.parenleftvertical = 0xfe35; - t.parenright = 0x0029; - t.parenrightaltonearabic = 0xfd3f; - t.parenrightbt = 0xf8f8; - t.parenrightex = 0xf8f7; - t.parenrightinferior = 0x208e; - t.parenrightmonospace = 0xff09; - t.parenrightsmall = 0xfe5a; - t.parenrightsuperior = 0x207e; - t.parenrighttp = 0xf8f6; - t.parenrightvertical = 0xfe36; - t.partialdiff = 0x2202; - t.paseqhebrew = 0x05c0; - t.pashtahebrew = 0x0599; - t.pasquare = 0x33a9; - t.patah = 0x05b7; - t.patah11 = 0x05b7; - t.patah1d = 0x05b7; - t.patah2a = 0x05b7; - t.patahhebrew = 0x05b7; - t.patahnarrowhebrew = 0x05b7; - t.patahquarterhebrew = 0x05b7; - t.patahwidehebrew = 0x05b7; - t.pazerhebrew = 0x05a1; - t.pbopomofo = 0x3106; - t.pcircle = 0x24df; - t.pdotaccent = 0x1e57; - t.pe = 0x05e4; - t.pecyrillic = 0x043f; - t.pedagesh = 0xfb44; - t.pedageshhebrew = 0xfb44; - t.peezisquare = 0x333b; - t.pefinaldageshhebrew = 0xfb43; - t.peharabic = 0x067e; - t.peharmenian = 0x057a; - t.pehebrew = 0x05e4; - t.pehfinalarabic = 0xfb57; - t.pehinitialarabic = 0xfb58; - t.pehiragana = 0x307a; - t.pehmedialarabic = 0xfb59; - t.pekatakana = 0x30da; - t.pemiddlehookcyrillic = 0x04a7; - t.perafehebrew = 0xfb4e; - t.percent = 0x0025; - t.percentarabic = 0x066a; - t.percentmonospace = 0xff05; - t.percentsmall = 0xfe6a; - t.period = 0x002e; - t.periodarmenian = 0x0589; - t.periodcentered = 0x00b7; - t.periodhalfwidth = 0xff61; - t.periodinferior = 0xf6e7; - t.periodmonospace = 0xff0e; - t.periodsmall = 0xfe52; - t.periodsuperior = 0xf6e8; - t.perispomenigreekcmb = 0x0342; - t.perpendicular = 0x22a5; - t.perthousand = 0x2030; - t.peseta = 0x20a7; - t.pfsquare = 0x338a; - t.phabengali = 0x09ab; - t.phadeva = 0x092b; - t.phagujarati = 0x0aab; - t.phagurmukhi = 0x0a2b; - t.phi = 0x03c6; - t.phi1 = 0x03d5; - t.phieuphacirclekorean = 0x327a; - t.phieuphaparenkorean = 0x321a; - t.phieuphcirclekorean = 0x326c; - t.phieuphkorean = 0x314d; - t.phieuphparenkorean = 0x320c; - t.philatin = 0x0278; - t.phinthuthai = 0x0e3a; - t.phisymbolgreek = 0x03d5; - t.phook = 0x01a5; - t.phophanthai = 0x0e1e; - t.phophungthai = 0x0e1c; - t.phosamphaothai = 0x0e20; - t.pi = 0x03c0; - t.pieupacirclekorean = 0x3273; - t.pieupaparenkorean = 0x3213; - t.pieupcieuckorean = 0x3176; - t.pieupcirclekorean = 0x3265; - t.pieupkiyeokkorean = 0x3172; - t.pieupkorean = 0x3142; - t.pieupparenkorean = 0x3205; - t.pieupsioskiyeokkorean = 0x3174; - t.pieupsioskorean = 0x3144; - t.pieupsiostikeutkorean = 0x3175; - t.pieupthieuthkorean = 0x3177; - t.pieuptikeutkorean = 0x3173; - t.pihiragana = 0x3074; - t.pikatakana = 0x30d4; - t.pisymbolgreek = 0x03d6; - t.piwrarmenian = 0x0583; - t.plus = 0x002b; - t.plusbelowcmb = 0x031f; - t.pluscircle = 0x2295; - t.plusminus = 0x00b1; - t.plusmod = 0x02d6; - t.plusmonospace = 0xff0b; - t.plussmall = 0xfe62; - t.plussuperior = 0x207a; - t.pmonospace = 0xff50; - t.pmsquare = 0x33d8; - t.pohiragana = 0x307d; - t.pointingindexdownwhite = 0x261f; - t.pointingindexleftwhite = 0x261c; - t.pointingindexrightwhite = 0x261e; - t.pointingindexupwhite = 0x261d; - t.pokatakana = 0x30dd; - t.poplathai = 0x0e1b; - t.postalmark = 0x3012; - t.postalmarkface = 0x3020; - t.pparen = 0x24ab; - t.precedes = 0x227a; - t.prescription = 0x211e; - t.primemod = 0x02b9; - t.primereversed = 0x2035; - t.product = 0x220f; - t.projective = 0x2305; - t.prolongedkana = 0x30fc; - t.propellor = 0x2318; - t.propersubset = 0x2282; - t.propersuperset = 0x2283; - t.proportion = 0x2237; - t.proportional = 0x221d; - t.psi = 0x03c8; - t.psicyrillic = 0x0471; - t.psilipneumatacyrilliccmb = 0x0486; - t.pssquare = 0x33b0; - t.puhiragana = 0x3077; - t.pukatakana = 0x30d7; - t.pvsquare = 0x33b4; - t.pwsquare = 0x33ba; - t.q = 0x0071; - t.qadeva = 0x0958; - t.qadmahebrew = 0x05a8; - t.qafarabic = 0x0642; - t.qaffinalarabic = 0xfed6; - t.qafinitialarabic = 0xfed7; - t.qafmedialarabic = 0xfed8; - t.qamats = 0x05b8; - t.qamats10 = 0x05b8; - t.qamats1a = 0x05b8; - t.qamats1c = 0x05b8; - t.qamats27 = 0x05b8; - t.qamats29 = 0x05b8; - t.qamats33 = 0x05b8; - t.qamatsde = 0x05b8; - t.qamatshebrew = 0x05b8; - t.qamatsnarrowhebrew = 0x05b8; - t.qamatsqatanhebrew = 0x05b8; - t.qamatsqatannarrowhebrew = 0x05b8; - t.qamatsqatanquarterhebrew = 0x05b8; - t.qamatsqatanwidehebrew = 0x05b8; - t.qamatsquarterhebrew = 0x05b8; - t.qamatswidehebrew = 0x05b8; - t.qarneyparahebrew = 0x059f; - t.qbopomofo = 0x3111; - t.qcircle = 0x24e0; - t.qhook = 0x02a0; - t.qmonospace = 0xff51; - t.qof = 0x05e7; - t.qofdagesh = 0xfb47; - t.qofdageshhebrew = 0xfb47; - t.qofhebrew = 0x05e7; - t.qparen = 0x24ac; - t.quarternote = 0x2669; - t.qubuts = 0x05bb; - t.qubuts18 = 0x05bb; - t.qubuts25 = 0x05bb; - t.qubuts31 = 0x05bb; - t.qubutshebrew = 0x05bb; - t.qubutsnarrowhebrew = 0x05bb; - t.qubutsquarterhebrew = 0x05bb; - t.qubutswidehebrew = 0x05bb; - t.question = 0x003f; - t.questionarabic = 0x061f; - t.questionarmenian = 0x055e; - t.questiondown = 0x00bf; - t.questiondownsmall = 0xf7bf; - t.questiongreek = 0x037e; - t.questionmonospace = 0xff1f; - t.questionsmall = 0xf73f; - t.quotedbl = 0x0022; - t.quotedblbase = 0x201e; - t.quotedblleft = 0x201c; - t.quotedblmonospace = 0xff02; - t.quotedblprime = 0x301e; - t.quotedblprimereversed = 0x301d; - t.quotedblright = 0x201d; - t.quoteleft = 0x2018; - t.quoteleftreversed = 0x201b; - t.quotereversed = 0x201b; - t.quoteright = 0x2019; - t.quoterightn = 0x0149; - t.quotesinglbase = 0x201a; - t.quotesingle = 0x0027; - t.quotesinglemonospace = 0xff07; - t.r = 0x0072; - t.raarmenian = 0x057c; - t.rabengali = 0x09b0; - t.racute = 0x0155; - t.radeva = 0x0930; - t.radical = 0x221a; - t.radicalex = 0xf8e5; - t.radoverssquare = 0x33ae; - t.radoverssquaredsquare = 0x33af; - t.radsquare = 0x33ad; - t.rafe = 0x05bf; - t.rafehebrew = 0x05bf; - t.ragujarati = 0x0ab0; - t.ragurmukhi = 0x0a30; - t.rahiragana = 0x3089; - t.rakatakana = 0x30e9; - t.rakatakanahalfwidth = 0xff97; - t.ralowerdiagonalbengali = 0x09f1; - t.ramiddlediagonalbengali = 0x09f0; - t.ramshorn = 0x0264; - t.ratio = 0x2236; - t.rbopomofo = 0x3116; - t.rcaron = 0x0159; - t.rcedilla = 0x0157; - t.rcircle = 0x24e1; - t.rcommaaccent = 0x0157; - t.rdblgrave = 0x0211; - t.rdotaccent = 0x1e59; - t.rdotbelow = 0x1e5b; - t.rdotbelowmacron = 0x1e5d; - t.referencemark = 0x203b; - t.reflexsubset = 0x2286; - t.reflexsuperset = 0x2287; - t.registered = 0x00ae; - t.registersans = 0xf8e8; - t.registerserif = 0xf6da; - t.reharabic = 0x0631; - t.reharmenian = 0x0580; - t.rehfinalarabic = 0xfeae; - t.rehiragana = 0x308c; - t.rekatakana = 0x30ec; - t.rekatakanahalfwidth = 0xff9a; - t.resh = 0x05e8; - t.reshdageshhebrew = 0xfb48; - t.reshhebrew = 0x05e8; - t.reversedtilde = 0x223d; - t.reviahebrew = 0x0597; - t.reviamugrashhebrew = 0x0597; - t.revlogicalnot = 0x2310; - t.rfishhook = 0x027e; - t.rfishhookreversed = 0x027f; - t.rhabengali = 0x09dd; - t.rhadeva = 0x095d; - t.rho = 0x03c1; - t.rhook = 0x027d; - t.rhookturned = 0x027b; - t.rhookturnedsuperior = 0x02b5; - t.rhosymbolgreek = 0x03f1; - t.rhotichookmod = 0x02de; - t.rieulacirclekorean = 0x3271; - t.rieulaparenkorean = 0x3211; - t.rieulcirclekorean = 0x3263; - t.rieulhieuhkorean = 0x3140; - t.rieulkiyeokkorean = 0x313a; - t.rieulkiyeoksioskorean = 0x3169; - t.rieulkorean = 0x3139; - t.rieulmieumkorean = 0x313b; - t.rieulpansioskorean = 0x316c; - t.rieulparenkorean = 0x3203; - t.rieulphieuphkorean = 0x313f; - t.rieulpieupkorean = 0x313c; - t.rieulpieupsioskorean = 0x316b; - t.rieulsioskorean = 0x313d; - t.rieulthieuthkorean = 0x313e; - t.rieultikeutkorean = 0x316a; - t.rieulyeorinhieuhkorean = 0x316d; - t.rightangle = 0x221f; - t.righttackbelowcmb = 0x0319; - t.righttriangle = 0x22bf; - t.rihiragana = 0x308a; - t.rikatakana = 0x30ea; - t.rikatakanahalfwidth = 0xff98; - t.ring = 0x02da; - t.ringbelowcmb = 0x0325; - t.ringcmb = 0x030a; - t.ringhalfleft = 0x02bf; - t.ringhalfleftarmenian = 0x0559; - t.ringhalfleftbelowcmb = 0x031c; - t.ringhalfleftcentered = 0x02d3; - t.ringhalfright = 0x02be; - t.ringhalfrightbelowcmb = 0x0339; - t.ringhalfrightcentered = 0x02d2; - t.rinvertedbreve = 0x0213; - t.rittorusquare = 0x3351; - t.rlinebelow = 0x1e5f; - t.rlongleg = 0x027c; - t.rlonglegturned = 0x027a; - t.rmonospace = 0xff52; - t.rohiragana = 0x308d; - t.rokatakana = 0x30ed; - t.rokatakanahalfwidth = 0xff9b; - t.roruathai = 0x0e23; - t.rparen = 0x24ad; - t.rrabengali = 0x09dc; - t.rradeva = 0x0931; - t.rragurmukhi = 0x0a5c; - t.rreharabic = 0x0691; - t.rrehfinalarabic = 0xfb8d; - t.rrvocalicbengali = 0x09e0; - t.rrvocalicdeva = 0x0960; - t.rrvocalicgujarati = 0x0ae0; - t.rrvocalicvowelsignbengali = 0x09c4; - t.rrvocalicvowelsigndeva = 0x0944; - t.rrvocalicvowelsigngujarati = 0x0ac4; - t.rsuperior = 0xf6f1; - t.rtblock = 0x2590; - t.rturned = 0x0279; - t.rturnedsuperior = 0x02b4; - t.ruhiragana = 0x308b; - t.rukatakana = 0x30eb; - t.rukatakanahalfwidth = 0xff99; - t.rupeemarkbengali = 0x09f2; - t.rupeesignbengali = 0x09f3; - t.rupiah = 0xf6dd; - t.ruthai = 0x0e24; - t.rvocalicbengali = 0x098b; - t.rvocalicdeva = 0x090b; - t.rvocalicgujarati = 0x0a8b; - t.rvocalicvowelsignbengali = 0x09c3; - t.rvocalicvowelsigndeva = 0x0943; - t.rvocalicvowelsigngujarati = 0x0ac3; - t.s = 0x0073; - t.sabengali = 0x09b8; - t.sacute = 0x015b; - t.sacutedotaccent = 0x1e65; - t.sadarabic = 0x0635; - t.sadeva = 0x0938; - t.sadfinalarabic = 0xfeba; - t.sadinitialarabic = 0xfebb; - t.sadmedialarabic = 0xfebc; - t.sagujarati = 0x0ab8; - t.sagurmukhi = 0x0a38; - t.sahiragana = 0x3055; - t.sakatakana = 0x30b5; - t.sakatakanahalfwidth = 0xff7b; - t.sallallahoualayhewasallamarabic = 0xfdfa; - t.samekh = 0x05e1; - t.samekhdagesh = 0xfb41; - t.samekhdageshhebrew = 0xfb41; - t.samekhhebrew = 0x05e1; - t.saraaathai = 0x0e32; - t.saraaethai = 0x0e41; - t.saraaimaimalaithai = 0x0e44; - t.saraaimaimuanthai = 0x0e43; - t.saraamthai = 0x0e33; - t.saraathai = 0x0e30; - t.saraethai = 0x0e40; - t.saraiileftthai = 0xf886; - t.saraiithai = 0x0e35; - t.saraileftthai = 0xf885; - t.saraithai = 0x0e34; - t.saraothai = 0x0e42; - t.saraueeleftthai = 0xf888; - t.saraueethai = 0x0e37; - t.saraueleftthai = 0xf887; - t.sarauethai = 0x0e36; - t.sarauthai = 0x0e38; - t.sarauuthai = 0x0e39; - t.sbopomofo = 0x3119; - t.scaron = 0x0161; - t.scarondotaccent = 0x1e67; - t.scedilla = 0x015f; - t.schwa = 0x0259; - t.schwacyrillic = 0x04d9; - t.schwadieresiscyrillic = 0x04db; - t.schwahook = 0x025a; - t.scircle = 0x24e2; - t.scircumflex = 0x015d; - t.scommaaccent = 0x0219; - t.sdotaccent = 0x1e61; - t.sdotbelow = 0x1e63; - t.sdotbelowdotaccent = 0x1e69; - t.seagullbelowcmb = 0x033c; - t.second = 0x2033; - t.secondtonechinese = 0x02ca; - t.section = 0x00a7; - t.seenarabic = 0x0633; - t.seenfinalarabic = 0xfeb2; - t.seeninitialarabic = 0xfeb3; - t.seenmedialarabic = 0xfeb4; - t.segol = 0x05b6; - t.segol13 = 0x05b6; - t.segol1f = 0x05b6; - t.segol2c = 0x05b6; - t.segolhebrew = 0x05b6; - t.segolnarrowhebrew = 0x05b6; - t.segolquarterhebrew = 0x05b6; - t.segoltahebrew = 0x0592; - t.segolwidehebrew = 0x05b6; - t.seharmenian = 0x057d; - t.sehiragana = 0x305b; - t.sekatakana = 0x30bb; - t.sekatakanahalfwidth = 0xff7e; - t.semicolon = 0x003b; - t.semicolonarabic = 0x061b; - t.semicolonmonospace = 0xff1b; - t.semicolonsmall = 0xfe54; - t.semivoicedmarkkana = 0x309c; - t.semivoicedmarkkanahalfwidth = 0xff9f; - t.sentisquare = 0x3322; - t.sentosquare = 0x3323; - t.seven = 0x0037; - t.sevenarabic = 0x0667; - t.sevenbengali = 0x09ed; - t.sevencircle = 0x2466; - t.sevencircleinversesansserif = 0x2790; - t.sevendeva = 0x096d; - t.seveneighths = 0x215e; - t.sevengujarati = 0x0aed; - t.sevengurmukhi = 0x0a6d; - t.sevenhackarabic = 0x0667; - t.sevenhangzhou = 0x3027; - t.sevenideographicparen = 0x3226; - t.seveninferior = 0x2087; - t.sevenmonospace = 0xff17; - t.sevenoldstyle = 0xf737; - t.sevenparen = 0x247a; - t.sevenperiod = 0x248e; - t.sevenpersian = 0x06f7; - t.sevenroman = 0x2176; - t.sevensuperior = 0x2077; - t.seventeencircle = 0x2470; - t.seventeenparen = 0x2484; - t.seventeenperiod = 0x2498; - t.seventhai = 0x0e57; - t.sfthyphen = 0x00ad; - t.shaarmenian = 0x0577; - t.shabengali = 0x09b6; - t.shacyrillic = 0x0448; - t.shaddaarabic = 0x0651; - t.shaddadammaarabic = 0xfc61; - t.shaddadammatanarabic = 0xfc5e; - t.shaddafathaarabic = 0xfc60; - t.shaddakasraarabic = 0xfc62; - t.shaddakasratanarabic = 0xfc5f; - t.shade = 0x2592; - t.shadedark = 0x2593; - t.shadelight = 0x2591; - t.shademedium = 0x2592; - t.shadeva = 0x0936; - t.shagujarati = 0x0ab6; - t.shagurmukhi = 0x0a36; - t.shalshelethebrew = 0x0593; - t.shbopomofo = 0x3115; - t.shchacyrillic = 0x0449; - t.sheenarabic = 0x0634; - t.sheenfinalarabic = 0xfeb6; - t.sheeninitialarabic = 0xfeb7; - t.sheenmedialarabic = 0xfeb8; - t.sheicoptic = 0x03e3; - t.sheqel = 0x20aa; - t.sheqelhebrew = 0x20aa; - t.sheva = 0x05b0; - t.sheva115 = 0x05b0; - t.sheva15 = 0x05b0; - t.sheva22 = 0x05b0; - t.sheva2e = 0x05b0; - t.shevahebrew = 0x05b0; - t.shevanarrowhebrew = 0x05b0; - t.shevaquarterhebrew = 0x05b0; - t.shevawidehebrew = 0x05b0; - t.shhacyrillic = 0x04bb; - t.shimacoptic = 0x03ed; - t.shin = 0x05e9; - t.shindagesh = 0xfb49; - t.shindageshhebrew = 0xfb49; - t.shindageshshindot = 0xfb2c; - t.shindageshshindothebrew = 0xfb2c; - t.shindageshsindot = 0xfb2d; - t.shindageshsindothebrew = 0xfb2d; - t.shindothebrew = 0x05c1; - t.shinhebrew = 0x05e9; - t.shinshindot = 0xfb2a; - t.shinshindothebrew = 0xfb2a; - t.shinsindot = 0xfb2b; - t.shinsindothebrew = 0xfb2b; - t.shook = 0x0282; - t.sigma = 0x03c3; - t.sigma1 = 0x03c2; - t.sigmafinal = 0x03c2; - t.sigmalunatesymbolgreek = 0x03f2; - t.sihiragana = 0x3057; - t.sikatakana = 0x30b7; - t.sikatakanahalfwidth = 0xff7c; - t.siluqhebrew = 0x05bd; - t.siluqlefthebrew = 0x05bd; - t.similar = 0x223c; - t.sindothebrew = 0x05c2; - t.siosacirclekorean = 0x3274; - t.siosaparenkorean = 0x3214; - t.sioscieuckorean = 0x317e; - t.sioscirclekorean = 0x3266; - t.sioskiyeokkorean = 0x317a; - t.sioskorean = 0x3145; - t.siosnieunkorean = 0x317b; - t.siosparenkorean = 0x3206; - t.siospieupkorean = 0x317d; - t.siostikeutkorean = 0x317c; - t.six = 0x0036; - t.sixarabic = 0x0666; - t.sixbengali = 0x09ec; - t.sixcircle = 0x2465; - t.sixcircleinversesansserif = 0x278f; - t.sixdeva = 0x096c; - t.sixgujarati = 0x0aec; - t.sixgurmukhi = 0x0a6c; - t.sixhackarabic = 0x0666; - t.sixhangzhou = 0x3026; - t.sixideographicparen = 0x3225; - t.sixinferior = 0x2086; - t.sixmonospace = 0xff16; - t.sixoldstyle = 0xf736; - t.sixparen = 0x2479; - t.sixperiod = 0x248d; - t.sixpersian = 0x06f6; - t.sixroman = 0x2175; - t.sixsuperior = 0x2076; - t.sixteencircle = 0x246f; - t.sixteencurrencydenominatorbengali = 0x09f9; - t.sixteenparen = 0x2483; - t.sixteenperiod = 0x2497; - t.sixthai = 0x0e56; - t.slash = 0x002f; - t.slashmonospace = 0xff0f; - t.slong = 0x017f; - t.slongdotaccent = 0x1e9b; - t.smileface = 0x263a; - t.smonospace = 0xff53; - t.sofpasuqhebrew = 0x05c3; - t.softhyphen = 0x00ad; - t.softsigncyrillic = 0x044c; - t.sohiragana = 0x305d; - t.sokatakana = 0x30bd; - t.sokatakanahalfwidth = 0xff7f; - t.soliduslongoverlaycmb = 0x0338; - t.solidusshortoverlaycmb = 0x0337; - t.sorusithai = 0x0e29; - t.sosalathai = 0x0e28; - t.sosothai = 0x0e0b; - t.sosuathai = 0x0e2a; - t.space = 0x0020; - t.spacehackarabic = 0x0020; - t.spade = 0x2660; - t.spadesuitblack = 0x2660; - t.spadesuitwhite = 0x2664; - t.sparen = 0x24ae; - t.squarebelowcmb = 0x033b; - t.squarecc = 0x33c4; - t.squarecm = 0x339d; - t.squarediagonalcrosshatchfill = 0x25a9; - t.squarehorizontalfill = 0x25a4; - t.squarekg = 0x338f; - t.squarekm = 0x339e; - t.squarekmcapital = 0x33ce; - t.squareln = 0x33d1; - t.squarelog = 0x33d2; - t.squaremg = 0x338e; - t.squaremil = 0x33d5; - t.squaremm = 0x339c; - t.squaremsquared = 0x33a1; - t.squareorthogonalcrosshatchfill = 0x25a6; - t.squareupperlefttolowerrightfill = 0x25a7; - t.squareupperrighttolowerleftfill = 0x25a8; - t.squareverticalfill = 0x25a5; - t.squarewhitewithsmallblack = 0x25a3; - t.srsquare = 0x33db; - t.ssabengali = 0x09b7; - t.ssadeva = 0x0937; - t.ssagujarati = 0x0ab7; - t.ssangcieuckorean = 0x3149; - t.ssanghieuhkorean = 0x3185; - t.ssangieungkorean = 0x3180; - t.ssangkiyeokkorean = 0x3132; - t.ssangnieunkorean = 0x3165; - t.ssangpieupkorean = 0x3143; - t.ssangsioskorean = 0x3146; - t.ssangtikeutkorean = 0x3138; - t.ssuperior = 0xf6f2; - t.sterling = 0x00a3; - t.sterlingmonospace = 0xffe1; - t.strokelongoverlaycmb = 0x0336; - t.strokeshortoverlaycmb = 0x0335; - t.subset = 0x2282; - t.subsetnotequal = 0x228a; - t.subsetorequal = 0x2286; - t.succeeds = 0x227b; - t.suchthat = 0x220b; - t.suhiragana = 0x3059; - t.sukatakana = 0x30b9; - t.sukatakanahalfwidth = 0xff7d; - t.sukunarabic = 0x0652; - t.summation = 0x2211; - t.sun = 0x263c; - t.superset = 0x2283; - t.supersetnotequal = 0x228b; - t.supersetorequal = 0x2287; - t.svsquare = 0x33dc; - t.syouwaerasquare = 0x337c; - t.t = 0x0074; - t.tabengali = 0x09a4; - t.tackdown = 0x22a4; - t.tackleft = 0x22a3; - t.tadeva = 0x0924; - t.tagujarati = 0x0aa4; - t.tagurmukhi = 0x0a24; - t.taharabic = 0x0637; - t.tahfinalarabic = 0xfec2; - t.tahinitialarabic = 0xfec3; - t.tahiragana = 0x305f; - t.tahmedialarabic = 0xfec4; - t.taisyouerasquare = 0x337d; - t.takatakana = 0x30bf; - t.takatakanahalfwidth = 0xff80; - t.tatweelarabic = 0x0640; - t.tau = 0x03c4; - t.tav = 0x05ea; - t.tavdages = 0xfb4a; - t.tavdagesh = 0xfb4a; - t.tavdageshhebrew = 0xfb4a; - t.tavhebrew = 0x05ea; - t.tbar = 0x0167; - t.tbopomofo = 0x310a; - t.tcaron = 0x0165; - t.tccurl = 0x02a8; - t.tcedilla = 0x0163; - t.tcheharabic = 0x0686; - t.tchehfinalarabic = 0xfb7b; - t.tchehinitialarabic = 0xfb7c; - t.tchehmedialarabic = 0xfb7d; - t.tcircle = 0x24e3; - t.tcircumflexbelow = 0x1e71; - t.tcommaaccent = 0x0163; - t.tdieresis = 0x1e97; - t.tdotaccent = 0x1e6b; - t.tdotbelow = 0x1e6d; - t.tecyrillic = 0x0442; - t.tedescendercyrillic = 0x04ad; - t.teharabic = 0x062a; - t.tehfinalarabic = 0xfe96; - t.tehhahinitialarabic = 0xfca2; - t.tehhahisolatedarabic = 0xfc0c; - t.tehinitialarabic = 0xfe97; - t.tehiragana = 0x3066; - t.tehjeeminitialarabic = 0xfca1; - t.tehjeemisolatedarabic = 0xfc0b; - t.tehmarbutaarabic = 0x0629; - t.tehmarbutafinalarabic = 0xfe94; - t.tehmedialarabic = 0xfe98; - t.tehmeeminitialarabic = 0xfca4; - t.tehmeemisolatedarabic = 0xfc0e; - t.tehnoonfinalarabic = 0xfc73; - t.tekatakana = 0x30c6; - t.tekatakanahalfwidth = 0xff83; - t.telephone = 0x2121; - t.telephoneblack = 0x260e; - t.telishagedolahebrew = 0x05a0; - t.telishaqetanahebrew = 0x05a9; - t.tencircle = 0x2469; - t.tenideographicparen = 0x3229; - t.tenparen = 0x247d; - t.tenperiod = 0x2491; - t.tenroman = 0x2179; - t.tesh = 0x02a7; - t.tet = 0x05d8; - t.tetdagesh = 0xfb38; - t.tetdageshhebrew = 0xfb38; - t.tethebrew = 0x05d8; - t.tetsecyrillic = 0x04b5; - t.tevirhebrew = 0x059b; - t.tevirlefthebrew = 0x059b; - t.thabengali = 0x09a5; - t.thadeva = 0x0925; - t.thagujarati = 0x0aa5; - t.thagurmukhi = 0x0a25; - t.thalarabic = 0x0630; - t.thalfinalarabic = 0xfeac; - t.thanthakhatlowleftthai = 0xf898; - t.thanthakhatlowrightthai = 0xf897; - t.thanthakhatthai = 0x0e4c; - t.thanthakhatupperleftthai = 0xf896; - t.theharabic = 0x062b; - t.thehfinalarabic = 0xfe9a; - t.thehinitialarabic = 0xfe9b; - t.thehmedialarabic = 0xfe9c; - t.thereexists = 0x2203; - t.therefore = 0x2234; - t.theta = 0x03b8; - t.theta1 = 0x03d1; - t.thetasymbolgreek = 0x03d1; - t.thieuthacirclekorean = 0x3279; - t.thieuthaparenkorean = 0x3219; - t.thieuthcirclekorean = 0x326b; - t.thieuthkorean = 0x314c; - t.thieuthparenkorean = 0x320b; - t.thirteencircle = 0x246c; - t.thirteenparen = 0x2480; - t.thirteenperiod = 0x2494; - t.thonangmonthothai = 0x0e11; - t.thook = 0x01ad; - t.thophuthaothai = 0x0e12; - t.thorn = 0x00fe; - t.thothahanthai = 0x0e17; - t.thothanthai = 0x0e10; - t.thothongthai = 0x0e18; - t.thothungthai = 0x0e16; - t.thousandcyrillic = 0x0482; - t.thousandsseparatorarabic = 0x066c; - t.thousandsseparatorpersian = 0x066c; - t.three = 0x0033; - t.threearabic = 0x0663; - t.threebengali = 0x09e9; - t.threecircle = 0x2462; - t.threecircleinversesansserif = 0x278c; - t.threedeva = 0x0969; - t.threeeighths = 0x215c; - t.threegujarati = 0x0ae9; - t.threegurmukhi = 0x0a69; - t.threehackarabic = 0x0663; - t.threehangzhou = 0x3023; - t.threeideographicparen = 0x3222; - t.threeinferior = 0x2083; - t.threemonospace = 0xff13; - t.threenumeratorbengali = 0x09f6; - t.threeoldstyle = 0xf733; - t.threeparen = 0x2476; - t.threeperiod = 0x248a; - t.threepersian = 0x06f3; - t.threequarters = 0x00be; - t.threequartersemdash = 0xf6de; - t.threeroman = 0x2172; - t.threesuperior = 0x00b3; - t.threethai = 0x0e53; - t.thzsquare = 0x3394; - t.tihiragana = 0x3061; - t.tikatakana = 0x30c1; - t.tikatakanahalfwidth = 0xff81; - t.tikeutacirclekorean = 0x3270; - t.tikeutaparenkorean = 0x3210; - t.tikeutcirclekorean = 0x3262; - t.tikeutkorean = 0x3137; - t.tikeutparenkorean = 0x3202; - t.tilde = 0x02dc; - t.tildebelowcmb = 0x0330; - t.tildecmb = 0x0303; - t.tildecomb = 0x0303; - t.tildedoublecmb = 0x0360; - t.tildeoperator = 0x223c; - t.tildeoverlaycmb = 0x0334; - t.tildeverticalcmb = 0x033e; - t.timescircle = 0x2297; - t.tipehahebrew = 0x0596; - t.tipehalefthebrew = 0x0596; - t.tippigurmukhi = 0x0a70; - t.titlocyrilliccmb = 0x0483; - t.tiwnarmenian = 0x057f; - t.tlinebelow = 0x1e6f; - t.tmonospace = 0xff54; - t.toarmenian = 0x0569; - t.tohiragana = 0x3068; - t.tokatakana = 0x30c8; - t.tokatakanahalfwidth = 0xff84; - t.tonebarextrahighmod = 0x02e5; - t.tonebarextralowmod = 0x02e9; - t.tonebarhighmod = 0x02e6; - t.tonebarlowmod = 0x02e8; - t.tonebarmidmod = 0x02e7; - t.tonefive = 0x01bd; - t.tonesix = 0x0185; - t.tonetwo = 0x01a8; - t.tonos = 0x0384; - t.tonsquare = 0x3327; - t.topatakthai = 0x0e0f; - t.tortoiseshellbracketleft = 0x3014; - t.tortoiseshellbracketleftsmall = 0xfe5d; - t.tortoiseshellbracketleftvertical = 0xfe39; - t.tortoiseshellbracketright = 0x3015; - t.tortoiseshellbracketrightsmall = 0xfe5e; - t.tortoiseshellbracketrightvertical = 0xfe3a; - t.totaothai = 0x0e15; - t.tpalatalhook = 0x01ab; - t.tparen = 0x24af; - t.trademark = 0x2122; - t.trademarksans = 0xf8ea; - t.trademarkserif = 0xf6db; - t.tretroflexhook = 0x0288; - t.triagdn = 0x25bc; - t.triaglf = 0x25c4; - t.triagrt = 0x25ba; - t.triagup = 0x25b2; - t.ts = 0x02a6; - t.tsadi = 0x05e6; - t.tsadidagesh = 0xfb46; - t.tsadidageshhebrew = 0xfb46; - t.tsadihebrew = 0x05e6; - t.tsecyrillic = 0x0446; - t.tsere = 0x05b5; - t.tsere12 = 0x05b5; - t.tsere1e = 0x05b5; - t.tsere2b = 0x05b5; - t.tserehebrew = 0x05b5; - t.tserenarrowhebrew = 0x05b5; - t.tserequarterhebrew = 0x05b5; - t.tserewidehebrew = 0x05b5; - t.tshecyrillic = 0x045b; - t.tsuperior = 0xf6f3; - t.ttabengali = 0x099f; - t.ttadeva = 0x091f; - t.ttagujarati = 0x0a9f; - t.ttagurmukhi = 0x0a1f; - t.tteharabic = 0x0679; - t.ttehfinalarabic = 0xfb67; - t.ttehinitialarabic = 0xfb68; - t.ttehmedialarabic = 0xfb69; - t.tthabengali = 0x09a0; - t.tthadeva = 0x0920; - t.tthagujarati = 0x0aa0; - t.tthagurmukhi = 0x0a20; - t.tturned = 0x0287; - t.tuhiragana = 0x3064; - t.tukatakana = 0x30c4; - t.tukatakanahalfwidth = 0xff82; - t.tusmallhiragana = 0x3063; - t.tusmallkatakana = 0x30c3; - t.tusmallkatakanahalfwidth = 0xff6f; - t.twelvecircle = 0x246b; - t.twelveparen = 0x247f; - t.twelveperiod = 0x2493; - t.twelveroman = 0x217b; - t.twentycircle = 0x2473; - t.twentyhangzhou = 0x5344; - t.twentyparen = 0x2487; - t.twentyperiod = 0x249b; - t.two = 0x0032; - t.twoarabic = 0x0662; - t.twobengali = 0x09e8; - t.twocircle = 0x2461; - t.twocircleinversesansserif = 0x278b; - t.twodeva = 0x0968; - t.twodotenleader = 0x2025; - t.twodotleader = 0x2025; - t.twodotleadervertical = 0xfe30; - t.twogujarati = 0x0ae8; - t.twogurmukhi = 0x0a68; - t.twohackarabic = 0x0662; - t.twohangzhou = 0x3022; - t.twoideographicparen = 0x3221; - t.twoinferior = 0x2082; - t.twomonospace = 0xff12; - t.twonumeratorbengali = 0x09f5; - t.twooldstyle = 0xf732; - t.twoparen = 0x2475; - t.twoperiod = 0x2489; - t.twopersian = 0x06f2; - t.tworoman = 0x2171; - t.twostroke = 0x01bb; - t.twosuperior = 0x00b2; - t.twothai = 0x0e52; - t.twothirds = 0x2154; - t.u = 0x0075; - t.uacute = 0x00fa; - t.ubar = 0x0289; - t.ubengali = 0x0989; - t.ubopomofo = 0x3128; - t.ubreve = 0x016d; - t.ucaron = 0x01d4; - t.ucircle = 0x24e4; - t.ucircumflex = 0x00fb; - t.ucircumflexbelow = 0x1e77; - t.ucyrillic = 0x0443; - t.udattadeva = 0x0951; - t.udblacute = 0x0171; - t.udblgrave = 0x0215; - t.udeva = 0x0909; - t.udieresis = 0x00fc; - t.udieresisacute = 0x01d8; - t.udieresisbelow = 0x1e73; - t.udieresiscaron = 0x01da; - t.udieresiscyrillic = 0x04f1; - t.udieresisgrave = 0x01dc; - t.udieresismacron = 0x01d6; - t.udotbelow = 0x1ee5; - t.ugrave = 0x00f9; - t.ugujarati = 0x0a89; - t.ugurmukhi = 0x0a09; - t.uhiragana = 0x3046; - t.uhookabove = 0x1ee7; - t.uhorn = 0x01b0; - t.uhornacute = 0x1ee9; - t.uhorndotbelow = 0x1ef1; - t.uhorngrave = 0x1eeb; - t.uhornhookabove = 0x1eed; - t.uhorntilde = 0x1eef; - t.uhungarumlaut = 0x0171; - t.uhungarumlautcyrillic = 0x04f3; - t.uinvertedbreve = 0x0217; - t.ukatakana = 0x30a6; - t.ukatakanahalfwidth = 0xff73; - t.ukcyrillic = 0x0479; - t.ukorean = 0x315c; - t.umacron = 0x016b; - t.umacroncyrillic = 0x04ef; - t.umacrondieresis = 0x1e7b; - t.umatragurmukhi = 0x0a41; - t.umonospace = 0xff55; - t.underscore = 0x005f; - t.underscoredbl = 0x2017; - t.underscoremonospace = 0xff3f; - t.underscorevertical = 0xfe33; - t.underscorewavy = 0xfe4f; - t.union = 0x222a; - t.universal = 0x2200; - t.uogonek = 0x0173; - t.uparen = 0x24b0; - t.upblock = 0x2580; - t.upperdothebrew = 0x05c4; - t.upsilon = 0x03c5; - t.upsilondieresis = 0x03cb; - t.upsilondieresistonos = 0x03b0; - t.upsilonlatin = 0x028a; - t.upsilontonos = 0x03cd; - t.uptackbelowcmb = 0x031d; - t.uptackmod = 0x02d4; - t.uragurmukhi = 0x0a73; - t.uring = 0x016f; - t.ushortcyrillic = 0x045e; - t.usmallhiragana = 0x3045; - t.usmallkatakana = 0x30a5; - t.usmallkatakanahalfwidth = 0xff69; - t.ustraightcyrillic = 0x04af; - t.ustraightstrokecyrillic = 0x04b1; - t.utilde = 0x0169; - t.utildeacute = 0x1e79; - t.utildebelow = 0x1e75; - t.uubengali = 0x098a; - t.uudeva = 0x090a; - t.uugujarati = 0x0a8a; - t.uugurmukhi = 0x0a0a; - t.uumatragurmukhi = 0x0a42; - t.uuvowelsignbengali = 0x09c2; - t.uuvowelsigndeva = 0x0942; - t.uuvowelsigngujarati = 0x0ac2; - t.uvowelsignbengali = 0x09c1; - t.uvowelsigndeva = 0x0941; - t.uvowelsigngujarati = 0x0ac1; - t.v = 0x0076; - t.vadeva = 0x0935; - t.vagujarati = 0x0ab5; - t.vagurmukhi = 0x0a35; - t.vakatakana = 0x30f7; - t.vav = 0x05d5; - t.vavdagesh = 0xfb35; - t.vavdagesh65 = 0xfb35; - t.vavdageshhebrew = 0xfb35; - t.vavhebrew = 0x05d5; - t.vavholam = 0xfb4b; - t.vavholamhebrew = 0xfb4b; - t.vavvavhebrew = 0x05f0; - t.vavyodhebrew = 0x05f1; - t.vcircle = 0x24e5; - t.vdotbelow = 0x1e7f; - t.vecyrillic = 0x0432; - t.veharabic = 0x06a4; - t.vehfinalarabic = 0xfb6b; - t.vehinitialarabic = 0xfb6c; - t.vehmedialarabic = 0xfb6d; - t.vekatakana = 0x30f9; - t.venus = 0x2640; - t.verticalbar = 0x007c; - t.verticallineabovecmb = 0x030d; - t.verticallinebelowcmb = 0x0329; - t.verticallinelowmod = 0x02cc; - t.verticallinemod = 0x02c8; - t.vewarmenian = 0x057e; - t.vhook = 0x028b; - t.vikatakana = 0x30f8; - t.viramabengali = 0x09cd; - t.viramadeva = 0x094d; - t.viramagujarati = 0x0acd; - t.visargabengali = 0x0983; - t.visargadeva = 0x0903; - t.visargagujarati = 0x0a83; - t.vmonospace = 0xff56; - t.voarmenian = 0x0578; - t.voicediterationhiragana = 0x309e; - t.voicediterationkatakana = 0x30fe; - t.voicedmarkkana = 0x309b; - t.voicedmarkkanahalfwidth = 0xff9e; - t.vokatakana = 0x30fa; - t.vparen = 0x24b1; - t.vtilde = 0x1e7d; - t.vturned = 0x028c; - t.vuhiragana = 0x3094; - t.vukatakana = 0x30f4; - t.w = 0x0077; - t.wacute = 0x1e83; - t.waekorean = 0x3159; - t.wahiragana = 0x308f; - t.wakatakana = 0x30ef; - t.wakatakanahalfwidth = 0xff9c; - t.wakorean = 0x3158; - t.wasmallhiragana = 0x308e; - t.wasmallkatakana = 0x30ee; - t.wattosquare = 0x3357; - t.wavedash = 0x301c; - t.wavyunderscorevertical = 0xfe34; - t.wawarabic = 0x0648; - t.wawfinalarabic = 0xfeee; - t.wawhamzaabovearabic = 0x0624; - t.wawhamzaabovefinalarabic = 0xfe86; - t.wbsquare = 0x33dd; - t.wcircle = 0x24e6; - t.wcircumflex = 0x0175; - t.wdieresis = 0x1e85; - t.wdotaccent = 0x1e87; - t.wdotbelow = 0x1e89; - t.wehiragana = 0x3091; - t.weierstrass = 0x2118; - t.wekatakana = 0x30f1; - t.wekorean = 0x315e; - t.weokorean = 0x315d; - t.wgrave = 0x1e81; - t.whitebullet = 0x25e6; - t.whitecircle = 0x25cb; - t.whitecircleinverse = 0x25d9; - t.whitecornerbracketleft = 0x300e; - t.whitecornerbracketleftvertical = 0xfe43; - t.whitecornerbracketright = 0x300f; - t.whitecornerbracketrightvertical = 0xfe44; - t.whitediamond = 0x25c7; - t.whitediamondcontainingblacksmalldiamond = 0x25c8; - t.whitedownpointingsmalltriangle = 0x25bf; - t.whitedownpointingtriangle = 0x25bd; - t.whiteleftpointingsmalltriangle = 0x25c3; - t.whiteleftpointingtriangle = 0x25c1; - t.whitelenticularbracketleft = 0x3016; - t.whitelenticularbracketright = 0x3017; - t.whiterightpointingsmalltriangle = 0x25b9; - t.whiterightpointingtriangle = 0x25b7; - t.whitesmallsquare = 0x25ab; - t.whitesmilingface = 0x263a; - t.whitesquare = 0x25a1; - t.whitestar = 0x2606; - t.whitetelephone = 0x260f; - t.whitetortoiseshellbracketleft = 0x3018; - t.whitetortoiseshellbracketright = 0x3019; - t.whiteuppointingsmalltriangle = 0x25b5; - t.whiteuppointingtriangle = 0x25b3; - t.wihiragana = 0x3090; - t.wikatakana = 0x30f0; - t.wikorean = 0x315f; - t.wmonospace = 0xff57; - t.wohiragana = 0x3092; - t.wokatakana = 0x30f2; - t.wokatakanahalfwidth = 0xff66; - t.won = 0x20a9; - t.wonmonospace = 0xffe6; - t.wowaenthai = 0x0e27; - t.wparen = 0x24b2; - t.wring = 0x1e98; - t.wsuperior = 0x02b7; - t.wturned = 0x028d; - t.wynn = 0x01bf; - t.x = 0x0078; - t.xabovecmb = 0x033d; - t.xbopomofo = 0x3112; - t.xcircle = 0x24e7; - t.xdieresis = 0x1e8d; - t.xdotaccent = 0x1e8b; - t.xeharmenian = 0x056d; - t.xi = 0x03be; - t.xmonospace = 0xff58; - t.xparen = 0x24b3; - t.xsuperior = 0x02e3; - t.y = 0x0079; - t.yaadosquare = 0x334e; - t.yabengali = 0x09af; - t.yacute = 0x00fd; - t.yadeva = 0x092f; - t.yaekorean = 0x3152; - t.yagujarati = 0x0aaf; - t.yagurmukhi = 0x0a2f; - t.yahiragana = 0x3084; - t.yakatakana = 0x30e4; - t.yakatakanahalfwidth = 0xff94; - t.yakorean = 0x3151; - t.yamakkanthai = 0x0e4e; - t.yasmallhiragana = 0x3083; - t.yasmallkatakana = 0x30e3; - t.yasmallkatakanahalfwidth = 0xff6c; - t.yatcyrillic = 0x0463; - t.ycircle = 0x24e8; - t.ycircumflex = 0x0177; - t.ydieresis = 0x00ff; - t.ydotaccent = 0x1e8f; - t.ydotbelow = 0x1ef5; - t.yeharabic = 0x064a; - t.yehbarreearabic = 0x06d2; - t.yehbarreefinalarabic = 0xfbaf; - t.yehfinalarabic = 0xfef2; - t.yehhamzaabovearabic = 0x0626; - t.yehhamzaabovefinalarabic = 0xfe8a; - t.yehhamzaaboveinitialarabic = 0xfe8b; - t.yehhamzaabovemedialarabic = 0xfe8c; - t.yehinitialarabic = 0xfef3; - t.yehmedialarabic = 0xfef4; - t.yehmeeminitialarabic = 0xfcdd; - t.yehmeemisolatedarabic = 0xfc58; - t.yehnoonfinalarabic = 0xfc94; - t.yehthreedotsbelowarabic = 0x06d1; - t.yekorean = 0x3156; - t.yen = 0x00a5; - t.yenmonospace = 0xffe5; - t.yeokorean = 0x3155; - t.yeorinhieuhkorean = 0x3186; - t.yerahbenyomohebrew = 0x05aa; - t.yerahbenyomolefthebrew = 0x05aa; - t.yericyrillic = 0x044b; - t.yerudieresiscyrillic = 0x04f9; - t.yesieungkorean = 0x3181; - t.yesieungpansioskorean = 0x3183; - t.yesieungsioskorean = 0x3182; - t.yetivhebrew = 0x059a; - t.ygrave = 0x1ef3; - t.yhook = 0x01b4; - t.yhookabove = 0x1ef7; - t.yiarmenian = 0x0575; - t.yicyrillic = 0x0457; - t.yikorean = 0x3162; - t.yinyang = 0x262f; - t.yiwnarmenian = 0x0582; - t.ymonospace = 0xff59; - t.yod = 0x05d9; - t.yoddagesh = 0xfb39; - t.yoddageshhebrew = 0xfb39; - t.yodhebrew = 0x05d9; - t.yodyodhebrew = 0x05f2; - t.yodyodpatahhebrew = 0xfb1f; - t.yohiragana = 0x3088; - t.yoikorean = 0x3189; - t.yokatakana = 0x30e8; - t.yokatakanahalfwidth = 0xff96; - t.yokorean = 0x315b; - t.yosmallhiragana = 0x3087; - t.yosmallkatakana = 0x30e7; - t.yosmallkatakanahalfwidth = 0xff6e; - t.yotgreek = 0x03f3; - t.yoyaekorean = 0x3188; - t.yoyakorean = 0x3187; - t.yoyakthai = 0x0e22; - t.yoyingthai = 0x0e0d; - t.yparen = 0x24b4; - t.ypogegrammeni = 0x037a; - t.ypogegrammenigreekcmb = 0x0345; - t.yr = 0x01a6; - t.yring = 0x1e99; - t.ysuperior = 0x02b8; - t.ytilde = 0x1ef9; - t.yturned = 0x028e; - t.yuhiragana = 0x3086; - t.yuikorean = 0x318c; - t.yukatakana = 0x30e6; - t.yukatakanahalfwidth = 0xff95; - t.yukorean = 0x3160; - t.yusbigcyrillic = 0x046b; - t.yusbigiotifiedcyrillic = 0x046d; - t.yuslittlecyrillic = 0x0467; - t.yuslittleiotifiedcyrillic = 0x0469; - t.yusmallhiragana = 0x3085; - t.yusmallkatakana = 0x30e5; - t.yusmallkatakanahalfwidth = 0xff6d; - t.yuyekorean = 0x318b; - t.yuyeokorean = 0x318a; - t.yyabengali = 0x09df; - t.yyadeva = 0x095f; - t.z = 0x007a; - t.zaarmenian = 0x0566; - t.zacute = 0x017a; - t.zadeva = 0x095b; - t.zagurmukhi = 0x0a5b; - t.zaharabic = 0x0638; - t.zahfinalarabic = 0xfec6; - t.zahinitialarabic = 0xfec7; - t.zahiragana = 0x3056; - t.zahmedialarabic = 0xfec8; - t.zainarabic = 0x0632; - t.zainfinalarabic = 0xfeb0; - t.zakatakana = 0x30b6; - t.zaqefgadolhebrew = 0x0595; - t.zaqefqatanhebrew = 0x0594; - t.zarqahebrew = 0x0598; - t.zayin = 0x05d6; - t.zayindagesh = 0xfb36; - t.zayindageshhebrew = 0xfb36; - t.zayinhebrew = 0x05d6; - t.zbopomofo = 0x3117; - t.zcaron = 0x017e; - t.zcircle = 0x24e9; - t.zcircumflex = 0x1e91; - t.zcurl = 0x0291; - t.zdot = 0x017c; - t.zdotaccent = 0x017c; - t.zdotbelow = 0x1e93; - t.zecyrillic = 0x0437; - t.zedescendercyrillic = 0x0499; - t.zedieresiscyrillic = 0x04df; - t.zehiragana = 0x305c; - t.zekatakana = 0x30bc; - t.zero = 0x0030; - t.zeroarabic = 0x0660; - t.zerobengali = 0x09e6; - t.zerodeva = 0x0966; - t.zerogujarati = 0x0ae6; - t.zerogurmukhi = 0x0a66; - t.zerohackarabic = 0x0660; - t.zeroinferior = 0x2080; - t.zeromonospace = 0xff10; - t.zerooldstyle = 0xf730; - t.zeropersian = 0x06f0; - t.zerosuperior = 0x2070; - t.zerothai = 0x0e50; - t.zerowidthjoiner = 0xfeff; - t.zerowidthnonjoiner = 0x200c; - t.zerowidthspace = 0x200b; - t.zeta = 0x03b6; - t.zhbopomofo = 0x3113; - t.zhearmenian = 0x056a; - t.zhebrevecyrillic = 0x04c2; - t.zhecyrillic = 0x0436; - t.zhedescendercyrillic = 0x0497; - t.zhedieresiscyrillic = 0x04dd; - t.zihiragana = 0x3058; - t.zikatakana = 0x30b8; - t.zinorhebrew = 0x05ae; - t.zlinebelow = 0x1e95; - t.zmonospace = 0xff5a; - t.zohiragana = 0x305e; - t.zokatakana = 0x30be; - t.zparen = 0x24b5; - t.zretroflexhook = 0x0290; - t.zstroke = 0x01b6; - t.zuhiragana = 0x305a; - t.zukatakana = 0x30ba; - t[".notdef"] = 0x0000; - t.angbracketleftbig = 0x2329; - t.angbracketleftBig = 0x2329; - t.angbracketleftbigg = 0x2329; - t.angbracketleftBigg = 0x2329; - t.angbracketrightBig = 0x232a; - t.angbracketrightbig = 0x232a; - t.angbracketrightBigg = 0x232a; - t.angbracketrightbigg = 0x232a; - t.arrowhookleft = 0x21aa; - t.arrowhookright = 0x21a9; - t.arrowlefttophalf = 0x21bc; - t.arrowleftbothalf = 0x21bd; - t.arrownortheast = 0x2197; - t.arrownorthwest = 0x2196; - t.arrowrighttophalf = 0x21c0; - t.arrowrightbothalf = 0x21c1; - t.arrowsoutheast = 0x2198; - t.arrowsouthwest = 0x2199; - t.backslashbig = 0x2216; - t.backslashBig = 0x2216; - t.backslashBigg = 0x2216; - t.backslashbigg = 0x2216; - t.bardbl = 0x2016; - t.bracehtipdownleft = 0xfe37; - t.bracehtipdownright = 0xfe37; - t.bracehtipupleft = 0xfe38; - t.bracehtipupright = 0xfe38; - t.braceleftBig = 0x007b; - t.braceleftbig = 0x007b; - t.braceleftbigg = 0x007b; - t.braceleftBigg = 0x007b; - t.bracerightBig = 0x007d; - t.bracerightbig = 0x007d; - t.bracerightbigg = 0x007d; - t.bracerightBigg = 0x007d; - t.bracketleftbig = 0x005b; - t.bracketleftBig = 0x005b; - t.bracketleftbigg = 0x005b; - t.bracketleftBigg = 0x005b; - t.bracketrightBig = 0x005d; - t.bracketrightbig = 0x005d; - t.bracketrightbigg = 0x005d; - t.bracketrightBigg = 0x005d; - t.ceilingleftbig = 0x2308; - t.ceilingleftBig = 0x2308; - t.ceilingleftBigg = 0x2308; - t.ceilingleftbigg = 0x2308; - t.ceilingrightbig = 0x2309; - t.ceilingrightBig = 0x2309; - t.ceilingrightbigg = 0x2309; - t.ceilingrightBigg = 0x2309; - t.circledotdisplay = 0x2299; - t.circledottext = 0x2299; - t.circlemultiplydisplay = 0x2297; - t.circlemultiplytext = 0x2297; - t.circleplusdisplay = 0x2295; - t.circleplustext = 0x2295; - t.contintegraldisplay = 0x222e; - t.contintegraltext = 0x222e; - t.coproductdisplay = 0x2210; - t.coproducttext = 0x2210; - t.floorleftBig = 0x230a; - t.floorleftbig = 0x230a; - t.floorleftbigg = 0x230a; - t.floorleftBigg = 0x230a; - t.floorrightbig = 0x230b; - t.floorrightBig = 0x230b; - t.floorrightBigg = 0x230b; - t.floorrightbigg = 0x230b; - t.hatwide = 0x0302; - t.hatwider = 0x0302; - t.hatwidest = 0x0302; - t.intercal = 0x1d40; - t.integraldisplay = 0x222b; - t.integraltext = 0x222b; - t.intersectiondisplay = 0x22c2; - t.intersectiontext = 0x22c2; - t.logicalanddisplay = 0x2227; - t.logicalandtext = 0x2227; - t.logicalordisplay = 0x2228; - t.logicalortext = 0x2228; - t.parenleftBig = 0x0028; - t.parenleftbig = 0x0028; - t.parenleftBigg = 0x0028; - t.parenleftbigg = 0x0028; - t.parenrightBig = 0x0029; - t.parenrightbig = 0x0029; - t.parenrightBigg = 0x0029; - t.parenrightbigg = 0x0029; - t.prime = 0x2032; - t.productdisplay = 0x220f; - t.producttext = 0x220f; - t.radicalbig = 0x221a; - t.radicalBig = 0x221a; - t.radicalBigg = 0x221a; - t.radicalbigg = 0x221a; - t.radicalbt = 0x221a; - t.radicaltp = 0x221a; - t.radicalvertex = 0x221a; - t.slashbig = 0x002f; - t.slashBig = 0x002f; - t.slashBigg = 0x002f; - t.slashbigg = 0x002f; - t.summationdisplay = 0x2211; - t.summationtext = 0x2211; - t.tildewide = 0x02dc; - t.tildewider = 0x02dc; - t.tildewidest = 0x02dc; - t.uniondisplay = 0x22c3; - t.unionmultidisplay = 0x228e; - t.unionmultitext = 0x228e; - t.unionsqdisplay = 0x2294; - t.unionsqtext = 0x2294; - t.uniontext = 0x22c3; - t.vextenddouble = 0x2225; - t.vextendsingle = 0x2223; -}); -var getDingbatsGlyphsUnicode = getLookupTableFactory(function (t) { - t.space = 0x0020; - t.a1 = 0x2701; - t.a2 = 0x2702; - t.a202 = 0x2703; - t.a3 = 0x2704; - t.a4 = 0x260e; - t.a5 = 0x2706; - t.a119 = 0x2707; - t.a118 = 0x2708; - t.a117 = 0x2709; - t.a11 = 0x261b; - t.a12 = 0x261e; - t.a13 = 0x270c; - t.a14 = 0x270d; - t.a15 = 0x270e; - t.a16 = 0x270f; - t.a105 = 0x2710; - t.a17 = 0x2711; - t.a18 = 0x2712; - t.a19 = 0x2713; - t.a20 = 0x2714; - t.a21 = 0x2715; - t.a22 = 0x2716; - t.a23 = 0x2717; - t.a24 = 0x2718; - t.a25 = 0x2719; - t.a26 = 0x271a; - t.a27 = 0x271b; - t.a28 = 0x271c; - t.a6 = 0x271d; - t.a7 = 0x271e; - t.a8 = 0x271f; - t.a9 = 0x2720; - t.a10 = 0x2721; - t.a29 = 0x2722; - t.a30 = 0x2723; - t.a31 = 0x2724; - t.a32 = 0x2725; - t.a33 = 0x2726; - t.a34 = 0x2727; - t.a35 = 0x2605; - t.a36 = 0x2729; - t.a37 = 0x272a; - t.a38 = 0x272b; - t.a39 = 0x272c; - t.a40 = 0x272d; - t.a41 = 0x272e; - t.a42 = 0x272f; - t.a43 = 0x2730; - t.a44 = 0x2731; - t.a45 = 0x2732; - t.a46 = 0x2733; - t.a47 = 0x2734; - t.a48 = 0x2735; - t.a49 = 0x2736; - t.a50 = 0x2737; - t.a51 = 0x2738; - t.a52 = 0x2739; - t.a53 = 0x273a; - t.a54 = 0x273b; - t.a55 = 0x273c; - t.a56 = 0x273d; - t.a57 = 0x273e; - t.a58 = 0x273f; - t.a59 = 0x2740; - t.a60 = 0x2741; - t.a61 = 0x2742; - t.a62 = 0x2743; - t.a63 = 0x2744; - t.a64 = 0x2745; - t.a65 = 0x2746; - t.a66 = 0x2747; - t.a67 = 0x2748; - t.a68 = 0x2749; - t.a69 = 0x274a; - t.a70 = 0x274b; - t.a71 = 0x25cf; - t.a72 = 0x274d; - t.a73 = 0x25a0; - t.a74 = 0x274f; - t.a203 = 0x2750; - t.a75 = 0x2751; - t.a204 = 0x2752; - t.a76 = 0x25b2; - t.a77 = 0x25bc; - t.a78 = 0x25c6; - t.a79 = 0x2756; - t.a81 = 0x25d7; - t.a82 = 0x2758; - t.a83 = 0x2759; - t.a84 = 0x275a; - t.a97 = 0x275b; - t.a98 = 0x275c; - t.a99 = 0x275d; - t.a100 = 0x275e; - t.a101 = 0x2761; - t.a102 = 0x2762; - t.a103 = 0x2763; - t.a104 = 0x2764; - t.a106 = 0x2765; - t.a107 = 0x2766; - t.a108 = 0x2767; - t.a112 = 0x2663; - t.a111 = 0x2666; - t.a110 = 0x2665; - t.a109 = 0x2660; - t.a120 = 0x2460; - t.a121 = 0x2461; - t.a122 = 0x2462; - t.a123 = 0x2463; - t.a124 = 0x2464; - t.a125 = 0x2465; - t.a126 = 0x2466; - t.a127 = 0x2467; - t.a128 = 0x2468; - t.a129 = 0x2469; - t.a130 = 0x2776; - t.a131 = 0x2777; - t.a132 = 0x2778; - t.a133 = 0x2779; - t.a134 = 0x277a; - t.a135 = 0x277b; - t.a136 = 0x277c; - t.a137 = 0x277d; - t.a138 = 0x277e; - t.a139 = 0x277f; - t.a140 = 0x2780; - t.a141 = 0x2781; - t.a142 = 0x2782; - t.a143 = 0x2783; - t.a144 = 0x2784; - t.a145 = 0x2785; - t.a146 = 0x2786; - t.a147 = 0x2787; - t.a148 = 0x2788; - t.a149 = 0x2789; - t.a150 = 0x278a; - t.a151 = 0x278b; - t.a152 = 0x278c; - t.a153 = 0x278d; - t.a154 = 0x278e; - t.a155 = 0x278f; - t.a156 = 0x2790; - t.a157 = 0x2791; - t.a158 = 0x2792; - t.a159 = 0x2793; - t.a160 = 0x2794; - t.a161 = 0x2192; - t.a163 = 0x2194; - t.a164 = 0x2195; - t.a196 = 0x2798; - t.a165 = 0x2799; - t.a192 = 0x279a; - t.a166 = 0x279b; - t.a167 = 0x279c; - t.a168 = 0x279d; - t.a169 = 0x279e; - t.a170 = 0x279f; - t.a171 = 0x27a0; - t.a172 = 0x27a1; - t.a173 = 0x27a2; - t.a162 = 0x27a3; - t.a174 = 0x27a4; - t.a175 = 0x27a5; - t.a176 = 0x27a6; - t.a177 = 0x27a7; - t.a178 = 0x27a8; - t.a179 = 0x27a9; - t.a193 = 0x27aa; - t.a180 = 0x27ab; - t.a199 = 0x27ac; - t.a181 = 0x27ad; - t.a200 = 0x27ae; - t.a182 = 0x27af; - t.a201 = 0x27b1; - t.a183 = 0x27b2; - t.a184 = 0x27b3; - t.a197 = 0x27b4; - t.a185 = 0x27b5; - t.a194 = 0x27b6; - t.a198 = 0x27b7; - t.a186 = 0x27b8; - t.a195 = 0x27b9; - t.a187 = 0x27ba; - t.a188 = 0x27bb; - t.a189 = 0x27bc; - t.a190 = 0x27bd; - t.a191 = 0x27be; - t.a89 = 0x2768; - t.a90 = 0x2769; - t.a93 = 0x276a; - t.a94 = 0x276b; - t.a91 = 0x276c; - t.a92 = 0x276d; - t.a205 = 0x276e; - t.a85 = 0x276f; - t.a206 = 0x2770; - t.a86 = 0x2771; - t.a87 = 0x2772; - t.a88 = 0x2773; - t.a95 = 0x2774; - t.a96 = 0x2775; - t[".notdef"] = 0x0000; -}); -exports.getGlyphsUnicode = getGlyphsUnicode; -exports.getDingbatsGlyphsUnicode = getDingbatsGlyphsUnicode; - -/***/ }), -/* 35 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 38 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.getSupplementalGlyphMapForCalibri = exports.getSupplementalGlyphMapForArialBlack = exports.getGlyphMapForStandardFonts = exports.getSymbolsFonts = exports.getSerifFonts = exports.getNonStdFontMap = exports.getStdFontMap = void 0; +})); +exports.SEAC_ANALYSIS_ENABLED = exports.MacStandardGlyphOrdering = exports.FontFlags = void 0; +exports.getFontType = getFontType; +exports.normalizeFontName = normalizeFontName; +exports.recoverGlyphName = recoverGlyphName; +exports.type1FontGlyphMapping = type1FontGlyphMapping; -var _core_utils = __w_pdfjs_require__(8); +var _util = __w_pdfjs_require__(2); -const getStdFontMap = (0, _core_utils.getLookupTableFactory)(function (t) { - t.ArialNarrow = "Helvetica"; - t["ArialNarrow-Bold"] = "Helvetica-Bold"; - t["ArialNarrow-BoldItalic"] = "Helvetica-BoldOblique"; - t["ArialNarrow-Italic"] = "Helvetica-Oblique"; - t.ArialBlack = "Helvetica"; - t["ArialBlack-Bold"] = "Helvetica-Bold"; - t["ArialBlack-BoldItalic"] = "Helvetica-BoldOblique"; - t["ArialBlack-Italic"] = "Helvetica-Oblique"; - t["Arial-Black"] = "Helvetica"; - t["Arial-Black-Bold"] = "Helvetica-Bold"; - t["Arial-Black-BoldItalic"] = "Helvetica-BoldOblique"; - t["Arial-Black-Italic"] = "Helvetica-Oblique"; - t.Arial = "Helvetica"; - t["Arial-Bold"] = "Helvetica-Bold"; - t["Arial-BoldItalic"] = "Helvetica-BoldOblique"; - t["Arial-Italic"] = "Helvetica-Oblique"; - t["Arial-BoldItalicMT"] = "Helvetica-BoldOblique"; - t["Arial-BoldMT"] = "Helvetica-Bold"; - t["Arial-ItalicMT"] = "Helvetica-Oblique"; - t.ArialMT = "Helvetica"; - t["Courier-Bold"] = "Courier-Bold"; - t["Courier-BoldItalic"] = "Courier-BoldOblique"; - t["Courier-Italic"] = "Courier-Oblique"; - t.CourierNew = "Courier"; - t["CourierNew-Bold"] = "Courier-Bold"; - t["CourierNew-BoldItalic"] = "Courier-BoldOblique"; - t["CourierNew-Italic"] = "Courier-Oblique"; - t["CourierNewPS-BoldItalicMT"] = "Courier-BoldOblique"; - t["CourierNewPS-BoldMT"] = "Courier-Bold"; - t["CourierNewPS-ItalicMT"] = "Courier-Oblique"; - t.CourierNewPSMT = "Courier"; - t.Helvetica = "Helvetica"; - t["Helvetica-Bold"] = "Helvetica-Bold"; - t["Helvetica-BoldItalic"] = "Helvetica-BoldOblique"; - t["Helvetica-BoldOblique"] = "Helvetica-BoldOblique"; - t["Helvetica-Italic"] = "Helvetica-Oblique"; - t["Helvetica-Oblique"] = "Helvetica-Oblique"; - t["Symbol-Bold"] = "Symbol"; - t["Symbol-BoldItalic"] = "Symbol"; - t["Symbol-Italic"] = "Symbol"; - t.TimesNewRoman = "Times-Roman"; - t["TimesNewRoman-Bold"] = "Times-Bold"; - t["TimesNewRoman-BoldItalic"] = "Times-BoldItalic"; - t["TimesNewRoman-Italic"] = "Times-Italic"; - t.TimesNewRomanPS = "Times-Roman"; - t["TimesNewRomanPS-Bold"] = "Times-Bold"; - t["TimesNewRomanPS-BoldItalic"] = "Times-BoldItalic"; - t["TimesNewRomanPS-BoldItalicMT"] = "Times-BoldItalic"; - t["TimesNewRomanPS-BoldMT"] = "Times-Bold"; - t["TimesNewRomanPS-Italic"] = "Times-Italic"; - t["TimesNewRomanPS-ItalicMT"] = "Times-Italic"; - t.TimesNewRomanPSMT = "Times-Roman"; - t["TimesNewRomanPSMT-Bold"] = "Times-Bold"; - t["TimesNewRomanPSMT-BoldItalic"] = "Times-BoldItalic"; - t["TimesNewRomanPSMT-Italic"] = "Times-Italic"; -}); -exports.getStdFontMap = getStdFontMap; -const getNonStdFontMap = (0, _core_utils.getLookupTableFactory)(function (t) { - t.Calibri = "Helvetica"; - t["Calibri-Bold"] = "Helvetica-Bold"; - t["Calibri-BoldItalic"] = "Helvetica-BoldOblique"; - t["Calibri-Italic"] = "Helvetica-Oblique"; - t.CenturyGothic = "Helvetica"; - t["CenturyGothic-Bold"] = "Helvetica-Bold"; - t["CenturyGothic-BoldItalic"] = "Helvetica-BoldOblique"; - t["CenturyGothic-Italic"] = "Helvetica-Oblique"; - t.ComicSansMS = "Comic Sans MS"; - t["ComicSansMS-Bold"] = "Comic Sans MS-Bold"; - t["ComicSansMS-BoldItalic"] = "Comic Sans MS-BoldItalic"; - t["ComicSansMS-Italic"] = "Comic Sans MS-Italic"; - t.LucidaConsole = "Courier"; - t["LucidaConsole-Bold"] = "Courier-Bold"; - t["LucidaConsole-BoldItalic"] = "Courier-BoldOblique"; - t["LucidaConsole-Italic"] = "Courier-Oblique"; - t["LucidaSans-Demi"] = "Helvetica-Bold"; - t["MS-Gothic"] = "MS Gothic"; - t["MS-Gothic-Bold"] = "MS Gothic-Bold"; - t["MS-Gothic-BoldItalic"] = "MS Gothic-BoldItalic"; - t["MS-Gothic-Italic"] = "MS Gothic-Italic"; - t["MS-Mincho"] = "MS Mincho"; - t["MS-Mincho-Bold"] = "MS Mincho-Bold"; - t["MS-Mincho-BoldItalic"] = "MS Mincho-BoldItalic"; - t["MS-Mincho-Italic"] = "MS Mincho-Italic"; - t["MS-PGothic"] = "MS PGothic"; - t["MS-PGothic-Bold"] = "MS PGothic-Bold"; - t["MS-PGothic-BoldItalic"] = "MS PGothic-BoldItalic"; - t["MS-PGothic-Italic"] = "MS PGothic-Italic"; - t["MS-PMincho"] = "MS PMincho"; - t["MS-PMincho-Bold"] = "MS PMincho-Bold"; - t["MS-PMincho-BoldItalic"] = "MS PMincho-BoldItalic"; - t["MS-PMincho-Italic"] = "MS PMincho-Italic"; - t.NuptialScript = "Times-Italic"; - t.SegoeUISymbol = "Helvetica"; - t.Wingdings = "ZapfDingbats"; - t["Wingdings-Regular"] = "ZapfDingbats"; -}); -exports.getNonStdFontMap = getNonStdFontMap; -const getSerifFonts = (0, _core_utils.getLookupTableFactory)(function (t) { - t["Adobe Jenson"] = true; - t["Adobe Text"] = true; - t.Albertus = true; - t.Aldus = true; - t.Alexandria = true; - t.Algerian = true; - t["American Typewriter"] = true; - t.Antiqua = true; - t.Apex = true; - t.Arno = true; - t.Aster = true; - t.Aurora = true; - t.Baskerville = true; - t.Bell = true; - t.Bembo = true; - t["Bembo Schoolbook"] = true; - t.Benguiat = true; - t["Berkeley Old Style"] = true; - t["Bernhard Modern"] = true; - t["Berthold City"] = true; - t.Bodoni = true; - t["Bauer Bodoni"] = true; - t["Book Antiqua"] = true; - t.Bookman = true; - t["Bordeaux Roman"] = true; - t["Californian FB"] = true; - t.Calisto = true; - t.Calvert = true; - t.Capitals = true; - t.Cambria = true; - t.Cartier = true; - t.Caslon = true; - t.Catull = true; - t.Centaur = true; - t["Century Old Style"] = true; - t["Century Schoolbook"] = true; - t.Chaparral = true; - t["Charis SIL"] = true; - t.Cheltenham = true; - t["Cholla Slab"] = true; - t.Clarendon = true; - t.Clearface = true; - t.Cochin = true; - t.Colonna = true; - t["Computer Modern"] = true; - t["Concrete Roman"] = true; - t.Constantia = true; - t["Cooper Black"] = true; - t.Corona = true; - t.Ecotype = true; - t.Egyptienne = true; - t.Elephant = true; - t.Excelsior = true; - t.Fairfield = true; - t["FF Scala"] = true; - t.Folkard = true; - t.Footlight = true; - t.FreeSerif = true; - t["Friz Quadrata"] = true; - t.Garamond = true; - t.Gentium = true; - t.Georgia = true; - t.Gloucester = true; - t["Goudy Old Style"] = true; - t["Goudy Schoolbook"] = true; - t["Goudy Pro Font"] = true; - t.Granjon = true; - t["Guardian Egyptian"] = true; - t.Heather = true; - t.Hercules = true; - t["High Tower Text"] = true; - t.Hiroshige = true; - t["Hoefler Text"] = true; - t["Humana Serif"] = true; - t.Imprint = true; - t["Ionic No. 5"] = true; - t.Janson = true; - t.Joanna = true; - t.Korinna = true; - t.Lexicon = true; - t["Liberation Serif"] = true; - t["Linux Libertine"] = true; - t.Literaturnaya = true; - t.Lucida = true; - t["Lucida Bright"] = true; - t.Melior = true; - t.Memphis = true; - t.Miller = true; - t.Minion = true; - t.Modern = true; - t["Mona Lisa"] = true; - t["Mrs Eaves"] = true; - t["MS Serif"] = true; - t["Museo Slab"] = true; - t["New York"] = true; - t["Nimbus Roman"] = true; - t["NPS Rawlinson Roadway"] = true; - t.NuptialScript = true; - t.Palatino = true; - t.Perpetua = true; - t.Plantin = true; - t["Plantin Schoolbook"] = true; - t.Playbill = true; - t["Poor Richard"] = true; - t["Rawlinson Roadway"] = true; - t.Renault = true; - t.Requiem = true; - t.Rockwell = true; - t.Roman = true; - t["Rotis Serif"] = true; - t.Sabon = true; - t.Scala = true; - t.Seagull = true; - t.Sistina = true; - t.Souvenir = true; - t.STIX = true; - t["Stone Informal"] = true; - t["Stone Serif"] = true; - t.Sylfaen = true; - t.Times = true; - t.Trajan = true; - t["Trinité"] = true; - t["Trump Mediaeval"] = true; - t.Utopia = true; - t["Vale Type"] = true; - t["Bitstream Vera"] = true; - t["Vera Serif"] = true; - t.Versailles = true; - t.Wanted = true; - t.Weiss = true; - t["Wide Latin"] = true; - t.Windsor = true; - t.XITS = true; -}); -exports.getSerifFonts = getSerifFonts; -const getSymbolsFonts = (0, _core_utils.getLookupTableFactory)(function (t) { - t.Dingbats = true; - t.Symbol = true; - t.ZapfDingbats = true; -}); -exports.getSymbolsFonts = getSymbolsFonts; -const getGlyphMapForStandardFonts = (0, _core_utils.getLookupTableFactory)(function (t) { - t[2] = 10; - t[3] = 32; - t[4] = 33; - t[5] = 34; - t[6] = 35; - t[7] = 36; - t[8] = 37; - t[9] = 38; - t[10] = 39; - t[11] = 40; - t[12] = 41; - t[13] = 42; - t[14] = 43; - t[15] = 44; - t[16] = 45; - t[17] = 46; - t[18] = 47; - t[19] = 48; - t[20] = 49; - t[21] = 50; - t[22] = 51; - t[23] = 52; - t[24] = 53; - t[25] = 54; - t[26] = 55; - t[27] = 56; - t[28] = 57; - t[29] = 58; - t[30] = 894; - t[31] = 60; - t[32] = 61; - t[33] = 62; - t[34] = 63; - t[35] = 64; - t[36] = 65; - t[37] = 66; - t[38] = 67; - t[39] = 68; - t[40] = 69; - t[41] = 70; - t[42] = 71; - t[43] = 72; - t[44] = 73; - t[45] = 74; - t[46] = 75; - t[47] = 76; - t[48] = 77; - t[49] = 78; - t[50] = 79; - t[51] = 80; - t[52] = 81; - t[53] = 82; - t[54] = 83; - t[55] = 84; - t[56] = 85; - t[57] = 86; - t[58] = 87; - t[59] = 88; - t[60] = 89; - t[61] = 90; - t[62] = 91; - t[63] = 92; - t[64] = 93; - t[65] = 94; - t[66] = 95; - t[67] = 96; - t[68] = 97; - t[69] = 98; - t[70] = 99; - t[71] = 100; - t[72] = 101; - t[73] = 102; - t[74] = 103; - t[75] = 104; - t[76] = 105; - t[77] = 106; - t[78] = 107; - t[79] = 108; - t[80] = 109; - t[81] = 110; - t[82] = 111; - t[83] = 112; - t[84] = 113; - t[85] = 114; - t[86] = 115; - t[87] = 116; - t[88] = 117; - t[89] = 118; - t[90] = 119; - t[91] = 120; - t[92] = 121; - t[93] = 122; - t[94] = 123; - t[95] = 124; - t[96] = 125; - t[97] = 126; - t[98] = 196; - t[99] = 197; - t[100] = 199; - t[101] = 201; - t[102] = 209; - t[103] = 214; - t[104] = 220; - t[105] = 225; - t[106] = 224; - t[107] = 226; - t[108] = 228; - t[109] = 227; - t[110] = 229; - t[111] = 231; - t[112] = 233; - t[113] = 232; - t[114] = 234; - t[115] = 235; - t[116] = 237; - t[117] = 236; - t[118] = 238; - t[119] = 239; - t[120] = 241; - t[121] = 243; - t[122] = 242; - t[123] = 244; - t[124] = 246; - t[125] = 245; - t[126] = 250; - t[127] = 249; - t[128] = 251; - t[129] = 252; - t[130] = 8224; - t[131] = 176; - t[132] = 162; - t[133] = 163; - t[134] = 167; - t[135] = 8226; - t[136] = 182; - t[137] = 223; - t[138] = 174; - t[139] = 169; - t[140] = 8482; - t[141] = 180; - t[142] = 168; - t[143] = 8800; - t[144] = 198; - t[145] = 216; - t[146] = 8734; - t[147] = 177; - t[148] = 8804; - t[149] = 8805; - t[150] = 165; - t[151] = 181; - t[152] = 8706; - t[153] = 8721; - t[154] = 8719; - t[156] = 8747; - t[157] = 170; - t[158] = 186; - t[159] = 8486; - t[160] = 230; - t[161] = 248; - t[162] = 191; - t[163] = 161; - t[164] = 172; - t[165] = 8730; - t[166] = 402; - t[167] = 8776; - t[168] = 8710; - t[169] = 171; - t[170] = 187; - t[171] = 8230; - t[210] = 218; - t[223] = 711; - t[224] = 321; - t[225] = 322; - t[227] = 353; - t[229] = 382; - t[234] = 253; - t[252] = 263; - t[253] = 268; - t[254] = 269; - t[258] = 258; - t[260] = 260; - t[261] = 261; - t[265] = 280; - t[266] = 281; - t[268] = 283; - t[269] = 313; - t[275] = 323; - t[276] = 324; - t[278] = 328; - t[284] = 345; - t[285] = 346; - t[286] = 347; - t[292] = 367; - t[295] = 377; - t[296] = 378; - t[298] = 380; - t[305] = 963; - t[306] = 964; - t[307] = 966; - t[308] = 8215; - t[309] = 8252; - t[310] = 8319; - t[311] = 8359; - t[312] = 8592; - t[313] = 8593; - t[337] = 9552; - t[493] = 1039; - t[494] = 1040; - t[705] = 1524; - t[706] = 8362; - t[710] = 64288; - t[711] = 64298; - t[759] = 1617; - t[761] = 1776; - t[763] = 1778; - t[775] = 1652; - t[777] = 1764; - t[778] = 1780; - t[779] = 1781; - t[780] = 1782; - t[782] = 771; - t[783] = 64726; - t[786] = 8363; - t[788] = 8532; - t[790] = 768; - t[791] = 769; - t[792] = 768; - t[795] = 803; - t[797] = 64336; - t[798] = 64337; - t[799] = 64342; - t[800] = 64343; - t[801] = 64344; - t[802] = 64345; - t[803] = 64362; - t[804] = 64363; - t[805] = 64364; - t[2424] = 7821; - t[2425] = 7822; - t[2426] = 7823; - t[2427] = 7824; - t[2428] = 7825; - t[2429] = 7826; - t[2430] = 7827; - t[2433] = 7682; - t[2678] = 8045; - t[2679] = 8046; - t[2830] = 1552; - t[2838] = 686; - t[2840] = 751; - t[2842] = 753; - t[2843] = 754; - t[2844] = 755; - t[2846] = 757; - t[2856] = 767; - t[2857] = 848; - t[2858] = 849; - t[2862] = 853; - t[2863] = 854; - t[2864] = 855; - t[2865] = 861; - t[2866] = 862; - t[2906] = 7460; - t[2908] = 7462; - t[2909] = 7463; - t[2910] = 7464; - t[2912] = 7466; - t[2913] = 7467; - t[2914] = 7468; - t[2916] = 7470; - t[2917] = 7471; - t[2918] = 7472; - t[2920] = 7474; - t[2921] = 7475; - t[2922] = 7476; - t[2924] = 7478; - t[2925] = 7479; - t[2926] = 7480; - t[2928] = 7482; - t[2929] = 7483; - t[2930] = 7484; - t[2932] = 7486; - t[2933] = 7487; - t[2934] = 7488; - t[2936] = 7490; - t[2937] = 7491; - t[2938] = 7492; - t[2940] = 7494; - t[2941] = 7495; - t[2942] = 7496; - t[2944] = 7498; - t[2946] = 7500; - t[2948] = 7502; - t[2950] = 7504; - t[2951] = 7505; - t[2952] = 7506; - t[2954] = 7508; - t[2955] = 7509; - t[2956] = 7510; - t[2958] = 7512; - t[2959] = 7513; - t[2960] = 7514; - t[2962] = 7516; - t[2963] = 7517; - t[2964] = 7518; - t[2966] = 7520; - t[2967] = 7521; - t[2968] = 7522; - t[2970] = 7524; - t[2971] = 7525; - t[2972] = 7526; - t[2974] = 7528; - t[2975] = 7529; - t[2976] = 7530; - t[2978] = 1537; - t[2979] = 1538; - t[2980] = 1539; - t[2982] = 1549; - t[2983] = 1551; - t[2984] = 1552; - t[2986] = 1554; - t[2987] = 1555; - t[2988] = 1556; - t[2990] = 1623; - t[2991] = 1624; - t[2995] = 1775; - t[2999] = 1791; - t[3002] = 64290; - t[3003] = 64291; - t[3004] = 64292; - t[3006] = 64294; - t[3007] = 64295; - t[3008] = 64296; - t[3011] = 1900; - t[3014] = 8223; - t[3015] = 8244; - t[3017] = 7532; - t[3018] = 7533; - t[3019] = 7534; - t[3075] = 7590; - t[3076] = 7591; - t[3079] = 7594; - t[3080] = 7595; - t[3083] = 7598; - t[3084] = 7599; - t[3087] = 7602; - t[3088] = 7603; - t[3091] = 7606; - t[3092] = 7607; - t[3095] = 7610; - t[3096] = 7611; - t[3099] = 7614; - t[3100] = 7615; - t[3103] = 7618; - t[3104] = 7619; - t[3107] = 8337; - t[3108] = 8338; - t[3116] = 1884; - t[3119] = 1885; - t[3120] = 1885; - t[3123] = 1886; - t[3124] = 1886; - t[3127] = 1887; - t[3128] = 1887; - t[3131] = 1888; - t[3132] = 1888; - t[3135] = 1889; - t[3136] = 1889; - t[3139] = 1890; - t[3140] = 1890; - t[3143] = 1891; - t[3144] = 1891; - t[3147] = 1892; - t[3148] = 1892; - t[3153] = 580; - t[3154] = 581; - t[3157] = 584; - t[3158] = 585; - t[3161] = 588; - t[3162] = 589; - t[3165] = 891; - t[3166] = 892; - t[3169] = 1274; - t[3170] = 1275; - t[3173] = 1278; - t[3174] = 1279; - t[3181] = 7622; - t[3182] = 7623; - t[3282] = 11799; - t[3316] = 578; - t[3379] = 42785; - t[3393] = 1159; - t[3416] = 8377; -}); -exports.getGlyphMapForStandardFonts = getGlyphMapForStandardFonts; -const getSupplementalGlyphMapForArialBlack = (0, _core_utils.getLookupTableFactory)(function (t) { - t[227] = 322; - t[264] = 261; - t[291] = 346; -}); -exports.getSupplementalGlyphMapForArialBlack = getSupplementalGlyphMapForArialBlack; -const getSupplementalGlyphMapForCalibri = (0, _core_utils.getLookupTableFactory)(function (t) { - t[1] = 32; - t[4] = 65; - t[17] = 66; - t[18] = 67; - t[24] = 68; - t[28] = 69; - t[38] = 70; - t[39] = 71; - t[44] = 72; - t[47] = 73; - t[58] = 74; - t[60] = 75; - t[62] = 76; - t[68] = 77; - t[69] = 78; - t[75] = 79; - t[87] = 80; - t[89] = 81; - t[90] = 82; - t[94] = 83; - t[100] = 84; - t[104] = 85; - t[115] = 86; - t[116] = 87; - t[121] = 88; - t[122] = 89; - t[127] = 90; - t[258] = 97; - t[268] = 261; - t[271] = 98; - t[272] = 99; - t[273] = 263; - t[282] = 100; - t[286] = 101; - t[295] = 281; - t[296] = 102; - t[336] = 103; - t[346] = 104; - t[349] = 105; - t[361] = 106; - t[364] = 107; - t[367] = 108; - t[371] = 322; - t[373] = 109; - t[374] = 110; - t[381] = 111; - t[383] = 243; - t[393] = 112; - t[395] = 113; - t[396] = 114; - t[400] = 115; - t[401] = 347; - t[410] = 116; - t[437] = 117; - t[448] = 118; - t[449] = 119; - t[454] = 120; - t[455] = 121; - t[460] = 122; - t[463] = 380; - t[853] = 44; - t[855] = 58; - t[856] = 46; - t[876] = 47; - t[878] = 45; - t[882] = 45; - t[894] = 40; - t[895] = 41; - t[896] = 91; - t[897] = 93; - t[923] = 64; - t[1004] = 48; - t[1005] = 49; - t[1006] = 50; - t[1007] = 51; - t[1008] = 52; - t[1009] = 53; - t[1010] = 54; - t[1011] = 55; - t[1012] = 56; - t[1013] = 57; - t[1081] = 37; - t[1085] = 43; - t[1086] = 45; -}); -exports.getSupplementalGlyphMapForCalibri = getSupplementalGlyphMapForCalibri; +var _encodings = __w_pdfjs_require__(37); + +var _glyphlist = __w_pdfjs_require__(39); + +var _unicode = __w_pdfjs_require__(40); + +const SEAC_ANALYSIS_ENABLED = true; +exports.SEAC_ANALYSIS_ENABLED = SEAC_ANALYSIS_ENABLED; +const FontFlags = { + FixedPitch: 1, + Serif: 2, + Symbolic: 4, + Script: 8, + Nonsymbolic: 32, + Italic: 64, + AllCap: 65536, + SmallCap: 131072, + ForceBold: 262144 +}; +exports.FontFlags = FontFlags; +const MacStandardGlyphOrdering = [".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", "thorn", "minus", "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter", "threequarters", "franc", "Gbreve", "gbreve", "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", "ccaron", "dcroat"]; +exports.MacStandardGlyphOrdering = MacStandardGlyphOrdering; + +function getFontType(type, subtype, isStandardFont = false) { + switch (type) { + case "Type1": + if (isStandardFont) { + return _util.FontType.TYPE1STANDARD; + } + + return subtype === "Type1C" ? _util.FontType.TYPE1C : _util.FontType.TYPE1; + + case "CIDFontType0": + return subtype === "CIDFontType0C" ? _util.FontType.CIDFONTTYPE0C : _util.FontType.CIDFONTTYPE0; + + case "OpenType": + return _util.FontType.OPENTYPE; + + case "TrueType": + return _util.FontType.TRUETYPE; + + case "CIDFontType2": + return _util.FontType.CIDFONTTYPE2; + + case "MMType1": + return _util.FontType.MMTYPE1; + + case "Type0": + return _util.FontType.TYPE0; + + default: + return _util.FontType.UNKNOWN; + } +} + +function recoverGlyphName(name, glyphsUnicodeMap) { + if (glyphsUnicodeMap[name] !== undefined) { + return name; + } + + const unicode = (0, _unicode.getUnicodeForGlyph)(name, glyphsUnicodeMap); + + if (unicode !== -1) { + for (const key in glyphsUnicodeMap) { + if (glyphsUnicodeMap[key] === unicode) { + return key; + } + } + } + + (0, _util.info)("Unable to recover a standard glyph name for: " + name); + return name; +} + +function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) { + const charCodeToGlyphId = Object.create(null); + let glyphId, charCode, baseEncoding; + const isSymbolicFont = !!(properties.flags & FontFlags.Symbolic); + + if (properties.isInternalFont) { + baseEncoding = builtInEncoding; + + for (charCode = 0; charCode < baseEncoding.length; charCode++) { + glyphId = glyphNames.indexOf(baseEncoding[charCode]); + + if (glyphId >= 0) { + charCodeToGlyphId[charCode] = glyphId; + } else { + charCodeToGlyphId[charCode] = 0; + } + } + } else if (properties.baseEncodingName) { + baseEncoding = (0, _encodings.getEncoding)(properties.baseEncodingName); + + for (charCode = 0; charCode < baseEncoding.length; charCode++) { + glyphId = glyphNames.indexOf(baseEncoding[charCode]); + + if (glyphId >= 0) { + charCodeToGlyphId[charCode] = glyphId; + } else { + charCodeToGlyphId[charCode] = 0; + } + } + } else if (isSymbolicFont) { + for (charCode in builtInEncoding) { + charCodeToGlyphId[charCode] = builtInEncoding[charCode]; + } + } else { + baseEncoding = _encodings.StandardEncoding; + + for (charCode = 0; charCode < baseEncoding.length; charCode++) { + glyphId = glyphNames.indexOf(baseEncoding[charCode]); + + if (glyphId >= 0) { + charCodeToGlyphId[charCode] = glyphId; + } else { + charCodeToGlyphId[charCode] = 0; + } + } + } + + const differences = properties.differences; + let glyphsUnicodeMap; + + if (differences) { + for (charCode in differences) { + const glyphName = differences[charCode]; + glyphId = glyphNames.indexOf(glyphName); + + if (glyphId === -1) { + if (!glyphsUnicodeMap) { + glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + } + + const standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap); + + if (standardGlyphName !== glyphName) { + glyphId = glyphNames.indexOf(standardGlyphName); + } + } + + if (glyphId >= 0) { + charCodeToGlyphId[charCode] = glyphId; + } else { + charCodeToGlyphId[charCode] = 0; + } + } + } + + return charCodeToGlyphId; +} + +function normalizeFontName(name) { + return name.replace(/[,_]/g, "-").replace(/\s/g, ""); +} /***/ }), -/* 36 */ -/***/ (function(module, exports, __w_pdfjs_require__) { +/* 39 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __w_pdfjs_require__) => { -var getLookupTableFactory = __w_pdfjs_require__(8).getLookupTableFactory; -var getSpecialPUASymbols = getLookupTableFactory(function (t) { +__w_pdfjs_require__.r(__webpack_exports__); +/* harmony export */ __w_pdfjs_require__.d(__webpack_exports__, { +/* harmony export */ "getDingbatsGlyphsUnicode": () => (/* binding */ getDingbatsGlyphsUnicode), +/* harmony export */ "getGlyphsUnicode": () => (/* binding */ getGlyphsUnicode) +/* harmony export */ }); +/* harmony import */ var _core_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __w_pdfjs_require__(6); + +const getGlyphsUnicode = (0,_core_utils_js__WEBPACK_IMPORTED_MODULE_0__.getArrayLookupTableFactory)(function () { + return [ + "A", + 0x0041, + "AE", + 0x00c6, + "AEacute", + 0x01fc, + "AEmacron", + 0x01e2, + "AEsmall", + 0xf7e6, + "Aacute", + 0x00c1, + "Aacutesmall", + 0xf7e1, + "Abreve", + 0x0102, + "Abreveacute", + 0x1eae, + "Abrevecyrillic", + 0x04d0, + "Abrevedotbelow", + 0x1eb6, + "Abrevegrave", + 0x1eb0, + "Abrevehookabove", + 0x1eb2, + "Abrevetilde", + 0x1eb4, + "Acaron", + 0x01cd, + "Acircle", + 0x24b6, + "Acircumflex", + 0x00c2, + "Acircumflexacute", + 0x1ea4, + "Acircumflexdotbelow", + 0x1eac, + "Acircumflexgrave", + 0x1ea6, + "Acircumflexhookabove", + 0x1ea8, + "Acircumflexsmall", + 0xf7e2, + "Acircumflextilde", + 0x1eaa, + "Acute", + 0xf6c9, + "Acutesmall", + 0xf7b4, + "Acyrillic", + 0x0410, + "Adblgrave", + 0x0200, + "Adieresis", + 0x00c4, + "Adieresiscyrillic", + 0x04d2, + "Adieresismacron", + 0x01de, + "Adieresissmall", + 0xf7e4, + "Adotbelow", + 0x1ea0, + "Adotmacron", + 0x01e0, + "Agrave", + 0x00c0, + "Agravesmall", + 0xf7e0, + "Ahookabove", + 0x1ea2, + "Aiecyrillic", + 0x04d4, + "Ainvertedbreve", + 0x0202, + "Alpha", + 0x0391, + "Alphatonos", + 0x0386, + "Amacron", + 0x0100, + "Amonospace", + 0xff21, + "Aogonek", + 0x0104, + "Aring", + 0x00c5, + "Aringacute", + 0x01fa, + "Aringbelow", + 0x1e00, + "Aringsmall", + 0xf7e5, + "Asmall", + 0xf761, + "Atilde", + 0x00c3, + "Atildesmall", + 0xf7e3, + "Aybarmenian", + 0x0531, + "B", + 0x0042, + "Bcircle", + 0x24b7, + "Bdotaccent", + 0x1e02, + "Bdotbelow", + 0x1e04, + "Becyrillic", + 0x0411, + "Benarmenian", + 0x0532, + "Beta", + 0x0392, + "Bhook", + 0x0181, + "Blinebelow", + 0x1e06, + "Bmonospace", + 0xff22, + "Brevesmall", + 0xf6f4, + "Bsmall", + 0xf762, + "Btopbar", + 0x0182, + "C", + 0x0043, + "Caarmenian", + 0x053e, + "Cacute", + 0x0106, + "Caron", + 0xf6ca, + "Caronsmall", + 0xf6f5, + "Ccaron", + 0x010c, + "Ccedilla", + 0x00c7, + "Ccedillaacute", + 0x1e08, + "Ccedillasmall", + 0xf7e7, + "Ccircle", + 0x24b8, + "Ccircumflex", + 0x0108, + "Cdot", + 0x010a, + "Cdotaccent", + 0x010a, + "Cedillasmall", + 0xf7b8, + "Chaarmenian", + 0x0549, + "Cheabkhasiancyrillic", + 0x04bc, + "Checyrillic", + 0x0427, + "Chedescenderabkhasiancyrillic", + 0x04be, + "Chedescendercyrillic", + 0x04b6, + "Chedieresiscyrillic", + 0x04f4, + "Cheharmenian", + 0x0543, + "Chekhakassiancyrillic", + 0x04cb, + "Cheverticalstrokecyrillic", + 0x04b8, + "Chi", + 0x03a7, + "Chook", + 0x0187, + "Circumflexsmall", + 0xf6f6, + "Cmonospace", + 0xff23, + "Coarmenian", + 0x0551, + "Csmall", + 0xf763, + "D", + 0x0044, + "DZ", + 0x01f1, + "DZcaron", + 0x01c4, + "Daarmenian", + 0x0534, + "Dafrican", + 0x0189, + "Dcaron", + 0x010e, + "Dcedilla", + 0x1e10, + "Dcircle", + 0x24b9, + "Dcircumflexbelow", + 0x1e12, + "Dcroat", + 0x0110, + "Ddotaccent", + 0x1e0a, + "Ddotbelow", + 0x1e0c, + "Decyrillic", + 0x0414, + "Deicoptic", + 0x03ee, + "Delta", + 0x2206, + "Deltagreek", + 0x0394, + "Dhook", + 0x018a, + "Dieresis", + 0xf6cb, + "DieresisAcute", + 0xf6cc, + "DieresisGrave", + 0xf6cd, + "Dieresissmall", + 0xf7a8, + "Digammagreek", + 0x03dc, + "Djecyrillic", + 0x0402, + "Dlinebelow", + 0x1e0e, + "Dmonospace", + 0xff24, + "Dotaccentsmall", + 0xf6f7, + "Dslash", + 0x0110, + "Dsmall", + 0xf764, + "Dtopbar", + 0x018b, + "Dz", + 0x01f2, + "Dzcaron", + 0x01c5, + "Dzeabkhasiancyrillic", + 0x04e0, + "Dzecyrillic", + 0x0405, + "Dzhecyrillic", + 0x040f, + "E", + 0x0045, + "Eacute", + 0x00c9, + "Eacutesmall", + 0xf7e9, + "Ebreve", + 0x0114, + "Ecaron", + 0x011a, + "Ecedillabreve", + 0x1e1c, + "Echarmenian", + 0x0535, + "Ecircle", + 0x24ba, + "Ecircumflex", + 0x00ca, + "Ecircumflexacute", + 0x1ebe, + "Ecircumflexbelow", + 0x1e18, + "Ecircumflexdotbelow", + 0x1ec6, + "Ecircumflexgrave", + 0x1ec0, + "Ecircumflexhookabove", + 0x1ec2, + "Ecircumflexsmall", + 0xf7ea, + "Ecircumflextilde", + 0x1ec4, + "Ecyrillic", + 0x0404, + "Edblgrave", + 0x0204, + "Edieresis", + 0x00cb, + "Edieresissmall", + 0xf7eb, + "Edot", + 0x0116, + "Edotaccent", + 0x0116, + "Edotbelow", + 0x1eb8, + "Efcyrillic", + 0x0424, + "Egrave", + 0x00c8, + "Egravesmall", + 0xf7e8, + "Eharmenian", + 0x0537, + "Ehookabove", + 0x1eba, + "Eightroman", + 0x2167, + "Einvertedbreve", + 0x0206, + "Eiotifiedcyrillic", + 0x0464, + "Elcyrillic", + 0x041b, + "Elevenroman", + 0x216a, + "Emacron", + 0x0112, + "Emacronacute", + 0x1e16, + "Emacrongrave", + 0x1e14, + "Emcyrillic", + 0x041c, + "Emonospace", + 0xff25, + "Encyrillic", + 0x041d, + "Endescendercyrillic", + 0x04a2, + "Eng", + 0x014a, + "Enghecyrillic", + 0x04a4, + "Enhookcyrillic", + 0x04c7, + "Eogonek", + 0x0118, + "Eopen", + 0x0190, + "Epsilon", + 0x0395, + "Epsilontonos", + 0x0388, + "Ercyrillic", + 0x0420, + "Ereversed", + 0x018e, + "Ereversedcyrillic", + 0x042d, + "Escyrillic", + 0x0421, + "Esdescendercyrillic", + 0x04aa, + "Esh", + 0x01a9, + "Esmall", + 0xf765, + "Eta", + 0x0397, + "Etarmenian", + 0x0538, + "Etatonos", + 0x0389, + "Eth", + 0x00d0, + "Ethsmall", + 0xf7f0, + "Etilde", + 0x1ebc, + "Etildebelow", + 0x1e1a, + "Euro", + 0x20ac, + "Ezh", + 0x01b7, + "Ezhcaron", + 0x01ee, + "Ezhreversed", + 0x01b8, + "F", + 0x0046, + "Fcircle", + 0x24bb, + "Fdotaccent", + 0x1e1e, + "Feharmenian", + 0x0556, + "Feicoptic", + 0x03e4, + "Fhook", + 0x0191, + "Fitacyrillic", + 0x0472, + "Fiveroman", + 0x2164, + "Fmonospace", + 0xff26, + "Fourroman", + 0x2163, + "Fsmall", + 0xf766, + "G", + 0x0047, + "GBsquare", + 0x3387, + "Gacute", + 0x01f4, + "Gamma", + 0x0393, + "Gammaafrican", + 0x0194, + "Gangiacoptic", + 0x03ea, + "Gbreve", + 0x011e, + "Gcaron", + 0x01e6, + "Gcedilla", + 0x0122, + "Gcircle", + 0x24bc, + "Gcircumflex", + 0x011c, + "Gcommaaccent", + 0x0122, + "Gdot", + 0x0120, + "Gdotaccent", + 0x0120, + "Gecyrillic", + 0x0413, + "Ghadarmenian", + 0x0542, + "Ghemiddlehookcyrillic", + 0x0494, + "Ghestrokecyrillic", + 0x0492, + "Gheupturncyrillic", + 0x0490, + "Ghook", + 0x0193, + "Gimarmenian", + 0x0533, + "Gjecyrillic", + 0x0403, + "Gmacron", + 0x1e20, + "Gmonospace", + 0xff27, + "Grave", + 0xf6ce, + "Gravesmall", + 0xf760, + "Gsmall", + 0xf767, + "Gsmallhook", + 0x029b, + "Gstroke", + 0x01e4, + "H", + 0x0048, + "H18533", + 0x25cf, + "H18543", + 0x25aa, + "H18551", + 0x25ab, + "H22073", + 0x25a1, + "HPsquare", + 0x33cb, + "Haabkhasiancyrillic", + 0x04a8, + "Hadescendercyrillic", + 0x04b2, + "Hardsigncyrillic", + 0x042a, + "Hbar", + 0x0126, + "Hbrevebelow", + 0x1e2a, + "Hcedilla", + 0x1e28, + "Hcircle", + 0x24bd, + "Hcircumflex", + 0x0124, + "Hdieresis", + 0x1e26, + "Hdotaccent", + 0x1e22, + "Hdotbelow", + 0x1e24, + "Hmonospace", + 0xff28, + "Hoarmenian", + 0x0540, + "Horicoptic", + 0x03e8, + "Hsmall", + 0xf768, + "Hungarumlaut", + 0xf6cf, + "Hungarumlautsmall", + 0xf6f8, + "Hzsquare", + 0x3390, + "I", + 0x0049, + "IAcyrillic", + 0x042f, + "IJ", + 0x0132, + "IUcyrillic", + 0x042e, + "Iacute", + 0x00cd, + "Iacutesmall", + 0xf7ed, + "Ibreve", + 0x012c, + "Icaron", + 0x01cf, + "Icircle", + 0x24be, + "Icircumflex", + 0x00ce, + "Icircumflexsmall", + 0xf7ee, + "Icyrillic", + 0x0406, + "Idblgrave", + 0x0208, + "Idieresis", + 0x00cf, + "Idieresisacute", + 0x1e2e, + "Idieresiscyrillic", + 0x04e4, + "Idieresissmall", + 0xf7ef, + "Idot", + 0x0130, + "Idotaccent", + 0x0130, + "Idotbelow", + 0x1eca, + "Iebrevecyrillic", + 0x04d6, + "Iecyrillic", + 0x0415, + "Ifraktur", + 0x2111, + "Igrave", + 0x00cc, + "Igravesmall", + 0xf7ec, + "Ihookabove", + 0x1ec8, + "Iicyrillic", + 0x0418, + "Iinvertedbreve", + 0x020a, + "Iishortcyrillic", + 0x0419, + "Imacron", + 0x012a, + "Imacroncyrillic", + 0x04e2, + "Imonospace", + 0xff29, + "Iniarmenian", + 0x053b, + "Iocyrillic", + 0x0401, + "Iogonek", + 0x012e, + "Iota", + 0x0399, + "Iotaafrican", + 0x0196, + "Iotadieresis", + 0x03aa, + "Iotatonos", + 0x038a, + "Ismall", + 0xf769, + "Istroke", + 0x0197, + "Itilde", + 0x0128, + "Itildebelow", + 0x1e2c, + "Izhitsacyrillic", + 0x0474, + "Izhitsadblgravecyrillic", + 0x0476, + "J", + 0x004a, + "Jaarmenian", + 0x0541, + "Jcircle", + 0x24bf, + "Jcircumflex", + 0x0134, + "Jecyrillic", + 0x0408, + "Jheharmenian", + 0x054b, + "Jmonospace", + 0xff2a, + "Jsmall", + 0xf76a, + "K", + 0x004b, + "KBsquare", + 0x3385, + "KKsquare", + 0x33cd, + "Kabashkircyrillic", + 0x04a0, + "Kacute", + 0x1e30, + "Kacyrillic", + 0x041a, + "Kadescendercyrillic", + 0x049a, + "Kahookcyrillic", + 0x04c3, + "Kappa", + 0x039a, + "Kastrokecyrillic", + 0x049e, + "Kaverticalstrokecyrillic", + 0x049c, + "Kcaron", + 0x01e8, + "Kcedilla", + 0x0136, + "Kcircle", + 0x24c0, + "Kcommaaccent", + 0x0136, + "Kdotbelow", + 0x1e32, + "Keharmenian", + 0x0554, + "Kenarmenian", + 0x053f, + "Khacyrillic", + 0x0425, + "Kheicoptic", + 0x03e6, + "Khook", + 0x0198, + "Kjecyrillic", + 0x040c, + "Klinebelow", + 0x1e34, + "Kmonospace", + 0xff2b, + "Koppacyrillic", + 0x0480, + "Koppagreek", + 0x03de, + "Ksicyrillic", + 0x046e, + "Ksmall", + 0xf76b, + "L", + 0x004c, + "LJ", + 0x01c7, + "LL", + 0xf6bf, + "Lacute", + 0x0139, + "Lambda", + 0x039b, + "Lcaron", + 0x013d, + "Lcedilla", + 0x013b, + "Lcircle", + 0x24c1, + "Lcircumflexbelow", + 0x1e3c, + "Lcommaaccent", + 0x013b, + "Ldot", + 0x013f, + "Ldotaccent", + 0x013f, + "Ldotbelow", + 0x1e36, + "Ldotbelowmacron", + 0x1e38, + "Liwnarmenian", + 0x053c, + "Lj", + 0x01c8, + "Ljecyrillic", + 0x0409, + "Llinebelow", + 0x1e3a, + "Lmonospace", + 0xff2c, + "Lslash", + 0x0141, + "Lslashsmall", + 0xf6f9, + "Lsmall", + 0xf76c, + "M", + 0x004d, + "MBsquare", + 0x3386, + "Macron", + 0xf6d0, + "Macronsmall", + 0xf7af, + "Macute", + 0x1e3e, + "Mcircle", + 0x24c2, + "Mdotaccent", + 0x1e40, + "Mdotbelow", + 0x1e42, + "Menarmenian", + 0x0544, + "Mmonospace", + 0xff2d, + "Msmall", + 0xf76d, + "Mturned", + 0x019c, + "Mu", + 0x039c, + "N", + 0x004e, + "NJ", + 0x01ca, + "Nacute", + 0x0143, + "Ncaron", + 0x0147, + "Ncedilla", + 0x0145, + "Ncircle", + 0x24c3, + "Ncircumflexbelow", + 0x1e4a, + "Ncommaaccent", + 0x0145, + "Ndotaccent", + 0x1e44, + "Ndotbelow", + 0x1e46, + "Nhookleft", + 0x019d, + "Nineroman", + 0x2168, + "Nj", + 0x01cb, + "Njecyrillic", + 0x040a, + "Nlinebelow", + 0x1e48, + "Nmonospace", + 0xff2e, + "Nowarmenian", + 0x0546, + "Nsmall", + 0xf76e, + "Ntilde", + 0x00d1, + "Ntildesmall", + 0xf7f1, + "Nu", + 0x039d, + "O", + 0x004f, + "OE", + 0x0152, + "OEsmall", + 0xf6fa, + "Oacute", + 0x00d3, + "Oacutesmall", + 0xf7f3, + "Obarredcyrillic", + 0x04e8, + "Obarreddieresiscyrillic", + 0x04ea, + "Obreve", + 0x014e, + "Ocaron", + 0x01d1, + "Ocenteredtilde", + 0x019f, + "Ocircle", + 0x24c4, + "Ocircumflex", + 0x00d4, + "Ocircumflexacute", + 0x1ed0, + "Ocircumflexdotbelow", + 0x1ed8, + "Ocircumflexgrave", + 0x1ed2, + "Ocircumflexhookabove", + 0x1ed4, + "Ocircumflexsmall", + 0xf7f4, + "Ocircumflextilde", + 0x1ed6, + "Ocyrillic", + 0x041e, + "Odblacute", + 0x0150, + "Odblgrave", + 0x020c, + "Odieresis", + 0x00d6, + "Odieresiscyrillic", + 0x04e6, + "Odieresissmall", + 0xf7f6, + "Odotbelow", + 0x1ecc, + "Ogoneksmall", + 0xf6fb, + "Ograve", + 0x00d2, + "Ogravesmall", + 0xf7f2, + "Oharmenian", + 0x0555, + "Ohm", + 0x2126, + "Ohookabove", + 0x1ece, + "Ohorn", + 0x01a0, + "Ohornacute", + 0x1eda, + "Ohorndotbelow", + 0x1ee2, + "Ohorngrave", + 0x1edc, + "Ohornhookabove", + 0x1ede, + "Ohorntilde", + 0x1ee0, + "Ohungarumlaut", + 0x0150, + "Oi", + 0x01a2, + "Oinvertedbreve", + 0x020e, + "Omacron", + 0x014c, + "Omacronacute", + 0x1e52, + "Omacrongrave", + 0x1e50, + "Omega", + 0x2126, + "Omegacyrillic", + 0x0460, + "Omegagreek", + 0x03a9, + "Omegaroundcyrillic", + 0x047a, + "Omegatitlocyrillic", + 0x047c, + "Omegatonos", + 0x038f, + "Omicron", + 0x039f, + "Omicrontonos", + 0x038c, + "Omonospace", + 0xff2f, + "Oneroman", + 0x2160, + "Oogonek", + 0x01ea, + "Oogonekmacron", + 0x01ec, + "Oopen", + 0x0186, + "Oslash", + 0x00d8, + "Oslashacute", + 0x01fe, + "Oslashsmall", + 0xf7f8, + "Osmall", + 0xf76f, + "Ostrokeacute", + 0x01fe, + "Otcyrillic", + 0x047e, + "Otilde", + 0x00d5, + "Otildeacute", + 0x1e4c, + "Otildedieresis", + 0x1e4e, + "Otildesmall", + 0xf7f5, + "P", + 0x0050, + "Pacute", + 0x1e54, + "Pcircle", + 0x24c5, + "Pdotaccent", + 0x1e56, + "Pecyrillic", + 0x041f, + "Peharmenian", + 0x054a, + "Pemiddlehookcyrillic", + 0x04a6, + "Phi", + 0x03a6, + "Phook", + 0x01a4, + "Pi", + 0x03a0, + "Piwrarmenian", + 0x0553, + "Pmonospace", + 0xff30, + "Psi", + 0x03a8, + "Psicyrillic", + 0x0470, + "Psmall", + 0xf770, + "Q", + 0x0051, + "Qcircle", + 0x24c6, + "Qmonospace", + 0xff31, + "Qsmall", + 0xf771, + "R", + 0x0052, + "Raarmenian", + 0x054c, + "Racute", + 0x0154, + "Rcaron", + 0x0158, + "Rcedilla", + 0x0156, + "Rcircle", + 0x24c7, + "Rcommaaccent", + 0x0156, + "Rdblgrave", + 0x0210, + "Rdotaccent", + 0x1e58, + "Rdotbelow", + 0x1e5a, + "Rdotbelowmacron", + 0x1e5c, + "Reharmenian", + 0x0550, + "Rfraktur", + 0x211c, + "Rho", + 0x03a1, + "Ringsmall", + 0xf6fc, + "Rinvertedbreve", + 0x0212, + "Rlinebelow", + 0x1e5e, + "Rmonospace", + 0xff32, + "Rsmall", + 0xf772, + "Rsmallinverted", + 0x0281, + "Rsmallinvertedsuperior", + 0x02b6, + "S", + 0x0053, + "SF010000", + 0x250c, + "SF020000", + 0x2514, + "SF030000", + 0x2510, + "SF040000", + 0x2518, + "SF050000", + 0x253c, + "SF060000", + 0x252c, + "SF070000", + 0x2534, + "SF080000", + 0x251c, + "SF090000", + 0x2524, + "SF100000", + 0x2500, + "SF110000", + 0x2502, + "SF190000", + 0x2561, + "SF200000", + 0x2562, + "SF210000", + 0x2556, + "SF220000", + 0x2555, + "SF230000", + 0x2563, + "SF240000", + 0x2551, + "SF250000", + 0x2557, + "SF260000", + 0x255d, + "SF270000", + 0x255c, + "SF280000", + 0x255b, + "SF360000", + 0x255e, + "SF370000", + 0x255f, + "SF380000", + 0x255a, + "SF390000", + 0x2554, + "SF400000", + 0x2569, + "SF410000", + 0x2566, + "SF420000", + 0x2560, + "SF430000", + 0x2550, + "SF440000", + 0x256c, + "SF450000", + 0x2567, + "SF460000", + 0x2568, + "SF470000", + 0x2564, + "SF480000", + 0x2565, + "SF490000", + 0x2559, + "SF500000", + 0x2558, + "SF510000", + 0x2552, + "SF520000", + 0x2553, + "SF530000", + 0x256b, + "SF540000", + 0x256a, + "Sacute", + 0x015a, + "Sacutedotaccent", + 0x1e64, + "Sampigreek", + 0x03e0, + "Scaron", + 0x0160, + "Scarondotaccent", + 0x1e66, + "Scaronsmall", + 0xf6fd, + "Scedilla", + 0x015e, + "Schwa", + 0x018f, + "Schwacyrillic", + 0x04d8, + "Schwadieresiscyrillic", + 0x04da, + "Scircle", + 0x24c8, + "Scircumflex", + 0x015c, + "Scommaaccent", + 0x0218, + "Sdotaccent", + 0x1e60, + "Sdotbelow", + 0x1e62, + "Sdotbelowdotaccent", + 0x1e68, + "Seharmenian", + 0x054d, + "Sevenroman", + 0x2166, + "Shaarmenian", + 0x0547, + "Shacyrillic", + 0x0428, + "Shchacyrillic", + 0x0429, + "Sheicoptic", + 0x03e2, + "Shhacyrillic", + 0x04ba, + "Shimacoptic", + 0x03ec, + "Sigma", + 0x03a3, + "Sixroman", + 0x2165, + "Smonospace", + 0xff33, + "Softsigncyrillic", + 0x042c, + "Ssmall", + 0xf773, + "Stigmagreek", + 0x03da, + "T", + 0x0054, + "Tau", + 0x03a4, + "Tbar", + 0x0166, + "Tcaron", + 0x0164, + "Tcedilla", + 0x0162, + "Tcircle", + 0x24c9, + "Tcircumflexbelow", + 0x1e70, + "Tcommaaccent", + 0x0162, + "Tdotaccent", + 0x1e6a, + "Tdotbelow", + 0x1e6c, + "Tecyrillic", + 0x0422, + "Tedescendercyrillic", + 0x04ac, + "Tenroman", + 0x2169, + "Tetsecyrillic", + 0x04b4, + "Theta", + 0x0398, + "Thook", + 0x01ac, + "Thorn", + 0x00de, + "Thornsmall", + 0xf7fe, + "Threeroman", + 0x2162, + "Tildesmall", + 0xf6fe, + "Tiwnarmenian", + 0x054f, + "Tlinebelow", + 0x1e6e, + "Tmonospace", + 0xff34, + "Toarmenian", + 0x0539, + "Tonefive", + 0x01bc, + "Tonesix", + 0x0184, + "Tonetwo", + 0x01a7, + "Tretroflexhook", + 0x01ae, + "Tsecyrillic", + 0x0426, + "Tshecyrillic", + 0x040b, + "Tsmall", + 0xf774, + "Twelveroman", + 0x216b, + "Tworoman", + 0x2161, + "U", + 0x0055, + "Uacute", + 0x00da, + "Uacutesmall", + 0xf7fa, + "Ubreve", + 0x016c, + "Ucaron", + 0x01d3, + "Ucircle", + 0x24ca, + "Ucircumflex", + 0x00db, + "Ucircumflexbelow", + 0x1e76, + "Ucircumflexsmall", + 0xf7fb, + "Ucyrillic", + 0x0423, + "Udblacute", + 0x0170, + "Udblgrave", + 0x0214, + "Udieresis", + 0x00dc, + "Udieresisacute", + 0x01d7, + "Udieresisbelow", + 0x1e72, + "Udieresiscaron", + 0x01d9, + "Udieresiscyrillic", + 0x04f0, + "Udieresisgrave", + 0x01db, + "Udieresismacron", + 0x01d5, + "Udieresissmall", + 0xf7fc, + "Udotbelow", + 0x1ee4, + "Ugrave", + 0x00d9, + "Ugravesmall", + 0xf7f9, + "Uhookabove", + 0x1ee6, + "Uhorn", + 0x01af, + "Uhornacute", + 0x1ee8, + "Uhorndotbelow", + 0x1ef0, + "Uhorngrave", + 0x1eea, + "Uhornhookabove", + 0x1eec, + "Uhorntilde", + 0x1eee, + "Uhungarumlaut", + 0x0170, + "Uhungarumlautcyrillic", + 0x04f2, + "Uinvertedbreve", + 0x0216, + "Ukcyrillic", + 0x0478, + "Umacron", + 0x016a, + "Umacroncyrillic", + 0x04ee, + "Umacrondieresis", + 0x1e7a, + "Umonospace", + 0xff35, + "Uogonek", + 0x0172, + "Upsilon", + 0x03a5, + "Upsilon1", + 0x03d2, + "Upsilonacutehooksymbolgreek", + 0x03d3, + "Upsilonafrican", + 0x01b1, + "Upsilondieresis", + 0x03ab, + "Upsilondieresishooksymbolgreek", + 0x03d4, + "Upsilonhooksymbol", + 0x03d2, + "Upsilontonos", + 0x038e, + "Uring", + 0x016e, + "Ushortcyrillic", + 0x040e, + "Usmall", + 0xf775, + "Ustraightcyrillic", + 0x04ae, + "Ustraightstrokecyrillic", + 0x04b0, + "Utilde", + 0x0168, + "Utildeacute", + 0x1e78, + "Utildebelow", + 0x1e74, + "V", + 0x0056, + "Vcircle", + 0x24cb, + "Vdotbelow", + 0x1e7e, + "Vecyrillic", + 0x0412, + "Vewarmenian", + 0x054e, + "Vhook", + 0x01b2, + "Vmonospace", + 0xff36, + "Voarmenian", + 0x0548, + "Vsmall", + 0xf776, + "Vtilde", + 0x1e7c, + "W", + 0x0057, + "Wacute", + 0x1e82, + "Wcircle", + 0x24cc, + "Wcircumflex", + 0x0174, + "Wdieresis", + 0x1e84, + "Wdotaccent", + 0x1e86, + "Wdotbelow", + 0x1e88, + "Wgrave", + 0x1e80, + "Wmonospace", + 0xff37, + "Wsmall", + 0xf777, + "X", + 0x0058, + "Xcircle", + 0x24cd, + "Xdieresis", + 0x1e8c, + "Xdotaccent", + 0x1e8a, + "Xeharmenian", + 0x053d, + "Xi", + 0x039e, + "Xmonospace", + 0xff38, + "Xsmall", + 0xf778, + "Y", + 0x0059, + "Yacute", + 0x00dd, + "Yacutesmall", + 0xf7fd, + "Yatcyrillic", + 0x0462, + "Ycircle", + 0x24ce, + "Ycircumflex", + 0x0176, + "Ydieresis", + 0x0178, + "Ydieresissmall", + 0xf7ff, + "Ydotaccent", + 0x1e8e, + "Ydotbelow", + 0x1ef4, + "Yericyrillic", + 0x042b, + "Yerudieresiscyrillic", + 0x04f8, + "Ygrave", + 0x1ef2, + "Yhook", + 0x01b3, + "Yhookabove", + 0x1ef6, + "Yiarmenian", + 0x0545, + "Yicyrillic", + 0x0407, + "Yiwnarmenian", + 0x0552, + "Ymonospace", + 0xff39, + "Ysmall", + 0xf779, + "Ytilde", + 0x1ef8, + "Yusbigcyrillic", + 0x046a, + "Yusbigiotifiedcyrillic", + 0x046c, + "Yuslittlecyrillic", + 0x0466, + "Yuslittleiotifiedcyrillic", + 0x0468, + "Z", + 0x005a, + "Zaarmenian", + 0x0536, + "Zacute", + 0x0179, + "Zcaron", + 0x017d, + "Zcaronsmall", + 0xf6ff, + "Zcircle", + 0x24cf, + "Zcircumflex", + 0x1e90, + "Zdot", + 0x017b, + "Zdotaccent", + 0x017b, + "Zdotbelow", + 0x1e92, + "Zecyrillic", + 0x0417, + "Zedescendercyrillic", + 0x0498, + "Zedieresiscyrillic", + 0x04de, + "Zeta", + 0x0396, + "Zhearmenian", + 0x053a, + "Zhebrevecyrillic", + 0x04c1, + "Zhecyrillic", + 0x0416, + "Zhedescendercyrillic", + 0x0496, + "Zhedieresiscyrillic", + 0x04dc, + "Zlinebelow", + 0x1e94, + "Zmonospace", + 0xff3a, + "Zsmall", + 0xf77a, + "Zstroke", + 0x01b5, + "a", + 0x0061, + "aabengali", + 0x0986, + "aacute", + 0x00e1, + "aadeva", + 0x0906, + "aagujarati", + 0x0a86, + "aagurmukhi", + 0x0a06, + "aamatragurmukhi", + 0x0a3e, + "aarusquare", + 0x3303, + "aavowelsignbengali", + 0x09be, + "aavowelsigndeva", + 0x093e, + "aavowelsigngujarati", + 0x0abe, + "abbreviationmarkarmenian", + 0x055f, + "abbreviationsigndeva", + 0x0970, + "abengali", + 0x0985, + "abopomofo", + 0x311a, + "abreve", + 0x0103, + "abreveacute", + 0x1eaf, + "abrevecyrillic", + 0x04d1, + "abrevedotbelow", + 0x1eb7, + "abrevegrave", + 0x1eb1, + "abrevehookabove", + 0x1eb3, + "abrevetilde", + 0x1eb5, + "acaron", + 0x01ce, + "acircle", + 0x24d0, + "acircumflex", + 0x00e2, + "acircumflexacute", + 0x1ea5, + "acircumflexdotbelow", + 0x1ead, + "acircumflexgrave", + 0x1ea7, + "acircumflexhookabove", + 0x1ea9, + "acircumflextilde", + 0x1eab, + "acute", + 0x00b4, + "acutebelowcmb", + 0x0317, + "acutecmb", + 0x0301, + "acutecomb", + 0x0301, + "acutedeva", + 0x0954, + "acutelowmod", + 0x02cf, + "acutetonecmb", + 0x0341, + "acyrillic", + 0x0430, + "adblgrave", + 0x0201, + "addakgurmukhi", + 0x0a71, + "adeva", + 0x0905, + "adieresis", + 0x00e4, + "adieresiscyrillic", + 0x04d3, + "adieresismacron", + 0x01df, + "adotbelow", + 0x1ea1, + "adotmacron", + 0x01e1, + "ae", + 0x00e6, + "aeacute", + 0x01fd, + "aekorean", + 0x3150, + "aemacron", + 0x01e3, + "afii00208", + 0x2015, + "afii08941", + 0x20a4, + "afii10017", + 0x0410, + "afii10018", + 0x0411, + "afii10019", + 0x0412, + "afii10020", + 0x0413, + "afii10021", + 0x0414, + "afii10022", + 0x0415, + "afii10023", + 0x0401, + "afii10024", + 0x0416, + "afii10025", + 0x0417, + "afii10026", + 0x0418, + "afii10027", + 0x0419, + "afii10028", + 0x041a, + "afii10029", + 0x041b, + "afii10030", + 0x041c, + "afii10031", + 0x041d, + "afii10032", + 0x041e, + "afii10033", + 0x041f, + "afii10034", + 0x0420, + "afii10035", + 0x0421, + "afii10036", + 0x0422, + "afii10037", + 0x0423, + "afii10038", + 0x0424, + "afii10039", + 0x0425, + "afii10040", + 0x0426, + "afii10041", + 0x0427, + "afii10042", + 0x0428, + "afii10043", + 0x0429, + "afii10044", + 0x042a, + "afii10045", + 0x042b, + "afii10046", + 0x042c, + "afii10047", + 0x042d, + "afii10048", + 0x042e, + "afii10049", + 0x042f, + "afii10050", + 0x0490, + "afii10051", + 0x0402, + "afii10052", + 0x0403, + "afii10053", + 0x0404, + "afii10054", + 0x0405, + "afii10055", + 0x0406, + "afii10056", + 0x0407, + "afii10057", + 0x0408, + "afii10058", + 0x0409, + "afii10059", + 0x040a, + "afii10060", + 0x040b, + "afii10061", + 0x040c, + "afii10062", + 0x040e, + "afii10063", + 0xf6c4, + "afii10064", + 0xf6c5, + "afii10065", + 0x0430, + "afii10066", + 0x0431, + "afii10067", + 0x0432, + "afii10068", + 0x0433, + "afii10069", + 0x0434, + "afii10070", + 0x0435, + "afii10071", + 0x0451, + "afii10072", + 0x0436, + "afii10073", + 0x0437, + "afii10074", + 0x0438, + "afii10075", + 0x0439, + "afii10076", + 0x043a, + "afii10077", + 0x043b, + "afii10078", + 0x043c, + "afii10079", + 0x043d, + "afii10080", + 0x043e, + "afii10081", + 0x043f, + "afii10082", + 0x0440, + "afii10083", + 0x0441, + "afii10084", + 0x0442, + "afii10085", + 0x0443, + "afii10086", + 0x0444, + "afii10087", + 0x0445, + "afii10088", + 0x0446, + "afii10089", + 0x0447, + "afii10090", + 0x0448, + "afii10091", + 0x0449, + "afii10092", + 0x044a, + "afii10093", + 0x044b, + "afii10094", + 0x044c, + "afii10095", + 0x044d, + "afii10096", + 0x044e, + "afii10097", + 0x044f, + "afii10098", + 0x0491, + "afii10099", + 0x0452, + "afii10100", + 0x0453, + "afii10101", + 0x0454, + "afii10102", + 0x0455, + "afii10103", + 0x0456, + "afii10104", + 0x0457, + "afii10105", + 0x0458, + "afii10106", + 0x0459, + "afii10107", + 0x045a, + "afii10108", + 0x045b, + "afii10109", + 0x045c, + "afii10110", + 0x045e, + "afii10145", + 0x040f, + "afii10146", + 0x0462, + "afii10147", + 0x0472, + "afii10148", + 0x0474, + "afii10192", + 0xf6c6, + "afii10193", + 0x045f, + "afii10194", + 0x0463, + "afii10195", + 0x0473, + "afii10196", + 0x0475, + "afii10831", + 0xf6c7, + "afii10832", + 0xf6c8, + "afii10846", + 0x04d9, + "afii299", + 0x200e, + "afii300", + 0x200f, + "afii301", + 0x200d, + "afii57381", + 0x066a, + "afii57388", + 0x060c, + "afii57392", + 0x0660, + "afii57393", + 0x0661, + "afii57394", + 0x0662, + "afii57395", + 0x0663, + "afii57396", + 0x0664, + "afii57397", + 0x0665, + "afii57398", + 0x0666, + "afii57399", + 0x0667, + "afii57400", + 0x0668, + "afii57401", + 0x0669, + "afii57403", + 0x061b, + "afii57407", + 0x061f, + "afii57409", + 0x0621, + "afii57410", + 0x0622, + "afii57411", + 0x0623, + "afii57412", + 0x0624, + "afii57413", + 0x0625, + "afii57414", + 0x0626, + "afii57415", + 0x0627, + "afii57416", + 0x0628, + "afii57417", + 0x0629, + "afii57418", + 0x062a, + "afii57419", + 0x062b, + "afii57420", + 0x062c, + "afii57421", + 0x062d, + "afii57422", + 0x062e, + "afii57423", + 0x062f, + "afii57424", + 0x0630, + "afii57425", + 0x0631, + "afii57426", + 0x0632, + "afii57427", + 0x0633, + "afii57428", + 0x0634, + "afii57429", + 0x0635, + "afii57430", + 0x0636, + "afii57431", + 0x0637, + "afii57432", + 0x0638, + "afii57433", + 0x0639, + "afii57434", + 0x063a, + "afii57440", + 0x0640, + "afii57441", + 0x0641, + "afii57442", + 0x0642, + "afii57443", + 0x0643, + "afii57444", + 0x0644, + "afii57445", + 0x0645, + "afii57446", + 0x0646, + "afii57448", + 0x0648, + "afii57449", + 0x0649, + "afii57450", + 0x064a, + "afii57451", + 0x064b, + "afii57452", + 0x064c, + "afii57453", + 0x064d, + "afii57454", + 0x064e, + "afii57455", + 0x064f, + "afii57456", + 0x0650, + "afii57457", + 0x0651, + "afii57458", + 0x0652, + "afii57470", + 0x0647, + "afii57505", + 0x06a4, + "afii57506", + 0x067e, + "afii57507", + 0x0686, + "afii57508", + 0x0698, + "afii57509", + 0x06af, + "afii57511", + 0x0679, + "afii57512", + 0x0688, + "afii57513", + 0x0691, + "afii57514", + 0x06ba, + "afii57519", + 0x06d2, + "afii57534", + 0x06d5, + "afii57636", + 0x20aa, + "afii57645", + 0x05be, + "afii57658", + 0x05c3, + "afii57664", + 0x05d0, + "afii57665", + 0x05d1, + "afii57666", + 0x05d2, + "afii57667", + 0x05d3, + "afii57668", + 0x05d4, + "afii57669", + 0x05d5, + "afii57670", + 0x05d6, + "afii57671", + 0x05d7, + "afii57672", + 0x05d8, + "afii57673", + 0x05d9, + "afii57674", + 0x05da, + "afii57675", + 0x05db, + "afii57676", + 0x05dc, + "afii57677", + 0x05dd, + "afii57678", + 0x05de, + "afii57679", + 0x05df, + "afii57680", + 0x05e0, + "afii57681", + 0x05e1, + "afii57682", + 0x05e2, + "afii57683", + 0x05e3, + "afii57684", + 0x05e4, + "afii57685", + 0x05e5, + "afii57686", + 0x05e6, + "afii57687", + 0x05e7, + "afii57688", + 0x05e8, + "afii57689", + 0x05e9, + "afii57690", + 0x05ea, + "afii57694", + 0xfb2a, + "afii57695", + 0xfb2b, + "afii57700", + 0xfb4b, + "afii57705", + 0xfb1f, + "afii57716", + 0x05f0, + "afii57717", + 0x05f1, + "afii57718", + 0x05f2, + "afii57723", + 0xfb35, + "afii57793", + 0x05b4, + "afii57794", + 0x05b5, + "afii57795", + 0x05b6, + "afii57796", + 0x05bb, + "afii57797", + 0x05b8, + "afii57798", + 0x05b7, + "afii57799", + 0x05b0, + "afii57800", + 0x05b2, + "afii57801", + 0x05b1, + "afii57802", + 0x05b3, + "afii57803", + 0x05c2, + "afii57804", + 0x05c1, + "afii57806", + 0x05b9, + "afii57807", + 0x05bc, + "afii57839", + 0x05bd, + "afii57841", + 0x05bf, + "afii57842", + 0x05c0, + "afii57929", + 0x02bc, + "afii61248", + 0x2105, + "afii61289", + 0x2113, + "afii61352", + 0x2116, + "afii61573", + 0x202c, + "afii61574", + 0x202d, + "afii61575", + 0x202e, + "afii61664", + 0x200c, + "afii63167", + 0x066d, + "afii64937", + 0x02bd, + "agrave", + 0x00e0, + "agujarati", + 0x0a85, + "agurmukhi", + 0x0a05, + "ahiragana", + 0x3042, + "ahookabove", + 0x1ea3, + "aibengali", + 0x0990, + "aibopomofo", + 0x311e, + "aideva", + 0x0910, + "aiecyrillic", + 0x04d5, + "aigujarati", + 0x0a90, + "aigurmukhi", + 0x0a10, + "aimatragurmukhi", + 0x0a48, + "ainarabic", + 0x0639, + "ainfinalarabic", + 0xfeca, + "aininitialarabic", + 0xfecb, + "ainmedialarabic", + 0xfecc, + "ainvertedbreve", + 0x0203, + "aivowelsignbengali", + 0x09c8, + "aivowelsigndeva", + 0x0948, + "aivowelsigngujarati", + 0x0ac8, + "akatakana", + 0x30a2, + "akatakanahalfwidth", + 0xff71, + "akorean", + 0x314f, + "alef", + 0x05d0, + "alefarabic", + 0x0627, + "alefdageshhebrew", + 0xfb30, + "aleffinalarabic", + 0xfe8e, + "alefhamzaabovearabic", + 0x0623, + "alefhamzaabovefinalarabic", + 0xfe84, + "alefhamzabelowarabic", + 0x0625, + "alefhamzabelowfinalarabic", + 0xfe88, + "alefhebrew", + 0x05d0, + "aleflamedhebrew", + 0xfb4f, + "alefmaddaabovearabic", + 0x0622, + "alefmaddaabovefinalarabic", + 0xfe82, + "alefmaksuraarabic", + 0x0649, + "alefmaksurafinalarabic", + 0xfef0, + "alefmaksurainitialarabic", + 0xfef3, + "alefmaksuramedialarabic", + 0xfef4, + "alefpatahhebrew", + 0xfb2e, + "alefqamatshebrew", + 0xfb2f, + "aleph", + 0x2135, + "allequal", + 0x224c, + "alpha", + 0x03b1, + "alphatonos", + 0x03ac, + "amacron", + 0x0101, + "amonospace", + 0xff41, + "ampersand", + 0x0026, + "ampersandmonospace", + 0xff06, + "ampersandsmall", + 0xf726, + "amsquare", + 0x33c2, + "anbopomofo", + 0x3122, + "angbopomofo", + 0x3124, + "angbracketleft", + 0x3008, + "angbracketright", + 0x3009, + "angkhankhuthai", + 0x0e5a, + "angle", + 0x2220, + "anglebracketleft", + 0x3008, + "anglebracketleftvertical", + 0xfe3f, + "anglebracketright", + 0x3009, + "anglebracketrightvertical", + 0xfe40, + "angleleft", + 0x2329, + "angleright", + 0x232a, + "angstrom", + 0x212b, + "anoteleia", + 0x0387, + "anudattadeva", + 0x0952, + "anusvarabengali", + 0x0982, + "anusvaradeva", + 0x0902, + "anusvaragujarati", + 0x0a82, + "aogonek", + 0x0105, + "apaatosquare", + 0x3300, + "aparen", + 0x249c, + "apostrophearmenian", + 0x055a, + "apostrophemod", + 0x02bc, + "apple", + 0xf8ff, + "approaches", + 0x2250, + "approxequal", + 0x2248, + "approxequalorimage", + 0x2252, + "approximatelyequal", + 0x2245, + "araeaekorean", + 0x318e, + "araeakorean", + 0x318d, + "arc", + 0x2312, + "arighthalfring", + 0x1e9a, + "aring", + 0x00e5, + "aringacute", + 0x01fb, + "aringbelow", + 0x1e01, + "arrowboth", + 0x2194, + "arrowdashdown", + 0x21e3, + "arrowdashleft", + 0x21e0, + "arrowdashright", + 0x21e2, + "arrowdashup", + 0x21e1, + "arrowdblboth", + 0x21d4, + "arrowdbldown", + 0x21d3, + "arrowdblleft", + 0x21d0, + "arrowdblright", + 0x21d2, + "arrowdblup", + 0x21d1, + "arrowdown", + 0x2193, + "arrowdownleft", + 0x2199, + "arrowdownright", + 0x2198, + "arrowdownwhite", + 0x21e9, + "arrowheaddownmod", + 0x02c5, + "arrowheadleftmod", + 0x02c2, + "arrowheadrightmod", + 0x02c3, + "arrowheadupmod", + 0x02c4, + "arrowhorizex", + 0xf8e7, + "arrowleft", + 0x2190, + "arrowleftdbl", + 0x21d0, + "arrowleftdblstroke", + 0x21cd, + "arrowleftoverright", + 0x21c6, + "arrowleftwhite", + 0x21e6, + "arrowright", + 0x2192, + "arrowrightdblstroke", + 0x21cf, + "arrowrightheavy", + 0x279e, + "arrowrightoverleft", + 0x21c4, + "arrowrightwhite", + 0x21e8, + "arrowtableft", + 0x21e4, + "arrowtabright", + 0x21e5, + "arrowup", + 0x2191, + "arrowupdn", + 0x2195, + "arrowupdnbse", + 0x21a8, + "arrowupdownbase", + 0x21a8, + "arrowupleft", + 0x2196, + "arrowupleftofdown", + 0x21c5, + "arrowupright", + 0x2197, + "arrowupwhite", + 0x21e7, + "arrowvertex", + 0xf8e6, + "asciicircum", + 0x005e, + "asciicircummonospace", + 0xff3e, + "asciitilde", + 0x007e, + "asciitildemonospace", + 0xff5e, + "ascript", + 0x0251, + "ascriptturned", + 0x0252, + "asmallhiragana", + 0x3041, + "asmallkatakana", + 0x30a1, + "asmallkatakanahalfwidth", + 0xff67, + "asterisk", + 0x002a, + "asteriskaltonearabic", + 0x066d, + "asteriskarabic", + 0x066d, + "asteriskmath", + 0x2217, + "asteriskmonospace", + 0xff0a, + "asterisksmall", + 0xfe61, + "asterism", + 0x2042, + "asuperior", + 0xf6e9, + "asymptoticallyequal", + 0x2243, + "at", + 0x0040, + "atilde", + 0x00e3, + "atmonospace", + 0xff20, + "atsmall", + 0xfe6b, + "aturned", + 0x0250, + "aubengali", + 0x0994, + "aubopomofo", + 0x3120, + "audeva", + 0x0914, + "augujarati", + 0x0a94, + "augurmukhi", + 0x0a14, + "aulengthmarkbengali", + 0x09d7, + "aumatragurmukhi", + 0x0a4c, + "auvowelsignbengali", + 0x09cc, + "auvowelsigndeva", + 0x094c, + "auvowelsigngujarati", + 0x0acc, + "avagrahadeva", + 0x093d, + "aybarmenian", + 0x0561, + "ayin", + 0x05e2, + "ayinaltonehebrew", + 0xfb20, + "ayinhebrew", + 0x05e2, + "b", + 0x0062, + "babengali", + 0x09ac, + "backslash", + 0x005c, + "backslashmonospace", + 0xff3c, + "badeva", + 0x092c, + "bagujarati", + 0x0aac, + "bagurmukhi", + 0x0a2c, + "bahiragana", + 0x3070, + "bahtthai", + 0x0e3f, + "bakatakana", + 0x30d0, + "bar", + 0x007c, + "barmonospace", + 0xff5c, + "bbopomofo", + 0x3105, + "bcircle", + 0x24d1, + "bdotaccent", + 0x1e03, + "bdotbelow", + 0x1e05, + "beamedsixteenthnotes", + 0x266c, + "because", + 0x2235, + "becyrillic", + 0x0431, + "beharabic", + 0x0628, + "behfinalarabic", + 0xfe90, + "behinitialarabic", + 0xfe91, + "behiragana", + 0x3079, + "behmedialarabic", + 0xfe92, + "behmeeminitialarabic", + 0xfc9f, + "behmeemisolatedarabic", + 0xfc08, + "behnoonfinalarabic", + 0xfc6d, + "bekatakana", + 0x30d9, + "benarmenian", + 0x0562, + "bet", + 0x05d1, + "beta", + 0x03b2, + "betasymbolgreek", + 0x03d0, + "betdagesh", + 0xfb31, + "betdageshhebrew", + 0xfb31, + "bethebrew", + 0x05d1, + "betrafehebrew", + 0xfb4c, + "bhabengali", + 0x09ad, + "bhadeva", + 0x092d, + "bhagujarati", + 0x0aad, + "bhagurmukhi", + 0x0a2d, + "bhook", + 0x0253, + "bihiragana", + 0x3073, + "bikatakana", + 0x30d3, + "bilabialclick", + 0x0298, + "bindigurmukhi", + 0x0a02, + "birusquare", + 0x3331, + "blackcircle", + 0x25cf, + "blackdiamond", + 0x25c6, + "blackdownpointingtriangle", + 0x25bc, + "blackleftpointingpointer", + 0x25c4, + "blackleftpointingtriangle", + 0x25c0, + "blacklenticularbracketleft", + 0x3010, + "blacklenticularbracketleftvertical", + 0xfe3b, + "blacklenticularbracketright", + 0x3011, + "blacklenticularbracketrightvertical", + 0xfe3c, + "blacklowerlefttriangle", + 0x25e3, + "blacklowerrighttriangle", + 0x25e2, + "blackrectangle", + 0x25ac, + "blackrightpointingpointer", + 0x25ba, + "blackrightpointingtriangle", + 0x25b6, + "blacksmallsquare", + 0x25aa, + "blacksmilingface", + 0x263b, + "blacksquare", + 0x25a0, + "blackstar", + 0x2605, + "blackupperlefttriangle", + 0x25e4, + "blackupperrighttriangle", + 0x25e5, + "blackuppointingsmalltriangle", + 0x25b4, + "blackuppointingtriangle", + 0x25b2, + "blank", + 0x2423, + "blinebelow", + 0x1e07, + "block", + 0x2588, + "bmonospace", + 0xff42, + "bobaimaithai", + 0x0e1a, + "bohiragana", + 0x307c, + "bokatakana", + 0x30dc, + "bparen", + 0x249d, + "bqsquare", + 0x33c3, + "braceex", + 0xf8f4, + "braceleft", + 0x007b, + "braceleftbt", + 0xf8f3, + "braceleftmid", + 0xf8f2, + "braceleftmonospace", + 0xff5b, + "braceleftsmall", + 0xfe5b, + "bracelefttp", + 0xf8f1, + "braceleftvertical", + 0xfe37, + "braceright", + 0x007d, + "bracerightbt", + 0xf8fe, + "bracerightmid", + 0xf8fd, + "bracerightmonospace", + 0xff5d, + "bracerightsmall", + 0xfe5c, + "bracerighttp", + 0xf8fc, + "bracerightvertical", + 0xfe38, + "bracketleft", + 0x005b, + "bracketleftbt", + 0xf8f0, + "bracketleftex", + 0xf8ef, + "bracketleftmonospace", + 0xff3b, + "bracketlefttp", + 0xf8ee, + "bracketright", + 0x005d, + "bracketrightbt", + 0xf8fb, + "bracketrightex", + 0xf8fa, + "bracketrightmonospace", + 0xff3d, + "bracketrighttp", + 0xf8f9, + "breve", + 0x02d8, + "brevebelowcmb", + 0x032e, + "brevecmb", + 0x0306, + "breveinvertedbelowcmb", + 0x032f, + "breveinvertedcmb", + 0x0311, + "breveinverteddoublecmb", + 0x0361, + "bridgebelowcmb", + 0x032a, + "bridgeinvertedbelowcmb", + 0x033a, + "brokenbar", + 0x00a6, + "bstroke", + 0x0180, + "bsuperior", + 0xf6ea, + "btopbar", + 0x0183, + "buhiragana", + 0x3076, + "bukatakana", + 0x30d6, + "bullet", + 0x2022, + "bulletinverse", + 0x25d8, + "bulletoperator", + 0x2219, + "bullseye", + 0x25ce, + "c", + 0x0063, + "caarmenian", + 0x056e, + "cabengali", + 0x099a, + "cacute", + 0x0107, + "cadeva", + 0x091a, + "cagujarati", + 0x0a9a, + "cagurmukhi", + 0x0a1a, + "calsquare", + 0x3388, + "candrabindubengali", + 0x0981, + "candrabinducmb", + 0x0310, + "candrabindudeva", + 0x0901, + "candrabindugujarati", + 0x0a81, + "capslock", + 0x21ea, + "careof", + 0x2105, + "caron", + 0x02c7, + "caronbelowcmb", + 0x032c, + "caroncmb", + 0x030c, + "carriagereturn", + 0x21b5, + "cbopomofo", + 0x3118, + "ccaron", + 0x010d, + "ccedilla", + 0x00e7, + "ccedillaacute", + 0x1e09, + "ccircle", + 0x24d2, + "ccircumflex", + 0x0109, + "ccurl", + 0x0255, + "cdot", + 0x010b, + "cdotaccent", + 0x010b, + "cdsquare", + 0x33c5, + "cedilla", + 0x00b8, + "cedillacmb", + 0x0327, + "cent", + 0x00a2, + "centigrade", + 0x2103, + "centinferior", + 0xf6df, + "centmonospace", + 0xffe0, + "centoldstyle", + 0xf7a2, + "centsuperior", + 0xf6e0, + "chaarmenian", + 0x0579, + "chabengali", + 0x099b, + "chadeva", + 0x091b, + "chagujarati", + 0x0a9b, + "chagurmukhi", + 0x0a1b, + "chbopomofo", + 0x3114, + "cheabkhasiancyrillic", + 0x04bd, + "checkmark", + 0x2713, + "checyrillic", + 0x0447, + "chedescenderabkhasiancyrillic", + 0x04bf, + "chedescendercyrillic", + 0x04b7, + "chedieresiscyrillic", + 0x04f5, + "cheharmenian", + 0x0573, + "chekhakassiancyrillic", + 0x04cc, + "cheverticalstrokecyrillic", + 0x04b9, + "chi", + 0x03c7, + "chieuchacirclekorean", + 0x3277, + "chieuchaparenkorean", + 0x3217, + "chieuchcirclekorean", + 0x3269, + "chieuchkorean", + 0x314a, + "chieuchparenkorean", + 0x3209, + "chochangthai", + 0x0e0a, + "chochanthai", + 0x0e08, + "chochingthai", + 0x0e09, + "chochoethai", + 0x0e0c, + "chook", + 0x0188, + "cieucacirclekorean", + 0x3276, + "cieucaparenkorean", + 0x3216, + "cieuccirclekorean", + 0x3268, + "cieuckorean", + 0x3148, + "cieucparenkorean", + 0x3208, + "cieucuparenkorean", + 0x321c, + "circle", + 0x25cb, + "circlecopyrt", + 0x00a9, + "circlemultiply", + 0x2297, + "circleot", + 0x2299, + "circleplus", + 0x2295, + "circlepostalmark", + 0x3036, + "circlewithlefthalfblack", + 0x25d0, + "circlewithrighthalfblack", + 0x25d1, + "circumflex", + 0x02c6, + "circumflexbelowcmb", + 0x032d, + "circumflexcmb", + 0x0302, + "clear", + 0x2327, + "clickalveolar", + 0x01c2, + "clickdental", + 0x01c0, + "clicklateral", + 0x01c1, + "clickretroflex", + 0x01c3, + "club", + 0x2663, + "clubsuitblack", + 0x2663, + "clubsuitwhite", + 0x2667, + "cmcubedsquare", + 0x33a4, + "cmonospace", + 0xff43, + "cmsquaredsquare", + 0x33a0, + "coarmenian", + 0x0581, + "colon", + 0x003a, + "colonmonetary", + 0x20a1, + "colonmonospace", + 0xff1a, + "colonsign", + 0x20a1, + "colonsmall", + 0xfe55, + "colontriangularhalfmod", + 0x02d1, + "colontriangularmod", + 0x02d0, + "comma", + 0x002c, + "commaabovecmb", + 0x0313, + "commaaboverightcmb", + 0x0315, + "commaaccent", + 0xf6c3, + "commaarabic", + 0x060c, + "commaarmenian", + 0x055d, + "commainferior", + 0xf6e1, + "commamonospace", + 0xff0c, + "commareversedabovecmb", + 0x0314, + "commareversedmod", + 0x02bd, + "commasmall", + 0xfe50, + "commasuperior", + 0xf6e2, + "commaturnedabovecmb", + 0x0312, + "commaturnedmod", + 0x02bb, + "compass", + 0x263c, + "congruent", + 0x2245, + "contourintegral", + 0x222e, + "control", + 0x2303, + "controlACK", + 0x0006, + "controlBEL", + 0x0007, + "controlBS", + 0x0008, + "controlCAN", + 0x0018, + "controlCR", + 0x000d, + "controlDC1", + 0x0011, + "controlDC2", + 0x0012, + "controlDC3", + 0x0013, + "controlDC4", + 0x0014, + "controlDEL", + 0x007f, + "controlDLE", + 0x0010, + "controlEM", + 0x0019, + "controlENQ", + 0x0005, + "controlEOT", + 0x0004, + "controlESC", + 0x001b, + "controlETB", + 0x0017, + "controlETX", + 0x0003, + "controlFF", + 0x000c, + "controlFS", + 0x001c, + "controlGS", + 0x001d, + "controlHT", + 0x0009, + "controlLF", + 0x000a, + "controlNAK", + 0x0015, + "controlNULL", + 0x0000, + "controlRS", + 0x001e, + "controlSI", + 0x000f, + "controlSO", + 0x000e, + "controlSOT", + 0x0002, + "controlSTX", + 0x0001, + "controlSUB", + 0x001a, + "controlSYN", + 0x0016, + "controlUS", + 0x001f, + "controlVT", + 0x000b, + "copyright", + 0x00a9, + "copyrightsans", + 0xf8e9, + "copyrightserif", + 0xf6d9, + "cornerbracketleft", + 0x300c, + "cornerbracketlefthalfwidth", + 0xff62, + "cornerbracketleftvertical", + 0xfe41, + "cornerbracketright", + 0x300d, + "cornerbracketrighthalfwidth", + 0xff63, + "cornerbracketrightvertical", + 0xfe42, + "corporationsquare", + 0x337f, + "cosquare", + 0x33c7, + "coverkgsquare", + 0x33c6, + "cparen", + 0x249e, + "cruzeiro", + 0x20a2, + "cstretched", + 0x0297, + "curlyand", + 0x22cf, + "curlyor", + 0x22ce, + "currency", + 0x00a4, + "cyrBreve", + 0xf6d1, + "cyrFlex", + 0xf6d2, + "cyrbreve", + 0xf6d4, + "cyrflex", + 0xf6d5, + "d", + 0x0064, + "daarmenian", + 0x0564, + "dabengali", + 0x09a6, + "dadarabic", + 0x0636, + "dadeva", + 0x0926, + "dadfinalarabic", + 0xfebe, + "dadinitialarabic", + 0xfebf, + "dadmedialarabic", + 0xfec0, + "dagesh", + 0x05bc, + "dageshhebrew", + 0x05bc, + "dagger", + 0x2020, + "daggerdbl", + 0x2021, + "dagujarati", + 0x0aa6, + "dagurmukhi", + 0x0a26, + "dahiragana", + 0x3060, + "dakatakana", + 0x30c0, + "dalarabic", + 0x062f, + "dalet", + 0x05d3, + "daletdagesh", + 0xfb33, + "daletdageshhebrew", + 0xfb33, + "dalethebrew", + 0x05d3, + "dalfinalarabic", + 0xfeaa, + "dammaarabic", + 0x064f, + "dammalowarabic", + 0x064f, + "dammatanaltonearabic", + 0x064c, + "dammatanarabic", + 0x064c, + "danda", + 0x0964, + "dargahebrew", + 0x05a7, + "dargalefthebrew", + 0x05a7, + "dasiapneumatacyrilliccmb", + 0x0485, + "dblGrave", + 0xf6d3, + "dblanglebracketleft", + 0x300a, + "dblanglebracketleftvertical", + 0xfe3d, + "dblanglebracketright", + 0x300b, + "dblanglebracketrightvertical", + 0xfe3e, + "dblarchinvertedbelowcmb", + 0x032b, + "dblarrowleft", + 0x21d4, + "dblarrowright", + 0x21d2, + "dbldanda", + 0x0965, + "dblgrave", + 0xf6d6, + "dblgravecmb", + 0x030f, + "dblintegral", + 0x222c, + "dbllowline", + 0x2017, + "dbllowlinecmb", + 0x0333, + "dbloverlinecmb", + 0x033f, + "dblprimemod", + 0x02ba, + "dblverticalbar", + 0x2016, + "dblverticallineabovecmb", + 0x030e, + "dbopomofo", + 0x3109, + "dbsquare", + 0x33c8, + "dcaron", + 0x010f, + "dcedilla", + 0x1e11, + "dcircle", + 0x24d3, + "dcircumflexbelow", + 0x1e13, + "dcroat", + 0x0111, + "ddabengali", + 0x09a1, + "ddadeva", + 0x0921, + "ddagujarati", + 0x0aa1, + "ddagurmukhi", + 0x0a21, + "ddalarabic", + 0x0688, + "ddalfinalarabic", + 0xfb89, + "dddhadeva", + 0x095c, + "ddhabengali", + 0x09a2, + "ddhadeva", + 0x0922, + "ddhagujarati", + 0x0aa2, + "ddhagurmukhi", + 0x0a22, + "ddotaccent", + 0x1e0b, + "ddotbelow", + 0x1e0d, + "decimalseparatorarabic", + 0x066b, + "decimalseparatorpersian", + 0x066b, + "decyrillic", + 0x0434, + "degree", + 0x00b0, + "dehihebrew", + 0x05ad, + "dehiragana", + 0x3067, + "deicoptic", + 0x03ef, + "dekatakana", + 0x30c7, + "deleteleft", + 0x232b, + "deleteright", + 0x2326, + "delta", + 0x03b4, + "deltaturned", + 0x018d, + "denominatorminusonenumeratorbengali", + 0x09f8, + "dezh", + 0x02a4, + "dhabengali", + 0x09a7, + "dhadeva", + 0x0927, + "dhagujarati", + 0x0aa7, + "dhagurmukhi", + 0x0a27, + "dhook", + 0x0257, + "dialytikatonos", + 0x0385, + "dialytikatonoscmb", + 0x0344, + "diamond", + 0x2666, + "diamondsuitwhite", + 0x2662, + "dieresis", + 0x00a8, + "dieresisacute", + 0xf6d7, + "dieresisbelowcmb", + 0x0324, + "dieresiscmb", + 0x0308, + "dieresisgrave", + 0xf6d8, + "dieresistonos", + 0x0385, + "dihiragana", + 0x3062, + "dikatakana", + 0x30c2, + "dittomark", + 0x3003, + "divide", + 0x00f7, + "divides", + 0x2223, + "divisionslash", + 0x2215, + "djecyrillic", + 0x0452, + "dkshade", + 0x2593, + "dlinebelow", + 0x1e0f, + "dlsquare", + 0x3397, + "dmacron", + 0x0111, + "dmonospace", + 0xff44, + "dnblock", + 0x2584, + "dochadathai", + 0x0e0e, + "dodekthai", + 0x0e14, + "dohiragana", + 0x3069, + "dokatakana", + 0x30c9, + "dollar", + 0x0024, + "dollarinferior", + 0xf6e3, + "dollarmonospace", + 0xff04, + "dollaroldstyle", + 0xf724, + "dollarsmall", + 0xfe69, + "dollarsuperior", + 0xf6e4, + "dong", + 0x20ab, + "dorusquare", + 0x3326, + "dotaccent", + 0x02d9, + "dotaccentcmb", + 0x0307, + "dotbelowcmb", + 0x0323, + "dotbelowcomb", + 0x0323, + "dotkatakana", + 0x30fb, + "dotlessi", + 0x0131, + "dotlessj", + 0xf6be, + "dotlessjstrokehook", + 0x0284, + "dotmath", + 0x22c5, + "dottedcircle", + 0x25cc, + "doubleyodpatah", + 0xfb1f, + "doubleyodpatahhebrew", + 0xfb1f, + "downtackbelowcmb", + 0x031e, + "downtackmod", + 0x02d5, + "dparen", + 0x249f, + "dsuperior", + 0xf6eb, + "dtail", + 0x0256, + "dtopbar", + 0x018c, + "duhiragana", + 0x3065, + "dukatakana", + 0x30c5, + "dz", + 0x01f3, + "dzaltone", + 0x02a3, + "dzcaron", + 0x01c6, + "dzcurl", + 0x02a5, + "dzeabkhasiancyrillic", + 0x04e1, + "dzecyrillic", + 0x0455, + "dzhecyrillic", + 0x045f, + "e", + 0x0065, + "eacute", + 0x00e9, + "earth", + 0x2641, + "ebengali", + 0x098f, + "ebopomofo", + 0x311c, + "ebreve", + 0x0115, + "ecandradeva", + 0x090d, + "ecandragujarati", + 0x0a8d, + "ecandravowelsigndeva", + 0x0945, + "ecandravowelsigngujarati", + 0x0ac5, + "ecaron", + 0x011b, + "ecedillabreve", + 0x1e1d, + "echarmenian", + 0x0565, + "echyiwnarmenian", + 0x0587, + "ecircle", + 0x24d4, + "ecircumflex", + 0x00ea, + "ecircumflexacute", + 0x1ebf, + "ecircumflexbelow", + 0x1e19, + "ecircumflexdotbelow", + 0x1ec7, + "ecircumflexgrave", + 0x1ec1, + "ecircumflexhookabove", + 0x1ec3, + "ecircumflextilde", + 0x1ec5, + "ecyrillic", + 0x0454, + "edblgrave", + 0x0205, + "edeva", + 0x090f, + "edieresis", + 0x00eb, + "edot", + 0x0117, + "edotaccent", + 0x0117, + "edotbelow", + 0x1eb9, + "eegurmukhi", + 0x0a0f, + "eematragurmukhi", + 0x0a47, + "efcyrillic", + 0x0444, + "egrave", + 0x00e8, + "egujarati", + 0x0a8f, + "eharmenian", + 0x0567, + "ehbopomofo", + 0x311d, + "ehiragana", + 0x3048, + "ehookabove", + 0x1ebb, + "eibopomofo", + 0x311f, + "eight", + 0x0038, + "eightarabic", + 0x0668, + "eightbengali", + 0x09ee, + "eightcircle", + 0x2467, + "eightcircleinversesansserif", + 0x2791, + "eightdeva", + 0x096e, + "eighteencircle", + 0x2471, + "eighteenparen", + 0x2485, + "eighteenperiod", + 0x2499, + "eightgujarati", + 0x0aee, + "eightgurmukhi", + 0x0a6e, + "eighthackarabic", + 0x0668, + "eighthangzhou", + 0x3028, + "eighthnotebeamed", + 0x266b, + "eightideographicparen", + 0x3227, + "eightinferior", + 0x2088, + "eightmonospace", + 0xff18, + "eightoldstyle", + 0xf738, + "eightparen", + 0x247b, + "eightperiod", + 0x248f, + "eightpersian", + 0x06f8, + "eightroman", + 0x2177, + "eightsuperior", + 0x2078, + "eightthai", + 0x0e58, + "einvertedbreve", + 0x0207, + "eiotifiedcyrillic", + 0x0465, + "ekatakana", + 0x30a8, + "ekatakanahalfwidth", + 0xff74, + "ekonkargurmukhi", + 0x0a74, + "ekorean", + 0x3154, + "elcyrillic", + 0x043b, + "element", + 0x2208, + "elevencircle", + 0x246a, + "elevenparen", + 0x247e, + "elevenperiod", + 0x2492, + "elevenroman", + 0x217a, + "ellipsis", + 0x2026, + "ellipsisvertical", + 0x22ee, + "emacron", + 0x0113, + "emacronacute", + 0x1e17, + "emacrongrave", + 0x1e15, + "emcyrillic", + 0x043c, + "emdash", + 0x2014, + "emdashvertical", + 0xfe31, + "emonospace", + 0xff45, + "emphasismarkarmenian", + 0x055b, + "emptyset", + 0x2205, + "enbopomofo", + 0x3123, + "encyrillic", + 0x043d, + "endash", + 0x2013, + "endashvertical", + 0xfe32, + "endescendercyrillic", + 0x04a3, + "eng", + 0x014b, + "engbopomofo", + 0x3125, + "enghecyrillic", + 0x04a5, + "enhookcyrillic", + 0x04c8, + "enspace", + 0x2002, + "eogonek", + 0x0119, + "eokorean", + 0x3153, + "eopen", + 0x025b, + "eopenclosed", + 0x029a, + "eopenreversed", + 0x025c, + "eopenreversedclosed", + 0x025e, + "eopenreversedhook", + 0x025d, + "eparen", + 0x24a0, + "epsilon", + 0x03b5, + "epsilontonos", + 0x03ad, + "equal", + 0x003d, + "equalmonospace", + 0xff1d, + "equalsmall", + 0xfe66, + "equalsuperior", + 0x207c, + "equivalence", + 0x2261, + "erbopomofo", + 0x3126, + "ercyrillic", + 0x0440, + "ereversed", + 0x0258, + "ereversedcyrillic", + 0x044d, + "escyrillic", + 0x0441, + "esdescendercyrillic", + 0x04ab, + "esh", + 0x0283, + "eshcurl", + 0x0286, + "eshortdeva", + 0x090e, + "eshortvowelsigndeva", + 0x0946, + "eshreversedloop", + 0x01aa, + "eshsquatreversed", + 0x0285, + "esmallhiragana", + 0x3047, + "esmallkatakana", + 0x30a7, + "esmallkatakanahalfwidth", + 0xff6a, + "estimated", + 0x212e, + "esuperior", + 0xf6ec, + "eta", + 0x03b7, + "etarmenian", + 0x0568, + "etatonos", + 0x03ae, + "eth", + 0x00f0, + "etilde", + 0x1ebd, + "etildebelow", + 0x1e1b, + "etnahtafoukhhebrew", + 0x0591, + "etnahtafoukhlefthebrew", + 0x0591, + "etnahtahebrew", + 0x0591, + "etnahtalefthebrew", + 0x0591, + "eturned", + 0x01dd, + "eukorean", + 0x3161, + "euro", + 0x20ac, + "evowelsignbengali", + 0x09c7, + "evowelsigndeva", + 0x0947, + "evowelsigngujarati", + 0x0ac7, + "exclam", + 0x0021, + "exclamarmenian", + 0x055c, + "exclamdbl", + 0x203c, + "exclamdown", + 0x00a1, + "exclamdownsmall", + 0xf7a1, + "exclammonospace", + 0xff01, + "exclamsmall", + 0xf721, + "existential", + 0x2203, + "ezh", + 0x0292, + "ezhcaron", + 0x01ef, + "ezhcurl", + 0x0293, + "ezhreversed", + 0x01b9, + "ezhtail", + 0x01ba, + "f", + 0x0066, + "fadeva", + 0x095e, + "fagurmukhi", + 0x0a5e, + "fahrenheit", + 0x2109, + "fathaarabic", + 0x064e, + "fathalowarabic", + 0x064e, + "fathatanarabic", + 0x064b, + "fbopomofo", + 0x3108, + "fcircle", + 0x24d5, + "fdotaccent", + 0x1e1f, + "feharabic", + 0x0641, + "feharmenian", + 0x0586, + "fehfinalarabic", + 0xfed2, + "fehinitialarabic", + 0xfed3, + "fehmedialarabic", + 0xfed4, + "feicoptic", + 0x03e5, + "female", + 0x2640, + "ff", + 0xfb00, + "f_f", + 0xfb00, + "ffi", + 0xfb03, + "ffl", + 0xfb04, + "fi", + 0xfb01, + "fifteencircle", + 0x246e, + "fifteenparen", + 0x2482, + "fifteenperiod", + 0x2496, + "figuredash", + 0x2012, + "filledbox", + 0x25a0, + "filledrect", + 0x25ac, + "finalkaf", + 0x05da, + "finalkafdagesh", + 0xfb3a, + "finalkafdageshhebrew", + 0xfb3a, + "finalkafhebrew", + 0x05da, + "finalmem", + 0x05dd, + "finalmemhebrew", + 0x05dd, + "finalnun", + 0x05df, + "finalnunhebrew", + 0x05df, + "finalpe", + 0x05e3, + "finalpehebrew", + 0x05e3, + "finaltsadi", + 0x05e5, + "finaltsadihebrew", + 0x05e5, + "firsttonechinese", + 0x02c9, + "fisheye", + 0x25c9, + "fitacyrillic", + 0x0473, + "five", + 0x0035, + "fivearabic", + 0x0665, + "fivebengali", + 0x09eb, + "fivecircle", + 0x2464, + "fivecircleinversesansserif", + 0x278e, + "fivedeva", + 0x096b, + "fiveeighths", + 0x215d, + "fivegujarati", + 0x0aeb, + "fivegurmukhi", + 0x0a6b, + "fivehackarabic", + 0x0665, + "fivehangzhou", + 0x3025, + "fiveideographicparen", + 0x3224, + "fiveinferior", + 0x2085, + "fivemonospace", + 0xff15, + "fiveoldstyle", + 0xf735, + "fiveparen", + 0x2478, + "fiveperiod", + 0x248c, + "fivepersian", + 0x06f5, + "fiveroman", + 0x2174, + "fivesuperior", + 0x2075, + "fivethai", + 0x0e55, + "fl", + 0xfb02, + "florin", + 0x0192, + "fmonospace", + 0xff46, + "fmsquare", + 0x3399, + "fofanthai", + 0x0e1f, + "fofathai", + 0x0e1d, + "fongmanthai", + 0x0e4f, + "forall", + 0x2200, + "four", + 0x0034, + "fourarabic", + 0x0664, + "fourbengali", + 0x09ea, + "fourcircle", + 0x2463, + "fourcircleinversesansserif", + 0x278d, + "fourdeva", + 0x096a, + "fourgujarati", + 0x0aea, + "fourgurmukhi", + 0x0a6a, + "fourhackarabic", + 0x0664, + "fourhangzhou", + 0x3024, + "fourideographicparen", + 0x3223, + "fourinferior", + 0x2084, + "fourmonospace", + 0xff14, + "fournumeratorbengali", + 0x09f7, + "fouroldstyle", + 0xf734, + "fourparen", + 0x2477, + "fourperiod", + 0x248b, + "fourpersian", + 0x06f4, + "fourroman", + 0x2173, + "foursuperior", + 0x2074, + "fourteencircle", + 0x246d, + "fourteenparen", + 0x2481, + "fourteenperiod", + 0x2495, + "fourthai", + 0x0e54, + "fourthtonechinese", + 0x02cb, + "fparen", + 0x24a1, + "fraction", + 0x2044, + "franc", + 0x20a3, + "g", + 0x0067, + "gabengali", + 0x0997, + "gacute", + 0x01f5, + "gadeva", + 0x0917, + "gafarabic", + 0x06af, + "gaffinalarabic", + 0xfb93, + "gafinitialarabic", + 0xfb94, + "gafmedialarabic", + 0xfb95, + "gagujarati", + 0x0a97, + "gagurmukhi", + 0x0a17, + "gahiragana", + 0x304c, + "gakatakana", + 0x30ac, + "gamma", + 0x03b3, + "gammalatinsmall", + 0x0263, + "gammasuperior", + 0x02e0, + "gangiacoptic", + 0x03eb, + "gbopomofo", + 0x310d, + "gbreve", + 0x011f, + "gcaron", + 0x01e7, + "gcedilla", + 0x0123, + "gcircle", + 0x24d6, + "gcircumflex", + 0x011d, + "gcommaaccent", + 0x0123, + "gdot", + 0x0121, + "gdotaccent", + 0x0121, + "gecyrillic", + 0x0433, + "gehiragana", + 0x3052, + "gekatakana", + 0x30b2, + "geometricallyequal", + 0x2251, + "gereshaccenthebrew", + 0x059c, + "gereshhebrew", + 0x05f3, + "gereshmuqdamhebrew", + 0x059d, + "germandbls", + 0x00df, + "gershayimaccenthebrew", + 0x059e, + "gershayimhebrew", + 0x05f4, + "getamark", + 0x3013, + "ghabengali", + 0x0998, + "ghadarmenian", + 0x0572, + "ghadeva", + 0x0918, + "ghagujarati", + 0x0a98, + "ghagurmukhi", + 0x0a18, + "ghainarabic", + 0x063a, + "ghainfinalarabic", + 0xfece, + "ghaininitialarabic", + 0xfecf, + "ghainmedialarabic", + 0xfed0, + "ghemiddlehookcyrillic", + 0x0495, + "ghestrokecyrillic", + 0x0493, + "gheupturncyrillic", + 0x0491, + "ghhadeva", + 0x095a, + "ghhagurmukhi", + 0x0a5a, + "ghook", + 0x0260, + "ghzsquare", + 0x3393, + "gihiragana", + 0x304e, + "gikatakana", + 0x30ae, + "gimarmenian", + 0x0563, + "gimel", + 0x05d2, + "gimeldagesh", + 0xfb32, + "gimeldageshhebrew", + 0xfb32, + "gimelhebrew", + 0x05d2, + "gjecyrillic", + 0x0453, + "glottalinvertedstroke", + 0x01be, + "glottalstop", + 0x0294, + "glottalstopinverted", + 0x0296, + "glottalstopmod", + 0x02c0, + "glottalstopreversed", + 0x0295, + "glottalstopreversedmod", + 0x02c1, + "glottalstopreversedsuperior", + 0x02e4, + "glottalstopstroke", + 0x02a1, + "glottalstopstrokereversed", + 0x02a2, + "gmacron", + 0x1e21, + "gmonospace", + 0xff47, + "gohiragana", + 0x3054, + "gokatakana", + 0x30b4, + "gparen", + 0x24a2, + "gpasquare", + 0x33ac, + "gradient", + 0x2207, + "grave", + 0x0060, + "gravebelowcmb", + 0x0316, + "gravecmb", + 0x0300, + "gravecomb", + 0x0300, + "gravedeva", + 0x0953, + "gravelowmod", + 0x02ce, + "gravemonospace", + 0xff40, + "gravetonecmb", + 0x0340, + "greater", + 0x003e, + "greaterequal", + 0x2265, + "greaterequalorless", + 0x22db, + "greatermonospace", + 0xff1e, + "greaterorequivalent", + 0x2273, + "greaterorless", + 0x2277, + "greateroverequal", + 0x2267, + "greatersmall", + 0xfe65, + "gscript", + 0x0261, + "gstroke", + 0x01e5, + "guhiragana", + 0x3050, + "guillemotleft", + 0x00ab, + "guillemotright", + 0x00bb, + "guilsinglleft", + 0x2039, + "guilsinglright", + 0x203a, + "gukatakana", + 0x30b0, + "guramusquare", + 0x3318, + "gysquare", + 0x33c9, + "h", + 0x0068, + "haabkhasiancyrillic", + 0x04a9, + "haaltonearabic", + 0x06c1, + "habengali", + 0x09b9, + "hadescendercyrillic", + 0x04b3, + "hadeva", + 0x0939, + "hagujarati", + 0x0ab9, + "hagurmukhi", + 0x0a39, + "haharabic", + 0x062d, + "hahfinalarabic", + 0xfea2, + "hahinitialarabic", + 0xfea3, + "hahiragana", + 0x306f, + "hahmedialarabic", + 0xfea4, + "haitusquare", + 0x332a, + "hakatakana", + 0x30cf, + "hakatakanahalfwidth", + 0xff8a, + "halantgurmukhi", + 0x0a4d, + "hamzaarabic", + 0x0621, + "hamzalowarabic", + 0x0621, + "hangulfiller", + 0x3164, + "hardsigncyrillic", + 0x044a, + "harpoonleftbarbup", + 0x21bc, + "harpoonrightbarbup", + 0x21c0, + "hasquare", + 0x33ca, + "hatafpatah", + 0x05b2, + "hatafpatah16", + 0x05b2, + "hatafpatah23", + 0x05b2, + "hatafpatah2f", + 0x05b2, + "hatafpatahhebrew", + 0x05b2, + "hatafpatahnarrowhebrew", + 0x05b2, + "hatafpatahquarterhebrew", + 0x05b2, + "hatafpatahwidehebrew", + 0x05b2, + "hatafqamats", + 0x05b3, + "hatafqamats1b", + 0x05b3, + "hatafqamats28", + 0x05b3, + "hatafqamats34", + 0x05b3, + "hatafqamatshebrew", + 0x05b3, + "hatafqamatsnarrowhebrew", + 0x05b3, + "hatafqamatsquarterhebrew", + 0x05b3, + "hatafqamatswidehebrew", + 0x05b3, + "hatafsegol", + 0x05b1, + "hatafsegol17", + 0x05b1, + "hatafsegol24", + 0x05b1, + "hatafsegol30", + 0x05b1, + "hatafsegolhebrew", + 0x05b1, + "hatafsegolnarrowhebrew", + 0x05b1, + "hatafsegolquarterhebrew", + 0x05b1, + "hatafsegolwidehebrew", + 0x05b1, + "hbar", + 0x0127, + "hbopomofo", + 0x310f, + "hbrevebelow", + 0x1e2b, + "hcedilla", + 0x1e29, + "hcircle", + 0x24d7, + "hcircumflex", + 0x0125, + "hdieresis", + 0x1e27, + "hdotaccent", + 0x1e23, + "hdotbelow", + 0x1e25, + "he", + 0x05d4, + "heart", + 0x2665, + "heartsuitblack", + 0x2665, + "heartsuitwhite", + 0x2661, + "hedagesh", + 0xfb34, + "hedageshhebrew", + 0xfb34, + "hehaltonearabic", + 0x06c1, + "heharabic", + 0x0647, + "hehebrew", + 0x05d4, + "hehfinalaltonearabic", + 0xfba7, + "hehfinalalttwoarabic", + 0xfeea, + "hehfinalarabic", + 0xfeea, + "hehhamzaabovefinalarabic", + 0xfba5, + "hehhamzaaboveisolatedarabic", + 0xfba4, + "hehinitialaltonearabic", + 0xfba8, + "hehinitialarabic", + 0xfeeb, + "hehiragana", + 0x3078, + "hehmedialaltonearabic", + 0xfba9, + "hehmedialarabic", + 0xfeec, + "heiseierasquare", + 0x337b, + "hekatakana", + 0x30d8, + "hekatakanahalfwidth", + 0xff8d, + "hekutaarusquare", + 0x3336, + "henghook", + 0x0267, + "herutusquare", + 0x3339, + "het", + 0x05d7, + "hethebrew", + 0x05d7, + "hhook", + 0x0266, + "hhooksuperior", + 0x02b1, + "hieuhacirclekorean", + 0x327b, + "hieuhaparenkorean", + 0x321b, + "hieuhcirclekorean", + 0x326d, + "hieuhkorean", + 0x314e, + "hieuhparenkorean", + 0x320d, + "hihiragana", + 0x3072, + "hikatakana", + 0x30d2, + "hikatakanahalfwidth", + 0xff8b, + "hiriq", + 0x05b4, + "hiriq14", + 0x05b4, + "hiriq21", + 0x05b4, + "hiriq2d", + 0x05b4, + "hiriqhebrew", + 0x05b4, + "hiriqnarrowhebrew", + 0x05b4, + "hiriqquarterhebrew", + 0x05b4, + "hiriqwidehebrew", + 0x05b4, + "hlinebelow", + 0x1e96, + "hmonospace", + 0xff48, + "hoarmenian", + 0x0570, + "hohipthai", + 0x0e2b, + "hohiragana", + 0x307b, + "hokatakana", + 0x30db, + "hokatakanahalfwidth", + 0xff8e, + "holam", + 0x05b9, + "holam19", + 0x05b9, + "holam26", + 0x05b9, + "holam32", + 0x05b9, + "holamhebrew", + 0x05b9, + "holamnarrowhebrew", + 0x05b9, + "holamquarterhebrew", + 0x05b9, + "holamwidehebrew", + 0x05b9, + "honokhukthai", + 0x0e2e, + "hookabovecomb", + 0x0309, + "hookcmb", + 0x0309, + "hookpalatalizedbelowcmb", + 0x0321, + "hookretroflexbelowcmb", + 0x0322, + "hoonsquare", + 0x3342, + "horicoptic", + 0x03e9, + "horizontalbar", + 0x2015, + "horncmb", + 0x031b, + "hotsprings", + 0x2668, + "house", + 0x2302, + "hparen", + 0x24a3, + "hsuperior", + 0x02b0, + "hturned", + 0x0265, + "huhiragana", + 0x3075, + "huiitosquare", + 0x3333, + "hukatakana", + 0x30d5, + "hukatakanahalfwidth", + 0xff8c, + "hungarumlaut", + 0x02dd, + "hungarumlautcmb", + 0x030b, + "hv", + 0x0195, + "hyphen", + 0x002d, + "hypheninferior", + 0xf6e5, + "hyphenmonospace", + 0xff0d, + "hyphensmall", + 0xfe63, + "hyphensuperior", + 0xf6e6, + "hyphentwo", + 0x2010, + "i", + 0x0069, + "iacute", + 0x00ed, + "iacyrillic", + 0x044f, + "ibengali", + 0x0987, + "ibopomofo", + 0x3127, + "ibreve", + 0x012d, + "icaron", + 0x01d0, + "icircle", + 0x24d8, + "icircumflex", + 0x00ee, + "icyrillic", + 0x0456, + "idblgrave", + 0x0209, + "ideographearthcircle", + 0x328f, + "ideographfirecircle", + 0x328b, + "ideographicallianceparen", + 0x323f, + "ideographiccallparen", + 0x323a, + "ideographiccentrecircle", + 0x32a5, + "ideographicclose", + 0x3006, + "ideographiccomma", + 0x3001, + "ideographiccommaleft", + 0xff64, + "ideographiccongratulationparen", + 0x3237, + "ideographiccorrectcircle", + 0x32a3, + "ideographicearthparen", + 0x322f, + "ideographicenterpriseparen", + 0x323d, + "ideographicexcellentcircle", + 0x329d, + "ideographicfestivalparen", + 0x3240, + "ideographicfinancialcircle", + 0x3296, + "ideographicfinancialparen", + 0x3236, + "ideographicfireparen", + 0x322b, + "ideographichaveparen", + 0x3232, + "ideographichighcircle", + 0x32a4, + "ideographiciterationmark", + 0x3005, + "ideographiclaborcircle", + 0x3298, + "ideographiclaborparen", + 0x3238, + "ideographicleftcircle", + 0x32a7, + "ideographiclowcircle", + 0x32a6, + "ideographicmedicinecircle", + 0x32a9, + "ideographicmetalparen", + 0x322e, + "ideographicmoonparen", + 0x322a, + "ideographicnameparen", + 0x3234, + "ideographicperiod", + 0x3002, + "ideographicprintcircle", + 0x329e, + "ideographicreachparen", + 0x3243, + "ideographicrepresentparen", + 0x3239, + "ideographicresourceparen", + 0x323e, + "ideographicrightcircle", + 0x32a8, + "ideographicsecretcircle", + 0x3299, + "ideographicselfparen", + 0x3242, + "ideographicsocietyparen", + 0x3233, + "ideographicspace", + 0x3000, + "ideographicspecialparen", + 0x3235, + "ideographicstockparen", + 0x3231, + "ideographicstudyparen", + 0x323b, + "ideographicsunparen", + 0x3230, + "ideographicsuperviseparen", + 0x323c, + "ideographicwaterparen", + 0x322c, + "ideographicwoodparen", + 0x322d, + "ideographiczero", + 0x3007, + "ideographmetalcircle", + 0x328e, + "ideographmooncircle", + 0x328a, + "ideographnamecircle", + 0x3294, + "ideographsuncircle", + 0x3290, + "ideographwatercircle", + 0x328c, + "ideographwoodcircle", + 0x328d, + "ideva", + 0x0907, + "idieresis", + 0x00ef, + "idieresisacute", + 0x1e2f, + "idieresiscyrillic", + 0x04e5, + "idotbelow", + 0x1ecb, + "iebrevecyrillic", + 0x04d7, + "iecyrillic", + 0x0435, + "ieungacirclekorean", + 0x3275, + "ieungaparenkorean", + 0x3215, + "ieungcirclekorean", + 0x3267, + "ieungkorean", + 0x3147, + "ieungparenkorean", + 0x3207, + "igrave", + 0x00ec, + "igujarati", + 0x0a87, + "igurmukhi", + 0x0a07, + "ihiragana", + 0x3044, + "ihookabove", + 0x1ec9, + "iibengali", + 0x0988, + "iicyrillic", + 0x0438, + "iideva", + 0x0908, + "iigujarati", + 0x0a88, + "iigurmukhi", + 0x0a08, + "iimatragurmukhi", + 0x0a40, + "iinvertedbreve", + 0x020b, + "iishortcyrillic", + 0x0439, + "iivowelsignbengali", + 0x09c0, + "iivowelsigndeva", + 0x0940, + "iivowelsigngujarati", + 0x0ac0, + "ij", + 0x0133, + "ikatakana", + 0x30a4, + "ikatakanahalfwidth", + 0xff72, + "ikorean", + 0x3163, + "ilde", + 0x02dc, + "iluyhebrew", + 0x05ac, + "imacron", + 0x012b, + "imacroncyrillic", + 0x04e3, + "imageorapproximatelyequal", + 0x2253, + "imatragurmukhi", + 0x0a3f, + "imonospace", + 0xff49, + "increment", + 0x2206, + "infinity", + 0x221e, + "iniarmenian", + 0x056b, + "integral", + 0x222b, + "integralbottom", + 0x2321, + "integralbt", + 0x2321, + "integralex", + 0xf8f5, + "integraltop", + 0x2320, + "integraltp", + 0x2320, + "intersection", + 0x2229, + "intisquare", + 0x3305, + "invbullet", + 0x25d8, + "invcircle", + 0x25d9, + "invsmileface", + 0x263b, + "iocyrillic", + 0x0451, + "iogonek", + 0x012f, + "iota", + 0x03b9, + "iotadieresis", + 0x03ca, + "iotadieresistonos", + 0x0390, + "iotalatin", + 0x0269, + "iotatonos", + 0x03af, + "iparen", + 0x24a4, + "irigurmukhi", + 0x0a72, + "ismallhiragana", + 0x3043, + "ismallkatakana", + 0x30a3, + "ismallkatakanahalfwidth", + 0xff68, + "issharbengali", + 0x09fa, + "istroke", + 0x0268, + "isuperior", + 0xf6ed, + "iterationhiragana", + 0x309d, + "iterationkatakana", + 0x30fd, + "itilde", + 0x0129, + "itildebelow", + 0x1e2d, + "iubopomofo", + 0x3129, + "iucyrillic", + 0x044e, + "ivowelsignbengali", + 0x09bf, + "ivowelsigndeva", + 0x093f, + "ivowelsigngujarati", + 0x0abf, + "izhitsacyrillic", + 0x0475, + "izhitsadblgravecyrillic", + 0x0477, + "j", + 0x006a, + "jaarmenian", + 0x0571, + "jabengali", + 0x099c, + "jadeva", + 0x091c, + "jagujarati", + 0x0a9c, + "jagurmukhi", + 0x0a1c, + "jbopomofo", + 0x3110, + "jcaron", + 0x01f0, + "jcircle", + 0x24d9, + "jcircumflex", + 0x0135, + "jcrossedtail", + 0x029d, + "jdotlessstroke", + 0x025f, + "jecyrillic", + 0x0458, + "jeemarabic", + 0x062c, + "jeemfinalarabic", + 0xfe9e, + "jeeminitialarabic", + 0xfe9f, + "jeemmedialarabic", + 0xfea0, + "jeharabic", + 0x0698, + "jehfinalarabic", + 0xfb8b, + "jhabengali", + 0x099d, + "jhadeva", + 0x091d, + "jhagujarati", + 0x0a9d, + "jhagurmukhi", + 0x0a1d, + "jheharmenian", + 0x057b, + "jis", + 0x3004, + "jmonospace", + 0xff4a, + "jparen", + 0x24a5, + "jsuperior", + 0x02b2, + "k", + 0x006b, + "kabashkircyrillic", + 0x04a1, + "kabengali", + 0x0995, + "kacute", + 0x1e31, + "kacyrillic", + 0x043a, + "kadescendercyrillic", + 0x049b, + "kadeva", + 0x0915, + "kaf", + 0x05db, + "kafarabic", + 0x0643, + "kafdagesh", + 0xfb3b, + "kafdageshhebrew", + 0xfb3b, + "kaffinalarabic", + 0xfeda, + "kafhebrew", + 0x05db, + "kafinitialarabic", + 0xfedb, + "kafmedialarabic", + 0xfedc, + "kafrafehebrew", + 0xfb4d, + "kagujarati", + 0x0a95, + "kagurmukhi", + 0x0a15, + "kahiragana", + 0x304b, + "kahookcyrillic", + 0x04c4, + "kakatakana", + 0x30ab, + "kakatakanahalfwidth", + 0xff76, + "kappa", + 0x03ba, + "kappasymbolgreek", + 0x03f0, + "kapyeounmieumkorean", + 0x3171, + "kapyeounphieuphkorean", + 0x3184, + "kapyeounpieupkorean", + 0x3178, + "kapyeounssangpieupkorean", + 0x3179, + "karoriisquare", + 0x330d, + "kashidaautoarabic", + 0x0640, + "kashidaautonosidebearingarabic", + 0x0640, + "kasmallkatakana", + 0x30f5, + "kasquare", + 0x3384, + "kasraarabic", + 0x0650, + "kasratanarabic", + 0x064d, + "kastrokecyrillic", + 0x049f, + "katahiraprolongmarkhalfwidth", + 0xff70, + "kaverticalstrokecyrillic", + 0x049d, + "kbopomofo", + 0x310e, + "kcalsquare", + 0x3389, + "kcaron", + 0x01e9, + "kcedilla", + 0x0137, + "kcircle", + 0x24da, + "kcommaaccent", + 0x0137, + "kdotbelow", + 0x1e33, + "keharmenian", + 0x0584, + "kehiragana", + 0x3051, + "kekatakana", + 0x30b1, + "kekatakanahalfwidth", + 0xff79, + "kenarmenian", + 0x056f, + "kesmallkatakana", + 0x30f6, + "kgreenlandic", + 0x0138, + "khabengali", + 0x0996, + "khacyrillic", + 0x0445, + "khadeva", + 0x0916, + "khagujarati", + 0x0a96, + "khagurmukhi", + 0x0a16, + "khaharabic", + 0x062e, + "khahfinalarabic", + 0xfea6, + "khahinitialarabic", + 0xfea7, + "khahmedialarabic", + 0xfea8, + "kheicoptic", + 0x03e7, + "khhadeva", + 0x0959, + "khhagurmukhi", + 0x0a59, + "khieukhacirclekorean", + 0x3278, + "khieukhaparenkorean", + 0x3218, + "khieukhcirclekorean", + 0x326a, + "khieukhkorean", + 0x314b, + "khieukhparenkorean", + 0x320a, + "khokhaithai", + 0x0e02, + "khokhonthai", + 0x0e05, + "khokhuatthai", + 0x0e03, + "khokhwaithai", + 0x0e04, + "khomutthai", + 0x0e5b, + "khook", + 0x0199, + "khorakhangthai", + 0x0e06, + "khzsquare", + 0x3391, + "kihiragana", + 0x304d, + "kikatakana", + 0x30ad, + "kikatakanahalfwidth", + 0xff77, + "kiroguramusquare", + 0x3315, + "kiromeetorusquare", + 0x3316, + "kirosquare", + 0x3314, + "kiyeokacirclekorean", + 0x326e, + "kiyeokaparenkorean", + 0x320e, + "kiyeokcirclekorean", + 0x3260, + "kiyeokkorean", + 0x3131, + "kiyeokparenkorean", + 0x3200, + "kiyeoksioskorean", + 0x3133, + "kjecyrillic", + 0x045c, + "klinebelow", + 0x1e35, + "klsquare", + 0x3398, + "kmcubedsquare", + 0x33a6, + "kmonospace", + 0xff4b, + "kmsquaredsquare", + 0x33a2, + "kohiragana", + 0x3053, + "kohmsquare", + 0x33c0, + "kokaithai", + 0x0e01, + "kokatakana", + 0x30b3, + "kokatakanahalfwidth", + 0xff7a, + "kooposquare", + 0x331e, + "koppacyrillic", + 0x0481, + "koreanstandardsymbol", + 0x327f, + "koroniscmb", + 0x0343, + "kparen", + 0x24a6, + "kpasquare", + 0x33aa, + "ksicyrillic", + 0x046f, + "ktsquare", + 0x33cf, + "kturned", + 0x029e, + "kuhiragana", + 0x304f, + "kukatakana", + 0x30af, + "kukatakanahalfwidth", + 0xff78, + "kvsquare", + 0x33b8, + "kwsquare", + 0x33be, + "l", + 0x006c, + "labengali", + 0x09b2, + "lacute", + 0x013a, + "ladeva", + 0x0932, + "lagujarati", + 0x0ab2, + "lagurmukhi", + 0x0a32, + "lakkhangyaothai", + 0x0e45, + "lamaleffinalarabic", + 0xfefc, + "lamalefhamzaabovefinalarabic", + 0xfef8, + "lamalefhamzaaboveisolatedarabic", + 0xfef7, + "lamalefhamzabelowfinalarabic", + 0xfefa, + "lamalefhamzabelowisolatedarabic", + 0xfef9, + "lamalefisolatedarabic", + 0xfefb, + "lamalefmaddaabovefinalarabic", + 0xfef6, + "lamalefmaddaaboveisolatedarabic", + 0xfef5, + "lamarabic", + 0x0644, + "lambda", + 0x03bb, + "lambdastroke", + 0x019b, + "lamed", + 0x05dc, + "lameddagesh", + 0xfb3c, + "lameddageshhebrew", + 0xfb3c, + "lamedhebrew", + 0x05dc, + "lamfinalarabic", + 0xfede, + "lamhahinitialarabic", + 0xfcca, + "laminitialarabic", + 0xfedf, + "lamjeeminitialarabic", + 0xfcc9, + "lamkhahinitialarabic", + 0xfccb, + "lamlamhehisolatedarabic", + 0xfdf2, + "lammedialarabic", + 0xfee0, + "lammeemhahinitialarabic", + 0xfd88, + "lammeeminitialarabic", + 0xfccc, + "largecircle", + 0x25ef, + "lbar", + 0x019a, + "lbelt", + 0x026c, + "lbopomofo", + 0x310c, + "lcaron", + 0x013e, + "lcedilla", + 0x013c, + "lcircle", + 0x24db, + "lcircumflexbelow", + 0x1e3d, + "lcommaaccent", + 0x013c, + "ldot", + 0x0140, + "ldotaccent", + 0x0140, + "ldotbelow", + 0x1e37, + "ldotbelowmacron", + 0x1e39, + "leftangleabovecmb", + 0x031a, + "lefttackbelowcmb", + 0x0318, + "less", + 0x003c, + "lessequal", + 0x2264, + "lessequalorgreater", + 0x22da, + "lessmonospace", + 0xff1c, + "lessorequivalent", + 0x2272, + "lessorgreater", + 0x2276, + "lessoverequal", + 0x2266, + "lesssmall", + 0xfe64, + "lezh", + 0x026e, + "lfblock", + 0x258c, + "lhookretroflex", + 0x026d, + "lira", + 0x20a4, + "liwnarmenian", + 0x056c, + "lj", + 0x01c9, + "ljecyrillic", + 0x0459, + "ll", + 0xf6c0, + "lladeva", + 0x0933, + "llagujarati", + 0x0ab3, + "llinebelow", + 0x1e3b, + "llladeva", + 0x0934, + "llvocalicbengali", + 0x09e1, + "llvocalicdeva", + 0x0961, + "llvocalicvowelsignbengali", + 0x09e3, + "llvocalicvowelsigndeva", + 0x0963, + "lmiddletilde", + 0x026b, + "lmonospace", + 0xff4c, + "lmsquare", + 0x33d0, + "lochulathai", + 0x0e2c, + "logicaland", + 0x2227, + "logicalnot", + 0x00ac, + "logicalnotreversed", + 0x2310, + "logicalor", + 0x2228, + "lolingthai", + 0x0e25, + "longs", + 0x017f, + "lowlinecenterline", + 0xfe4e, + "lowlinecmb", + 0x0332, + "lowlinedashed", + 0xfe4d, + "lozenge", + 0x25ca, + "lparen", + 0x24a7, + "lslash", + 0x0142, + "lsquare", + 0x2113, + "lsuperior", + 0xf6ee, + "ltshade", + 0x2591, + "luthai", + 0x0e26, + "lvocalicbengali", + 0x098c, + "lvocalicdeva", + 0x090c, + "lvocalicvowelsignbengali", + 0x09e2, + "lvocalicvowelsigndeva", + 0x0962, + "lxsquare", + 0x33d3, + "m", + 0x006d, + "mabengali", + 0x09ae, + "macron", + 0x00af, + "macronbelowcmb", + 0x0331, + "macroncmb", + 0x0304, + "macronlowmod", + 0x02cd, + "macronmonospace", + 0xffe3, + "macute", + 0x1e3f, + "madeva", + 0x092e, + "magujarati", + 0x0aae, + "magurmukhi", + 0x0a2e, + "mahapakhhebrew", + 0x05a4, + "mahapakhlefthebrew", + 0x05a4, + "mahiragana", + 0x307e, + "maichattawalowleftthai", + 0xf895, + "maichattawalowrightthai", + 0xf894, + "maichattawathai", + 0x0e4b, + "maichattawaupperleftthai", + 0xf893, + "maieklowleftthai", + 0xf88c, + "maieklowrightthai", + 0xf88b, + "maiekthai", + 0x0e48, + "maiekupperleftthai", + 0xf88a, + "maihanakatleftthai", + 0xf884, + "maihanakatthai", + 0x0e31, + "maitaikhuleftthai", + 0xf889, + "maitaikhuthai", + 0x0e47, + "maitholowleftthai", + 0xf88f, + "maitholowrightthai", + 0xf88e, + "maithothai", + 0x0e49, + "maithoupperleftthai", + 0xf88d, + "maitrilowleftthai", + 0xf892, + "maitrilowrightthai", + 0xf891, + "maitrithai", + 0x0e4a, + "maitriupperleftthai", + 0xf890, + "maiyamokthai", + 0x0e46, + "makatakana", + 0x30de, + "makatakanahalfwidth", + 0xff8f, + "male", + 0x2642, + "mansyonsquare", + 0x3347, + "maqafhebrew", + 0x05be, + "mars", + 0x2642, + "masoracirclehebrew", + 0x05af, + "masquare", + 0x3383, + "mbopomofo", + 0x3107, + "mbsquare", + 0x33d4, + "mcircle", + 0x24dc, + "mcubedsquare", + 0x33a5, + "mdotaccent", + 0x1e41, + "mdotbelow", + 0x1e43, + "meemarabic", + 0x0645, + "meemfinalarabic", + 0xfee2, + "meeminitialarabic", + 0xfee3, + "meemmedialarabic", + 0xfee4, + "meemmeeminitialarabic", + 0xfcd1, + "meemmeemisolatedarabic", + 0xfc48, + "meetorusquare", + 0x334d, + "mehiragana", + 0x3081, + "meizierasquare", + 0x337e, + "mekatakana", + 0x30e1, + "mekatakanahalfwidth", + 0xff92, + "mem", + 0x05de, + "memdagesh", + 0xfb3e, + "memdageshhebrew", + 0xfb3e, + "memhebrew", + 0x05de, + "menarmenian", + 0x0574, + "merkhahebrew", + 0x05a5, + "merkhakefulahebrew", + 0x05a6, + "merkhakefulalefthebrew", + 0x05a6, + "merkhalefthebrew", + 0x05a5, + "mhook", + 0x0271, + "mhzsquare", + 0x3392, + "middledotkatakanahalfwidth", + 0xff65, + "middot", + 0x00b7, + "mieumacirclekorean", + 0x3272, + "mieumaparenkorean", + 0x3212, + "mieumcirclekorean", + 0x3264, + "mieumkorean", + 0x3141, + "mieumpansioskorean", + 0x3170, + "mieumparenkorean", + 0x3204, + "mieumpieupkorean", + 0x316e, + "mieumsioskorean", + 0x316f, + "mihiragana", + 0x307f, + "mikatakana", + 0x30df, + "mikatakanahalfwidth", + 0xff90, + "minus", + 0x2212, + "minusbelowcmb", + 0x0320, + "minuscircle", + 0x2296, + "minusmod", + 0x02d7, + "minusplus", + 0x2213, + "minute", + 0x2032, + "miribaarusquare", + 0x334a, + "mirisquare", + 0x3349, + "mlonglegturned", + 0x0270, + "mlsquare", + 0x3396, + "mmcubedsquare", + 0x33a3, + "mmonospace", + 0xff4d, + "mmsquaredsquare", + 0x339f, + "mohiragana", + 0x3082, + "mohmsquare", + 0x33c1, + "mokatakana", + 0x30e2, + "mokatakanahalfwidth", + 0xff93, + "molsquare", + 0x33d6, + "momathai", + 0x0e21, + "moverssquare", + 0x33a7, + "moverssquaredsquare", + 0x33a8, + "mparen", + 0x24a8, + "mpasquare", + 0x33ab, + "mssquare", + 0x33b3, + "msuperior", + 0xf6ef, + "mturned", + 0x026f, + "mu", + 0x00b5, + "mu1", + 0x00b5, + "muasquare", + 0x3382, + "muchgreater", + 0x226b, + "muchless", + 0x226a, + "mufsquare", + 0x338c, + "mugreek", + 0x03bc, + "mugsquare", + 0x338d, + "muhiragana", + 0x3080, + "mukatakana", + 0x30e0, + "mukatakanahalfwidth", + 0xff91, + "mulsquare", + 0x3395, + "multiply", + 0x00d7, + "mumsquare", + 0x339b, + "munahhebrew", + 0x05a3, + "munahlefthebrew", + 0x05a3, + "musicalnote", + 0x266a, + "musicalnotedbl", + 0x266b, + "musicflatsign", + 0x266d, + "musicsharpsign", + 0x266f, + "mussquare", + 0x33b2, + "muvsquare", + 0x33b6, + "muwsquare", + 0x33bc, + "mvmegasquare", + 0x33b9, + "mvsquare", + 0x33b7, + "mwmegasquare", + 0x33bf, + "mwsquare", + 0x33bd, + "n", + 0x006e, + "nabengali", + 0x09a8, + "nabla", + 0x2207, + "nacute", + 0x0144, + "nadeva", + 0x0928, + "nagujarati", + 0x0aa8, + "nagurmukhi", + 0x0a28, + "nahiragana", + 0x306a, + "nakatakana", + 0x30ca, + "nakatakanahalfwidth", + 0xff85, + "napostrophe", + 0x0149, + "nasquare", + 0x3381, + "nbopomofo", + 0x310b, + "nbspace", + 0x00a0, + "ncaron", + 0x0148, + "ncedilla", + 0x0146, + "ncircle", + 0x24dd, + "ncircumflexbelow", + 0x1e4b, + "ncommaaccent", + 0x0146, + "ndotaccent", + 0x1e45, + "ndotbelow", + 0x1e47, + "nehiragana", + 0x306d, + "nekatakana", + 0x30cd, + "nekatakanahalfwidth", + 0xff88, + "newsheqelsign", + 0x20aa, + "nfsquare", + 0x338b, + "ngabengali", + 0x0999, + "ngadeva", + 0x0919, + "ngagujarati", + 0x0a99, + "ngagurmukhi", + 0x0a19, + "ngonguthai", + 0x0e07, + "nhiragana", + 0x3093, + "nhookleft", + 0x0272, + "nhookretroflex", + 0x0273, + "nieunacirclekorean", + 0x326f, + "nieunaparenkorean", + 0x320f, + "nieuncieuckorean", + 0x3135, + "nieuncirclekorean", + 0x3261, + "nieunhieuhkorean", + 0x3136, + "nieunkorean", + 0x3134, + "nieunpansioskorean", + 0x3168, + "nieunparenkorean", + 0x3201, + "nieunsioskorean", + 0x3167, + "nieuntikeutkorean", + 0x3166, + "nihiragana", + 0x306b, + "nikatakana", + 0x30cb, + "nikatakanahalfwidth", + 0xff86, + "nikhahitleftthai", + 0xf899, + "nikhahitthai", + 0x0e4d, + "nine", + 0x0039, + "ninearabic", + 0x0669, + "ninebengali", + 0x09ef, + "ninecircle", + 0x2468, + "ninecircleinversesansserif", + 0x2792, + "ninedeva", + 0x096f, + "ninegujarati", + 0x0aef, + "ninegurmukhi", + 0x0a6f, + "ninehackarabic", + 0x0669, + "ninehangzhou", + 0x3029, + "nineideographicparen", + 0x3228, + "nineinferior", + 0x2089, + "ninemonospace", + 0xff19, + "nineoldstyle", + 0xf739, + "nineparen", + 0x247c, + "nineperiod", + 0x2490, + "ninepersian", + 0x06f9, + "nineroman", + 0x2178, + "ninesuperior", + 0x2079, + "nineteencircle", + 0x2472, + "nineteenparen", + 0x2486, + "nineteenperiod", + 0x249a, + "ninethai", + 0x0e59, + "nj", + 0x01cc, + "njecyrillic", + 0x045a, + "nkatakana", + 0x30f3, + "nkatakanahalfwidth", + 0xff9d, + "nlegrightlong", + 0x019e, + "nlinebelow", + 0x1e49, + "nmonospace", + 0xff4e, + "nmsquare", + 0x339a, + "nnabengali", + 0x09a3, + "nnadeva", + 0x0923, + "nnagujarati", + 0x0aa3, + "nnagurmukhi", + 0x0a23, + "nnnadeva", + 0x0929, + "nohiragana", + 0x306e, + "nokatakana", + 0x30ce, + "nokatakanahalfwidth", + 0xff89, + "nonbreakingspace", + 0x00a0, + "nonenthai", + 0x0e13, + "nonuthai", + 0x0e19, + "noonarabic", + 0x0646, + "noonfinalarabic", + 0xfee6, + "noonghunnaarabic", + 0x06ba, + "noonghunnafinalarabic", + 0xfb9f, + "nooninitialarabic", + 0xfee7, + "noonjeeminitialarabic", + 0xfcd2, + "noonjeemisolatedarabic", + 0xfc4b, + "noonmedialarabic", + 0xfee8, + "noonmeeminitialarabic", + 0xfcd5, + "noonmeemisolatedarabic", + 0xfc4e, + "noonnoonfinalarabic", + 0xfc8d, + "notcontains", + 0x220c, + "notelement", + 0x2209, + "notelementof", + 0x2209, + "notequal", + 0x2260, + "notgreater", + 0x226f, + "notgreaternorequal", + 0x2271, + "notgreaternorless", + 0x2279, + "notidentical", + 0x2262, + "notless", + 0x226e, + "notlessnorequal", + 0x2270, + "notparallel", + 0x2226, + "notprecedes", + 0x2280, + "notsubset", + 0x2284, + "notsucceeds", + 0x2281, + "notsuperset", + 0x2285, + "nowarmenian", + 0x0576, + "nparen", + 0x24a9, + "nssquare", + 0x33b1, + "nsuperior", + 0x207f, + "ntilde", + 0x00f1, + "nu", + 0x03bd, + "nuhiragana", + 0x306c, + "nukatakana", + 0x30cc, + "nukatakanahalfwidth", + 0xff87, + "nuktabengali", + 0x09bc, + "nuktadeva", + 0x093c, + "nuktagujarati", + 0x0abc, + "nuktagurmukhi", + 0x0a3c, + "numbersign", + 0x0023, + "numbersignmonospace", + 0xff03, + "numbersignsmall", + 0xfe5f, + "numeralsigngreek", + 0x0374, + "numeralsignlowergreek", + 0x0375, + "numero", + 0x2116, + "nun", + 0x05e0, + "nundagesh", + 0xfb40, + "nundageshhebrew", + 0xfb40, + "nunhebrew", + 0x05e0, + "nvsquare", + 0x33b5, + "nwsquare", + 0x33bb, + "nyabengali", + 0x099e, + "nyadeva", + 0x091e, + "nyagujarati", + 0x0a9e, + "nyagurmukhi", + 0x0a1e, + "o", + 0x006f, + "oacute", + 0x00f3, + "oangthai", + 0x0e2d, + "obarred", + 0x0275, + "obarredcyrillic", + 0x04e9, + "obarreddieresiscyrillic", + 0x04eb, + "obengali", + 0x0993, + "obopomofo", + 0x311b, + "obreve", + 0x014f, + "ocandradeva", + 0x0911, + "ocandragujarati", + 0x0a91, + "ocandravowelsigndeva", + 0x0949, + "ocandravowelsigngujarati", + 0x0ac9, + "ocaron", + 0x01d2, + "ocircle", + 0x24de, + "ocircumflex", + 0x00f4, + "ocircumflexacute", + 0x1ed1, + "ocircumflexdotbelow", + 0x1ed9, + "ocircumflexgrave", + 0x1ed3, + "ocircumflexhookabove", + 0x1ed5, + "ocircumflextilde", + 0x1ed7, + "ocyrillic", + 0x043e, + "odblacute", + 0x0151, + "odblgrave", + 0x020d, + "odeva", + 0x0913, + "odieresis", + 0x00f6, + "odieresiscyrillic", + 0x04e7, + "odotbelow", + 0x1ecd, + "oe", + 0x0153, + "oekorean", + 0x315a, + "ogonek", + 0x02db, + "ogonekcmb", + 0x0328, + "ograve", + 0x00f2, + "ogujarati", + 0x0a93, + "oharmenian", + 0x0585, + "ohiragana", + 0x304a, + "ohookabove", + 0x1ecf, + "ohorn", + 0x01a1, + "ohornacute", + 0x1edb, + "ohorndotbelow", + 0x1ee3, + "ohorngrave", + 0x1edd, + "ohornhookabove", + 0x1edf, + "ohorntilde", + 0x1ee1, + "ohungarumlaut", + 0x0151, + "oi", + 0x01a3, + "oinvertedbreve", + 0x020f, + "okatakana", + 0x30aa, + "okatakanahalfwidth", + 0xff75, + "okorean", + 0x3157, + "olehebrew", + 0x05ab, + "omacron", + 0x014d, + "omacronacute", + 0x1e53, + "omacrongrave", + 0x1e51, + "omdeva", + 0x0950, + "omega", + 0x03c9, + "omega1", + 0x03d6, + "omegacyrillic", + 0x0461, + "omegalatinclosed", + 0x0277, + "omegaroundcyrillic", + 0x047b, + "omegatitlocyrillic", + 0x047d, + "omegatonos", + 0x03ce, + "omgujarati", + 0x0ad0, + "omicron", + 0x03bf, + "omicrontonos", + 0x03cc, + "omonospace", + 0xff4f, + "one", + 0x0031, + "onearabic", + 0x0661, + "onebengali", + 0x09e7, + "onecircle", + 0x2460, + "onecircleinversesansserif", + 0x278a, + "onedeva", + 0x0967, + "onedotenleader", + 0x2024, + "oneeighth", + 0x215b, + "onefitted", + 0xf6dc, + "onegujarati", + 0x0ae7, + "onegurmukhi", + 0x0a67, + "onehackarabic", + 0x0661, + "onehalf", + 0x00bd, + "onehangzhou", + 0x3021, + "oneideographicparen", + 0x3220, + "oneinferior", + 0x2081, + "onemonospace", + 0xff11, + "onenumeratorbengali", + 0x09f4, + "oneoldstyle", + 0xf731, + "oneparen", + 0x2474, + "oneperiod", + 0x2488, + "onepersian", + 0x06f1, + "onequarter", + 0x00bc, + "oneroman", + 0x2170, + "onesuperior", + 0x00b9, + "onethai", + 0x0e51, + "onethird", + 0x2153, + "oogonek", + 0x01eb, + "oogonekmacron", + 0x01ed, + "oogurmukhi", + 0x0a13, + "oomatragurmukhi", + 0x0a4b, + "oopen", + 0x0254, + "oparen", + 0x24aa, + "openbullet", + 0x25e6, + "option", + 0x2325, + "ordfeminine", + 0x00aa, + "ordmasculine", + 0x00ba, + "orthogonal", + 0x221f, + "oshortdeva", + 0x0912, + "oshortvowelsigndeva", + 0x094a, + "oslash", + 0x00f8, + "oslashacute", + 0x01ff, + "osmallhiragana", + 0x3049, + "osmallkatakana", + 0x30a9, + "osmallkatakanahalfwidth", + 0xff6b, + "ostrokeacute", + 0x01ff, + "osuperior", + 0xf6f0, + "otcyrillic", + 0x047f, + "otilde", + 0x00f5, + "otildeacute", + 0x1e4d, + "otildedieresis", + 0x1e4f, + "oubopomofo", + 0x3121, + "overline", + 0x203e, + "overlinecenterline", + 0xfe4a, + "overlinecmb", + 0x0305, + "overlinedashed", + 0xfe49, + "overlinedblwavy", + 0xfe4c, + "overlinewavy", + 0xfe4b, + "overscore", + 0x00af, + "ovowelsignbengali", + 0x09cb, + "ovowelsigndeva", + 0x094b, + "ovowelsigngujarati", + 0x0acb, + "p", + 0x0070, + "paampssquare", + 0x3380, + "paasentosquare", + 0x332b, + "pabengali", + 0x09aa, + "pacute", + 0x1e55, + "padeva", + 0x092a, + "pagedown", + 0x21df, + "pageup", + 0x21de, + "pagujarati", + 0x0aaa, + "pagurmukhi", + 0x0a2a, + "pahiragana", + 0x3071, + "paiyannoithai", + 0x0e2f, + "pakatakana", + 0x30d1, + "palatalizationcyrilliccmb", + 0x0484, + "palochkacyrillic", + 0x04c0, + "pansioskorean", + 0x317f, + "paragraph", + 0x00b6, + "parallel", + 0x2225, + "parenleft", + 0x0028, + "parenleftaltonearabic", + 0xfd3e, + "parenleftbt", + 0xf8ed, + "parenleftex", + 0xf8ec, + "parenleftinferior", + 0x208d, + "parenleftmonospace", + 0xff08, + "parenleftsmall", + 0xfe59, + "parenleftsuperior", + 0x207d, + "parenlefttp", + 0xf8eb, + "parenleftvertical", + 0xfe35, + "parenright", + 0x0029, + "parenrightaltonearabic", + 0xfd3f, + "parenrightbt", + 0xf8f8, + "parenrightex", + 0xf8f7, + "parenrightinferior", + 0x208e, + "parenrightmonospace", + 0xff09, + "parenrightsmall", + 0xfe5a, + "parenrightsuperior", + 0x207e, + "parenrighttp", + 0xf8f6, + "parenrightvertical", + 0xfe36, + "partialdiff", + 0x2202, + "paseqhebrew", + 0x05c0, + "pashtahebrew", + 0x0599, + "pasquare", + 0x33a9, + "patah", + 0x05b7, + "patah11", + 0x05b7, + "patah1d", + 0x05b7, + "patah2a", + 0x05b7, + "patahhebrew", + 0x05b7, + "patahnarrowhebrew", + 0x05b7, + "patahquarterhebrew", + 0x05b7, + "patahwidehebrew", + 0x05b7, + "pazerhebrew", + 0x05a1, + "pbopomofo", + 0x3106, + "pcircle", + 0x24df, + "pdotaccent", + 0x1e57, + "pe", + 0x05e4, + "pecyrillic", + 0x043f, + "pedagesh", + 0xfb44, + "pedageshhebrew", + 0xfb44, + "peezisquare", + 0x333b, + "pefinaldageshhebrew", + 0xfb43, + "peharabic", + 0x067e, + "peharmenian", + 0x057a, + "pehebrew", + 0x05e4, + "pehfinalarabic", + 0xfb57, + "pehinitialarabic", + 0xfb58, + "pehiragana", + 0x307a, + "pehmedialarabic", + 0xfb59, + "pekatakana", + 0x30da, + "pemiddlehookcyrillic", + 0x04a7, + "perafehebrew", + 0xfb4e, + "percent", + 0x0025, + "percentarabic", + 0x066a, + "percentmonospace", + 0xff05, + "percentsmall", + 0xfe6a, + "period", + 0x002e, + "periodarmenian", + 0x0589, + "periodcentered", + 0x00b7, + "periodhalfwidth", + 0xff61, + "periodinferior", + 0xf6e7, + "periodmonospace", + 0xff0e, + "periodsmall", + 0xfe52, + "periodsuperior", + 0xf6e8, + "perispomenigreekcmb", + 0x0342, + "perpendicular", + 0x22a5, + "perthousand", + 0x2030, + "peseta", + 0x20a7, + "pfsquare", + 0x338a, + "phabengali", + 0x09ab, + "phadeva", + 0x092b, + "phagujarati", + 0x0aab, + "phagurmukhi", + 0x0a2b, + "phi", + 0x03c6, + "phi1", + 0x03d5, + "phieuphacirclekorean", + 0x327a, + "phieuphaparenkorean", + 0x321a, + "phieuphcirclekorean", + 0x326c, + "phieuphkorean", + 0x314d, + "phieuphparenkorean", + 0x320c, + "philatin", + 0x0278, + "phinthuthai", + 0x0e3a, + "phisymbolgreek", + 0x03d5, + "phook", + 0x01a5, + "phophanthai", + 0x0e1e, + "phophungthai", + 0x0e1c, + "phosamphaothai", + 0x0e20, + "pi", + 0x03c0, + "pieupacirclekorean", + 0x3273, + "pieupaparenkorean", + 0x3213, + "pieupcieuckorean", + 0x3176, + "pieupcirclekorean", + 0x3265, + "pieupkiyeokkorean", + 0x3172, + "pieupkorean", + 0x3142, + "pieupparenkorean", + 0x3205, + "pieupsioskiyeokkorean", + 0x3174, + "pieupsioskorean", + 0x3144, + "pieupsiostikeutkorean", + 0x3175, + "pieupthieuthkorean", + 0x3177, + "pieuptikeutkorean", + 0x3173, + "pihiragana", + 0x3074, + "pikatakana", + 0x30d4, + "pisymbolgreek", + 0x03d6, + "piwrarmenian", + 0x0583, + "plus", + 0x002b, + "plusbelowcmb", + 0x031f, + "pluscircle", + 0x2295, + "plusminus", + 0x00b1, + "plusmod", + 0x02d6, + "plusmonospace", + 0xff0b, + "plussmall", + 0xfe62, + "plussuperior", + 0x207a, + "pmonospace", + 0xff50, + "pmsquare", + 0x33d8, + "pohiragana", + 0x307d, + "pointingindexdownwhite", + 0x261f, + "pointingindexleftwhite", + 0x261c, + "pointingindexrightwhite", + 0x261e, + "pointingindexupwhite", + 0x261d, + "pokatakana", + 0x30dd, + "poplathai", + 0x0e1b, + "postalmark", + 0x3012, + "postalmarkface", + 0x3020, + "pparen", + 0x24ab, + "precedes", + 0x227a, + "prescription", + 0x211e, + "primemod", + 0x02b9, + "primereversed", + 0x2035, + "product", + 0x220f, + "projective", + 0x2305, + "prolongedkana", + 0x30fc, + "propellor", + 0x2318, + "propersubset", + 0x2282, + "propersuperset", + 0x2283, + "proportion", + 0x2237, + "proportional", + 0x221d, + "psi", + 0x03c8, + "psicyrillic", + 0x0471, + "psilipneumatacyrilliccmb", + 0x0486, + "pssquare", + 0x33b0, + "puhiragana", + 0x3077, + "pukatakana", + 0x30d7, + "pvsquare", + 0x33b4, + "pwsquare", + 0x33ba, + "q", + 0x0071, + "qadeva", + 0x0958, + "qadmahebrew", + 0x05a8, + "qafarabic", + 0x0642, + "qaffinalarabic", + 0xfed6, + "qafinitialarabic", + 0xfed7, + "qafmedialarabic", + 0xfed8, + "qamats", + 0x05b8, + "qamats10", + 0x05b8, + "qamats1a", + 0x05b8, + "qamats1c", + 0x05b8, + "qamats27", + 0x05b8, + "qamats29", + 0x05b8, + "qamats33", + 0x05b8, + "qamatsde", + 0x05b8, + "qamatshebrew", + 0x05b8, + "qamatsnarrowhebrew", + 0x05b8, + "qamatsqatanhebrew", + 0x05b8, + "qamatsqatannarrowhebrew", + 0x05b8, + "qamatsqatanquarterhebrew", + 0x05b8, + "qamatsqatanwidehebrew", + 0x05b8, + "qamatsquarterhebrew", + 0x05b8, + "qamatswidehebrew", + 0x05b8, + "qarneyparahebrew", + 0x059f, + "qbopomofo", + 0x3111, + "qcircle", + 0x24e0, + "qhook", + 0x02a0, + "qmonospace", + 0xff51, + "qof", + 0x05e7, + "qofdagesh", + 0xfb47, + "qofdageshhebrew", + 0xfb47, + "qofhebrew", + 0x05e7, + "qparen", + 0x24ac, + "quarternote", + 0x2669, + "qubuts", + 0x05bb, + "qubuts18", + 0x05bb, + "qubuts25", + 0x05bb, + "qubuts31", + 0x05bb, + "qubutshebrew", + 0x05bb, + "qubutsnarrowhebrew", + 0x05bb, + "qubutsquarterhebrew", + 0x05bb, + "qubutswidehebrew", + 0x05bb, + "question", + 0x003f, + "questionarabic", + 0x061f, + "questionarmenian", + 0x055e, + "questiondown", + 0x00bf, + "questiondownsmall", + 0xf7bf, + "questiongreek", + 0x037e, + "questionmonospace", + 0xff1f, + "questionsmall", + 0xf73f, + "quotedbl", + 0x0022, + "quotedblbase", + 0x201e, + "quotedblleft", + 0x201c, + "quotedblmonospace", + 0xff02, + "quotedblprime", + 0x301e, + "quotedblprimereversed", + 0x301d, + "quotedblright", + 0x201d, + "quoteleft", + 0x2018, + "quoteleftreversed", + 0x201b, + "quotereversed", + 0x201b, + "quoteright", + 0x2019, + "quoterightn", + 0x0149, + "quotesinglbase", + 0x201a, + "quotesingle", + 0x0027, + "quotesinglemonospace", + 0xff07, + "r", + 0x0072, + "raarmenian", + 0x057c, + "rabengali", + 0x09b0, + "racute", + 0x0155, + "radeva", + 0x0930, + "radical", + 0x221a, + "radicalex", + 0xf8e5, + "radoverssquare", + 0x33ae, + "radoverssquaredsquare", + 0x33af, + "radsquare", + 0x33ad, + "rafe", + 0x05bf, + "rafehebrew", + 0x05bf, + "ragujarati", + 0x0ab0, + "ragurmukhi", + 0x0a30, + "rahiragana", + 0x3089, + "rakatakana", + 0x30e9, + "rakatakanahalfwidth", + 0xff97, + "ralowerdiagonalbengali", + 0x09f1, + "ramiddlediagonalbengali", + 0x09f0, + "ramshorn", + 0x0264, + "ratio", + 0x2236, + "rbopomofo", + 0x3116, + "rcaron", + 0x0159, + "rcedilla", + 0x0157, + "rcircle", + 0x24e1, + "rcommaaccent", + 0x0157, + "rdblgrave", + 0x0211, + "rdotaccent", + 0x1e59, + "rdotbelow", + 0x1e5b, + "rdotbelowmacron", + 0x1e5d, + "referencemark", + 0x203b, + "reflexsubset", + 0x2286, + "reflexsuperset", + 0x2287, + "registered", + 0x00ae, + "registersans", + 0xf8e8, + "registerserif", + 0xf6da, + "reharabic", + 0x0631, + "reharmenian", + 0x0580, + "rehfinalarabic", + 0xfeae, + "rehiragana", + 0x308c, + "rekatakana", + 0x30ec, + "rekatakanahalfwidth", + 0xff9a, + "resh", + 0x05e8, + "reshdageshhebrew", + 0xfb48, + "reshhebrew", + 0x05e8, + "reversedtilde", + 0x223d, + "reviahebrew", + 0x0597, + "reviamugrashhebrew", + 0x0597, + "revlogicalnot", + 0x2310, + "rfishhook", + 0x027e, + "rfishhookreversed", + 0x027f, + "rhabengali", + 0x09dd, + "rhadeva", + 0x095d, + "rho", + 0x03c1, + "rhook", + 0x027d, + "rhookturned", + 0x027b, + "rhookturnedsuperior", + 0x02b5, + "rhosymbolgreek", + 0x03f1, + "rhotichookmod", + 0x02de, + "rieulacirclekorean", + 0x3271, + "rieulaparenkorean", + 0x3211, + "rieulcirclekorean", + 0x3263, + "rieulhieuhkorean", + 0x3140, + "rieulkiyeokkorean", + 0x313a, + "rieulkiyeoksioskorean", + 0x3169, + "rieulkorean", + 0x3139, + "rieulmieumkorean", + 0x313b, + "rieulpansioskorean", + 0x316c, + "rieulparenkorean", + 0x3203, + "rieulphieuphkorean", + 0x313f, + "rieulpieupkorean", + 0x313c, + "rieulpieupsioskorean", + 0x316b, + "rieulsioskorean", + 0x313d, + "rieulthieuthkorean", + 0x313e, + "rieultikeutkorean", + 0x316a, + "rieulyeorinhieuhkorean", + 0x316d, + "rightangle", + 0x221f, + "righttackbelowcmb", + 0x0319, + "righttriangle", + 0x22bf, + "rihiragana", + 0x308a, + "rikatakana", + 0x30ea, + "rikatakanahalfwidth", + 0xff98, + "ring", + 0x02da, + "ringbelowcmb", + 0x0325, + "ringcmb", + 0x030a, + "ringhalfleft", + 0x02bf, + "ringhalfleftarmenian", + 0x0559, + "ringhalfleftbelowcmb", + 0x031c, + "ringhalfleftcentered", + 0x02d3, + "ringhalfright", + 0x02be, + "ringhalfrightbelowcmb", + 0x0339, + "ringhalfrightcentered", + 0x02d2, + "rinvertedbreve", + 0x0213, + "rittorusquare", + 0x3351, + "rlinebelow", + 0x1e5f, + "rlongleg", + 0x027c, + "rlonglegturned", + 0x027a, + "rmonospace", + 0xff52, + "rohiragana", + 0x308d, + "rokatakana", + 0x30ed, + "rokatakanahalfwidth", + 0xff9b, + "roruathai", + 0x0e23, + "rparen", + 0x24ad, + "rrabengali", + 0x09dc, + "rradeva", + 0x0931, + "rragurmukhi", + 0x0a5c, + "rreharabic", + 0x0691, + "rrehfinalarabic", + 0xfb8d, + "rrvocalicbengali", + 0x09e0, + "rrvocalicdeva", + 0x0960, + "rrvocalicgujarati", + 0x0ae0, + "rrvocalicvowelsignbengali", + 0x09c4, + "rrvocalicvowelsigndeva", + 0x0944, + "rrvocalicvowelsigngujarati", + 0x0ac4, + "rsuperior", + 0xf6f1, + "rtblock", + 0x2590, + "rturned", + 0x0279, + "rturnedsuperior", + 0x02b4, + "ruhiragana", + 0x308b, + "rukatakana", + 0x30eb, + "rukatakanahalfwidth", + 0xff99, + "rupeemarkbengali", + 0x09f2, + "rupeesignbengali", + 0x09f3, + "rupiah", + 0xf6dd, + "ruthai", + 0x0e24, + "rvocalicbengali", + 0x098b, + "rvocalicdeva", + 0x090b, + "rvocalicgujarati", + 0x0a8b, + "rvocalicvowelsignbengali", + 0x09c3, + "rvocalicvowelsigndeva", + 0x0943, + "rvocalicvowelsigngujarati", + 0x0ac3, + "s", + 0x0073, + "sabengali", + 0x09b8, + "sacute", + 0x015b, + "sacutedotaccent", + 0x1e65, + "sadarabic", + 0x0635, + "sadeva", + 0x0938, + "sadfinalarabic", + 0xfeba, + "sadinitialarabic", + 0xfebb, + "sadmedialarabic", + 0xfebc, + "sagujarati", + 0x0ab8, + "sagurmukhi", + 0x0a38, + "sahiragana", + 0x3055, + "sakatakana", + 0x30b5, + "sakatakanahalfwidth", + 0xff7b, + "sallallahoualayhewasallamarabic", + 0xfdfa, + "samekh", + 0x05e1, + "samekhdagesh", + 0xfb41, + "samekhdageshhebrew", + 0xfb41, + "samekhhebrew", + 0x05e1, + "saraaathai", + 0x0e32, + "saraaethai", + 0x0e41, + "saraaimaimalaithai", + 0x0e44, + "saraaimaimuanthai", + 0x0e43, + "saraamthai", + 0x0e33, + "saraathai", + 0x0e30, + "saraethai", + 0x0e40, + "saraiileftthai", + 0xf886, + "saraiithai", + 0x0e35, + "saraileftthai", + 0xf885, + "saraithai", + 0x0e34, + "saraothai", + 0x0e42, + "saraueeleftthai", + 0xf888, + "saraueethai", + 0x0e37, + "saraueleftthai", + 0xf887, + "sarauethai", + 0x0e36, + "sarauthai", + 0x0e38, + "sarauuthai", + 0x0e39, + "sbopomofo", + 0x3119, + "scaron", + 0x0161, + "scarondotaccent", + 0x1e67, + "scedilla", + 0x015f, + "schwa", + 0x0259, + "schwacyrillic", + 0x04d9, + "schwadieresiscyrillic", + 0x04db, + "schwahook", + 0x025a, + "scircle", + 0x24e2, + "scircumflex", + 0x015d, + "scommaaccent", + 0x0219, + "sdotaccent", + 0x1e61, + "sdotbelow", + 0x1e63, + "sdotbelowdotaccent", + 0x1e69, + "seagullbelowcmb", + 0x033c, + "second", + 0x2033, + "secondtonechinese", + 0x02ca, + "section", + 0x00a7, + "seenarabic", + 0x0633, + "seenfinalarabic", + 0xfeb2, + "seeninitialarabic", + 0xfeb3, + "seenmedialarabic", + 0xfeb4, + "segol", + 0x05b6, + "segol13", + 0x05b6, + "segol1f", + 0x05b6, + "segol2c", + 0x05b6, + "segolhebrew", + 0x05b6, + "segolnarrowhebrew", + 0x05b6, + "segolquarterhebrew", + 0x05b6, + "segoltahebrew", + 0x0592, + "segolwidehebrew", + 0x05b6, + "seharmenian", + 0x057d, + "sehiragana", + 0x305b, + "sekatakana", + 0x30bb, + "sekatakanahalfwidth", + 0xff7e, + "semicolon", + 0x003b, + "semicolonarabic", + 0x061b, + "semicolonmonospace", + 0xff1b, + "semicolonsmall", + 0xfe54, + "semivoicedmarkkana", + 0x309c, + "semivoicedmarkkanahalfwidth", + 0xff9f, + "sentisquare", + 0x3322, + "sentosquare", + 0x3323, + "seven", + 0x0037, + "sevenarabic", + 0x0667, + "sevenbengali", + 0x09ed, + "sevencircle", + 0x2466, + "sevencircleinversesansserif", + 0x2790, + "sevendeva", + 0x096d, + "seveneighths", + 0x215e, + "sevengujarati", + 0x0aed, + "sevengurmukhi", + 0x0a6d, + "sevenhackarabic", + 0x0667, + "sevenhangzhou", + 0x3027, + "sevenideographicparen", + 0x3226, + "seveninferior", + 0x2087, + "sevenmonospace", + 0xff17, + "sevenoldstyle", + 0xf737, + "sevenparen", + 0x247a, + "sevenperiod", + 0x248e, + "sevenpersian", + 0x06f7, + "sevenroman", + 0x2176, + "sevensuperior", + 0x2077, + "seventeencircle", + 0x2470, + "seventeenparen", + 0x2484, + "seventeenperiod", + 0x2498, + "seventhai", + 0x0e57, + "sfthyphen", + 0x00ad, + "shaarmenian", + 0x0577, + "shabengali", + 0x09b6, + "shacyrillic", + 0x0448, + "shaddaarabic", + 0x0651, + "shaddadammaarabic", + 0xfc61, + "shaddadammatanarabic", + 0xfc5e, + "shaddafathaarabic", + 0xfc60, + "shaddakasraarabic", + 0xfc62, + "shaddakasratanarabic", + 0xfc5f, + "shade", + 0x2592, + "shadedark", + 0x2593, + "shadelight", + 0x2591, + "shademedium", + 0x2592, + "shadeva", + 0x0936, + "shagujarati", + 0x0ab6, + "shagurmukhi", + 0x0a36, + "shalshelethebrew", + 0x0593, + "shbopomofo", + 0x3115, + "shchacyrillic", + 0x0449, + "sheenarabic", + 0x0634, + "sheenfinalarabic", + 0xfeb6, + "sheeninitialarabic", + 0xfeb7, + "sheenmedialarabic", + 0xfeb8, + "sheicoptic", + 0x03e3, + "sheqel", + 0x20aa, + "sheqelhebrew", + 0x20aa, + "sheva", + 0x05b0, + "sheva115", + 0x05b0, + "sheva15", + 0x05b0, + "sheva22", + 0x05b0, + "sheva2e", + 0x05b0, + "shevahebrew", + 0x05b0, + "shevanarrowhebrew", + 0x05b0, + "shevaquarterhebrew", + 0x05b0, + "shevawidehebrew", + 0x05b0, + "shhacyrillic", + 0x04bb, + "shimacoptic", + 0x03ed, + "shin", + 0x05e9, + "shindagesh", + 0xfb49, + "shindageshhebrew", + 0xfb49, + "shindageshshindot", + 0xfb2c, + "shindageshshindothebrew", + 0xfb2c, + "shindageshsindot", + 0xfb2d, + "shindageshsindothebrew", + 0xfb2d, + "shindothebrew", + 0x05c1, + "shinhebrew", + 0x05e9, + "shinshindot", + 0xfb2a, + "shinshindothebrew", + 0xfb2a, + "shinsindot", + 0xfb2b, + "shinsindothebrew", + 0xfb2b, + "shook", + 0x0282, + "sigma", + 0x03c3, + "sigma1", + 0x03c2, + "sigmafinal", + 0x03c2, + "sigmalunatesymbolgreek", + 0x03f2, + "sihiragana", + 0x3057, + "sikatakana", + 0x30b7, + "sikatakanahalfwidth", + 0xff7c, + "siluqhebrew", + 0x05bd, + "siluqlefthebrew", + 0x05bd, + "similar", + 0x223c, + "sindothebrew", + 0x05c2, + "siosacirclekorean", + 0x3274, + "siosaparenkorean", + 0x3214, + "sioscieuckorean", + 0x317e, + "sioscirclekorean", + 0x3266, + "sioskiyeokkorean", + 0x317a, + "sioskorean", + 0x3145, + "siosnieunkorean", + 0x317b, + "siosparenkorean", + 0x3206, + "siospieupkorean", + 0x317d, + "siostikeutkorean", + 0x317c, + "six", + 0x0036, + "sixarabic", + 0x0666, + "sixbengali", + 0x09ec, + "sixcircle", + 0x2465, + "sixcircleinversesansserif", + 0x278f, + "sixdeva", + 0x096c, + "sixgujarati", + 0x0aec, + "sixgurmukhi", + 0x0a6c, + "sixhackarabic", + 0x0666, + "sixhangzhou", + 0x3026, + "sixideographicparen", + 0x3225, + "sixinferior", + 0x2086, + "sixmonospace", + 0xff16, + "sixoldstyle", + 0xf736, + "sixparen", + 0x2479, + "sixperiod", + 0x248d, + "sixpersian", + 0x06f6, + "sixroman", + 0x2175, + "sixsuperior", + 0x2076, + "sixteencircle", + 0x246f, + "sixteencurrencydenominatorbengali", + 0x09f9, + "sixteenparen", + 0x2483, + "sixteenperiod", + 0x2497, + "sixthai", + 0x0e56, + "slash", + 0x002f, + "slashmonospace", + 0xff0f, + "slong", + 0x017f, + "slongdotaccent", + 0x1e9b, + "smileface", + 0x263a, + "smonospace", + 0xff53, + "sofpasuqhebrew", + 0x05c3, + "softhyphen", + 0x00ad, + "softsigncyrillic", + 0x044c, + "sohiragana", + 0x305d, + "sokatakana", + 0x30bd, + "sokatakanahalfwidth", + 0xff7f, + "soliduslongoverlaycmb", + 0x0338, + "solidusshortoverlaycmb", + 0x0337, + "sorusithai", + 0x0e29, + "sosalathai", + 0x0e28, + "sosothai", + 0x0e0b, + "sosuathai", + 0x0e2a, + "space", + 0x0020, + "spacehackarabic", + 0x0020, + "spade", + 0x2660, + "spadesuitblack", + 0x2660, + "spadesuitwhite", + 0x2664, + "sparen", + 0x24ae, + "squarebelowcmb", + 0x033b, + "squarecc", + 0x33c4, + "squarecm", + 0x339d, + "squarediagonalcrosshatchfill", + 0x25a9, + "squarehorizontalfill", + 0x25a4, + "squarekg", + 0x338f, + "squarekm", + 0x339e, + "squarekmcapital", + 0x33ce, + "squareln", + 0x33d1, + "squarelog", + 0x33d2, + "squaremg", + 0x338e, + "squaremil", + 0x33d5, + "squaremm", + 0x339c, + "squaremsquared", + 0x33a1, + "squareorthogonalcrosshatchfill", + 0x25a6, + "squareupperlefttolowerrightfill", + 0x25a7, + "squareupperrighttolowerleftfill", + 0x25a8, + "squareverticalfill", + 0x25a5, + "squarewhitewithsmallblack", + 0x25a3, + "srsquare", + 0x33db, + "ssabengali", + 0x09b7, + "ssadeva", + 0x0937, + "ssagujarati", + 0x0ab7, + "ssangcieuckorean", + 0x3149, + "ssanghieuhkorean", + 0x3185, + "ssangieungkorean", + 0x3180, + "ssangkiyeokkorean", + 0x3132, + "ssangnieunkorean", + 0x3165, + "ssangpieupkorean", + 0x3143, + "ssangsioskorean", + 0x3146, + "ssangtikeutkorean", + 0x3138, + "ssuperior", + 0xf6f2, + "sterling", + 0x00a3, + "sterlingmonospace", + 0xffe1, + "strokelongoverlaycmb", + 0x0336, + "strokeshortoverlaycmb", + 0x0335, + "subset", + 0x2282, + "subsetnotequal", + 0x228a, + "subsetorequal", + 0x2286, + "succeeds", + 0x227b, + "suchthat", + 0x220b, + "suhiragana", + 0x3059, + "sukatakana", + 0x30b9, + "sukatakanahalfwidth", + 0xff7d, + "sukunarabic", + 0x0652, + "summation", + 0x2211, + "sun", + 0x263c, + "superset", + 0x2283, + "supersetnotequal", + 0x228b, + "supersetorequal", + 0x2287, + "svsquare", + 0x33dc, + "syouwaerasquare", + 0x337c, + "t", + 0x0074, + "tabengali", + 0x09a4, + "tackdown", + 0x22a4, + "tackleft", + 0x22a3, + "tadeva", + 0x0924, + "tagujarati", + 0x0aa4, + "tagurmukhi", + 0x0a24, + "taharabic", + 0x0637, + "tahfinalarabic", + 0xfec2, + "tahinitialarabic", + 0xfec3, + "tahiragana", + 0x305f, + "tahmedialarabic", + 0xfec4, + "taisyouerasquare", + 0x337d, + "takatakana", + 0x30bf, + "takatakanahalfwidth", + 0xff80, + "tatweelarabic", + 0x0640, + "tau", + 0x03c4, + "tav", + 0x05ea, + "tavdages", + 0xfb4a, + "tavdagesh", + 0xfb4a, + "tavdageshhebrew", + 0xfb4a, + "tavhebrew", + 0x05ea, + "tbar", + 0x0167, + "tbopomofo", + 0x310a, + "tcaron", + 0x0165, + "tccurl", + 0x02a8, + "tcedilla", + 0x0163, + "tcheharabic", + 0x0686, + "tchehfinalarabic", + 0xfb7b, + "tchehinitialarabic", + 0xfb7c, + "tchehmedialarabic", + 0xfb7d, + "tcircle", + 0x24e3, + "tcircumflexbelow", + 0x1e71, + "tcommaaccent", + 0x0163, + "tdieresis", + 0x1e97, + "tdotaccent", + 0x1e6b, + "tdotbelow", + 0x1e6d, + "tecyrillic", + 0x0442, + "tedescendercyrillic", + 0x04ad, + "teharabic", + 0x062a, + "tehfinalarabic", + 0xfe96, + "tehhahinitialarabic", + 0xfca2, + "tehhahisolatedarabic", + 0xfc0c, + "tehinitialarabic", + 0xfe97, + "tehiragana", + 0x3066, + "tehjeeminitialarabic", + 0xfca1, + "tehjeemisolatedarabic", + 0xfc0b, + "tehmarbutaarabic", + 0x0629, + "tehmarbutafinalarabic", + 0xfe94, + "tehmedialarabic", + 0xfe98, + "tehmeeminitialarabic", + 0xfca4, + "tehmeemisolatedarabic", + 0xfc0e, + "tehnoonfinalarabic", + 0xfc73, + "tekatakana", + 0x30c6, + "tekatakanahalfwidth", + 0xff83, + "telephone", + 0x2121, + "telephoneblack", + 0x260e, + "telishagedolahebrew", + 0x05a0, + "telishaqetanahebrew", + 0x05a9, + "tencircle", + 0x2469, + "tenideographicparen", + 0x3229, + "tenparen", + 0x247d, + "tenperiod", + 0x2491, + "tenroman", + 0x2179, + "tesh", + 0x02a7, + "tet", + 0x05d8, + "tetdagesh", + 0xfb38, + "tetdageshhebrew", + 0xfb38, + "tethebrew", + 0x05d8, + "tetsecyrillic", + 0x04b5, + "tevirhebrew", + 0x059b, + "tevirlefthebrew", + 0x059b, + "thabengali", + 0x09a5, + "thadeva", + 0x0925, + "thagujarati", + 0x0aa5, + "thagurmukhi", + 0x0a25, + "thalarabic", + 0x0630, + "thalfinalarabic", + 0xfeac, + "thanthakhatlowleftthai", + 0xf898, + "thanthakhatlowrightthai", + 0xf897, + "thanthakhatthai", + 0x0e4c, + "thanthakhatupperleftthai", + 0xf896, + "theharabic", + 0x062b, + "thehfinalarabic", + 0xfe9a, + "thehinitialarabic", + 0xfe9b, + "thehmedialarabic", + 0xfe9c, + "thereexists", + 0x2203, + "therefore", + 0x2234, + "theta", + 0x03b8, + "theta1", + 0x03d1, + "thetasymbolgreek", + 0x03d1, + "thieuthacirclekorean", + 0x3279, + "thieuthaparenkorean", + 0x3219, + "thieuthcirclekorean", + 0x326b, + "thieuthkorean", + 0x314c, + "thieuthparenkorean", + 0x320b, + "thirteencircle", + 0x246c, + "thirteenparen", + 0x2480, + "thirteenperiod", + 0x2494, + "thonangmonthothai", + 0x0e11, + "thook", + 0x01ad, + "thophuthaothai", + 0x0e12, + "thorn", + 0x00fe, + "thothahanthai", + 0x0e17, + "thothanthai", + 0x0e10, + "thothongthai", + 0x0e18, + "thothungthai", + 0x0e16, + "thousandcyrillic", + 0x0482, + "thousandsseparatorarabic", + 0x066c, + "thousandsseparatorpersian", + 0x066c, + "three", + 0x0033, + "threearabic", + 0x0663, + "threebengali", + 0x09e9, + "threecircle", + 0x2462, + "threecircleinversesansserif", + 0x278c, + "threedeva", + 0x0969, + "threeeighths", + 0x215c, + "threegujarati", + 0x0ae9, + "threegurmukhi", + 0x0a69, + "threehackarabic", + 0x0663, + "threehangzhou", + 0x3023, + "threeideographicparen", + 0x3222, + "threeinferior", + 0x2083, + "threemonospace", + 0xff13, + "threenumeratorbengali", + 0x09f6, + "threeoldstyle", + 0xf733, + "threeparen", + 0x2476, + "threeperiod", + 0x248a, + "threepersian", + 0x06f3, + "threequarters", + 0x00be, + "threequartersemdash", + 0xf6de, + "threeroman", + 0x2172, + "threesuperior", + 0x00b3, + "threethai", + 0x0e53, + "thzsquare", + 0x3394, + "tihiragana", + 0x3061, + "tikatakana", + 0x30c1, + "tikatakanahalfwidth", + 0xff81, + "tikeutacirclekorean", + 0x3270, + "tikeutaparenkorean", + 0x3210, + "tikeutcirclekorean", + 0x3262, + "tikeutkorean", + 0x3137, + "tikeutparenkorean", + 0x3202, + "tilde", + 0x02dc, + "tildebelowcmb", + 0x0330, + "tildecmb", + 0x0303, + "tildecomb", + 0x0303, + "tildedoublecmb", + 0x0360, + "tildeoperator", + 0x223c, + "tildeoverlaycmb", + 0x0334, + "tildeverticalcmb", + 0x033e, + "timescircle", + 0x2297, + "tipehahebrew", + 0x0596, + "tipehalefthebrew", + 0x0596, + "tippigurmukhi", + 0x0a70, + "titlocyrilliccmb", + 0x0483, + "tiwnarmenian", + 0x057f, + "tlinebelow", + 0x1e6f, + "tmonospace", + 0xff54, + "toarmenian", + 0x0569, + "tohiragana", + 0x3068, + "tokatakana", + 0x30c8, + "tokatakanahalfwidth", + 0xff84, + "tonebarextrahighmod", + 0x02e5, + "tonebarextralowmod", + 0x02e9, + "tonebarhighmod", + 0x02e6, + "tonebarlowmod", + 0x02e8, + "tonebarmidmod", + 0x02e7, + "tonefive", + 0x01bd, + "tonesix", + 0x0185, + "tonetwo", + 0x01a8, + "tonos", + 0x0384, + "tonsquare", + 0x3327, + "topatakthai", + 0x0e0f, + "tortoiseshellbracketleft", + 0x3014, + "tortoiseshellbracketleftsmall", + 0xfe5d, + "tortoiseshellbracketleftvertical", + 0xfe39, + "tortoiseshellbracketright", + 0x3015, + "tortoiseshellbracketrightsmall", + 0xfe5e, + "tortoiseshellbracketrightvertical", + 0xfe3a, + "totaothai", + 0x0e15, + "tpalatalhook", + 0x01ab, + "tparen", + 0x24af, + "trademark", + 0x2122, + "trademarksans", + 0xf8ea, + "trademarkserif", + 0xf6db, + "tretroflexhook", + 0x0288, + "triagdn", + 0x25bc, + "triaglf", + 0x25c4, + "triagrt", + 0x25ba, + "triagup", + 0x25b2, + "ts", + 0x02a6, + "tsadi", + 0x05e6, + "tsadidagesh", + 0xfb46, + "tsadidageshhebrew", + 0xfb46, + "tsadihebrew", + 0x05e6, + "tsecyrillic", + 0x0446, + "tsere", + 0x05b5, + "tsere12", + 0x05b5, + "tsere1e", + 0x05b5, + "tsere2b", + 0x05b5, + "tserehebrew", + 0x05b5, + "tserenarrowhebrew", + 0x05b5, + "tserequarterhebrew", + 0x05b5, + "tserewidehebrew", + 0x05b5, + "tshecyrillic", + 0x045b, + "tsuperior", + 0xf6f3, + "ttabengali", + 0x099f, + "ttadeva", + 0x091f, + "ttagujarati", + 0x0a9f, + "ttagurmukhi", + 0x0a1f, + "tteharabic", + 0x0679, + "ttehfinalarabic", + 0xfb67, + "ttehinitialarabic", + 0xfb68, + "ttehmedialarabic", + 0xfb69, + "tthabengali", + 0x09a0, + "tthadeva", + 0x0920, + "tthagujarati", + 0x0aa0, + "tthagurmukhi", + 0x0a20, + "tturned", + 0x0287, + "tuhiragana", + 0x3064, + "tukatakana", + 0x30c4, + "tukatakanahalfwidth", + 0xff82, + "tusmallhiragana", + 0x3063, + "tusmallkatakana", + 0x30c3, + "tusmallkatakanahalfwidth", + 0xff6f, + "twelvecircle", + 0x246b, + "twelveparen", + 0x247f, + "twelveperiod", + 0x2493, + "twelveroman", + 0x217b, + "twentycircle", + 0x2473, + "twentyhangzhou", + 0x5344, + "twentyparen", + 0x2487, + "twentyperiod", + 0x249b, + "two", + 0x0032, + "twoarabic", + 0x0662, + "twobengali", + 0x09e8, + "twocircle", + 0x2461, + "twocircleinversesansserif", + 0x278b, + "twodeva", + 0x0968, + "twodotenleader", + 0x2025, + "twodotleader", + 0x2025, + "twodotleadervertical", + 0xfe30, + "twogujarati", + 0x0ae8, + "twogurmukhi", + 0x0a68, + "twohackarabic", + 0x0662, + "twohangzhou", + 0x3022, + "twoideographicparen", + 0x3221, + "twoinferior", + 0x2082, + "twomonospace", + 0xff12, + "twonumeratorbengali", + 0x09f5, + "twooldstyle", + 0xf732, + "twoparen", + 0x2475, + "twoperiod", + 0x2489, + "twopersian", + 0x06f2, + "tworoman", + 0x2171, + "twostroke", + 0x01bb, + "twosuperior", + 0x00b2, + "twothai", + 0x0e52, + "twothirds", + 0x2154, + "u", + 0x0075, + "uacute", + 0x00fa, + "ubar", + 0x0289, + "ubengali", + 0x0989, + "ubopomofo", + 0x3128, + "ubreve", + 0x016d, + "ucaron", + 0x01d4, + "ucircle", + 0x24e4, + "ucircumflex", + 0x00fb, + "ucircumflexbelow", + 0x1e77, + "ucyrillic", + 0x0443, + "udattadeva", + 0x0951, + "udblacute", + 0x0171, + "udblgrave", + 0x0215, + "udeva", + 0x0909, + "udieresis", + 0x00fc, + "udieresisacute", + 0x01d8, + "udieresisbelow", + 0x1e73, + "udieresiscaron", + 0x01da, + "udieresiscyrillic", + 0x04f1, + "udieresisgrave", + 0x01dc, + "udieresismacron", + 0x01d6, + "udotbelow", + 0x1ee5, + "ugrave", + 0x00f9, + "ugujarati", + 0x0a89, + "ugurmukhi", + 0x0a09, + "uhiragana", + 0x3046, + "uhookabove", + 0x1ee7, + "uhorn", + 0x01b0, + "uhornacute", + 0x1ee9, + "uhorndotbelow", + 0x1ef1, + "uhorngrave", + 0x1eeb, + "uhornhookabove", + 0x1eed, + "uhorntilde", + 0x1eef, + "uhungarumlaut", + 0x0171, + "uhungarumlautcyrillic", + 0x04f3, + "uinvertedbreve", + 0x0217, + "ukatakana", + 0x30a6, + "ukatakanahalfwidth", + 0xff73, + "ukcyrillic", + 0x0479, + "ukorean", + 0x315c, + "umacron", + 0x016b, + "umacroncyrillic", + 0x04ef, + "umacrondieresis", + 0x1e7b, + "umatragurmukhi", + 0x0a41, + "umonospace", + 0xff55, + "underscore", + 0x005f, + "underscoredbl", + 0x2017, + "underscoremonospace", + 0xff3f, + "underscorevertical", + 0xfe33, + "underscorewavy", + 0xfe4f, + "union", + 0x222a, + "universal", + 0x2200, + "uogonek", + 0x0173, + "uparen", + 0x24b0, + "upblock", + 0x2580, + "upperdothebrew", + 0x05c4, + "upsilon", + 0x03c5, + "upsilondieresis", + 0x03cb, + "upsilondieresistonos", + 0x03b0, + "upsilonlatin", + 0x028a, + "upsilontonos", + 0x03cd, + "uptackbelowcmb", + 0x031d, + "uptackmod", + 0x02d4, + "uragurmukhi", + 0x0a73, + "uring", + 0x016f, + "ushortcyrillic", + 0x045e, + "usmallhiragana", + 0x3045, + "usmallkatakana", + 0x30a5, + "usmallkatakanahalfwidth", + 0xff69, + "ustraightcyrillic", + 0x04af, + "ustraightstrokecyrillic", + 0x04b1, + "utilde", + 0x0169, + "utildeacute", + 0x1e79, + "utildebelow", + 0x1e75, + "uubengali", + 0x098a, + "uudeva", + 0x090a, + "uugujarati", + 0x0a8a, + "uugurmukhi", + 0x0a0a, + "uumatragurmukhi", + 0x0a42, + "uuvowelsignbengali", + 0x09c2, + "uuvowelsigndeva", + 0x0942, + "uuvowelsigngujarati", + 0x0ac2, + "uvowelsignbengali", + 0x09c1, + "uvowelsigndeva", + 0x0941, + "uvowelsigngujarati", + 0x0ac1, + "v", + 0x0076, + "vadeva", + 0x0935, + "vagujarati", + 0x0ab5, + "vagurmukhi", + 0x0a35, + "vakatakana", + 0x30f7, + "vav", + 0x05d5, + "vavdagesh", + 0xfb35, + "vavdagesh65", + 0xfb35, + "vavdageshhebrew", + 0xfb35, + "vavhebrew", + 0x05d5, + "vavholam", + 0xfb4b, + "vavholamhebrew", + 0xfb4b, + "vavvavhebrew", + 0x05f0, + "vavyodhebrew", + 0x05f1, + "vcircle", + 0x24e5, + "vdotbelow", + 0x1e7f, + "vecyrillic", + 0x0432, + "veharabic", + 0x06a4, + "vehfinalarabic", + 0xfb6b, + "vehinitialarabic", + 0xfb6c, + "vehmedialarabic", + 0xfb6d, + "vekatakana", + 0x30f9, + "venus", + 0x2640, + "verticalbar", + 0x007c, + "verticallineabovecmb", + 0x030d, + "verticallinebelowcmb", + 0x0329, + "verticallinelowmod", + 0x02cc, + "verticallinemod", + 0x02c8, + "vewarmenian", + 0x057e, + "vhook", + 0x028b, + "vikatakana", + 0x30f8, + "viramabengali", + 0x09cd, + "viramadeva", + 0x094d, + "viramagujarati", + 0x0acd, + "visargabengali", + 0x0983, + "visargadeva", + 0x0903, + "visargagujarati", + 0x0a83, + "vmonospace", + 0xff56, + "voarmenian", + 0x0578, + "voicediterationhiragana", + 0x309e, + "voicediterationkatakana", + 0x30fe, + "voicedmarkkana", + 0x309b, + "voicedmarkkanahalfwidth", + 0xff9e, + "vokatakana", + 0x30fa, + "vparen", + 0x24b1, + "vtilde", + 0x1e7d, + "vturned", + 0x028c, + "vuhiragana", + 0x3094, + "vukatakana", + 0x30f4, + "w", + 0x0077, + "wacute", + 0x1e83, + "waekorean", + 0x3159, + "wahiragana", + 0x308f, + "wakatakana", + 0x30ef, + "wakatakanahalfwidth", + 0xff9c, + "wakorean", + 0x3158, + "wasmallhiragana", + 0x308e, + "wasmallkatakana", + 0x30ee, + "wattosquare", + 0x3357, + "wavedash", + 0x301c, + "wavyunderscorevertical", + 0xfe34, + "wawarabic", + 0x0648, + "wawfinalarabic", + 0xfeee, + "wawhamzaabovearabic", + 0x0624, + "wawhamzaabovefinalarabic", + 0xfe86, + "wbsquare", + 0x33dd, + "wcircle", + 0x24e6, + "wcircumflex", + 0x0175, + "wdieresis", + 0x1e85, + "wdotaccent", + 0x1e87, + "wdotbelow", + 0x1e89, + "wehiragana", + 0x3091, + "weierstrass", + 0x2118, + "wekatakana", + 0x30f1, + "wekorean", + 0x315e, + "weokorean", + 0x315d, + "wgrave", + 0x1e81, + "whitebullet", + 0x25e6, + "whitecircle", + 0x25cb, + "whitecircleinverse", + 0x25d9, + "whitecornerbracketleft", + 0x300e, + "whitecornerbracketleftvertical", + 0xfe43, + "whitecornerbracketright", + 0x300f, + "whitecornerbracketrightvertical", + 0xfe44, + "whitediamond", + 0x25c7, + "whitediamondcontainingblacksmalldiamond", + 0x25c8, + "whitedownpointingsmalltriangle", + 0x25bf, + "whitedownpointingtriangle", + 0x25bd, + "whiteleftpointingsmalltriangle", + 0x25c3, + "whiteleftpointingtriangle", + 0x25c1, + "whitelenticularbracketleft", + 0x3016, + "whitelenticularbracketright", + 0x3017, + "whiterightpointingsmalltriangle", + 0x25b9, + "whiterightpointingtriangle", + 0x25b7, + "whitesmallsquare", + 0x25ab, + "whitesmilingface", + 0x263a, + "whitesquare", + 0x25a1, + "whitestar", + 0x2606, + "whitetelephone", + 0x260f, + "whitetortoiseshellbracketleft", + 0x3018, + "whitetortoiseshellbracketright", + 0x3019, + "whiteuppointingsmalltriangle", + 0x25b5, + "whiteuppointingtriangle", + 0x25b3, + "wihiragana", + 0x3090, + "wikatakana", + 0x30f0, + "wikorean", + 0x315f, + "wmonospace", + 0xff57, + "wohiragana", + 0x3092, + "wokatakana", + 0x30f2, + "wokatakanahalfwidth", + 0xff66, + "won", + 0x20a9, + "wonmonospace", + 0xffe6, + "wowaenthai", + 0x0e27, + "wparen", + 0x24b2, + "wring", + 0x1e98, + "wsuperior", + 0x02b7, + "wturned", + 0x028d, + "wynn", + 0x01bf, + "x", + 0x0078, + "xabovecmb", + 0x033d, + "xbopomofo", + 0x3112, + "xcircle", + 0x24e7, + "xdieresis", + 0x1e8d, + "xdotaccent", + 0x1e8b, + "xeharmenian", + 0x056d, + "xi", + 0x03be, + "xmonospace", + 0xff58, + "xparen", + 0x24b3, + "xsuperior", + 0x02e3, + "y", + 0x0079, + "yaadosquare", + 0x334e, + "yabengali", + 0x09af, + "yacute", + 0x00fd, + "yadeva", + 0x092f, + "yaekorean", + 0x3152, + "yagujarati", + 0x0aaf, + "yagurmukhi", + 0x0a2f, + "yahiragana", + 0x3084, + "yakatakana", + 0x30e4, + "yakatakanahalfwidth", + 0xff94, + "yakorean", + 0x3151, + "yamakkanthai", + 0x0e4e, + "yasmallhiragana", + 0x3083, + "yasmallkatakana", + 0x30e3, + "yasmallkatakanahalfwidth", + 0xff6c, + "yatcyrillic", + 0x0463, + "ycircle", + 0x24e8, + "ycircumflex", + 0x0177, + "ydieresis", + 0x00ff, + "ydotaccent", + 0x1e8f, + "ydotbelow", + 0x1ef5, + "yeharabic", + 0x064a, + "yehbarreearabic", + 0x06d2, + "yehbarreefinalarabic", + 0xfbaf, + "yehfinalarabic", + 0xfef2, + "yehhamzaabovearabic", + 0x0626, + "yehhamzaabovefinalarabic", + 0xfe8a, + "yehhamzaaboveinitialarabic", + 0xfe8b, + "yehhamzaabovemedialarabic", + 0xfe8c, + "yehinitialarabic", + 0xfef3, + "yehmedialarabic", + 0xfef4, + "yehmeeminitialarabic", + 0xfcdd, + "yehmeemisolatedarabic", + 0xfc58, + "yehnoonfinalarabic", + 0xfc94, + "yehthreedotsbelowarabic", + 0x06d1, + "yekorean", + 0x3156, + "yen", + 0x00a5, + "yenmonospace", + 0xffe5, + "yeokorean", + 0x3155, + "yeorinhieuhkorean", + 0x3186, + "yerahbenyomohebrew", + 0x05aa, + "yerahbenyomolefthebrew", + 0x05aa, + "yericyrillic", + 0x044b, + "yerudieresiscyrillic", + 0x04f9, + "yesieungkorean", + 0x3181, + "yesieungpansioskorean", + 0x3183, + "yesieungsioskorean", + 0x3182, + "yetivhebrew", + 0x059a, + "ygrave", + 0x1ef3, + "yhook", + 0x01b4, + "yhookabove", + 0x1ef7, + "yiarmenian", + 0x0575, + "yicyrillic", + 0x0457, + "yikorean", + 0x3162, + "yinyang", + 0x262f, + "yiwnarmenian", + 0x0582, + "ymonospace", + 0xff59, + "yod", + 0x05d9, + "yoddagesh", + 0xfb39, + "yoddageshhebrew", + 0xfb39, + "yodhebrew", + 0x05d9, + "yodyodhebrew", + 0x05f2, + "yodyodpatahhebrew", + 0xfb1f, + "yohiragana", + 0x3088, + "yoikorean", + 0x3189, + "yokatakana", + 0x30e8, + "yokatakanahalfwidth", + 0xff96, + "yokorean", + 0x315b, + "yosmallhiragana", + 0x3087, + "yosmallkatakana", + 0x30e7, + "yosmallkatakanahalfwidth", + 0xff6e, + "yotgreek", + 0x03f3, + "yoyaekorean", + 0x3188, + "yoyakorean", + 0x3187, + "yoyakthai", + 0x0e22, + "yoyingthai", + 0x0e0d, + "yparen", + 0x24b4, + "ypogegrammeni", + 0x037a, + "ypogegrammenigreekcmb", + 0x0345, + "yr", + 0x01a6, + "yring", + 0x1e99, + "ysuperior", + 0x02b8, + "ytilde", + 0x1ef9, + "yturned", + 0x028e, + "yuhiragana", + 0x3086, + "yuikorean", + 0x318c, + "yukatakana", + 0x30e6, + "yukatakanahalfwidth", + 0xff95, + "yukorean", + 0x3160, + "yusbigcyrillic", + 0x046b, + "yusbigiotifiedcyrillic", + 0x046d, + "yuslittlecyrillic", + 0x0467, + "yuslittleiotifiedcyrillic", + 0x0469, + "yusmallhiragana", + 0x3085, + "yusmallkatakana", + 0x30e5, + "yusmallkatakanahalfwidth", + 0xff6d, + "yuyekorean", + 0x318b, + "yuyeokorean", + 0x318a, + "yyabengali", + 0x09df, + "yyadeva", + 0x095f, + "z", + 0x007a, + "zaarmenian", + 0x0566, + "zacute", + 0x017a, + "zadeva", + 0x095b, + "zagurmukhi", + 0x0a5b, + "zaharabic", + 0x0638, + "zahfinalarabic", + 0xfec6, + "zahinitialarabic", + 0xfec7, + "zahiragana", + 0x3056, + "zahmedialarabic", + 0xfec8, + "zainarabic", + 0x0632, + "zainfinalarabic", + 0xfeb0, + "zakatakana", + 0x30b6, + "zaqefgadolhebrew", + 0x0595, + "zaqefqatanhebrew", + 0x0594, + "zarqahebrew", + 0x0598, + "zayin", + 0x05d6, + "zayindagesh", + 0xfb36, + "zayindageshhebrew", + 0xfb36, + "zayinhebrew", + 0x05d6, + "zbopomofo", + 0x3117, + "zcaron", + 0x017e, + "zcircle", + 0x24e9, + "zcircumflex", + 0x1e91, + "zcurl", + 0x0291, + "zdot", + 0x017c, + "zdotaccent", + 0x017c, + "zdotbelow", + 0x1e93, + "zecyrillic", + 0x0437, + "zedescendercyrillic", + 0x0499, + "zedieresiscyrillic", + 0x04df, + "zehiragana", + 0x305c, + "zekatakana", + 0x30bc, + "zero", + 0x0030, + "zeroarabic", + 0x0660, + "zerobengali", + 0x09e6, + "zerodeva", + 0x0966, + "zerogujarati", + 0x0ae6, + "zerogurmukhi", + 0x0a66, + "zerohackarabic", + 0x0660, + "zeroinferior", + 0x2080, + "zeromonospace", + 0xff10, + "zerooldstyle", + 0xf730, + "zeropersian", + 0x06f0, + "zerosuperior", + 0x2070, + "zerothai", + 0x0e50, + "zerowidthjoiner", + 0xfeff, + "zerowidthnonjoiner", + 0x200c, + "zerowidthspace", + 0x200b, + "zeta", + 0x03b6, + "zhbopomofo", + 0x3113, + "zhearmenian", + 0x056a, + "zhebrevecyrillic", + 0x04c2, + "zhecyrillic", + 0x0436, + "zhedescendercyrillic", + 0x0497, + "zhedieresiscyrillic", + 0x04dd, + "zihiragana", + 0x3058, + "zikatakana", + 0x30b8, + "zinorhebrew", + 0x05ae, + "zlinebelow", + 0x1e95, + "zmonospace", + 0xff5a, + "zohiragana", + 0x305e, + "zokatakana", + 0x30be, + "zparen", + 0x24b5, + "zretroflexhook", + 0x0290, + "zstroke", + 0x01b6, + "zuhiragana", + 0x305a, + "zukatakana", + 0x30ba, + ".notdef", + 0x0000, + "angbracketleftbig", + 0x2329, + "angbracketleftBig", + 0x2329, + "angbracketleftbigg", + 0x2329, + "angbracketleftBigg", + 0x2329, + "angbracketrightBig", + 0x232a, + "angbracketrightbig", + 0x232a, + "angbracketrightBigg", + 0x232a, + "angbracketrightbigg", + 0x232a, + "arrowhookleft", + 0x21aa, + "arrowhookright", + 0x21a9, + "arrowlefttophalf", + 0x21bc, + "arrowleftbothalf", + 0x21bd, + "arrownortheast", + 0x2197, + "arrownorthwest", + 0x2196, + "arrowrighttophalf", + 0x21c0, + "arrowrightbothalf", + 0x21c1, + "arrowsoutheast", + 0x2198, + "arrowsouthwest", + 0x2199, + "backslashbig", + 0x2216, + "backslashBig", + 0x2216, + "backslashBigg", + 0x2216, + "backslashbigg", + 0x2216, + "bardbl", + 0x2016, + "bracehtipdownleft", + 0xfe37, + "bracehtipdownright", + 0xfe37, + "bracehtipupleft", + 0xfe38, + "bracehtipupright", + 0xfe38, + "braceleftBig", + 0x007b, + "braceleftbig", + 0x007b, + "braceleftbigg", + 0x007b, + "braceleftBigg", + 0x007b, + "bracerightBig", + 0x007d, + "bracerightbig", + 0x007d, + "bracerightbigg", + 0x007d, + "bracerightBigg", + 0x007d, + "bracketleftbig", + 0x005b, + "bracketleftBig", + 0x005b, + "bracketleftbigg", + 0x005b, + "bracketleftBigg", + 0x005b, + "bracketrightBig", + 0x005d, + "bracketrightbig", + 0x005d, + "bracketrightbigg", + 0x005d, + "bracketrightBigg", + 0x005d, + "ceilingleftbig", + 0x2308, + "ceilingleftBig", + 0x2308, + "ceilingleftBigg", + 0x2308, + "ceilingleftbigg", + 0x2308, + "ceilingrightbig", + 0x2309, + "ceilingrightBig", + 0x2309, + "ceilingrightbigg", + 0x2309, + "ceilingrightBigg", + 0x2309, + "circledotdisplay", + 0x2299, + "circledottext", + 0x2299, + "circlemultiplydisplay", + 0x2297, + "circlemultiplytext", + 0x2297, + "circleplusdisplay", + 0x2295, + "circleplustext", + 0x2295, + "contintegraldisplay", + 0x222e, + "contintegraltext", + 0x222e, + "coproductdisplay", + 0x2210, + "coproducttext", + 0x2210, + "floorleftBig", + 0x230a, + "floorleftbig", + 0x230a, + "floorleftbigg", + 0x230a, + "floorleftBigg", + 0x230a, + "floorrightbig", + 0x230b, + "floorrightBig", + 0x230b, + "floorrightBigg", + 0x230b, + "floorrightbigg", + 0x230b, + "hatwide", + 0x0302, + "hatwider", + 0x0302, + "hatwidest", + 0x0302, + "intercal", + 0x1d40, + "integraldisplay", + 0x222b, + "integraltext", + 0x222b, + "intersectiondisplay", + 0x22c2, + "intersectiontext", + 0x22c2, + "logicalanddisplay", + 0x2227, + "logicalandtext", + 0x2227, + "logicalordisplay", + 0x2228, + "logicalortext", + 0x2228, + "parenleftBig", + 0x0028, + "parenleftbig", + 0x0028, + "parenleftBigg", + 0x0028, + "parenleftbigg", + 0x0028, + "parenrightBig", + 0x0029, + "parenrightbig", + 0x0029, + "parenrightBigg", + 0x0029, + "parenrightbigg", + 0x0029, + "prime", + 0x2032, + "productdisplay", + 0x220f, + "producttext", + 0x220f, + "radicalbig", + 0x221a, + "radicalBig", + 0x221a, + "radicalBigg", + 0x221a, + "radicalbigg", + 0x221a, + "radicalbt", + 0x221a, + "radicaltp", + 0x221a, + "radicalvertex", + 0x221a, + "slashbig", + 0x002f, + "slashBig", + 0x002f, + "slashBigg", + 0x002f, + "slashbigg", + 0x002f, + "summationdisplay", + 0x2211, + "summationtext", + 0x2211, + "tildewide", + 0x02dc, + "tildewider", + 0x02dc, + "tildewidest", + 0x02dc, + "uniondisplay", + 0x22c3, + "unionmultidisplay", + 0x228e, + "unionmultitext", + 0x228e, + "unionsqdisplay", + 0x2294, + "unionsqtext", + 0x2294, + "uniontext", + 0x22c3, + "vextenddouble", + 0x2225, + "vextendsingle", + 0x2223 + ]; +}); +const getDingbatsGlyphsUnicode = (0,_core_utils_js__WEBPACK_IMPORTED_MODULE_0__.getArrayLookupTableFactory)(function () { + return [ + "space", + 0x0020, + "a1", + 0x2701, + "a2", + 0x2702, + "a202", + 0x2703, + "a3", + 0x2704, + "a4", + 0x260e, + "a5", + 0x2706, + "a119", + 0x2707, + "a118", + 0x2708, + "a117", + 0x2709, + "a11", + 0x261b, + "a12", + 0x261e, + "a13", + 0x270c, + "a14", + 0x270d, + "a15", + 0x270e, + "a16", + 0x270f, + "a105", + 0x2710, + "a17", + 0x2711, + "a18", + 0x2712, + "a19", + 0x2713, + "a20", + 0x2714, + "a21", + 0x2715, + "a22", + 0x2716, + "a23", + 0x2717, + "a24", + 0x2718, + "a25", + 0x2719, + "a26", + 0x271a, + "a27", + 0x271b, + "a28", + 0x271c, + "a6", + 0x271d, + "a7", + 0x271e, + "a8", + 0x271f, + "a9", + 0x2720, + "a10", + 0x2721, + "a29", + 0x2722, + "a30", + 0x2723, + "a31", + 0x2724, + "a32", + 0x2725, + "a33", + 0x2726, + "a34", + 0x2727, + "a35", + 0x2605, + "a36", + 0x2729, + "a37", + 0x272a, + "a38", + 0x272b, + "a39", + 0x272c, + "a40", + 0x272d, + "a41", + 0x272e, + "a42", + 0x272f, + "a43", + 0x2730, + "a44", + 0x2731, + "a45", + 0x2732, + "a46", + 0x2733, + "a47", + 0x2734, + "a48", + 0x2735, + "a49", + 0x2736, + "a50", + 0x2737, + "a51", + 0x2738, + "a52", + 0x2739, + "a53", + 0x273a, + "a54", + 0x273b, + "a55", + 0x273c, + "a56", + 0x273d, + "a57", + 0x273e, + "a58", + 0x273f, + "a59", + 0x2740, + "a60", + 0x2741, + "a61", + 0x2742, + "a62", + 0x2743, + "a63", + 0x2744, + "a64", + 0x2745, + "a65", + 0x2746, + "a66", + 0x2747, + "a67", + 0x2748, + "a68", + 0x2749, + "a69", + 0x274a, + "a70", + 0x274b, + "a71", + 0x25cf, + "a72", + 0x274d, + "a73", + 0x25a0, + "a74", + 0x274f, + "a203", + 0x2750, + "a75", + 0x2751, + "a204", + 0x2752, + "a76", + 0x25b2, + "a77", + 0x25bc, + "a78", + 0x25c6, + "a79", + 0x2756, + "a81", + 0x25d7, + "a82", + 0x2758, + "a83", + 0x2759, + "a84", + 0x275a, + "a97", + 0x275b, + "a98", + 0x275c, + "a99", + 0x275d, + "a100", + 0x275e, + "a101", + 0x2761, + "a102", + 0x2762, + "a103", + 0x2763, + "a104", + 0x2764, + "a106", + 0x2765, + "a107", + 0x2766, + "a108", + 0x2767, + "a112", + 0x2663, + "a111", + 0x2666, + "a110", + 0x2665, + "a109", + 0x2660, + "a120", + 0x2460, + "a121", + 0x2461, + "a122", + 0x2462, + "a123", + 0x2463, + "a124", + 0x2464, + "a125", + 0x2465, + "a126", + 0x2466, + "a127", + 0x2467, + "a128", + 0x2468, + "a129", + 0x2469, + "a130", + 0x2776, + "a131", + 0x2777, + "a132", + 0x2778, + "a133", + 0x2779, + "a134", + 0x277a, + "a135", + 0x277b, + "a136", + 0x277c, + "a137", + 0x277d, + "a138", + 0x277e, + "a139", + 0x277f, + "a140", + 0x2780, + "a141", + 0x2781, + "a142", + 0x2782, + "a143", + 0x2783, + "a144", + 0x2784, + "a145", + 0x2785, + "a146", + 0x2786, + "a147", + 0x2787, + "a148", + 0x2788, + "a149", + 0x2789, + "a150", + 0x278a, + "a151", + 0x278b, + "a152", + 0x278c, + "a153", + 0x278d, + "a154", + 0x278e, + "a155", + 0x278f, + "a156", + 0x2790, + "a157", + 0x2791, + "a158", + 0x2792, + "a159", + 0x2793, + "a160", + 0x2794, + "a161", + 0x2192, + "a163", + 0x2194, + "a164", + 0x2195, + "a196", + 0x2798, + "a165", + 0x2799, + "a192", + 0x279a, + "a166", + 0x279b, + "a167", + 0x279c, + "a168", + 0x279d, + "a169", + 0x279e, + "a170", + 0x279f, + "a171", + 0x27a0, + "a172", + 0x27a1, + "a173", + 0x27a2, + "a162", + 0x27a3, + "a174", + 0x27a4, + "a175", + 0x27a5, + "a176", + 0x27a6, + "a177", + 0x27a7, + "a178", + 0x27a8, + "a179", + 0x27a9, + "a193", + 0x27aa, + "a180", + 0x27ab, + "a199", + 0x27ac, + "a181", + 0x27ad, + "a200", + 0x27ae, + "a182", + 0x27af, + "a201", + 0x27b1, + "a183", + 0x27b2, + "a184", + 0x27b3, + "a197", + 0x27b4, + "a185", + 0x27b5, + "a194", + 0x27b6, + "a198", + 0x27b7, + "a186", + 0x27b8, + "a195", + 0x27b9, + "a187", + 0x27ba, + "a188", + 0x27bb, + "a189", + 0x27bc, + "a190", + 0x27bd, + "a191", + 0x27be, + "a89", + 0x2768, + "a90", + 0x2769, + "a93", + 0x276a, + "a94", + 0x276b, + "a91", + 0x276c, + "a92", + 0x276d, + "a205", + 0x276e, + "a85", + 0x276f, + "a206", + 0x2770, + "a86", + 0x2771, + "a87", + 0x2772, + "a88", + 0x2773, + "a95", + 0x2774, + "a96", + 0x2775, + ".notdef", + 0x0000 + ]; +}); + + +/***/ }), +/* 40 */ +/***/ ((__unused_webpack_module, __webpack_exports__, __w_pdfjs_require__) => { + +__w_pdfjs_require__.r(__webpack_exports__); +/* harmony export */ __w_pdfjs_require__.d(__webpack_exports__, { +/* harmony export */ "clearUnicodeCaches": () => (/* binding */ clearUnicodeCaches), +/* harmony export */ "getCharUnicodeCategory": () => (/* binding */ getCharUnicodeCategory), +/* harmony export */ "getNormalizedUnicodes": () => (/* binding */ getNormalizedUnicodes), +/* harmony export */ "getUnicodeForGlyph": () => (/* binding */ getUnicodeForGlyph), +/* harmony export */ "getUnicodeRangeFor": () => (/* binding */ getUnicodeRangeFor), +/* harmony export */ "mapSpecialUnicodeValues": () => (/* binding */ mapSpecialUnicodeValues), +/* harmony export */ "reverseIfRtl": () => (/* binding */ reverseIfRtl) +/* harmony export */ }); +/* harmony import */ var _core_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __w_pdfjs_require__(6); + +const getSpecialPUASymbols = (0,_core_utils_js__WEBPACK_IMPORTED_MODULE_0__.getLookupTableFactory)(function (t) { t[63721] = 0x00a9; t[63193] = 0x00a9; t[63720] = 0x00ae; @@ -36669,7 +39141,7 @@ function mapSpecialUnicodeValues(code) { return code; } function getUnicodeForGlyph(name, glyphsUnicodeMap) { - var unicode = glyphsUnicodeMap[name]; + let unicode = glyphsUnicodeMap[name]; if (unicode !== undefined) { return unicode; } @@ -36677,7 +39149,8 @@ function getUnicodeForGlyph(name, glyphsUnicodeMap) { return -1; } if (name[0] === "u") { - var nameLen = name.length, hexStr; + const nameLen = name.length; + let hexStr; if (nameLen === 7 && name[1] === "n" && name[2] === "i") { hexStr = name.substring(3); } else if (nameLen >= 5 && nameLen <= 7) { @@ -36694,7 +39167,7 @@ function getUnicodeForGlyph(name, glyphsUnicodeMap) { } return -1; } -var UnicodeRanges = [ +const UnicodeRanges = [ { begin: 0x0000, end: 0x007f @@ -37189,8 +39662,8 @@ var UnicodeRanges = [ } ]; function getUnicodeRangeFor(value) { - for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) { - var range = UnicodeRanges[i]; + for (let i = 0, ii = UnicodeRanges.length; i < ii; i++) { + const range = UnicodeRanges[i]; if (value >= range.begin && value < range.end) { return i; } @@ -37198,7 +39671,7 @@ function getUnicodeRangeFor(value) { return -1; } function isRTLRangeFor(value) { - var range = UnicodeRanges[13]; + let range = UnicodeRanges[13]; if (value >= range.begin && value < range.end) { return true; } @@ -37208,2074 +39681,4346 @@ function isRTLRangeFor(value) { } return false; } -var getNormalizedUnicodes = getLookupTableFactory(function (t) { - t["\u00A8"] = "\u0020\u0308"; - t["\u00AF"] = "\u0020\u0304"; - t["\u00B4"] = "\u0020\u0301"; - t["\u00B5"] = "\u03BC"; - t["\u00B8"] = "\u0020\u0327"; - t["\u0132"] = "\u0049\u004A"; - t["\u0133"] = "\u0069\u006A"; - t["\u013F"] = "\u004C\u00B7"; - t["\u0140"] = "\u006C\u00B7"; - t["\u0149"] = "\u02BC\u006E"; - t["\u017F"] = "\u0073"; - t["\u01C4"] = "\u0044\u017D"; - t["\u01C5"] = "\u0044\u017E"; - t["\u01C6"] = "\u0064\u017E"; - t["\u01C7"] = "\u004C\u004A"; - t["\u01C8"] = "\u004C\u006A"; - t["\u01C9"] = "\u006C\u006A"; - t["\u01CA"] = "\u004E\u004A"; - t["\u01CB"] = "\u004E\u006A"; - t["\u01CC"] = "\u006E\u006A"; - t["\u01F1"] = "\u0044\u005A"; - t["\u01F2"] = "\u0044\u007A"; - t["\u01F3"] = "\u0064\u007A"; - t["\u02D8"] = "\u0020\u0306"; - t["\u02D9"] = "\u0020\u0307"; - t["\u02DA"] = "\u0020\u030A"; - t["\u02DB"] = "\u0020\u0328"; - t["\u02DC"] = "\u0020\u0303"; - t["\u02DD"] = "\u0020\u030B"; - t["\u037A"] = "\u0020\u0345"; - t["\u0384"] = "\u0020\u0301"; - t["\u03D0"] = "\u03B2"; - t["\u03D1"] = "\u03B8"; - t["\u03D2"] = "\u03A5"; - t["\u03D5"] = "\u03C6"; - t["\u03D6"] = "\u03C0"; - t["\u03F0"] = "\u03BA"; - t["\u03F1"] = "\u03C1"; - t["\u03F2"] = "\u03C2"; - t["\u03F4"] = "\u0398"; - t["\u03F5"] = "\u03B5"; - t["\u03F9"] = "\u03A3"; - t["\u0587"] = "\u0565\u0582"; - t["\u0675"] = "\u0627\u0674"; - t["\u0676"] = "\u0648\u0674"; - t["\u0677"] = "\u06C7\u0674"; - t["\u0678"] = "\u064A\u0674"; - t["\u0E33"] = "\u0E4D\u0E32"; - t["\u0EB3"] = "\u0ECD\u0EB2"; - t["\u0EDC"] = "\u0EAB\u0E99"; - t["\u0EDD"] = "\u0EAB\u0EA1"; - t["\u0F77"] = "\u0FB2\u0F81"; - t["\u0F79"] = "\u0FB3\u0F81"; - t["\u1E9A"] = "\u0061\u02BE"; - t["\u1FBD"] = "\u0020\u0313"; - t["\u1FBF"] = "\u0020\u0313"; - t["\u1FC0"] = "\u0020\u0342"; - t["\u1FFE"] = "\u0020\u0314"; - t["\u2002"] = "\u0020"; - t["\u2003"] = "\u0020"; - t["\u2004"] = "\u0020"; - t["\u2005"] = "\u0020"; - t["\u2006"] = "\u0020"; - t["\u2008"] = "\u0020"; - t["\u2009"] = "\u0020"; - t["\u200A"] = "\u0020"; - t["\u2017"] = "\u0020\u0333"; - t["\u2024"] = "\u002E"; - t["\u2025"] = "\u002E\u002E"; - t["\u2026"] = "\u002E\u002E\u002E"; - t["\u2033"] = "\u2032\u2032"; - t["\u2034"] = "\u2032\u2032\u2032"; - t["\u2036"] = "\u2035\u2035"; - t["\u2037"] = "\u2035\u2035\u2035"; - t["\u203C"] = "\u0021\u0021"; - t["\u203E"] = "\u0020\u0305"; - t["\u2047"] = "\u003F\u003F"; - t["\u2048"] = "\u003F\u0021"; - t["\u2049"] = "\u0021\u003F"; - t["\u2057"] = "\u2032\u2032\u2032\u2032"; - t["\u205F"] = "\u0020"; - t["\u20A8"] = "\u0052\u0073"; - t["\u2100"] = "\u0061\u002F\u0063"; - t["\u2101"] = "\u0061\u002F\u0073"; - t["\u2103"] = "\u00B0\u0043"; - t["\u2105"] = "\u0063\u002F\u006F"; - t["\u2106"] = "\u0063\u002F\u0075"; - t["\u2107"] = "\u0190"; - t["\u2109"] = "\u00B0\u0046"; - t["\u2116"] = "\u004E\u006F"; - t["\u2121"] = "\u0054\u0045\u004C"; - t["\u2135"] = "\u05D0"; - t["\u2136"] = "\u05D1"; - t["\u2137"] = "\u05D2"; - t["\u2138"] = "\u05D3"; - t["\u213B"] = "\u0046\u0041\u0058"; - t["\u2160"] = "\u0049"; - t["\u2161"] = "\u0049\u0049"; - t["\u2162"] = "\u0049\u0049\u0049"; - t["\u2163"] = "\u0049\u0056"; - t["\u2164"] = "\u0056"; - t["\u2165"] = "\u0056\u0049"; - t["\u2166"] = "\u0056\u0049\u0049"; - t["\u2167"] = "\u0056\u0049\u0049\u0049"; - t["\u2168"] = "\u0049\u0058"; - t["\u2169"] = "\u0058"; - t["\u216A"] = "\u0058\u0049"; - t["\u216B"] = "\u0058\u0049\u0049"; - t["\u216C"] = "\u004C"; - t["\u216D"] = "\u0043"; - t["\u216E"] = "\u0044"; - t["\u216F"] = "\u004D"; - t["\u2170"] = "\u0069"; - t["\u2171"] = "\u0069\u0069"; - t["\u2172"] = "\u0069\u0069\u0069"; - t["\u2173"] = "\u0069\u0076"; - t["\u2174"] = "\u0076"; - t["\u2175"] = "\u0076\u0069"; - t["\u2176"] = "\u0076\u0069\u0069"; - t["\u2177"] = "\u0076\u0069\u0069\u0069"; - t["\u2178"] = "\u0069\u0078"; - t["\u2179"] = "\u0078"; - t["\u217A"] = "\u0078\u0069"; - t["\u217B"] = "\u0078\u0069\u0069"; - t["\u217C"] = "\u006C"; - t["\u217D"] = "\u0063"; - t["\u217E"] = "\u0064"; - t["\u217F"] = "\u006D"; - t["\u222C"] = "\u222B\u222B"; - t["\u222D"] = "\u222B\u222B\u222B"; - t["\u222F"] = "\u222E\u222E"; - t["\u2230"] = "\u222E\u222E\u222E"; - t["\u2474"] = "\u0028\u0031\u0029"; - t["\u2475"] = "\u0028\u0032\u0029"; - t["\u2476"] = "\u0028\u0033\u0029"; - t["\u2477"] = "\u0028\u0034\u0029"; - t["\u2478"] = "\u0028\u0035\u0029"; - t["\u2479"] = "\u0028\u0036\u0029"; - t["\u247A"] = "\u0028\u0037\u0029"; - t["\u247B"] = "\u0028\u0038\u0029"; - t["\u247C"] = "\u0028\u0039\u0029"; - t["\u247D"] = "\u0028\u0031\u0030\u0029"; - t["\u247E"] = "\u0028\u0031\u0031\u0029"; - t["\u247F"] = "\u0028\u0031\u0032\u0029"; - t["\u2480"] = "\u0028\u0031\u0033\u0029"; - t["\u2481"] = "\u0028\u0031\u0034\u0029"; - t["\u2482"] = "\u0028\u0031\u0035\u0029"; - t["\u2483"] = "\u0028\u0031\u0036\u0029"; - t["\u2484"] = "\u0028\u0031\u0037\u0029"; - t["\u2485"] = "\u0028\u0031\u0038\u0029"; - t["\u2486"] = "\u0028\u0031\u0039\u0029"; - t["\u2487"] = "\u0028\u0032\u0030\u0029"; - t["\u2488"] = "\u0031\u002E"; - t["\u2489"] = "\u0032\u002E"; - t["\u248A"] = "\u0033\u002E"; - t["\u248B"] = "\u0034\u002E"; - t["\u248C"] = "\u0035\u002E"; - t["\u248D"] = "\u0036\u002E"; - t["\u248E"] = "\u0037\u002E"; - t["\u248F"] = "\u0038\u002E"; - t["\u2490"] = "\u0039\u002E"; - t["\u2491"] = "\u0031\u0030\u002E"; - t["\u2492"] = "\u0031\u0031\u002E"; - t["\u2493"] = "\u0031\u0032\u002E"; - t["\u2494"] = "\u0031\u0033\u002E"; - t["\u2495"] = "\u0031\u0034\u002E"; - t["\u2496"] = "\u0031\u0035\u002E"; - t["\u2497"] = "\u0031\u0036\u002E"; - t["\u2498"] = "\u0031\u0037\u002E"; - t["\u2499"] = "\u0031\u0038\u002E"; - t["\u249A"] = "\u0031\u0039\u002E"; - t["\u249B"] = "\u0032\u0030\u002E"; - t["\u249C"] = "\u0028\u0061\u0029"; - t["\u249D"] = "\u0028\u0062\u0029"; - t["\u249E"] = "\u0028\u0063\u0029"; - t["\u249F"] = "\u0028\u0064\u0029"; - t["\u24A0"] = "\u0028\u0065\u0029"; - t["\u24A1"] = "\u0028\u0066\u0029"; - t["\u24A2"] = "\u0028\u0067\u0029"; - t["\u24A3"] = "\u0028\u0068\u0029"; - t["\u24A4"] = "\u0028\u0069\u0029"; - t["\u24A5"] = "\u0028\u006A\u0029"; - t["\u24A6"] = "\u0028\u006B\u0029"; - t["\u24A7"] = "\u0028\u006C\u0029"; - t["\u24A8"] = "\u0028\u006D\u0029"; - t["\u24A9"] = "\u0028\u006E\u0029"; - t["\u24AA"] = "\u0028\u006F\u0029"; - t["\u24AB"] = "\u0028\u0070\u0029"; - t["\u24AC"] = "\u0028\u0071\u0029"; - t["\u24AD"] = "\u0028\u0072\u0029"; - t["\u24AE"] = "\u0028\u0073\u0029"; - t["\u24AF"] = "\u0028\u0074\u0029"; - t["\u24B0"] = "\u0028\u0075\u0029"; - t["\u24B1"] = "\u0028\u0076\u0029"; - t["\u24B2"] = "\u0028\u0077\u0029"; - t["\u24B3"] = "\u0028\u0078\u0029"; - t["\u24B4"] = "\u0028\u0079\u0029"; - t["\u24B5"] = "\u0028\u007A\u0029"; - t["\u2A0C"] = "\u222B\u222B\u222B\u222B"; - t["\u2A74"] = "\u003A\u003A\u003D"; - t["\u2A75"] = "\u003D\u003D"; - t["\u2A76"] = "\u003D\u003D\u003D"; - t["\u2E9F"] = "\u6BCD"; - t["\u2EF3"] = "\u9F9F"; - t["\u2F00"] = "\u4E00"; - t["\u2F01"] = "\u4E28"; - t["\u2F02"] = "\u4E36"; - t["\u2F03"] = "\u4E3F"; - t["\u2F04"] = "\u4E59"; - t["\u2F05"] = "\u4E85"; - t["\u2F06"] = "\u4E8C"; - t["\u2F07"] = "\u4EA0"; - t["\u2F08"] = "\u4EBA"; - t["\u2F09"] = "\u513F"; - t["\u2F0A"] = "\u5165"; - t["\u2F0B"] = "\u516B"; - t["\u2F0C"] = "\u5182"; - t["\u2F0D"] = "\u5196"; - t["\u2F0E"] = "\u51AB"; - t["\u2F0F"] = "\u51E0"; - t["\u2F10"] = "\u51F5"; - t["\u2F11"] = "\u5200"; - t["\u2F12"] = "\u529B"; - t["\u2F13"] = "\u52F9"; - t["\u2F14"] = "\u5315"; - t["\u2F15"] = "\u531A"; - t["\u2F16"] = "\u5338"; - t["\u2F17"] = "\u5341"; - t["\u2F18"] = "\u535C"; - t["\u2F19"] = "\u5369"; - t["\u2F1A"] = "\u5382"; - t["\u2F1B"] = "\u53B6"; - t["\u2F1C"] = "\u53C8"; - t["\u2F1D"] = "\u53E3"; - t["\u2F1E"] = "\u56D7"; - t["\u2F1F"] = "\u571F"; - t["\u2F20"] = "\u58EB"; - t["\u2F21"] = "\u5902"; - t["\u2F22"] = "\u590A"; - t["\u2F23"] = "\u5915"; - t["\u2F24"] = "\u5927"; - t["\u2F25"] = "\u5973"; - t["\u2F26"] = "\u5B50"; - t["\u2F27"] = "\u5B80"; - t["\u2F28"] = "\u5BF8"; - t["\u2F29"] = "\u5C0F"; - t["\u2F2A"] = "\u5C22"; - t["\u2F2B"] = "\u5C38"; - t["\u2F2C"] = "\u5C6E"; - t["\u2F2D"] = "\u5C71"; - t["\u2F2E"] = "\u5DDB"; - t["\u2F2F"] = "\u5DE5"; - t["\u2F30"] = "\u5DF1"; - t["\u2F31"] = "\u5DFE"; - t["\u2F32"] = "\u5E72"; - t["\u2F33"] = "\u5E7A"; - t["\u2F34"] = "\u5E7F"; - t["\u2F35"] = "\u5EF4"; - t["\u2F36"] = "\u5EFE"; - t["\u2F37"] = "\u5F0B"; - t["\u2F38"] = "\u5F13"; - t["\u2F39"] = "\u5F50"; - t["\u2F3A"] = "\u5F61"; - t["\u2F3B"] = "\u5F73"; - t["\u2F3C"] = "\u5FC3"; - t["\u2F3D"] = "\u6208"; - t["\u2F3E"] = "\u6236"; - t["\u2F3F"] = "\u624B"; - t["\u2F40"] = "\u652F"; - t["\u2F41"] = "\u6534"; - t["\u2F42"] = "\u6587"; - t["\u2F43"] = "\u6597"; - t["\u2F44"] = "\u65A4"; - t["\u2F45"] = "\u65B9"; - t["\u2F46"] = "\u65E0"; - t["\u2F47"] = "\u65E5"; - t["\u2F48"] = "\u66F0"; - t["\u2F49"] = "\u6708"; - t["\u2F4A"] = "\u6728"; - t["\u2F4B"] = "\u6B20"; - t["\u2F4C"] = "\u6B62"; - t["\u2F4D"] = "\u6B79"; - t["\u2F4E"] = "\u6BB3"; - t["\u2F4F"] = "\u6BCB"; - t["\u2F50"] = "\u6BD4"; - t["\u2F51"] = "\u6BDB"; - t["\u2F52"] = "\u6C0F"; - t["\u2F53"] = "\u6C14"; - t["\u2F54"] = "\u6C34"; - t["\u2F55"] = "\u706B"; - t["\u2F56"] = "\u722A"; - t["\u2F57"] = "\u7236"; - t["\u2F58"] = "\u723B"; - t["\u2F59"] = "\u723F"; - t["\u2F5A"] = "\u7247"; - t["\u2F5B"] = "\u7259"; - t["\u2F5C"] = "\u725B"; - t["\u2F5D"] = "\u72AC"; - t["\u2F5E"] = "\u7384"; - t["\u2F5F"] = "\u7389"; - t["\u2F60"] = "\u74DC"; - t["\u2F61"] = "\u74E6"; - t["\u2F62"] = "\u7518"; - t["\u2F63"] = "\u751F"; - t["\u2F64"] = "\u7528"; - t["\u2F65"] = "\u7530"; - t["\u2F66"] = "\u758B"; - t["\u2F67"] = "\u7592"; - t["\u2F68"] = "\u7676"; - t["\u2F69"] = "\u767D"; - t["\u2F6A"] = "\u76AE"; - t["\u2F6B"] = "\u76BF"; - t["\u2F6C"] = "\u76EE"; - t["\u2F6D"] = "\u77DB"; - t["\u2F6E"] = "\u77E2"; - t["\u2F6F"] = "\u77F3"; - t["\u2F70"] = "\u793A"; - t["\u2F71"] = "\u79B8"; - t["\u2F72"] = "\u79BE"; - t["\u2F73"] = "\u7A74"; - t["\u2F74"] = "\u7ACB"; - t["\u2F75"] = "\u7AF9"; - t["\u2F76"] = "\u7C73"; - t["\u2F77"] = "\u7CF8"; - t["\u2F78"] = "\u7F36"; - t["\u2F79"] = "\u7F51"; - t["\u2F7A"] = "\u7F8A"; - t["\u2F7B"] = "\u7FBD"; - t["\u2F7C"] = "\u8001"; - t["\u2F7D"] = "\u800C"; - t["\u2F7E"] = "\u8012"; - t["\u2F7F"] = "\u8033"; - t["\u2F80"] = "\u807F"; - t["\u2F81"] = "\u8089"; - t["\u2F82"] = "\u81E3"; - t["\u2F83"] = "\u81EA"; - t["\u2F84"] = "\u81F3"; - t["\u2F85"] = "\u81FC"; - t["\u2F86"] = "\u820C"; - t["\u2F87"] = "\u821B"; - t["\u2F88"] = "\u821F"; - t["\u2F89"] = "\u826E"; - t["\u2F8A"] = "\u8272"; - t["\u2F8B"] = "\u8278"; - t["\u2F8C"] = "\u864D"; - t["\u2F8D"] = "\u866B"; - t["\u2F8E"] = "\u8840"; - t["\u2F8F"] = "\u884C"; - t["\u2F90"] = "\u8863"; - t["\u2F91"] = "\u897E"; - t["\u2F92"] = "\u898B"; - t["\u2F93"] = "\u89D2"; - t["\u2F94"] = "\u8A00"; - t["\u2F95"] = "\u8C37"; - t["\u2F96"] = "\u8C46"; - t["\u2F97"] = "\u8C55"; - t["\u2F98"] = "\u8C78"; - t["\u2F99"] = "\u8C9D"; - t["\u2F9A"] = "\u8D64"; - t["\u2F9B"] = "\u8D70"; - t["\u2F9C"] = "\u8DB3"; - t["\u2F9D"] = "\u8EAB"; - t["\u2F9E"] = "\u8ECA"; - t["\u2F9F"] = "\u8F9B"; - t["\u2FA0"] = "\u8FB0"; - t["\u2FA1"] = "\u8FB5"; - t["\u2FA2"] = "\u9091"; - t["\u2FA3"] = "\u9149"; - t["\u2FA4"] = "\u91C6"; - t["\u2FA5"] = "\u91CC"; - t["\u2FA6"] = "\u91D1"; - t["\u2FA7"] = "\u9577"; - t["\u2FA8"] = "\u9580"; - t["\u2FA9"] = "\u961C"; - t["\u2FAA"] = "\u96B6"; - t["\u2FAB"] = "\u96B9"; - t["\u2FAC"] = "\u96E8"; - t["\u2FAD"] = "\u9751"; - t["\u2FAE"] = "\u975E"; - t["\u2FAF"] = "\u9762"; - t["\u2FB0"] = "\u9769"; - t["\u2FB1"] = "\u97CB"; - t["\u2FB2"] = "\u97ED"; - t["\u2FB3"] = "\u97F3"; - t["\u2FB4"] = "\u9801"; - t["\u2FB5"] = "\u98A8"; - t["\u2FB6"] = "\u98DB"; - t["\u2FB7"] = "\u98DF"; - t["\u2FB8"] = "\u9996"; - t["\u2FB9"] = "\u9999"; - t["\u2FBA"] = "\u99AC"; - t["\u2FBB"] = "\u9AA8"; - t["\u2FBC"] = "\u9AD8"; - t["\u2FBD"] = "\u9ADF"; - t["\u2FBE"] = "\u9B25"; - t["\u2FBF"] = "\u9B2F"; - t["\u2FC0"] = "\u9B32"; - t["\u2FC1"] = "\u9B3C"; - t["\u2FC2"] = "\u9B5A"; - t["\u2FC3"] = "\u9CE5"; - t["\u2FC4"] = "\u9E75"; - t["\u2FC5"] = "\u9E7F"; - t["\u2FC6"] = "\u9EA5"; - t["\u2FC7"] = "\u9EBB"; - t["\u2FC8"] = "\u9EC3"; - t["\u2FC9"] = "\u9ECD"; - t["\u2FCA"] = "\u9ED1"; - t["\u2FCB"] = "\u9EF9"; - t["\u2FCC"] = "\u9EFD"; - t["\u2FCD"] = "\u9F0E"; - t["\u2FCE"] = "\u9F13"; - t["\u2FCF"] = "\u9F20"; - t["\u2FD0"] = "\u9F3B"; - t["\u2FD1"] = "\u9F4A"; - t["\u2FD2"] = "\u9F52"; - t["\u2FD3"] = "\u9F8D"; - t["\u2FD4"] = "\u9F9C"; - t["\u2FD5"] = "\u9FA0"; - t["\u3036"] = "\u3012"; - t["\u3038"] = "\u5341"; - t["\u3039"] = "\u5344"; - t["\u303A"] = "\u5345"; - t["\u309B"] = "\u0020\u3099"; - t["\u309C"] = "\u0020\u309A"; - t["\u3131"] = "\u1100"; - t["\u3132"] = "\u1101"; - t["\u3133"] = "\u11AA"; - t["\u3134"] = "\u1102"; - t["\u3135"] = "\u11AC"; - t["\u3136"] = "\u11AD"; - t["\u3137"] = "\u1103"; - t["\u3138"] = "\u1104"; - t["\u3139"] = "\u1105"; - t["\u313A"] = "\u11B0"; - t["\u313B"] = "\u11B1"; - t["\u313C"] = "\u11B2"; - t["\u313D"] = "\u11B3"; - t["\u313E"] = "\u11B4"; - t["\u313F"] = "\u11B5"; - t["\u3140"] = "\u111A"; - t["\u3141"] = "\u1106"; - t["\u3142"] = "\u1107"; - t["\u3143"] = "\u1108"; - t["\u3144"] = "\u1121"; - t["\u3145"] = "\u1109"; - t["\u3146"] = "\u110A"; - t["\u3147"] = "\u110B"; - t["\u3148"] = "\u110C"; - t["\u3149"] = "\u110D"; - t["\u314A"] = "\u110E"; - t["\u314B"] = "\u110F"; - t["\u314C"] = "\u1110"; - t["\u314D"] = "\u1111"; - t["\u314E"] = "\u1112"; - t["\u314F"] = "\u1161"; - t["\u3150"] = "\u1162"; - t["\u3151"] = "\u1163"; - t["\u3152"] = "\u1164"; - t["\u3153"] = "\u1165"; - t["\u3154"] = "\u1166"; - t["\u3155"] = "\u1167"; - t["\u3156"] = "\u1168"; - t["\u3157"] = "\u1169"; - t["\u3158"] = "\u116A"; - t["\u3159"] = "\u116B"; - t["\u315A"] = "\u116C"; - t["\u315B"] = "\u116D"; - t["\u315C"] = "\u116E"; - t["\u315D"] = "\u116F"; - t["\u315E"] = "\u1170"; - t["\u315F"] = "\u1171"; - t["\u3160"] = "\u1172"; - t["\u3161"] = "\u1173"; - t["\u3162"] = "\u1174"; - t["\u3163"] = "\u1175"; - t["\u3164"] = "\u1160"; - t["\u3165"] = "\u1114"; - t["\u3166"] = "\u1115"; - t["\u3167"] = "\u11C7"; - t["\u3168"] = "\u11C8"; - t["\u3169"] = "\u11CC"; - t["\u316A"] = "\u11CE"; - t["\u316B"] = "\u11D3"; - t["\u316C"] = "\u11D7"; - t["\u316D"] = "\u11D9"; - t["\u316E"] = "\u111C"; - t["\u316F"] = "\u11DD"; - t["\u3170"] = "\u11DF"; - t["\u3171"] = "\u111D"; - t["\u3172"] = "\u111E"; - t["\u3173"] = "\u1120"; - t["\u3174"] = "\u1122"; - t["\u3175"] = "\u1123"; - t["\u3176"] = "\u1127"; - t["\u3177"] = "\u1129"; - t["\u3178"] = "\u112B"; - t["\u3179"] = "\u112C"; - t["\u317A"] = "\u112D"; - t["\u317B"] = "\u112E"; - t["\u317C"] = "\u112F"; - t["\u317D"] = "\u1132"; - t["\u317E"] = "\u1136"; - t["\u317F"] = "\u1140"; - t["\u3180"] = "\u1147"; - t["\u3181"] = "\u114C"; - t["\u3182"] = "\u11F1"; - t["\u3183"] = "\u11F2"; - t["\u3184"] = "\u1157"; - t["\u3185"] = "\u1158"; - t["\u3186"] = "\u1159"; - t["\u3187"] = "\u1184"; - t["\u3188"] = "\u1185"; - t["\u3189"] = "\u1188"; - t["\u318A"] = "\u1191"; - t["\u318B"] = "\u1192"; - t["\u318C"] = "\u1194"; - t["\u318D"] = "\u119E"; - t["\u318E"] = "\u11A1"; - t["\u3200"] = "\u0028\u1100\u0029"; - t["\u3201"] = "\u0028\u1102\u0029"; - t["\u3202"] = "\u0028\u1103\u0029"; - t["\u3203"] = "\u0028\u1105\u0029"; - t["\u3204"] = "\u0028\u1106\u0029"; - t["\u3205"] = "\u0028\u1107\u0029"; - t["\u3206"] = "\u0028\u1109\u0029"; - t["\u3207"] = "\u0028\u110B\u0029"; - t["\u3208"] = "\u0028\u110C\u0029"; - t["\u3209"] = "\u0028\u110E\u0029"; - t["\u320A"] = "\u0028\u110F\u0029"; - t["\u320B"] = "\u0028\u1110\u0029"; - t["\u320C"] = "\u0028\u1111\u0029"; - t["\u320D"] = "\u0028\u1112\u0029"; - t["\u320E"] = "\u0028\u1100\u1161\u0029"; - t["\u320F"] = "\u0028\u1102\u1161\u0029"; - t["\u3210"] = "\u0028\u1103\u1161\u0029"; - t["\u3211"] = "\u0028\u1105\u1161\u0029"; - t["\u3212"] = "\u0028\u1106\u1161\u0029"; - t["\u3213"] = "\u0028\u1107\u1161\u0029"; - t["\u3214"] = "\u0028\u1109\u1161\u0029"; - t["\u3215"] = "\u0028\u110B\u1161\u0029"; - t["\u3216"] = "\u0028\u110C\u1161\u0029"; - t["\u3217"] = "\u0028\u110E\u1161\u0029"; - t["\u3218"] = "\u0028\u110F\u1161\u0029"; - t["\u3219"] = "\u0028\u1110\u1161\u0029"; - t["\u321A"] = "\u0028\u1111\u1161\u0029"; - t["\u321B"] = "\u0028\u1112\u1161\u0029"; - t["\u321C"] = "\u0028\u110C\u116E\u0029"; - t["\u321D"] = "\u0028\u110B\u1169\u110C\u1165\u11AB\u0029"; - t["\u321E"] = "\u0028\u110B\u1169\u1112\u116E\u0029"; - t["\u3220"] = "\u0028\u4E00\u0029"; - t["\u3221"] = "\u0028\u4E8C\u0029"; - t["\u3222"] = "\u0028\u4E09\u0029"; - t["\u3223"] = "\u0028\u56DB\u0029"; - t["\u3224"] = "\u0028\u4E94\u0029"; - t["\u3225"] = "\u0028\u516D\u0029"; - t["\u3226"] = "\u0028\u4E03\u0029"; - t["\u3227"] = "\u0028\u516B\u0029"; - t["\u3228"] = "\u0028\u4E5D\u0029"; - t["\u3229"] = "\u0028\u5341\u0029"; - t["\u322A"] = "\u0028\u6708\u0029"; - t["\u322B"] = "\u0028\u706B\u0029"; - t["\u322C"] = "\u0028\u6C34\u0029"; - t["\u322D"] = "\u0028\u6728\u0029"; - t["\u322E"] = "\u0028\u91D1\u0029"; - t["\u322F"] = "\u0028\u571F\u0029"; - t["\u3230"] = "\u0028\u65E5\u0029"; - t["\u3231"] = "\u0028\u682A\u0029"; - t["\u3232"] = "\u0028\u6709\u0029"; - t["\u3233"] = "\u0028\u793E\u0029"; - t["\u3234"] = "\u0028\u540D\u0029"; - t["\u3235"] = "\u0028\u7279\u0029"; - t["\u3236"] = "\u0028\u8CA1\u0029"; - t["\u3237"] = "\u0028\u795D\u0029"; - t["\u3238"] = "\u0028\u52B4\u0029"; - t["\u3239"] = "\u0028\u4EE3\u0029"; - t["\u323A"] = "\u0028\u547C\u0029"; - t["\u323B"] = "\u0028\u5B66\u0029"; - t["\u323C"] = "\u0028\u76E3\u0029"; - t["\u323D"] = "\u0028\u4F01\u0029"; - t["\u323E"] = "\u0028\u8CC7\u0029"; - t["\u323F"] = "\u0028\u5354\u0029"; - t["\u3240"] = "\u0028\u796D\u0029"; - t["\u3241"] = "\u0028\u4F11\u0029"; - t["\u3242"] = "\u0028\u81EA\u0029"; - t["\u3243"] = "\u0028\u81F3\u0029"; - t["\u32C0"] = "\u0031\u6708"; - t["\u32C1"] = "\u0032\u6708"; - t["\u32C2"] = "\u0033\u6708"; - t["\u32C3"] = "\u0034\u6708"; - t["\u32C4"] = "\u0035\u6708"; - t["\u32C5"] = "\u0036\u6708"; - t["\u32C6"] = "\u0037\u6708"; - t["\u32C7"] = "\u0038\u6708"; - t["\u32C8"] = "\u0039\u6708"; - t["\u32C9"] = "\u0031\u0030\u6708"; - t["\u32CA"] = "\u0031\u0031\u6708"; - t["\u32CB"] = "\u0031\u0032\u6708"; - t["\u3358"] = "\u0030\u70B9"; - t["\u3359"] = "\u0031\u70B9"; - t["\u335A"] = "\u0032\u70B9"; - t["\u335B"] = "\u0033\u70B9"; - t["\u335C"] = "\u0034\u70B9"; - t["\u335D"] = "\u0035\u70B9"; - t["\u335E"] = "\u0036\u70B9"; - t["\u335F"] = "\u0037\u70B9"; - t["\u3360"] = "\u0038\u70B9"; - t["\u3361"] = "\u0039\u70B9"; - t["\u3362"] = "\u0031\u0030\u70B9"; - t["\u3363"] = "\u0031\u0031\u70B9"; - t["\u3364"] = "\u0031\u0032\u70B9"; - t["\u3365"] = "\u0031\u0033\u70B9"; - t["\u3366"] = "\u0031\u0034\u70B9"; - t["\u3367"] = "\u0031\u0035\u70B9"; - t["\u3368"] = "\u0031\u0036\u70B9"; - t["\u3369"] = "\u0031\u0037\u70B9"; - t["\u336A"] = "\u0031\u0038\u70B9"; - t["\u336B"] = "\u0031\u0039\u70B9"; - t["\u336C"] = "\u0032\u0030\u70B9"; - t["\u336D"] = "\u0032\u0031\u70B9"; - t["\u336E"] = "\u0032\u0032\u70B9"; - t["\u336F"] = "\u0032\u0033\u70B9"; - t["\u3370"] = "\u0032\u0034\u70B9"; - t["\u33E0"] = "\u0031\u65E5"; - t["\u33E1"] = "\u0032\u65E5"; - t["\u33E2"] = "\u0033\u65E5"; - t["\u33E3"] = "\u0034\u65E5"; - t["\u33E4"] = "\u0035\u65E5"; - t["\u33E5"] = "\u0036\u65E5"; - t["\u33E6"] = "\u0037\u65E5"; - t["\u33E7"] = "\u0038\u65E5"; - t["\u33E8"] = "\u0039\u65E5"; - t["\u33E9"] = "\u0031\u0030\u65E5"; - t["\u33EA"] = "\u0031\u0031\u65E5"; - t["\u33EB"] = "\u0031\u0032\u65E5"; - t["\u33EC"] = "\u0031\u0033\u65E5"; - t["\u33ED"] = "\u0031\u0034\u65E5"; - t["\u33EE"] = "\u0031\u0035\u65E5"; - t["\u33EF"] = "\u0031\u0036\u65E5"; - t["\u33F0"] = "\u0031\u0037\u65E5"; - t["\u33F1"] = "\u0031\u0038\u65E5"; - t["\u33F2"] = "\u0031\u0039\u65E5"; - t["\u33F3"] = "\u0032\u0030\u65E5"; - t["\u33F4"] = "\u0032\u0031\u65E5"; - t["\u33F5"] = "\u0032\u0032\u65E5"; - t["\u33F6"] = "\u0032\u0033\u65E5"; - t["\u33F7"] = "\u0032\u0034\u65E5"; - t["\u33F8"] = "\u0032\u0035\u65E5"; - t["\u33F9"] = "\u0032\u0036\u65E5"; - t["\u33FA"] = "\u0032\u0037\u65E5"; - t["\u33FB"] = "\u0032\u0038\u65E5"; - t["\u33FC"] = "\u0032\u0039\u65E5"; - t["\u33FD"] = "\u0033\u0030\u65E5"; - t["\u33FE"] = "\u0033\u0031\u65E5"; - t["\uFB00"] = "\u0066\u0066"; - t["\uFB01"] = "\u0066\u0069"; - t["\uFB02"] = "\u0066\u006C"; - t["\uFB03"] = "\u0066\u0066\u0069"; - t["\uFB04"] = "\u0066\u0066\u006C"; - t["\uFB05"] = "\u017F\u0074"; - t["\uFB06"] = "\u0073\u0074"; - t["\uFB13"] = "\u0574\u0576"; - t["\uFB14"] = "\u0574\u0565"; - t["\uFB15"] = "\u0574\u056B"; - t["\uFB16"] = "\u057E\u0576"; - t["\uFB17"] = "\u0574\u056D"; - t["\uFB4F"] = "\u05D0\u05DC"; - t["\uFB50"] = "\u0671"; - t["\uFB51"] = "\u0671"; - t["\uFB52"] = "\u067B"; - t["\uFB53"] = "\u067B"; - t["\uFB54"] = "\u067B"; - t["\uFB55"] = "\u067B"; - t["\uFB56"] = "\u067E"; - t["\uFB57"] = "\u067E"; - t["\uFB58"] = "\u067E"; - t["\uFB59"] = "\u067E"; - t["\uFB5A"] = "\u0680"; - t["\uFB5B"] = "\u0680"; - t["\uFB5C"] = "\u0680"; - t["\uFB5D"] = "\u0680"; - t["\uFB5E"] = "\u067A"; - t["\uFB5F"] = "\u067A"; - t["\uFB60"] = "\u067A"; - t["\uFB61"] = "\u067A"; - t["\uFB62"] = "\u067F"; - t["\uFB63"] = "\u067F"; - t["\uFB64"] = "\u067F"; - t["\uFB65"] = "\u067F"; - t["\uFB66"] = "\u0679"; - t["\uFB67"] = "\u0679"; - t["\uFB68"] = "\u0679"; - t["\uFB69"] = "\u0679"; - t["\uFB6A"] = "\u06A4"; - t["\uFB6B"] = "\u06A4"; - t["\uFB6C"] = "\u06A4"; - t["\uFB6D"] = "\u06A4"; - t["\uFB6E"] = "\u06A6"; - t["\uFB6F"] = "\u06A6"; - t["\uFB70"] = "\u06A6"; - t["\uFB71"] = "\u06A6"; - t["\uFB72"] = "\u0684"; - t["\uFB73"] = "\u0684"; - t["\uFB74"] = "\u0684"; - t["\uFB75"] = "\u0684"; - t["\uFB76"] = "\u0683"; - t["\uFB77"] = "\u0683"; - t["\uFB78"] = "\u0683"; - t["\uFB79"] = "\u0683"; - t["\uFB7A"] = "\u0686"; - t["\uFB7B"] = "\u0686"; - t["\uFB7C"] = "\u0686"; - t["\uFB7D"] = "\u0686"; - t["\uFB7E"] = "\u0687"; - t["\uFB7F"] = "\u0687"; - t["\uFB80"] = "\u0687"; - t["\uFB81"] = "\u0687"; - t["\uFB82"] = "\u068D"; - t["\uFB83"] = "\u068D"; - t["\uFB84"] = "\u068C"; - t["\uFB85"] = "\u068C"; - t["\uFB86"] = "\u068E"; - t["\uFB87"] = "\u068E"; - t["\uFB88"] = "\u0688"; - t["\uFB89"] = "\u0688"; - t["\uFB8A"] = "\u0698"; - t["\uFB8B"] = "\u0698"; - t["\uFB8C"] = "\u0691"; - t["\uFB8D"] = "\u0691"; - t["\uFB8E"] = "\u06A9"; - t["\uFB8F"] = "\u06A9"; - t["\uFB90"] = "\u06A9"; - t["\uFB91"] = "\u06A9"; - t["\uFB92"] = "\u06AF"; - t["\uFB93"] = "\u06AF"; - t["\uFB94"] = "\u06AF"; - t["\uFB95"] = "\u06AF"; - t["\uFB96"] = "\u06B3"; - t["\uFB97"] = "\u06B3"; - t["\uFB98"] = "\u06B3"; - t["\uFB99"] = "\u06B3"; - t["\uFB9A"] = "\u06B1"; - t["\uFB9B"] = "\u06B1"; - t["\uFB9C"] = "\u06B1"; - t["\uFB9D"] = "\u06B1"; - t["\uFB9E"] = "\u06BA"; - t["\uFB9F"] = "\u06BA"; - t["\uFBA0"] = "\u06BB"; - t["\uFBA1"] = "\u06BB"; - t["\uFBA2"] = "\u06BB"; - t["\uFBA3"] = "\u06BB"; - t["\uFBA4"] = "\u06C0"; - t["\uFBA5"] = "\u06C0"; - t["\uFBA6"] = "\u06C1"; - t["\uFBA7"] = "\u06C1"; - t["\uFBA8"] = "\u06C1"; - t["\uFBA9"] = "\u06C1"; - t["\uFBAA"] = "\u06BE"; - t["\uFBAB"] = "\u06BE"; - t["\uFBAC"] = "\u06BE"; - t["\uFBAD"] = "\u06BE"; - t["\uFBAE"] = "\u06D2"; - t["\uFBAF"] = "\u06D2"; - t["\uFBB0"] = "\u06D3"; - t["\uFBB1"] = "\u06D3"; - t["\uFBD3"] = "\u06AD"; - t["\uFBD4"] = "\u06AD"; - t["\uFBD5"] = "\u06AD"; - t["\uFBD6"] = "\u06AD"; - t["\uFBD7"] = "\u06C7"; - t["\uFBD8"] = "\u06C7"; - t["\uFBD9"] = "\u06C6"; - t["\uFBDA"] = "\u06C6"; - t["\uFBDB"] = "\u06C8"; - t["\uFBDC"] = "\u06C8"; - t["\uFBDD"] = "\u0677"; - t["\uFBDE"] = "\u06CB"; - t["\uFBDF"] = "\u06CB"; - t["\uFBE0"] = "\u06C5"; - t["\uFBE1"] = "\u06C5"; - t["\uFBE2"] = "\u06C9"; - t["\uFBE3"] = "\u06C9"; - t["\uFBE4"] = "\u06D0"; - t["\uFBE5"] = "\u06D0"; - t["\uFBE6"] = "\u06D0"; - t["\uFBE7"] = "\u06D0"; - t["\uFBE8"] = "\u0649"; - t["\uFBE9"] = "\u0649"; - t["\uFBEA"] = "\u0626\u0627"; - t["\uFBEB"] = "\u0626\u0627"; - t["\uFBEC"] = "\u0626\u06D5"; - t["\uFBED"] = "\u0626\u06D5"; - t["\uFBEE"] = "\u0626\u0648"; - t["\uFBEF"] = "\u0626\u0648"; - t["\uFBF0"] = "\u0626\u06C7"; - t["\uFBF1"] = "\u0626\u06C7"; - t["\uFBF2"] = "\u0626\u06C6"; - t["\uFBF3"] = "\u0626\u06C6"; - t["\uFBF4"] = "\u0626\u06C8"; - t["\uFBF5"] = "\u0626\u06C8"; - t["\uFBF6"] = "\u0626\u06D0"; - t["\uFBF7"] = "\u0626\u06D0"; - t["\uFBF8"] = "\u0626\u06D0"; - t["\uFBF9"] = "\u0626\u0649"; - t["\uFBFA"] = "\u0626\u0649"; - t["\uFBFB"] = "\u0626\u0649"; - t["\uFBFC"] = "\u06CC"; - t["\uFBFD"] = "\u06CC"; - t["\uFBFE"] = "\u06CC"; - t["\uFBFF"] = "\u06CC"; - t["\uFC00"] = "\u0626\u062C"; - t["\uFC01"] = "\u0626\u062D"; - t["\uFC02"] = "\u0626\u0645"; - t["\uFC03"] = "\u0626\u0649"; - t["\uFC04"] = "\u0626\u064A"; - t["\uFC05"] = "\u0628\u062C"; - t["\uFC06"] = "\u0628\u062D"; - t["\uFC07"] = "\u0628\u062E"; - t["\uFC08"] = "\u0628\u0645"; - t["\uFC09"] = "\u0628\u0649"; - t["\uFC0A"] = "\u0628\u064A"; - t["\uFC0B"] = "\u062A\u062C"; - t["\uFC0C"] = "\u062A\u062D"; - t["\uFC0D"] = "\u062A\u062E"; - t["\uFC0E"] = "\u062A\u0645"; - t["\uFC0F"] = "\u062A\u0649"; - t["\uFC10"] = "\u062A\u064A"; - t["\uFC11"] = "\u062B\u062C"; - t["\uFC12"] = "\u062B\u0645"; - t["\uFC13"] = "\u062B\u0649"; - t["\uFC14"] = "\u062B\u064A"; - t["\uFC15"] = "\u062C\u062D"; - t["\uFC16"] = "\u062C\u0645"; - t["\uFC17"] = "\u062D\u062C"; - t["\uFC18"] = "\u062D\u0645"; - t["\uFC19"] = "\u062E\u062C"; - t["\uFC1A"] = "\u062E\u062D"; - t["\uFC1B"] = "\u062E\u0645"; - t["\uFC1C"] = "\u0633\u062C"; - t["\uFC1D"] = "\u0633\u062D"; - t["\uFC1E"] = "\u0633\u062E"; - t["\uFC1F"] = "\u0633\u0645"; - t["\uFC20"] = "\u0635\u062D"; - t["\uFC21"] = "\u0635\u0645"; - t["\uFC22"] = "\u0636\u062C"; - t["\uFC23"] = "\u0636\u062D"; - t["\uFC24"] = "\u0636\u062E"; - t["\uFC25"] = "\u0636\u0645"; - t["\uFC26"] = "\u0637\u062D"; - t["\uFC27"] = "\u0637\u0645"; - t["\uFC28"] = "\u0638\u0645"; - t["\uFC29"] = "\u0639\u062C"; - t["\uFC2A"] = "\u0639\u0645"; - t["\uFC2B"] = "\u063A\u062C"; - t["\uFC2C"] = "\u063A\u0645"; - t["\uFC2D"] = "\u0641\u062C"; - t["\uFC2E"] = "\u0641\u062D"; - t["\uFC2F"] = "\u0641\u062E"; - t["\uFC30"] = "\u0641\u0645"; - t["\uFC31"] = "\u0641\u0649"; - t["\uFC32"] = "\u0641\u064A"; - t["\uFC33"] = "\u0642\u062D"; - t["\uFC34"] = "\u0642\u0645"; - t["\uFC35"] = "\u0642\u0649"; - t["\uFC36"] = "\u0642\u064A"; - t["\uFC37"] = "\u0643\u0627"; - t["\uFC38"] = "\u0643\u062C"; - t["\uFC39"] = "\u0643\u062D"; - t["\uFC3A"] = "\u0643\u062E"; - t["\uFC3B"] = "\u0643\u0644"; - t["\uFC3C"] = "\u0643\u0645"; - t["\uFC3D"] = "\u0643\u0649"; - t["\uFC3E"] = "\u0643\u064A"; - t["\uFC3F"] = "\u0644\u062C"; - t["\uFC40"] = "\u0644\u062D"; - t["\uFC41"] = "\u0644\u062E"; - t["\uFC42"] = "\u0644\u0645"; - t["\uFC43"] = "\u0644\u0649"; - t["\uFC44"] = "\u0644\u064A"; - t["\uFC45"] = "\u0645\u062C"; - t["\uFC46"] = "\u0645\u062D"; - t["\uFC47"] = "\u0645\u062E"; - t["\uFC48"] = "\u0645\u0645"; - t["\uFC49"] = "\u0645\u0649"; - t["\uFC4A"] = "\u0645\u064A"; - t["\uFC4B"] = "\u0646\u062C"; - t["\uFC4C"] = "\u0646\u062D"; - t["\uFC4D"] = "\u0646\u062E"; - t["\uFC4E"] = "\u0646\u0645"; - t["\uFC4F"] = "\u0646\u0649"; - t["\uFC50"] = "\u0646\u064A"; - t["\uFC51"] = "\u0647\u062C"; - t["\uFC52"] = "\u0647\u0645"; - t["\uFC53"] = "\u0647\u0649"; - t["\uFC54"] = "\u0647\u064A"; - t["\uFC55"] = "\u064A\u062C"; - t["\uFC56"] = "\u064A\u062D"; - t["\uFC57"] = "\u064A\u062E"; - t["\uFC58"] = "\u064A\u0645"; - t["\uFC59"] = "\u064A\u0649"; - t["\uFC5A"] = "\u064A\u064A"; - t["\uFC5B"] = "\u0630\u0670"; - t["\uFC5C"] = "\u0631\u0670"; - t["\uFC5D"] = "\u0649\u0670"; - t["\uFC5E"] = "\u0020\u064C\u0651"; - t["\uFC5F"] = "\u0020\u064D\u0651"; - t["\uFC60"] = "\u0020\u064E\u0651"; - t["\uFC61"] = "\u0020\u064F\u0651"; - t["\uFC62"] = "\u0020\u0650\u0651"; - t["\uFC63"] = "\u0020\u0651\u0670"; - t["\uFC64"] = "\u0626\u0631"; - t["\uFC65"] = "\u0626\u0632"; - t["\uFC66"] = "\u0626\u0645"; - t["\uFC67"] = "\u0626\u0646"; - t["\uFC68"] = "\u0626\u0649"; - t["\uFC69"] = "\u0626\u064A"; - t["\uFC6A"] = "\u0628\u0631"; - t["\uFC6B"] = "\u0628\u0632"; - t["\uFC6C"] = "\u0628\u0645"; - t["\uFC6D"] = "\u0628\u0646"; - t["\uFC6E"] = "\u0628\u0649"; - t["\uFC6F"] = "\u0628\u064A"; - t["\uFC70"] = "\u062A\u0631"; - t["\uFC71"] = "\u062A\u0632"; - t["\uFC72"] = "\u062A\u0645"; - t["\uFC73"] = "\u062A\u0646"; - t["\uFC74"] = "\u062A\u0649"; - t["\uFC75"] = "\u062A\u064A"; - t["\uFC76"] = "\u062B\u0631"; - t["\uFC77"] = "\u062B\u0632"; - t["\uFC78"] = "\u062B\u0645"; - t["\uFC79"] = "\u062B\u0646"; - t["\uFC7A"] = "\u062B\u0649"; - t["\uFC7B"] = "\u062B\u064A"; - t["\uFC7C"] = "\u0641\u0649"; - t["\uFC7D"] = "\u0641\u064A"; - t["\uFC7E"] = "\u0642\u0649"; - t["\uFC7F"] = "\u0642\u064A"; - t["\uFC80"] = "\u0643\u0627"; - t["\uFC81"] = "\u0643\u0644"; - t["\uFC82"] = "\u0643\u0645"; - t["\uFC83"] = "\u0643\u0649"; - t["\uFC84"] = "\u0643\u064A"; - t["\uFC85"] = "\u0644\u0645"; - t["\uFC86"] = "\u0644\u0649"; - t["\uFC87"] = "\u0644\u064A"; - t["\uFC88"] = "\u0645\u0627"; - t["\uFC89"] = "\u0645\u0645"; - t["\uFC8A"] = "\u0646\u0631"; - t["\uFC8B"] = "\u0646\u0632"; - t["\uFC8C"] = "\u0646\u0645"; - t["\uFC8D"] = "\u0646\u0646"; - t["\uFC8E"] = "\u0646\u0649"; - t["\uFC8F"] = "\u0646\u064A"; - t["\uFC90"] = "\u0649\u0670"; - t["\uFC91"] = "\u064A\u0631"; - t["\uFC92"] = "\u064A\u0632"; - t["\uFC93"] = "\u064A\u0645"; - t["\uFC94"] = "\u064A\u0646"; - t["\uFC95"] = "\u064A\u0649"; - t["\uFC96"] = "\u064A\u064A"; - t["\uFC97"] = "\u0626\u062C"; - t["\uFC98"] = "\u0626\u062D"; - t["\uFC99"] = "\u0626\u062E"; - t["\uFC9A"] = "\u0626\u0645"; - t["\uFC9B"] = "\u0626\u0647"; - t["\uFC9C"] = "\u0628\u062C"; - t["\uFC9D"] = "\u0628\u062D"; - t["\uFC9E"] = "\u0628\u062E"; - t["\uFC9F"] = "\u0628\u0645"; - t["\uFCA0"] = "\u0628\u0647"; - t["\uFCA1"] = "\u062A\u062C"; - t["\uFCA2"] = "\u062A\u062D"; - t["\uFCA3"] = "\u062A\u062E"; - t["\uFCA4"] = "\u062A\u0645"; - t["\uFCA5"] = "\u062A\u0647"; - t["\uFCA6"] = "\u062B\u0645"; - t["\uFCA7"] = "\u062C\u062D"; - t["\uFCA8"] = "\u062C\u0645"; - t["\uFCA9"] = "\u062D\u062C"; - t["\uFCAA"] = "\u062D\u0645"; - t["\uFCAB"] = "\u062E\u062C"; - t["\uFCAC"] = "\u062E\u0645"; - t["\uFCAD"] = "\u0633\u062C"; - t["\uFCAE"] = "\u0633\u062D"; - t["\uFCAF"] = "\u0633\u062E"; - t["\uFCB0"] = "\u0633\u0645"; - t["\uFCB1"] = "\u0635\u062D"; - t["\uFCB2"] = "\u0635\u062E"; - t["\uFCB3"] = "\u0635\u0645"; - t["\uFCB4"] = "\u0636\u062C"; - t["\uFCB5"] = "\u0636\u062D"; - t["\uFCB6"] = "\u0636\u062E"; - t["\uFCB7"] = "\u0636\u0645"; - t["\uFCB8"] = "\u0637\u062D"; - t["\uFCB9"] = "\u0638\u0645"; - t["\uFCBA"] = "\u0639\u062C"; - t["\uFCBB"] = "\u0639\u0645"; - t["\uFCBC"] = "\u063A\u062C"; - t["\uFCBD"] = "\u063A\u0645"; - t["\uFCBE"] = "\u0641\u062C"; - t["\uFCBF"] = "\u0641\u062D"; - t["\uFCC0"] = "\u0641\u062E"; - t["\uFCC1"] = "\u0641\u0645"; - t["\uFCC2"] = "\u0642\u062D"; - t["\uFCC3"] = "\u0642\u0645"; - t["\uFCC4"] = "\u0643\u062C"; - t["\uFCC5"] = "\u0643\u062D"; - t["\uFCC6"] = "\u0643\u062E"; - t["\uFCC7"] = "\u0643\u0644"; - t["\uFCC8"] = "\u0643\u0645"; - t["\uFCC9"] = "\u0644\u062C"; - t["\uFCCA"] = "\u0644\u062D"; - t["\uFCCB"] = "\u0644\u062E"; - t["\uFCCC"] = "\u0644\u0645"; - t["\uFCCD"] = "\u0644\u0647"; - t["\uFCCE"] = "\u0645\u062C"; - t["\uFCCF"] = "\u0645\u062D"; - t["\uFCD0"] = "\u0645\u062E"; - t["\uFCD1"] = "\u0645\u0645"; - t["\uFCD2"] = "\u0646\u062C"; - t["\uFCD3"] = "\u0646\u062D"; - t["\uFCD4"] = "\u0646\u062E"; - t["\uFCD5"] = "\u0646\u0645"; - t["\uFCD6"] = "\u0646\u0647"; - t["\uFCD7"] = "\u0647\u062C"; - t["\uFCD8"] = "\u0647\u0645"; - t["\uFCD9"] = "\u0647\u0670"; - t["\uFCDA"] = "\u064A\u062C"; - t["\uFCDB"] = "\u064A\u062D"; - t["\uFCDC"] = "\u064A\u062E"; - t["\uFCDD"] = "\u064A\u0645"; - t["\uFCDE"] = "\u064A\u0647"; - t["\uFCDF"] = "\u0626\u0645"; - t["\uFCE0"] = "\u0626\u0647"; - t["\uFCE1"] = "\u0628\u0645"; - t["\uFCE2"] = "\u0628\u0647"; - t["\uFCE3"] = "\u062A\u0645"; - t["\uFCE4"] = "\u062A\u0647"; - t["\uFCE5"] = "\u062B\u0645"; - t["\uFCE6"] = "\u062B\u0647"; - t["\uFCE7"] = "\u0633\u0645"; - t["\uFCE8"] = "\u0633\u0647"; - t["\uFCE9"] = "\u0634\u0645"; - t["\uFCEA"] = "\u0634\u0647"; - t["\uFCEB"] = "\u0643\u0644"; - t["\uFCEC"] = "\u0643\u0645"; - t["\uFCED"] = "\u0644\u0645"; - t["\uFCEE"] = "\u0646\u0645"; - t["\uFCEF"] = "\u0646\u0647"; - t["\uFCF0"] = "\u064A\u0645"; - t["\uFCF1"] = "\u064A\u0647"; - t["\uFCF2"] = "\u0640\u064E\u0651"; - t["\uFCF3"] = "\u0640\u064F\u0651"; - t["\uFCF4"] = "\u0640\u0650\u0651"; - t["\uFCF5"] = "\u0637\u0649"; - t["\uFCF6"] = "\u0637\u064A"; - t["\uFCF7"] = "\u0639\u0649"; - t["\uFCF8"] = "\u0639\u064A"; - t["\uFCF9"] = "\u063A\u0649"; - t["\uFCFA"] = "\u063A\u064A"; - t["\uFCFB"] = "\u0633\u0649"; - t["\uFCFC"] = "\u0633\u064A"; - t["\uFCFD"] = "\u0634\u0649"; - t["\uFCFE"] = "\u0634\u064A"; - t["\uFCFF"] = "\u062D\u0649"; - t["\uFD00"] = "\u062D\u064A"; - t["\uFD01"] = "\u062C\u0649"; - t["\uFD02"] = "\u062C\u064A"; - t["\uFD03"] = "\u062E\u0649"; - t["\uFD04"] = "\u062E\u064A"; - t["\uFD05"] = "\u0635\u0649"; - t["\uFD06"] = "\u0635\u064A"; - t["\uFD07"] = "\u0636\u0649"; - t["\uFD08"] = "\u0636\u064A"; - t["\uFD09"] = "\u0634\u062C"; - t["\uFD0A"] = "\u0634\u062D"; - t["\uFD0B"] = "\u0634\u062E"; - t["\uFD0C"] = "\u0634\u0645"; - t["\uFD0D"] = "\u0634\u0631"; - t["\uFD0E"] = "\u0633\u0631"; - t["\uFD0F"] = "\u0635\u0631"; - t["\uFD10"] = "\u0636\u0631"; - t["\uFD11"] = "\u0637\u0649"; - t["\uFD12"] = "\u0637\u064A"; - t["\uFD13"] = "\u0639\u0649"; - t["\uFD14"] = "\u0639\u064A"; - t["\uFD15"] = "\u063A\u0649"; - t["\uFD16"] = "\u063A\u064A"; - t["\uFD17"] = "\u0633\u0649"; - t["\uFD18"] = "\u0633\u064A"; - t["\uFD19"] = "\u0634\u0649"; - t["\uFD1A"] = "\u0634\u064A"; - t["\uFD1B"] = "\u062D\u0649"; - t["\uFD1C"] = "\u062D\u064A"; - t["\uFD1D"] = "\u062C\u0649"; - t["\uFD1E"] = "\u062C\u064A"; - t["\uFD1F"] = "\u062E\u0649"; - t["\uFD20"] = "\u062E\u064A"; - t["\uFD21"] = "\u0635\u0649"; - t["\uFD22"] = "\u0635\u064A"; - t["\uFD23"] = "\u0636\u0649"; - t["\uFD24"] = "\u0636\u064A"; - t["\uFD25"] = "\u0634\u062C"; - t["\uFD26"] = "\u0634\u062D"; - t["\uFD27"] = "\u0634\u062E"; - t["\uFD28"] = "\u0634\u0645"; - t["\uFD29"] = "\u0634\u0631"; - t["\uFD2A"] = "\u0633\u0631"; - t["\uFD2B"] = "\u0635\u0631"; - t["\uFD2C"] = "\u0636\u0631"; - t["\uFD2D"] = "\u0634\u062C"; - t["\uFD2E"] = "\u0634\u062D"; - t["\uFD2F"] = "\u0634\u062E"; - t["\uFD30"] = "\u0634\u0645"; - t["\uFD31"] = "\u0633\u0647"; - t["\uFD32"] = "\u0634\u0647"; - t["\uFD33"] = "\u0637\u0645"; - t["\uFD34"] = "\u0633\u062C"; - t["\uFD35"] = "\u0633\u062D"; - t["\uFD36"] = "\u0633\u062E"; - t["\uFD37"] = "\u0634\u062C"; - t["\uFD38"] = "\u0634\u062D"; - t["\uFD39"] = "\u0634\u062E"; - t["\uFD3A"] = "\u0637\u0645"; - t["\uFD3B"] = "\u0638\u0645"; - t["\uFD3C"] = "\u0627\u064B"; - t["\uFD3D"] = "\u0627\u064B"; - t["\uFD50"] = "\u062A\u062C\u0645"; - t["\uFD51"] = "\u062A\u062D\u062C"; - t["\uFD52"] = "\u062A\u062D\u062C"; - t["\uFD53"] = "\u062A\u062D\u0645"; - t["\uFD54"] = "\u062A\u062E\u0645"; - t["\uFD55"] = "\u062A\u0645\u062C"; - t["\uFD56"] = "\u062A\u0645\u062D"; - t["\uFD57"] = "\u062A\u0645\u062E"; - t["\uFD58"] = "\u062C\u0645\u062D"; - t["\uFD59"] = "\u062C\u0645\u062D"; - t["\uFD5A"] = "\u062D\u0645\u064A"; - t["\uFD5B"] = "\u062D\u0645\u0649"; - t["\uFD5C"] = "\u0633\u062D\u062C"; - t["\uFD5D"] = "\u0633\u062C\u062D"; - t["\uFD5E"] = "\u0633\u062C\u0649"; - t["\uFD5F"] = "\u0633\u0645\u062D"; - t["\uFD60"] = "\u0633\u0645\u062D"; - t["\uFD61"] = "\u0633\u0645\u062C"; - t["\uFD62"] = "\u0633\u0645\u0645"; - t["\uFD63"] = "\u0633\u0645\u0645"; - t["\uFD64"] = "\u0635\u062D\u062D"; - t["\uFD65"] = "\u0635\u062D\u062D"; - t["\uFD66"] = "\u0635\u0645\u0645"; - t["\uFD67"] = "\u0634\u062D\u0645"; - t["\uFD68"] = "\u0634\u062D\u0645"; - t["\uFD69"] = "\u0634\u062C\u064A"; - t["\uFD6A"] = "\u0634\u0645\u062E"; - t["\uFD6B"] = "\u0634\u0645\u062E"; - t["\uFD6C"] = "\u0634\u0645\u0645"; - t["\uFD6D"] = "\u0634\u0645\u0645"; - t["\uFD6E"] = "\u0636\u062D\u0649"; - t["\uFD6F"] = "\u0636\u062E\u0645"; - t["\uFD70"] = "\u0636\u062E\u0645"; - t["\uFD71"] = "\u0637\u0645\u062D"; - t["\uFD72"] = "\u0637\u0645\u062D"; - t["\uFD73"] = "\u0637\u0645\u0645"; - t["\uFD74"] = "\u0637\u0645\u064A"; - t["\uFD75"] = "\u0639\u062C\u0645"; - t["\uFD76"] = "\u0639\u0645\u0645"; - t["\uFD77"] = "\u0639\u0645\u0645"; - t["\uFD78"] = "\u0639\u0645\u0649"; - t["\uFD79"] = "\u063A\u0645\u0645"; - t["\uFD7A"] = "\u063A\u0645\u064A"; - t["\uFD7B"] = "\u063A\u0645\u0649"; - t["\uFD7C"] = "\u0641\u062E\u0645"; - t["\uFD7D"] = "\u0641\u062E\u0645"; - t["\uFD7E"] = "\u0642\u0645\u062D"; - t["\uFD7F"] = "\u0642\u0645\u0645"; - t["\uFD80"] = "\u0644\u062D\u0645"; - t["\uFD81"] = "\u0644\u062D\u064A"; - t["\uFD82"] = "\u0644\u062D\u0649"; - t["\uFD83"] = "\u0644\u062C\u062C"; - t["\uFD84"] = "\u0644\u062C\u062C"; - t["\uFD85"] = "\u0644\u062E\u0645"; - t["\uFD86"] = "\u0644\u062E\u0645"; - t["\uFD87"] = "\u0644\u0645\u062D"; - t["\uFD88"] = "\u0644\u0645\u062D"; - t["\uFD89"] = "\u0645\u062D\u062C"; - t["\uFD8A"] = "\u0645\u062D\u0645"; - t["\uFD8B"] = "\u0645\u062D\u064A"; - t["\uFD8C"] = "\u0645\u062C\u062D"; - t["\uFD8D"] = "\u0645\u062C\u0645"; - t["\uFD8E"] = "\u0645\u062E\u062C"; - t["\uFD8F"] = "\u0645\u062E\u0645"; - t["\uFD92"] = "\u0645\u062C\u062E"; - t["\uFD93"] = "\u0647\u0645\u062C"; - t["\uFD94"] = "\u0647\u0645\u0645"; - t["\uFD95"] = "\u0646\u062D\u0645"; - t["\uFD96"] = "\u0646\u062D\u0649"; - t["\uFD97"] = "\u0646\u062C\u0645"; - t["\uFD98"] = "\u0646\u062C\u0645"; - t["\uFD99"] = "\u0646\u062C\u0649"; - t["\uFD9A"] = "\u0646\u0645\u064A"; - t["\uFD9B"] = "\u0646\u0645\u0649"; - t["\uFD9C"] = "\u064A\u0645\u0645"; - t["\uFD9D"] = "\u064A\u0645\u0645"; - t["\uFD9E"] = "\u0628\u062E\u064A"; - t["\uFD9F"] = "\u062A\u062C\u064A"; - t["\uFDA0"] = "\u062A\u062C\u0649"; - t["\uFDA1"] = "\u062A\u062E\u064A"; - t["\uFDA2"] = "\u062A\u062E\u0649"; - t["\uFDA3"] = "\u062A\u0645\u064A"; - t["\uFDA4"] = "\u062A\u0645\u0649"; - t["\uFDA5"] = "\u062C\u0645\u064A"; - t["\uFDA6"] = "\u062C\u062D\u0649"; - t["\uFDA7"] = "\u062C\u0645\u0649"; - t["\uFDA8"] = "\u0633\u062E\u0649"; - t["\uFDA9"] = "\u0635\u062D\u064A"; - t["\uFDAA"] = "\u0634\u062D\u064A"; - t["\uFDAB"] = "\u0636\u062D\u064A"; - t["\uFDAC"] = "\u0644\u062C\u064A"; - t["\uFDAD"] = "\u0644\u0645\u064A"; - t["\uFDAE"] = "\u064A\u062D\u064A"; - t["\uFDAF"] = "\u064A\u062C\u064A"; - t["\uFDB0"] = "\u064A\u0645\u064A"; - t["\uFDB1"] = "\u0645\u0645\u064A"; - t["\uFDB2"] = "\u0642\u0645\u064A"; - t["\uFDB3"] = "\u0646\u062D\u064A"; - t["\uFDB4"] = "\u0642\u0645\u062D"; - t["\uFDB5"] = "\u0644\u062D\u0645"; - t["\uFDB6"] = "\u0639\u0645\u064A"; - t["\uFDB7"] = "\u0643\u0645\u064A"; - t["\uFDB8"] = "\u0646\u062C\u062D"; - t["\uFDB9"] = "\u0645\u062E\u064A"; - t["\uFDBA"] = "\u0644\u062C\u0645"; - t["\uFDBB"] = "\u0643\u0645\u0645"; - t["\uFDBC"] = "\u0644\u062C\u0645"; - t["\uFDBD"] = "\u0646\u062C\u062D"; - t["\uFDBE"] = "\u062C\u062D\u064A"; - t["\uFDBF"] = "\u062D\u062C\u064A"; - t["\uFDC0"] = "\u0645\u062C\u064A"; - t["\uFDC1"] = "\u0641\u0645\u064A"; - t["\uFDC2"] = "\u0628\u062D\u064A"; - t["\uFDC3"] = "\u0643\u0645\u0645"; - t["\uFDC4"] = "\u0639\u062C\u0645"; - t["\uFDC5"] = "\u0635\u0645\u0645"; - t["\uFDC6"] = "\u0633\u062E\u064A"; - t["\uFDC7"] = "\u0646\u062C\u064A"; - t["\uFE49"] = "\u203E"; - t["\uFE4A"] = "\u203E"; - t["\uFE4B"] = "\u203E"; - t["\uFE4C"] = "\u203E"; - t["\uFE4D"] = "\u005F"; - t["\uFE4E"] = "\u005F"; - t["\uFE4F"] = "\u005F"; - t["\uFE80"] = "\u0621"; - t["\uFE81"] = "\u0622"; - t["\uFE82"] = "\u0622"; - t["\uFE83"] = "\u0623"; - t["\uFE84"] = "\u0623"; - t["\uFE85"] = "\u0624"; - t["\uFE86"] = "\u0624"; - t["\uFE87"] = "\u0625"; - t["\uFE88"] = "\u0625"; - t["\uFE89"] = "\u0626"; - t["\uFE8A"] = "\u0626"; - t["\uFE8B"] = "\u0626"; - t["\uFE8C"] = "\u0626"; - t["\uFE8D"] = "\u0627"; - t["\uFE8E"] = "\u0627"; - t["\uFE8F"] = "\u0628"; - t["\uFE90"] = "\u0628"; - t["\uFE91"] = "\u0628"; - t["\uFE92"] = "\u0628"; - t["\uFE93"] = "\u0629"; - t["\uFE94"] = "\u0629"; - t["\uFE95"] = "\u062A"; - t["\uFE96"] = "\u062A"; - t["\uFE97"] = "\u062A"; - t["\uFE98"] = "\u062A"; - t["\uFE99"] = "\u062B"; - t["\uFE9A"] = "\u062B"; - t["\uFE9B"] = "\u062B"; - t["\uFE9C"] = "\u062B"; - t["\uFE9D"] = "\u062C"; - t["\uFE9E"] = "\u062C"; - t["\uFE9F"] = "\u062C"; - t["\uFEA0"] = "\u062C"; - t["\uFEA1"] = "\u062D"; - t["\uFEA2"] = "\u062D"; - t["\uFEA3"] = "\u062D"; - t["\uFEA4"] = "\u062D"; - t["\uFEA5"] = "\u062E"; - t["\uFEA6"] = "\u062E"; - t["\uFEA7"] = "\u062E"; - t["\uFEA8"] = "\u062E"; - t["\uFEA9"] = "\u062F"; - t["\uFEAA"] = "\u062F"; - t["\uFEAB"] = "\u0630"; - t["\uFEAC"] = "\u0630"; - t["\uFEAD"] = "\u0631"; - t["\uFEAE"] = "\u0631"; - t["\uFEAF"] = "\u0632"; - t["\uFEB0"] = "\u0632"; - t["\uFEB1"] = "\u0633"; - t["\uFEB2"] = "\u0633"; - t["\uFEB3"] = "\u0633"; - t["\uFEB4"] = "\u0633"; - t["\uFEB5"] = "\u0634"; - t["\uFEB6"] = "\u0634"; - t["\uFEB7"] = "\u0634"; - t["\uFEB8"] = "\u0634"; - t["\uFEB9"] = "\u0635"; - t["\uFEBA"] = "\u0635"; - t["\uFEBB"] = "\u0635"; - t["\uFEBC"] = "\u0635"; - t["\uFEBD"] = "\u0636"; - t["\uFEBE"] = "\u0636"; - t["\uFEBF"] = "\u0636"; - t["\uFEC0"] = "\u0636"; - t["\uFEC1"] = "\u0637"; - t["\uFEC2"] = "\u0637"; - t["\uFEC3"] = "\u0637"; - t["\uFEC4"] = "\u0637"; - t["\uFEC5"] = "\u0638"; - t["\uFEC6"] = "\u0638"; - t["\uFEC7"] = "\u0638"; - t["\uFEC8"] = "\u0638"; - t["\uFEC9"] = "\u0639"; - t["\uFECA"] = "\u0639"; - t["\uFECB"] = "\u0639"; - t["\uFECC"] = "\u0639"; - t["\uFECD"] = "\u063A"; - t["\uFECE"] = "\u063A"; - t["\uFECF"] = "\u063A"; - t["\uFED0"] = "\u063A"; - t["\uFED1"] = "\u0641"; - t["\uFED2"] = "\u0641"; - t["\uFED3"] = "\u0641"; - t["\uFED4"] = "\u0641"; - t["\uFED5"] = "\u0642"; - t["\uFED6"] = "\u0642"; - t["\uFED7"] = "\u0642"; - t["\uFED8"] = "\u0642"; - t["\uFED9"] = "\u0643"; - t["\uFEDA"] = "\u0643"; - t["\uFEDB"] = "\u0643"; - t["\uFEDC"] = "\u0643"; - t["\uFEDD"] = "\u0644"; - t["\uFEDE"] = "\u0644"; - t["\uFEDF"] = "\u0644"; - t["\uFEE0"] = "\u0644"; - t["\uFEE1"] = "\u0645"; - t["\uFEE2"] = "\u0645"; - t["\uFEE3"] = "\u0645"; - t["\uFEE4"] = "\u0645"; - t["\uFEE5"] = "\u0646"; - t["\uFEE6"] = "\u0646"; - t["\uFEE7"] = "\u0646"; - t["\uFEE8"] = "\u0646"; - t["\uFEE9"] = "\u0647"; - t["\uFEEA"] = "\u0647"; - t["\uFEEB"] = "\u0647"; - t["\uFEEC"] = "\u0647"; - t["\uFEED"] = "\u0648"; - t["\uFEEE"] = "\u0648"; - t["\uFEEF"] = "\u0649"; - t["\uFEF0"] = "\u0649"; - t["\uFEF1"] = "\u064A"; - t["\uFEF2"] = "\u064A"; - t["\uFEF3"] = "\u064A"; - t["\uFEF4"] = "\u064A"; - t["\uFEF5"] = "\u0644\u0622"; - t["\uFEF6"] = "\u0644\u0622"; - t["\uFEF7"] = "\u0644\u0623"; - t["\uFEF8"] = "\u0644\u0623"; - t["\uFEF9"] = "\u0644\u0625"; - t["\uFEFA"] = "\u0644\u0625"; - t["\uFEFB"] = "\u0644\u0627"; - t["\uFEFC"] = "\u0644\u0627"; +const getNormalizedUnicodes = (0,_core_utils_js__WEBPACK_IMPORTED_MODULE_0__.getArrayLookupTableFactory)(function () { + return [ + "\u00A8", + "\u0020\u0308", + "\u00AF", + "\u0020\u0304", + "\u00B4", + "\u0020\u0301", + "\u00B5", + "\u03BC", + "\u00B8", + "\u0020\u0327", + "\u0132", + "\u0049\u004A", + "\u0133", + "\u0069\u006A", + "\u013F", + "\u004C\u00B7", + "\u0140", + "\u006C\u00B7", + "\u0149", + "\u02BC\u006E", + "\u017F", + "\u0073", + "\u01C4", + "\u0044\u017D", + "\u01C5", + "\u0044\u017E", + "\u01C6", + "\u0064\u017E", + "\u01C7", + "\u004C\u004A", + "\u01C8", + "\u004C\u006A", + "\u01C9", + "\u006C\u006A", + "\u01CA", + "\u004E\u004A", + "\u01CB", + "\u004E\u006A", + "\u01CC", + "\u006E\u006A", + "\u01F1", + "\u0044\u005A", + "\u01F2", + "\u0044\u007A", + "\u01F3", + "\u0064\u007A", + "\u02D8", + "\u0020\u0306", + "\u02D9", + "\u0020\u0307", + "\u02DA", + "\u0020\u030A", + "\u02DB", + "\u0020\u0328", + "\u02DC", + "\u0020\u0303", + "\u02DD", + "\u0020\u030B", + "\u037A", + "\u0020\u0345", + "\u0384", + "\u0020\u0301", + "\u03D0", + "\u03B2", + "\u03D1", + "\u03B8", + "\u03D2", + "\u03A5", + "\u03D5", + "\u03C6", + "\u03D6", + "\u03C0", + "\u03F0", + "\u03BA", + "\u03F1", + "\u03C1", + "\u03F2", + "\u03C2", + "\u03F4", + "\u0398", + "\u03F5", + "\u03B5", + "\u03F9", + "\u03A3", + "\u0587", + "\u0565\u0582", + "\u0675", + "\u0627\u0674", + "\u0676", + "\u0648\u0674", + "\u0677", + "\u06C7\u0674", + "\u0678", + "\u064A\u0674", + "\u0E33", + "\u0E4D\u0E32", + "\u0EB3", + "\u0ECD\u0EB2", + "\u0EDC", + "\u0EAB\u0E99", + "\u0EDD", + "\u0EAB\u0EA1", + "\u0F77", + "\u0FB2\u0F81", + "\u0F79", + "\u0FB3\u0F81", + "\u1E9A", + "\u0061\u02BE", + "\u1FBD", + "\u0020\u0313", + "\u1FBF", + "\u0020\u0313", + "\u1FC0", + "\u0020\u0342", + "\u1FFE", + "\u0020\u0314", + "\u2002", + "\u0020", + "\u2003", + "\u0020", + "\u2004", + "\u0020", + "\u2005", + "\u0020", + "\u2006", + "\u0020", + "\u2008", + "\u0020", + "\u2009", + "\u0020", + "\u200A", + "\u0020", + "\u2017", + "\u0020\u0333", + "\u2024", + "\u002E", + "\u2025", + "\u002E\u002E", + "\u2026", + "\u002E\u002E\u002E", + "\u2033", + "\u2032\u2032", + "\u2034", + "\u2032\u2032\u2032", + "\u2036", + "\u2035\u2035", + "\u2037", + "\u2035\u2035\u2035", + "\u203C", + "\u0021\u0021", + "\u203E", + "\u0020\u0305", + "\u2047", + "\u003F\u003F", + "\u2048", + "\u003F\u0021", + "\u2049", + "\u0021\u003F", + "\u2057", + "\u2032\u2032\u2032\u2032", + "\u205F", + "\u0020", + "\u20A8", + "\u0052\u0073", + "\u2100", + "\u0061\u002F\u0063", + "\u2101", + "\u0061\u002F\u0073", + "\u2103", + "\u00B0\u0043", + "\u2105", + "\u0063\u002F\u006F", + "\u2106", + "\u0063\u002F\u0075", + "\u2107", + "\u0190", + "\u2109", + "\u00B0\u0046", + "\u2116", + "\u004E\u006F", + "\u2121", + "\u0054\u0045\u004C", + "\u2135", + "\u05D0", + "\u2136", + "\u05D1", + "\u2137", + "\u05D2", + "\u2138", + "\u05D3", + "\u213B", + "\u0046\u0041\u0058", + "\u2160", + "\u0049", + "\u2161", + "\u0049\u0049", + "\u2162", + "\u0049\u0049\u0049", + "\u2163", + "\u0049\u0056", + "\u2164", + "\u0056", + "\u2165", + "\u0056\u0049", + "\u2166", + "\u0056\u0049\u0049", + "\u2167", + "\u0056\u0049\u0049\u0049", + "\u2168", + "\u0049\u0058", + "\u2169", + "\u0058", + "\u216A", + "\u0058\u0049", + "\u216B", + "\u0058\u0049\u0049", + "\u216C", + "\u004C", + "\u216D", + "\u0043", + "\u216E", + "\u0044", + "\u216F", + "\u004D", + "\u2170", + "\u0069", + "\u2171", + "\u0069\u0069", + "\u2172", + "\u0069\u0069\u0069", + "\u2173", + "\u0069\u0076", + "\u2174", + "\u0076", + "\u2175", + "\u0076\u0069", + "\u2176", + "\u0076\u0069\u0069", + "\u2177", + "\u0076\u0069\u0069\u0069", + "\u2178", + "\u0069\u0078", + "\u2179", + "\u0078", + "\u217A", + "\u0078\u0069", + "\u217B", + "\u0078\u0069\u0069", + "\u217C", + "\u006C", + "\u217D", + "\u0063", + "\u217E", + "\u0064", + "\u217F", + "\u006D", + "\u222C", + "\u222B\u222B", + "\u222D", + "\u222B\u222B\u222B", + "\u222F", + "\u222E\u222E", + "\u2230", + "\u222E\u222E\u222E", + "\u2474", + "\u0028\u0031\u0029", + "\u2475", + "\u0028\u0032\u0029", + "\u2476", + "\u0028\u0033\u0029", + "\u2477", + "\u0028\u0034\u0029", + "\u2478", + "\u0028\u0035\u0029", + "\u2479", + "\u0028\u0036\u0029", + "\u247A", + "\u0028\u0037\u0029", + "\u247B", + "\u0028\u0038\u0029", + "\u247C", + "\u0028\u0039\u0029", + "\u247D", + "\u0028\u0031\u0030\u0029", + "\u247E", + "\u0028\u0031\u0031\u0029", + "\u247F", + "\u0028\u0031\u0032\u0029", + "\u2480", + "\u0028\u0031\u0033\u0029", + "\u2481", + "\u0028\u0031\u0034\u0029", + "\u2482", + "\u0028\u0031\u0035\u0029", + "\u2483", + "\u0028\u0031\u0036\u0029", + "\u2484", + "\u0028\u0031\u0037\u0029", + "\u2485", + "\u0028\u0031\u0038\u0029", + "\u2486", + "\u0028\u0031\u0039\u0029", + "\u2487", + "\u0028\u0032\u0030\u0029", + "\u2488", + "\u0031\u002E", + "\u2489", + "\u0032\u002E", + "\u248A", + "\u0033\u002E", + "\u248B", + "\u0034\u002E", + "\u248C", + "\u0035\u002E", + "\u248D", + "\u0036\u002E", + "\u248E", + "\u0037\u002E", + "\u248F", + "\u0038\u002E", + "\u2490", + "\u0039\u002E", + "\u2491", + "\u0031\u0030\u002E", + "\u2492", + "\u0031\u0031\u002E", + "\u2493", + "\u0031\u0032\u002E", + "\u2494", + "\u0031\u0033\u002E", + "\u2495", + "\u0031\u0034\u002E", + "\u2496", + "\u0031\u0035\u002E", + "\u2497", + "\u0031\u0036\u002E", + "\u2498", + "\u0031\u0037\u002E", + "\u2499", + "\u0031\u0038\u002E", + "\u249A", + "\u0031\u0039\u002E", + "\u249B", + "\u0032\u0030\u002E", + "\u249C", + "\u0028\u0061\u0029", + "\u249D", + "\u0028\u0062\u0029", + "\u249E", + "\u0028\u0063\u0029", + "\u249F", + "\u0028\u0064\u0029", + "\u24A0", + "\u0028\u0065\u0029", + "\u24A1", + "\u0028\u0066\u0029", + "\u24A2", + "\u0028\u0067\u0029", + "\u24A3", + "\u0028\u0068\u0029", + "\u24A4", + "\u0028\u0069\u0029", + "\u24A5", + "\u0028\u006A\u0029", + "\u24A6", + "\u0028\u006B\u0029", + "\u24A7", + "\u0028\u006C\u0029", + "\u24A8", + "\u0028\u006D\u0029", + "\u24A9", + "\u0028\u006E\u0029", + "\u24AA", + "\u0028\u006F\u0029", + "\u24AB", + "\u0028\u0070\u0029", + "\u24AC", + "\u0028\u0071\u0029", + "\u24AD", + "\u0028\u0072\u0029", + "\u24AE", + "\u0028\u0073\u0029", + "\u24AF", + "\u0028\u0074\u0029", + "\u24B0", + "\u0028\u0075\u0029", + "\u24B1", + "\u0028\u0076\u0029", + "\u24B2", + "\u0028\u0077\u0029", + "\u24B3", + "\u0028\u0078\u0029", + "\u24B4", + "\u0028\u0079\u0029", + "\u24B5", + "\u0028\u007A\u0029", + "\u2A0C", + "\u222B\u222B\u222B\u222B", + "\u2A74", + "\u003A\u003A\u003D", + "\u2A75", + "\u003D\u003D", + "\u2A76", + "\u003D\u003D\u003D", + "\u2E9F", + "\u6BCD", + "\u2EF3", + "\u9F9F", + "\u2F00", + "\u4E00", + "\u2F01", + "\u4E28", + "\u2F02", + "\u4E36", + "\u2F03", + "\u4E3F", + "\u2F04", + "\u4E59", + "\u2F05", + "\u4E85", + "\u2F06", + "\u4E8C", + "\u2F07", + "\u4EA0", + "\u2F08", + "\u4EBA", + "\u2F09", + "\u513F", + "\u2F0A", + "\u5165", + "\u2F0B", + "\u516B", + "\u2F0C", + "\u5182", + "\u2F0D", + "\u5196", + "\u2F0E", + "\u51AB", + "\u2F0F", + "\u51E0", + "\u2F10", + "\u51F5", + "\u2F11", + "\u5200", + "\u2F12", + "\u529B", + "\u2F13", + "\u52F9", + "\u2F14", + "\u5315", + "\u2F15", + "\u531A", + "\u2F16", + "\u5338", + "\u2F17", + "\u5341", + "\u2F18", + "\u535C", + "\u2F19", + "\u5369", + "\u2F1A", + "\u5382", + "\u2F1B", + "\u53B6", + "\u2F1C", + "\u53C8", + "\u2F1D", + "\u53E3", + "\u2F1E", + "\u56D7", + "\u2F1F", + "\u571F", + "\u2F20", + "\u58EB", + "\u2F21", + "\u5902", + "\u2F22", + "\u590A", + "\u2F23", + "\u5915", + "\u2F24", + "\u5927", + "\u2F25", + "\u5973", + "\u2F26", + "\u5B50", + "\u2F27", + "\u5B80", + "\u2F28", + "\u5BF8", + "\u2F29", + "\u5C0F", + "\u2F2A", + "\u5C22", + "\u2F2B", + "\u5C38", + "\u2F2C", + "\u5C6E", + "\u2F2D", + "\u5C71", + "\u2F2E", + "\u5DDB", + "\u2F2F", + "\u5DE5", + "\u2F30", + "\u5DF1", + "\u2F31", + "\u5DFE", + "\u2F32", + "\u5E72", + "\u2F33", + "\u5E7A", + "\u2F34", + "\u5E7F", + "\u2F35", + "\u5EF4", + "\u2F36", + "\u5EFE", + "\u2F37", + "\u5F0B", + "\u2F38", + "\u5F13", + "\u2F39", + "\u5F50", + "\u2F3A", + "\u5F61", + "\u2F3B", + "\u5F73", + "\u2F3C", + "\u5FC3", + "\u2F3D", + "\u6208", + "\u2F3E", + "\u6236", + "\u2F3F", + "\u624B", + "\u2F40", + "\u652F", + "\u2F41", + "\u6534", + "\u2F42", + "\u6587", + "\u2F43", + "\u6597", + "\u2F44", + "\u65A4", + "\u2F45", + "\u65B9", + "\u2F46", + "\u65E0", + "\u2F47", + "\u65E5", + "\u2F48", + "\u66F0", + "\u2F49", + "\u6708", + "\u2F4A", + "\u6728", + "\u2F4B", + "\u6B20", + "\u2F4C", + "\u6B62", + "\u2F4D", + "\u6B79", + "\u2F4E", + "\u6BB3", + "\u2F4F", + "\u6BCB", + "\u2F50", + "\u6BD4", + "\u2F51", + "\u6BDB", + "\u2F52", + "\u6C0F", + "\u2F53", + "\u6C14", + "\u2F54", + "\u6C34", + "\u2F55", + "\u706B", + "\u2F56", + "\u722A", + "\u2F57", + "\u7236", + "\u2F58", + "\u723B", + "\u2F59", + "\u723F", + "\u2F5A", + "\u7247", + "\u2F5B", + "\u7259", + "\u2F5C", + "\u725B", + "\u2F5D", + "\u72AC", + "\u2F5E", + "\u7384", + "\u2F5F", + "\u7389", + "\u2F60", + "\u74DC", + "\u2F61", + "\u74E6", + "\u2F62", + "\u7518", + "\u2F63", + "\u751F", + "\u2F64", + "\u7528", + "\u2F65", + "\u7530", + "\u2F66", + "\u758B", + "\u2F67", + "\u7592", + "\u2F68", + "\u7676", + "\u2F69", + "\u767D", + "\u2F6A", + "\u76AE", + "\u2F6B", + "\u76BF", + "\u2F6C", + "\u76EE", + "\u2F6D", + "\u77DB", + "\u2F6E", + "\u77E2", + "\u2F6F", + "\u77F3", + "\u2F70", + "\u793A", + "\u2F71", + "\u79B8", + "\u2F72", + "\u79BE", + "\u2F73", + "\u7A74", + "\u2F74", + "\u7ACB", + "\u2F75", + "\u7AF9", + "\u2F76", + "\u7C73", + "\u2F77", + "\u7CF8", + "\u2F78", + "\u7F36", + "\u2F79", + "\u7F51", + "\u2F7A", + "\u7F8A", + "\u2F7B", + "\u7FBD", + "\u2F7C", + "\u8001", + "\u2F7D", + "\u800C", + "\u2F7E", + "\u8012", + "\u2F7F", + "\u8033", + "\u2F80", + "\u807F", + "\u2F81", + "\u8089", + "\u2F82", + "\u81E3", + "\u2F83", + "\u81EA", + "\u2F84", + "\u81F3", + "\u2F85", + "\u81FC", + "\u2F86", + "\u820C", + "\u2F87", + "\u821B", + "\u2F88", + "\u821F", + "\u2F89", + "\u826E", + "\u2F8A", + "\u8272", + "\u2F8B", + "\u8278", + "\u2F8C", + "\u864D", + "\u2F8D", + "\u866B", + "\u2F8E", + "\u8840", + "\u2F8F", + "\u884C", + "\u2F90", + "\u8863", + "\u2F91", + "\u897E", + "\u2F92", + "\u898B", + "\u2F93", + "\u89D2", + "\u2F94", + "\u8A00", + "\u2F95", + "\u8C37", + "\u2F96", + "\u8C46", + "\u2F97", + "\u8C55", + "\u2F98", + "\u8C78", + "\u2F99", + "\u8C9D", + "\u2F9A", + "\u8D64", + "\u2F9B", + "\u8D70", + "\u2F9C", + "\u8DB3", + "\u2F9D", + "\u8EAB", + "\u2F9E", + "\u8ECA", + "\u2F9F", + "\u8F9B", + "\u2FA0", + "\u8FB0", + "\u2FA1", + "\u8FB5", + "\u2FA2", + "\u9091", + "\u2FA3", + "\u9149", + "\u2FA4", + "\u91C6", + "\u2FA5", + "\u91CC", + "\u2FA6", + "\u91D1", + "\u2FA7", + "\u9577", + "\u2FA8", + "\u9580", + "\u2FA9", + "\u961C", + "\u2FAA", + "\u96B6", + "\u2FAB", + "\u96B9", + "\u2FAC", + "\u96E8", + "\u2FAD", + "\u9751", + "\u2FAE", + "\u975E", + "\u2FAF", + "\u9762", + "\u2FB0", + "\u9769", + "\u2FB1", + "\u97CB", + "\u2FB2", + "\u97ED", + "\u2FB3", + "\u97F3", + "\u2FB4", + "\u9801", + "\u2FB5", + "\u98A8", + "\u2FB6", + "\u98DB", + "\u2FB7", + "\u98DF", + "\u2FB8", + "\u9996", + "\u2FB9", + "\u9999", + "\u2FBA", + "\u99AC", + "\u2FBB", + "\u9AA8", + "\u2FBC", + "\u9AD8", + "\u2FBD", + "\u9ADF", + "\u2FBE", + "\u9B25", + "\u2FBF", + "\u9B2F", + "\u2FC0", + "\u9B32", + "\u2FC1", + "\u9B3C", + "\u2FC2", + "\u9B5A", + "\u2FC3", + "\u9CE5", + "\u2FC4", + "\u9E75", + "\u2FC5", + "\u9E7F", + "\u2FC6", + "\u9EA5", + "\u2FC7", + "\u9EBB", + "\u2FC8", + "\u9EC3", + "\u2FC9", + "\u9ECD", + "\u2FCA", + "\u9ED1", + "\u2FCB", + "\u9EF9", + "\u2FCC", + "\u9EFD", + "\u2FCD", + "\u9F0E", + "\u2FCE", + "\u9F13", + "\u2FCF", + "\u9F20", + "\u2FD0", + "\u9F3B", + "\u2FD1", + "\u9F4A", + "\u2FD2", + "\u9F52", + "\u2FD3", + "\u9F8D", + "\u2FD4", + "\u9F9C", + "\u2FD5", + "\u9FA0", + "\u3036", + "\u3012", + "\u3038", + "\u5341", + "\u3039", + "\u5344", + "\u303A", + "\u5345", + "\u309B", + "\u0020\u3099", + "\u309C", + "\u0020\u309A", + "\u3131", + "\u1100", + "\u3132", + "\u1101", + "\u3133", + "\u11AA", + "\u3134", + "\u1102", + "\u3135", + "\u11AC", + "\u3136", + "\u11AD", + "\u3137", + "\u1103", + "\u3138", + "\u1104", + "\u3139", + "\u1105", + "\u313A", + "\u11B0", + "\u313B", + "\u11B1", + "\u313C", + "\u11B2", + "\u313D", + "\u11B3", + "\u313E", + "\u11B4", + "\u313F", + "\u11B5", + "\u3140", + "\u111A", + "\u3141", + "\u1106", + "\u3142", + "\u1107", + "\u3143", + "\u1108", + "\u3144", + "\u1121", + "\u3145", + "\u1109", + "\u3146", + "\u110A", + "\u3147", + "\u110B", + "\u3148", + "\u110C", + "\u3149", + "\u110D", + "\u314A", + "\u110E", + "\u314B", + "\u110F", + "\u314C", + "\u1110", + "\u314D", + "\u1111", + "\u314E", + "\u1112", + "\u314F", + "\u1161", + "\u3150", + "\u1162", + "\u3151", + "\u1163", + "\u3152", + "\u1164", + "\u3153", + "\u1165", + "\u3154", + "\u1166", + "\u3155", + "\u1167", + "\u3156", + "\u1168", + "\u3157", + "\u1169", + "\u3158", + "\u116A", + "\u3159", + "\u116B", + "\u315A", + "\u116C", + "\u315B", + "\u116D", + "\u315C", + "\u116E", + "\u315D", + "\u116F", + "\u315E", + "\u1170", + "\u315F", + "\u1171", + "\u3160", + "\u1172", + "\u3161", + "\u1173", + "\u3162", + "\u1174", + "\u3163", + "\u1175", + "\u3164", + "\u1160", + "\u3165", + "\u1114", + "\u3166", + "\u1115", + "\u3167", + "\u11C7", + "\u3168", + "\u11C8", + "\u3169", + "\u11CC", + "\u316A", + "\u11CE", + "\u316B", + "\u11D3", + "\u316C", + "\u11D7", + "\u316D", + "\u11D9", + "\u316E", + "\u111C", + "\u316F", + "\u11DD", + "\u3170", + "\u11DF", + "\u3171", + "\u111D", + "\u3172", + "\u111E", + "\u3173", + "\u1120", + "\u3174", + "\u1122", + "\u3175", + "\u1123", + "\u3176", + "\u1127", + "\u3177", + "\u1129", + "\u3178", + "\u112B", + "\u3179", + "\u112C", + "\u317A", + "\u112D", + "\u317B", + "\u112E", + "\u317C", + "\u112F", + "\u317D", + "\u1132", + "\u317E", + "\u1136", + "\u317F", + "\u1140", + "\u3180", + "\u1147", + "\u3181", + "\u114C", + "\u3182", + "\u11F1", + "\u3183", + "\u11F2", + "\u3184", + "\u1157", + "\u3185", + "\u1158", + "\u3186", + "\u1159", + "\u3187", + "\u1184", + "\u3188", + "\u1185", + "\u3189", + "\u1188", + "\u318A", + "\u1191", + "\u318B", + "\u1192", + "\u318C", + "\u1194", + "\u318D", + "\u119E", + "\u318E", + "\u11A1", + "\u3200", + "\u0028\u1100\u0029", + "\u3201", + "\u0028\u1102\u0029", + "\u3202", + "\u0028\u1103\u0029", + "\u3203", + "\u0028\u1105\u0029", + "\u3204", + "\u0028\u1106\u0029", + "\u3205", + "\u0028\u1107\u0029", + "\u3206", + "\u0028\u1109\u0029", + "\u3207", + "\u0028\u110B\u0029", + "\u3208", + "\u0028\u110C\u0029", + "\u3209", + "\u0028\u110E\u0029", + "\u320A", + "\u0028\u110F\u0029", + "\u320B", + "\u0028\u1110\u0029", + "\u320C", + "\u0028\u1111\u0029", + "\u320D", + "\u0028\u1112\u0029", + "\u320E", + "\u0028\u1100\u1161\u0029", + "\u320F", + "\u0028\u1102\u1161\u0029", + "\u3210", + "\u0028\u1103\u1161\u0029", + "\u3211", + "\u0028\u1105\u1161\u0029", + "\u3212", + "\u0028\u1106\u1161\u0029", + "\u3213", + "\u0028\u1107\u1161\u0029", + "\u3214", + "\u0028\u1109\u1161\u0029", + "\u3215", + "\u0028\u110B\u1161\u0029", + "\u3216", + "\u0028\u110C\u1161\u0029", + "\u3217", + "\u0028\u110E\u1161\u0029", + "\u3218", + "\u0028\u110F\u1161\u0029", + "\u3219", + "\u0028\u1110\u1161\u0029", + "\u321A", + "\u0028\u1111\u1161\u0029", + "\u321B", + "\u0028\u1112\u1161\u0029", + "\u321C", + "\u0028\u110C\u116E\u0029", + "\u321D", + "\u0028\u110B\u1169\u110C\u1165\u11AB\u0029", + "\u321E", + "\u0028\u110B\u1169\u1112\u116E\u0029", + "\u3220", + "\u0028\u4E00\u0029", + "\u3221", + "\u0028\u4E8C\u0029", + "\u3222", + "\u0028\u4E09\u0029", + "\u3223", + "\u0028\u56DB\u0029", + "\u3224", + "\u0028\u4E94\u0029", + "\u3225", + "\u0028\u516D\u0029", + "\u3226", + "\u0028\u4E03\u0029", + "\u3227", + "\u0028\u516B\u0029", + "\u3228", + "\u0028\u4E5D\u0029", + "\u3229", + "\u0028\u5341\u0029", + "\u322A", + "\u0028\u6708\u0029", + "\u322B", + "\u0028\u706B\u0029", + "\u322C", + "\u0028\u6C34\u0029", + "\u322D", + "\u0028\u6728\u0029", + "\u322E", + "\u0028\u91D1\u0029", + "\u322F", + "\u0028\u571F\u0029", + "\u3230", + "\u0028\u65E5\u0029", + "\u3231", + "\u0028\u682A\u0029", + "\u3232", + "\u0028\u6709\u0029", + "\u3233", + "\u0028\u793E\u0029", + "\u3234", + "\u0028\u540D\u0029", + "\u3235", + "\u0028\u7279\u0029", + "\u3236", + "\u0028\u8CA1\u0029", + "\u3237", + "\u0028\u795D\u0029", + "\u3238", + "\u0028\u52B4\u0029", + "\u3239", + "\u0028\u4EE3\u0029", + "\u323A", + "\u0028\u547C\u0029", + "\u323B", + "\u0028\u5B66\u0029", + "\u323C", + "\u0028\u76E3\u0029", + "\u323D", + "\u0028\u4F01\u0029", + "\u323E", + "\u0028\u8CC7\u0029", + "\u323F", + "\u0028\u5354\u0029", + "\u3240", + "\u0028\u796D\u0029", + "\u3241", + "\u0028\u4F11\u0029", + "\u3242", + "\u0028\u81EA\u0029", + "\u3243", + "\u0028\u81F3\u0029", + "\u32C0", + "\u0031\u6708", + "\u32C1", + "\u0032\u6708", + "\u32C2", + "\u0033\u6708", + "\u32C3", + "\u0034\u6708", + "\u32C4", + "\u0035\u6708", + "\u32C5", + "\u0036\u6708", + "\u32C6", + "\u0037\u6708", + "\u32C7", + "\u0038\u6708", + "\u32C8", + "\u0039\u6708", + "\u32C9", + "\u0031\u0030\u6708", + "\u32CA", + "\u0031\u0031\u6708", + "\u32CB", + "\u0031\u0032\u6708", + "\u3358", + "\u0030\u70B9", + "\u3359", + "\u0031\u70B9", + "\u335A", + "\u0032\u70B9", + "\u335B", + "\u0033\u70B9", + "\u335C", + "\u0034\u70B9", + "\u335D", + "\u0035\u70B9", + "\u335E", + "\u0036\u70B9", + "\u335F", + "\u0037\u70B9", + "\u3360", + "\u0038\u70B9", + "\u3361", + "\u0039\u70B9", + "\u3362", + "\u0031\u0030\u70B9", + "\u3363", + "\u0031\u0031\u70B9", + "\u3364", + "\u0031\u0032\u70B9", + "\u3365", + "\u0031\u0033\u70B9", + "\u3366", + "\u0031\u0034\u70B9", + "\u3367", + "\u0031\u0035\u70B9", + "\u3368", + "\u0031\u0036\u70B9", + "\u3369", + "\u0031\u0037\u70B9", + "\u336A", + "\u0031\u0038\u70B9", + "\u336B", + "\u0031\u0039\u70B9", + "\u336C", + "\u0032\u0030\u70B9", + "\u336D", + "\u0032\u0031\u70B9", + "\u336E", + "\u0032\u0032\u70B9", + "\u336F", + "\u0032\u0033\u70B9", + "\u3370", + "\u0032\u0034\u70B9", + "\u33E0", + "\u0031\u65E5", + "\u33E1", + "\u0032\u65E5", + "\u33E2", + "\u0033\u65E5", + "\u33E3", + "\u0034\u65E5", + "\u33E4", + "\u0035\u65E5", + "\u33E5", + "\u0036\u65E5", + "\u33E6", + "\u0037\u65E5", + "\u33E7", + "\u0038\u65E5", + "\u33E8", + "\u0039\u65E5", + "\u33E9", + "\u0031\u0030\u65E5", + "\u33EA", + "\u0031\u0031\u65E5", + "\u33EB", + "\u0031\u0032\u65E5", + "\u33EC", + "\u0031\u0033\u65E5", + "\u33ED", + "\u0031\u0034\u65E5", + "\u33EE", + "\u0031\u0035\u65E5", + "\u33EF", + "\u0031\u0036\u65E5", + "\u33F0", + "\u0031\u0037\u65E5", + "\u33F1", + "\u0031\u0038\u65E5", + "\u33F2", + "\u0031\u0039\u65E5", + "\u33F3", + "\u0032\u0030\u65E5", + "\u33F4", + "\u0032\u0031\u65E5", + "\u33F5", + "\u0032\u0032\u65E5", + "\u33F6", + "\u0032\u0033\u65E5", + "\u33F7", + "\u0032\u0034\u65E5", + "\u33F8", + "\u0032\u0035\u65E5", + "\u33F9", + "\u0032\u0036\u65E5", + "\u33FA", + "\u0032\u0037\u65E5", + "\u33FB", + "\u0032\u0038\u65E5", + "\u33FC", + "\u0032\u0039\u65E5", + "\u33FD", + "\u0033\u0030\u65E5", + "\u33FE", + "\u0033\u0031\u65E5", + "\uFB00", + "\u0066\u0066", + "\uFB01", + "\u0066\u0069", + "\uFB02", + "\u0066\u006C", + "\uFB03", + "\u0066\u0066\u0069", + "\uFB04", + "\u0066\u0066\u006C", + "\uFB05", + "\u017F\u0074", + "\uFB06", + "\u0073\u0074", + "\uFB13", + "\u0574\u0576", + "\uFB14", + "\u0574\u0565", + "\uFB15", + "\u0574\u056B", + "\uFB16", + "\u057E\u0576", + "\uFB17", + "\u0574\u056D", + "\uFB4F", + "\u05D0\u05DC", + "\uFB50", + "\u0671", + "\uFB51", + "\u0671", + "\uFB52", + "\u067B", + "\uFB53", + "\u067B", + "\uFB54", + "\u067B", + "\uFB55", + "\u067B", + "\uFB56", + "\u067E", + "\uFB57", + "\u067E", + "\uFB58", + "\u067E", + "\uFB59", + "\u067E", + "\uFB5A", + "\u0680", + "\uFB5B", + "\u0680", + "\uFB5C", + "\u0680", + "\uFB5D", + "\u0680", + "\uFB5E", + "\u067A", + "\uFB5F", + "\u067A", + "\uFB60", + "\u067A", + "\uFB61", + "\u067A", + "\uFB62", + "\u067F", + "\uFB63", + "\u067F", + "\uFB64", + "\u067F", + "\uFB65", + "\u067F", + "\uFB66", + "\u0679", + "\uFB67", + "\u0679", + "\uFB68", + "\u0679", + "\uFB69", + "\u0679", + "\uFB6A", + "\u06A4", + "\uFB6B", + "\u06A4", + "\uFB6C", + "\u06A4", + "\uFB6D", + "\u06A4", + "\uFB6E", + "\u06A6", + "\uFB6F", + "\u06A6", + "\uFB70", + "\u06A6", + "\uFB71", + "\u06A6", + "\uFB72", + "\u0684", + "\uFB73", + "\u0684", + "\uFB74", + "\u0684", + "\uFB75", + "\u0684", + "\uFB76", + "\u0683", + "\uFB77", + "\u0683", + "\uFB78", + "\u0683", + "\uFB79", + "\u0683", + "\uFB7A", + "\u0686", + "\uFB7B", + "\u0686", + "\uFB7C", + "\u0686", + "\uFB7D", + "\u0686", + "\uFB7E", + "\u0687", + "\uFB7F", + "\u0687", + "\uFB80", + "\u0687", + "\uFB81", + "\u0687", + "\uFB82", + "\u068D", + "\uFB83", + "\u068D", + "\uFB84", + "\u068C", + "\uFB85", + "\u068C", + "\uFB86", + "\u068E", + "\uFB87", + "\u068E", + "\uFB88", + "\u0688", + "\uFB89", + "\u0688", + "\uFB8A", + "\u0698", + "\uFB8B", + "\u0698", + "\uFB8C", + "\u0691", + "\uFB8D", + "\u0691", + "\uFB8E", + "\u06A9", + "\uFB8F", + "\u06A9", + "\uFB90", + "\u06A9", + "\uFB91", + "\u06A9", + "\uFB92", + "\u06AF", + "\uFB93", + "\u06AF", + "\uFB94", + "\u06AF", + "\uFB95", + "\u06AF", + "\uFB96", + "\u06B3", + "\uFB97", + "\u06B3", + "\uFB98", + "\u06B3", + "\uFB99", + "\u06B3", + "\uFB9A", + "\u06B1", + "\uFB9B", + "\u06B1", + "\uFB9C", + "\u06B1", + "\uFB9D", + "\u06B1", + "\uFB9E", + "\u06BA", + "\uFB9F", + "\u06BA", + "\uFBA0", + "\u06BB", + "\uFBA1", + "\u06BB", + "\uFBA2", + "\u06BB", + "\uFBA3", + "\u06BB", + "\uFBA4", + "\u06C0", + "\uFBA5", + "\u06C0", + "\uFBA6", + "\u06C1", + "\uFBA7", + "\u06C1", + "\uFBA8", + "\u06C1", + "\uFBA9", + "\u06C1", + "\uFBAA", + "\u06BE", + "\uFBAB", + "\u06BE", + "\uFBAC", + "\u06BE", + "\uFBAD", + "\u06BE", + "\uFBAE", + "\u06D2", + "\uFBAF", + "\u06D2", + "\uFBB0", + "\u06D3", + "\uFBB1", + "\u06D3", + "\uFBD3", + "\u06AD", + "\uFBD4", + "\u06AD", + "\uFBD5", + "\u06AD", + "\uFBD6", + "\u06AD", + "\uFBD7", + "\u06C7", + "\uFBD8", + "\u06C7", + "\uFBD9", + "\u06C6", + "\uFBDA", + "\u06C6", + "\uFBDB", + "\u06C8", + "\uFBDC", + "\u06C8", + "\uFBDD", + "\u0677", + "\uFBDE", + "\u06CB", + "\uFBDF", + "\u06CB", + "\uFBE0", + "\u06C5", + "\uFBE1", + "\u06C5", + "\uFBE2", + "\u06C9", + "\uFBE3", + "\u06C9", + "\uFBE4", + "\u06D0", + "\uFBE5", + "\u06D0", + "\uFBE6", + "\u06D0", + "\uFBE7", + "\u06D0", + "\uFBE8", + "\u0649", + "\uFBE9", + "\u0649", + "\uFBEA", + "\u0626\u0627", + "\uFBEB", + "\u0626\u0627", + "\uFBEC", + "\u0626\u06D5", + "\uFBED", + "\u0626\u06D5", + "\uFBEE", + "\u0626\u0648", + "\uFBEF", + "\u0626\u0648", + "\uFBF0", + "\u0626\u06C7", + "\uFBF1", + "\u0626\u06C7", + "\uFBF2", + "\u0626\u06C6", + "\uFBF3", + "\u0626\u06C6", + "\uFBF4", + "\u0626\u06C8", + "\uFBF5", + "\u0626\u06C8", + "\uFBF6", + "\u0626\u06D0", + "\uFBF7", + "\u0626\u06D0", + "\uFBF8", + "\u0626\u06D0", + "\uFBF9", + "\u0626\u0649", + "\uFBFA", + "\u0626\u0649", + "\uFBFB", + "\u0626\u0649", + "\uFBFC", + "\u06CC", + "\uFBFD", + "\u06CC", + "\uFBFE", + "\u06CC", + "\uFBFF", + "\u06CC", + "\uFC00", + "\u0626\u062C", + "\uFC01", + "\u0626\u062D", + "\uFC02", + "\u0626\u0645", + "\uFC03", + "\u0626\u0649", + "\uFC04", + "\u0626\u064A", + "\uFC05", + "\u0628\u062C", + "\uFC06", + "\u0628\u062D", + "\uFC07", + "\u0628\u062E", + "\uFC08", + "\u0628\u0645", + "\uFC09", + "\u0628\u0649", + "\uFC0A", + "\u0628\u064A", + "\uFC0B", + "\u062A\u062C", + "\uFC0C", + "\u062A\u062D", + "\uFC0D", + "\u062A\u062E", + "\uFC0E", + "\u062A\u0645", + "\uFC0F", + "\u062A\u0649", + "\uFC10", + "\u062A\u064A", + "\uFC11", + "\u062B\u062C", + "\uFC12", + "\u062B\u0645", + "\uFC13", + "\u062B\u0649", + "\uFC14", + "\u062B\u064A", + "\uFC15", + "\u062C\u062D", + "\uFC16", + "\u062C\u0645", + "\uFC17", + "\u062D\u062C", + "\uFC18", + "\u062D\u0645", + "\uFC19", + "\u062E\u062C", + "\uFC1A", + "\u062E\u062D", + "\uFC1B", + "\u062E\u0645", + "\uFC1C", + "\u0633\u062C", + "\uFC1D", + "\u0633\u062D", + "\uFC1E", + "\u0633\u062E", + "\uFC1F", + "\u0633\u0645", + "\uFC20", + "\u0635\u062D", + "\uFC21", + "\u0635\u0645", + "\uFC22", + "\u0636\u062C", + "\uFC23", + "\u0636\u062D", + "\uFC24", + "\u0636\u062E", + "\uFC25", + "\u0636\u0645", + "\uFC26", + "\u0637\u062D", + "\uFC27", + "\u0637\u0645", + "\uFC28", + "\u0638\u0645", + "\uFC29", + "\u0639\u062C", + "\uFC2A", + "\u0639\u0645", + "\uFC2B", + "\u063A\u062C", + "\uFC2C", + "\u063A\u0645", + "\uFC2D", + "\u0641\u062C", + "\uFC2E", + "\u0641\u062D", + "\uFC2F", + "\u0641\u062E", + "\uFC30", + "\u0641\u0645", + "\uFC31", + "\u0641\u0649", + "\uFC32", + "\u0641\u064A", + "\uFC33", + "\u0642\u062D", + "\uFC34", + "\u0642\u0645", + "\uFC35", + "\u0642\u0649", + "\uFC36", + "\u0642\u064A", + "\uFC37", + "\u0643\u0627", + "\uFC38", + "\u0643\u062C", + "\uFC39", + "\u0643\u062D", + "\uFC3A", + "\u0643\u062E", + "\uFC3B", + "\u0643\u0644", + "\uFC3C", + "\u0643\u0645", + "\uFC3D", + "\u0643\u0649", + "\uFC3E", + "\u0643\u064A", + "\uFC3F", + "\u0644\u062C", + "\uFC40", + "\u0644\u062D", + "\uFC41", + "\u0644\u062E", + "\uFC42", + "\u0644\u0645", + "\uFC43", + "\u0644\u0649", + "\uFC44", + "\u0644\u064A", + "\uFC45", + "\u0645\u062C", + "\uFC46", + "\u0645\u062D", + "\uFC47", + "\u0645\u062E", + "\uFC48", + "\u0645\u0645", + "\uFC49", + "\u0645\u0649", + "\uFC4A", + "\u0645\u064A", + "\uFC4B", + "\u0646\u062C", + "\uFC4C", + "\u0646\u062D", + "\uFC4D", + "\u0646\u062E", + "\uFC4E", + "\u0646\u0645", + "\uFC4F", + "\u0646\u0649", + "\uFC50", + "\u0646\u064A", + "\uFC51", + "\u0647\u062C", + "\uFC52", + "\u0647\u0645", + "\uFC53", + "\u0647\u0649", + "\uFC54", + "\u0647\u064A", + "\uFC55", + "\u064A\u062C", + "\uFC56", + "\u064A\u062D", + "\uFC57", + "\u064A\u062E", + "\uFC58", + "\u064A\u0645", + "\uFC59", + "\u064A\u0649", + "\uFC5A", + "\u064A\u064A", + "\uFC5B", + "\u0630\u0670", + "\uFC5C", + "\u0631\u0670", + "\uFC5D", + "\u0649\u0670", + "\uFC5E", + "\u0020\u064C\u0651", + "\uFC5F", + "\u0020\u064D\u0651", + "\uFC60", + "\u0020\u064E\u0651", + "\uFC61", + "\u0020\u064F\u0651", + "\uFC62", + "\u0020\u0650\u0651", + "\uFC63", + "\u0020\u0651\u0670", + "\uFC64", + "\u0626\u0631", + "\uFC65", + "\u0626\u0632", + "\uFC66", + "\u0626\u0645", + "\uFC67", + "\u0626\u0646", + "\uFC68", + "\u0626\u0649", + "\uFC69", + "\u0626\u064A", + "\uFC6A", + "\u0628\u0631", + "\uFC6B", + "\u0628\u0632", + "\uFC6C", + "\u0628\u0645", + "\uFC6D", + "\u0628\u0646", + "\uFC6E", + "\u0628\u0649", + "\uFC6F", + "\u0628\u064A", + "\uFC70", + "\u062A\u0631", + "\uFC71", + "\u062A\u0632", + "\uFC72", + "\u062A\u0645", + "\uFC73", + "\u062A\u0646", + "\uFC74", + "\u062A\u0649", + "\uFC75", + "\u062A\u064A", + "\uFC76", + "\u062B\u0631", + "\uFC77", + "\u062B\u0632", + "\uFC78", + "\u062B\u0645", + "\uFC79", + "\u062B\u0646", + "\uFC7A", + "\u062B\u0649", + "\uFC7B", + "\u062B\u064A", + "\uFC7C", + "\u0641\u0649", + "\uFC7D", + "\u0641\u064A", + "\uFC7E", + "\u0642\u0649", + "\uFC7F", + "\u0642\u064A", + "\uFC80", + "\u0643\u0627", + "\uFC81", + "\u0643\u0644", + "\uFC82", + "\u0643\u0645", + "\uFC83", + "\u0643\u0649", + "\uFC84", + "\u0643\u064A", + "\uFC85", + "\u0644\u0645", + "\uFC86", + "\u0644\u0649", + "\uFC87", + "\u0644\u064A", + "\uFC88", + "\u0645\u0627", + "\uFC89", + "\u0645\u0645", + "\uFC8A", + "\u0646\u0631", + "\uFC8B", + "\u0646\u0632", + "\uFC8C", + "\u0646\u0645", + "\uFC8D", + "\u0646\u0646", + "\uFC8E", + "\u0646\u0649", + "\uFC8F", + "\u0646\u064A", + "\uFC90", + "\u0649\u0670", + "\uFC91", + "\u064A\u0631", + "\uFC92", + "\u064A\u0632", + "\uFC93", + "\u064A\u0645", + "\uFC94", + "\u064A\u0646", + "\uFC95", + "\u064A\u0649", + "\uFC96", + "\u064A\u064A", + "\uFC97", + "\u0626\u062C", + "\uFC98", + "\u0626\u062D", + "\uFC99", + "\u0626\u062E", + "\uFC9A", + "\u0626\u0645", + "\uFC9B", + "\u0626\u0647", + "\uFC9C", + "\u0628\u062C", + "\uFC9D", + "\u0628\u062D", + "\uFC9E", + "\u0628\u062E", + "\uFC9F", + "\u0628\u0645", + "\uFCA0", + "\u0628\u0647", + "\uFCA1", + "\u062A\u062C", + "\uFCA2", + "\u062A\u062D", + "\uFCA3", + "\u062A\u062E", + "\uFCA4", + "\u062A\u0645", + "\uFCA5", + "\u062A\u0647", + "\uFCA6", + "\u062B\u0645", + "\uFCA7", + "\u062C\u062D", + "\uFCA8", + "\u062C\u0645", + "\uFCA9", + "\u062D\u062C", + "\uFCAA", + "\u062D\u0645", + "\uFCAB", + "\u062E\u062C", + "\uFCAC", + "\u062E\u0645", + "\uFCAD", + "\u0633\u062C", + "\uFCAE", + "\u0633\u062D", + "\uFCAF", + "\u0633\u062E", + "\uFCB0", + "\u0633\u0645", + "\uFCB1", + "\u0635\u062D", + "\uFCB2", + "\u0635\u062E", + "\uFCB3", + "\u0635\u0645", + "\uFCB4", + "\u0636\u062C", + "\uFCB5", + "\u0636\u062D", + "\uFCB6", + "\u0636\u062E", + "\uFCB7", + "\u0636\u0645", + "\uFCB8", + "\u0637\u062D", + "\uFCB9", + "\u0638\u0645", + "\uFCBA", + "\u0639\u062C", + "\uFCBB", + "\u0639\u0645", + "\uFCBC", + "\u063A\u062C", + "\uFCBD", + "\u063A\u0645", + "\uFCBE", + "\u0641\u062C", + "\uFCBF", + "\u0641\u062D", + "\uFCC0", + "\u0641\u062E", + "\uFCC1", + "\u0641\u0645", + "\uFCC2", + "\u0642\u062D", + "\uFCC3", + "\u0642\u0645", + "\uFCC4", + "\u0643\u062C", + "\uFCC5", + "\u0643\u062D", + "\uFCC6", + "\u0643\u062E", + "\uFCC7", + "\u0643\u0644", + "\uFCC8", + "\u0643\u0645", + "\uFCC9", + "\u0644\u062C", + "\uFCCA", + "\u0644\u062D", + "\uFCCB", + "\u0644\u062E", + "\uFCCC", + "\u0644\u0645", + "\uFCCD", + "\u0644\u0647", + "\uFCCE", + "\u0645\u062C", + "\uFCCF", + "\u0645\u062D", + "\uFCD0", + "\u0645\u062E", + "\uFCD1", + "\u0645\u0645", + "\uFCD2", + "\u0646\u062C", + "\uFCD3", + "\u0646\u062D", + "\uFCD4", + "\u0646\u062E", + "\uFCD5", + "\u0646\u0645", + "\uFCD6", + "\u0646\u0647", + "\uFCD7", + "\u0647\u062C", + "\uFCD8", + "\u0647\u0645", + "\uFCD9", + "\u0647\u0670", + "\uFCDA", + "\u064A\u062C", + "\uFCDB", + "\u064A\u062D", + "\uFCDC", + "\u064A\u062E", + "\uFCDD", + "\u064A\u0645", + "\uFCDE", + "\u064A\u0647", + "\uFCDF", + "\u0626\u0645", + "\uFCE0", + "\u0626\u0647", + "\uFCE1", + "\u0628\u0645", + "\uFCE2", + "\u0628\u0647", + "\uFCE3", + "\u062A\u0645", + "\uFCE4", + "\u062A\u0647", + "\uFCE5", + "\u062B\u0645", + "\uFCE6", + "\u062B\u0647", + "\uFCE7", + "\u0633\u0645", + "\uFCE8", + "\u0633\u0647", + "\uFCE9", + "\u0634\u0645", + "\uFCEA", + "\u0634\u0647", + "\uFCEB", + "\u0643\u0644", + "\uFCEC", + "\u0643\u0645", + "\uFCED", + "\u0644\u0645", + "\uFCEE", + "\u0646\u0645", + "\uFCEF", + "\u0646\u0647", + "\uFCF0", + "\u064A\u0645", + "\uFCF1", + "\u064A\u0647", + "\uFCF2", + "\u0640\u064E\u0651", + "\uFCF3", + "\u0640\u064F\u0651", + "\uFCF4", + "\u0640\u0650\u0651", + "\uFCF5", + "\u0637\u0649", + "\uFCF6", + "\u0637\u064A", + "\uFCF7", + "\u0639\u0649", + "\uFCF8", + "\u0639\u064A", + "\uFCF9", + "\u063A\u0649", + "\uFCFA", + "\u063A\u064A", + "\uFCFB", + "\u0633\u0649", + "\uFCFC", + "\u0633\u064A", + "\uFCFD", + "\u0634\u0649", + "\uFCFE", + "\u0634\u064A", + "\uFCFF", + "\u062D\u0649", + "\uFD00", + "\u062D\u064A", + "\uFD01", + "\u062C\u0649", + "\uFD02", + "\u062C\u064A", + "\uFD03", + "\u062E\u0649", + "\uFD04", + "\u062E\u064A", + "\uFD05", + "\u0635\u0649", + "\uFD06", + "\u0635\u064A", + "\uFD07", + "\u0636\u0649", + "\uFD08", + "\u0636\u064A", + "\uFD09", + "\u0634\u062C", + "\uFD0A", + "\u0634\u062D", + "\uFD0B", + "\u0634\u062E", + "\uFD0C", + "\u0634\u0645", + "\uFD0D", + "\u0634\u0631", + "\uFD0E", + "\u0633\u0631", + "\uFD0F", + "\u0635\u0631", + "\uFD10", + "\u0636\u0631", + "\uFD11", + "\u0637\u0649", + "\uFD12", + "\u0637\u064A", + "\uFD13", + "\u0639\u0649", + "\uFD14", + "\u0639\u064A", + "\uFD15", + "\u063A\u0649", + "\uFD16", + "\u063A\u064A", + "\uFD17", + "\u0633\u0649", + "\uFD18", + "\u0633\u064A", + "\uFD19", + "\u0634\u0649", + "\uFD1A", + "\u0634\u064A", + "\uFD1B", + "\u062D\u0649", + "\uFD1C", + "\u062D\u064A", + "\uFD1D", + "\u062C\u0649", + "\uFD1E", + "\u062C\u064A", + "\uFD1F", + "\u062E\u0649", + "\uFD20", + "\u062E\u064A", + "\uFD21", + "\u0635\u0649", + "\uFD22", + "\u0635\u064A", + "\uFD23", + "\u0636\u0649", + "\uFD24", + "\u0636\u064A", + "\uFD25", + "\u0634\u062C", + "\uFD26", + "\u0634\u062D", + "\uFD27", + "\u0634\u062E", + "\uFD28", + "\u0634\u0645", + "\uFD29", + "\u0634\u0631", + "\uFD2A", + "\u0633\u0631", + "\uFD2B", + "\u0635\u0631", + "\uFD2C", + "\u0636\u0631", + "\uFD2D", + "\u0634\u062C", + "\uFD2E", + "\u0634\u062D", + "\uFD2F", + "\u0634\u062E", + "\uFD30", + "\u0634\u0645", + "\uFD31", + "\u0633\u0647", + "\uFD32", + "\u0634\u0647", + "\uFD33", + "\u0637\u0645", + "\uFD34", + "\u0633\u062C", + "\uFD35", + "\u0633\u062D", + "\uFD36", + "\u0633\u062E", + "\uFD37", + "\u0634\u062C", + "\uFD38", + "\u0634\u062D", + "\uFD39", + "\u0634\u062E", + "\uFD3A", + "\u0637\u0645", + "\uFD3B", + "\u0638\u0645", + "\uFD3C", + "\u0627\u064B", + "\uFD3D", + "\u0627\u064B", + "\uFD50", + "\u062A\u062C\u0645", + "\uFD51", + "\u062A\u062D\u062C", + "\uFD52", + "\u062A\u062D\u062C", + "\uFD53", + "\u062A\u062D\u0645", + "\uFD54", + "\u062A\u062E\u0645", + "\uFD55", + "\u062A\u0645\u062C", + "\uFD56", + "\u062A\u0645\u062D", + "\uFD57", + "\u062A\u0645\u062E", + "\uFD58", + "\u062C\u0645\u062D", + "\uFD59", + "\u062C\u0645\u062D", + "\uFD5A", + "\u062D\u0645\u064A", + "\uFD5B", + "\u062D\u0645\u0649", + "\uFD5C", + "\u0633\u062D\u062C", + "\uFD5D", + "\u0633\u062C\u062D", + "\uFD5E", + "\u0633\u062C\u0649", + "\uFD5F", + "\u0633\u0645\u062D", + "\uFD60", + "\u0633\u0645\u062D", + "\uFD61", + "\u0633\u0645\u062C", + "\uFD62", + "\u0633\u0645\u0645", + "\uFD63", + "\u0633\u0645\u0645", + "\uFD64", + "\u0635\u062D\u062D", + "\uFD65", + "\u0635\u062D\u062D", + "\uFD66", + "\u0635\u0645\u0645", + "\uFD67", + "\u0634\u062D\u0645", + "\uFD68", + "\u0634\u062D\u0645", + "\uFD69", + "\u0634\u062C\u064A", + "\uFD6A", + "\u0634\u0645\u062E", + "\uFD6B", + "\u0634\u0645\u062E", + "\uFD6C", + "\u0634\u0645\u0645", + "\uFD6D", + "\u0634\u0645\u0645", + "\uFD6E", + "\u0636\u062D\u0649", + "\uFD6F", + "\u0636\u062E\u0645", + "\uFD70", + "\u0636\u062E\u0645", + "\uFD71", + "\u0637\u0645\u062D", + "\uFD72", + "\u0637\u0645\u062D", + "\uFD73", + "\u0637\u0645\u0645", + "\uFD74", + "\u0637\u0645\u064A", + "\uFD75", + "\u0639\u062C\u0645", + "\uFD76", + "\u0639\u0645\u0645", + "\uFD77", + "\u0639\u0645\u0645", + "\uFD78", + "\u0639\u0645\u0649", + "\uFD79", + "\u063A\u0645\u0645", + "\uFD7A", + "\u063A\u0645\u064A", + "\uFD7B", + "\u063A\u0645\u0649", + "\uFD7C", + "\u0641\u062E\u0645", + "\uFD7D", + "\u0641\u062E\u0645", + "\uFD7E", + "\u0642\u0645\u062D", + "\uFD7F", + "\u0642\u0645\u0645", + "\uFD80", + "\u0644\u062D\u0645", + "\uFD81", + "\u0644\u062D\u064A", + "\uFD82", + "\u0644\u062D\u0649", + "\uFD83", + "\u0644\u062C\u062C", + "\uFD84", + "\u0644\u062C\u062C", + "\uFD85", + "\u0644\u062E\u0645", + "\uFD86", + "\u0644\u062E\u0645", + "\uFD87", + "\u0644\u0645\u062D", + "\uFD88", + "\u0644\u0645\u062D", + "\uFD89", + "\u0645\u062D\u062C", + "\uFD8A", + "\u0645\u062D\u0645", + "\uFD8B", + "\u0645\u062D\u064A", + "\uFD8C", + "\u0645\u062C\u062D", + "\uFD8D", + "\u0645\u062C\u0645", + "\uFD8E", + "\u0645\u062E\u062C", + "\uFD8F", + "\u0645\u062E\u0645", + "\uFD92", + "\u0645\u062C\u062E", + "\uFD93", + "\u0647\u0645\u062C", + "\uFD94", + "\u0647\u0645\u0645", + "\uFD95", + "\u0646\u062D\u0645", + "\uFD96", + "\u0646\u062D\u0649", + "\uFD97", + "\u0646\u062C\u0645", + "\uFD98", + "\u0646\u062C\u0645", + "\uFD99", + "\u0646\u062C\u0649", + "\uFD9A", + "\u0646\u0645\u064A", + "\uFD9B", + "\u0646\u0645\u0649", + "\uFD9C", + "\u064A\u0645\u0645", + "\uFD9D", + "\u064A\u0645\u0645", + "\uFD9E", + "\u0628\u062E\u064A", + "\uFD9F", + "\u062A\u062C\u064A", + "\uFDA0", + "\u062A\u062C\u0649", + "\uFDA1", + "\u062A\u062E\u064A", + "\uFDA2", + "\u062A\u062E\u0649", + "\uFDA3", + "\u062A\u0645\u064A", + "\uFDA4", + "\u062A\u0645\u0649", + "\uFDA5", + "\u062C\u0645\u064A", + "\uFDA6", + "\u062C\u062D\u0649", + "\uFDA7", + "\u062C\u0645\u0649", + "\uFDA8", + "\u0633\u062E\u0649", + "\uFDA9", + "\u0635\u062D\u064A", + "\uFDAA", + "\u0634\u062D\u064A", + "\uFDAB", + "\u0636\u062D\u064A", + "\uFDAC", + "\u0644\u062C\u064A", + "\uFDAD", + "\u0644\u0645\u064A", + "\uFDAE", + "\u064A\u062D\u064A", + "\uFDAF", + "\u064A\u062C\u064A", + "\uFDB0", + "\u064A\u0645\u064A", + "\uFDB1", + "\u0645\u0645\u064A", + "\uFDB2", + "\u0642\u0645\u064A", + "\uFDB3", + "\u0646\u062D\u064A", + "\uFDB4", + "\u0642\u0645\u062D", + "\uFDB5", + "\u0644\u062D\u0645", + "\uFDB6", + "\u0639\u0645\u064A", + "\uFDB7", + "\u0643\u0645\u064A", + "\uFDB8", + "\u0646\u062C\u062D", + "\uFDB9", + "\u0645\u062E\u064A", + "\uFDBA", + "\u0644\u062C\u0645", + "\uFDBB", + "\u0643\u0645\u0645", + "\uFDBC", + "\u0644\u062C\u0645", + "\uFDBD", + "\u0646\u062C\u062D", + "\uFDBE", + "\u062C\u062D\u064A", + "\uFDBF", + "\u062D\u062C\u064A", + "\uFDC0", + "\u0645\u062C\u064A", + "\uFDC1", + "\u0641\u0645\u064A", + "\uFDC2", + "\u0628\u062D\u064A", + "\uFDC3", + "\u0643\u0645\u0645", + "\uFDC4", + "\u0639\u062C\u0645", + "\uFDC5", + "\u0635\u0645\u0645", + "\uFDC6", + "\u0633\u062E\u064A", + "\uFDC7", + "\u0646\u062C\u064A", + "\uFE49", + "\u203E", + "\uFE4A", + "\u203E", + "\uFE4B", + "\u203E", + "\uFE4C", + "\u203E", + "\uFE4D", + "\u005F", + "\uFE4E", + "\u005F", + "\uFE4F", + "\u005F", + "\uFE80", + "\u0621", + "\uFE81", + "\u0622", + "\uFE82", + "\u0622", + "\uFE83", + "\u0623", + "\uFE84", + "\u0623", + "\uFE85", + "\u0624", + "\uFE86", + "\u0624", + "\uFE87", + "\u0625", + "\uFE88", + "\u0625", + "\uFE89", + "\u0626", + "\uFE8A", + "\u0626", + "\uFE8B", + "\u0626", + "\uFE8C", + "\u0626", + "\uFE8D", + "\u0627", + "\uFE8E", + "\u0627", + "\uFE8F", + "\u0628", + "\uFE90", + "\u0628", + "\uFE91", + "\u0628", + "\uFE92", + "\u0628", + "\uFE93", + "\u0629", + "\uFE94", + "\u0629", + "\uFE95", + "\u062A", + "\uFE96", + "\u062A", + "\uFE97", + "\u062A", + "\uFE98", + "\u062A", + "\uFE99", + "\u062B", + "\uFE9A", + "\u062B", + "\uFE9B", + "\u062B", + "\uFE9C", + "\u062B", + "\uFE9D", + "\u062C", + "\uFE9E", + "\u062C", + "\uFE9F", + "\u062C", + "\uFEA0", + "\u062C", + "\uFEA1", + "\u062D", + "\uFEA2", + "\u062D", + "\uFEA3", + "\u062D", + "\uFEA4", + "\u062D", + "\uFEA5", + "\u062E", + "\uFEA6", + "\u062E", + "\uFEA7", + "\u062E", + "\uFEA8", + "\u062E", + "\uFEA9", + "\u062F", + "\uFEAA", + "\u062F", + "\uFEAB", + "\u0630", + "\uFEAC", + "\u0630", + "\uFEAD", + "\u0631", + "\uFEAE", + "\u0631", + "\uFEAF", + "\u0632", + "\uFEB0", + "\u0632", + "\uFEB1", + "\u0633", + "\uFEB2", + "\u0633", + "\uFEB3", + "\u0633", + "\uFEB4", + "\u0633", + "\uFEB5", + "\u0634", + "\uFEB6", + "\u0634", + "\uFEB7", + "\u0634", + "\uFEB8", + "\u0634", + "\uFEB9", + "\u0635", + "\uFEBA", + "\u0635", + "\uFEBB", + "\u0635", + "\uFEBC", + "\u0635", + "\uFEBD", + "\u0636", + "\uFEBE", + "\u0636", + "\uFEBF", + "\u0636", + "\uFEC0", + "\u0636", + "\uFEC1", + "\u0637", + "\uFEC2", + "\u0637", + "\uFEC3", + "\u0637", + "\uFEC4", + "\u0637", + "\uFEC5", + "\u0638", + "\uFEC6", + "\u0638", + "\uFEC7", + "\u0638", + "\uFEC8", + "\u0638", + "\uFEC9", + "\u0639", + "\uFECA", + "\u0639", + "\uFECB", + "\u0639", + "\uFECC", + "\u0639", + "\uFECD", + "\u063A", + "\uFECE", + "\u063A", + "\uFECF", + "\u063A", + "\uFED0", + "\u063A", + "\uFED1", + "\u0641", + "\uFED2", + "\u0641", + "\uFED3", + "\u0641", + "\uFED4", + "\u0641", + "\uFED5", + "\u0642", + "\uFED6", + "\u0642", + "\uFED7", + "\u0642", + "\uFED8", + "\u0642", + "\uFED9", + "\u0643", + "\uFEDA", + "\u0643", + "\uFEDB", + "\u0643", + "\uFEDC", + "\u0643", + "\uFEDD", + "\u0644", + "\uFEDE", + "\u0644", + "\uFEDF", + "\u0644", + "\uFEE0", + "\u0644", + "\uFEE1", + "\u0645", + "\uFEE2", + "\u0645", + "\uFEE3", + "\u0645", + "\uFEE4", + "\u0645", + "\uFEE5", + "\u0646", + "\uFEE6", + "\u0646", + "\uFEE7", + "\u0646", + "\uFEE8", + "\u0646", + "\uFEE9", + "\u0647", + "\uFEEA", + "\u0647", + "\uFEEB", + "\u0647", + "\uFEEC", + "\u0647", + "\uFEED", + "\u0648", + "\uFEEE", + "\u0648", + "\uFEEF", + "\u0649", + "\uFEF0", + "\u0649", + "\uFEF1", + "\u064A", + "\uFEF2", + "\u064A", + "\uFEF3", + "\u064A", + "\uFEF4", + "\u064A", + "\uFEF5", + "\u0644\u0622", + "\uFEF6", + "\u0644\u0622", + "\uFEF7", + "\u0644\u0623", + "\uFEF8", + "\u0644\u0623", + "\uFEF9", + "\u0644\u0625", + "\uFEFA", + "\u0644\u0625", + "\uFEFB", + "\u0644\u0627", + "\uFEFC", + "\u0644\u0627" + ]; }); function reverseIfRtl(chars) { - var charsLength = chars.length; + const charsLength = chars.length; if (charsLength <= 1 || !isRTLRangeFor(chars.charCodeAt(0))) { return chars; } - var s = ""; - for (var ii = charsLength - 1; ii >= 0; ii--) { - s += chars[ii]; + const buf = []; + for (let ii = charsLength - 1; ii >= 0; ii--) { + buf.push(chars[ii]); } - return s; + return buf.join(""); } -exports.mapSpecialUnicodeValues = mapSpecialUnicodeValues; -exports.reverseIfRtl = reverseIfRtl; -exports.getUnicodeRangeFor = getUnicodeRangeFor; -exports.getNormalizedUnicodes = getNormalizedUnicodes; -exports.getUnicodeForGlyph = getUnicodeForGlyph; +const SpecialCharRegExp = new RegExp("^(\\s)|(\\p{Mn})|(\\p{Cf})$", "u"); +const CategoryCache = new Map(); +function getCharUnicodeCategory(char) { + const cachedCategory = CategoryCache.get(char); + if (cachedCategory) { + return cachedCategory; + } + const groups = char.match(SpecialCharRegExp); + const category = { + isWhitespace: !!(groups && groups[1]), + isZeroWidthDiacritic: !!(groups && groups[2]), + isInvisibleFormatMark: !!(groups && groups[3]) + }; + CategoryCache.set(char, category); + return category; +} +function clearUnicodeCaches() { + CategoryCache.clear(); +} + /***/ }), -/* 37 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 41 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true +})); +exports.getSerifFonts = exports.getNonStdFontMap = exports.getGlyphMapForStandardFonts = exports.getFontNameToFileMap = void 0; +exports.getStandardFontName = getStandardFontName; +exports.getSymbolsFonts = exports.getSupplementalGlyphMapForCalibri = exports.getSupplementalGlyphMapForArialBlack = exports.getStdFontMap = void 0; + +var _core_utils = __w_pdfjs_require__(6); + +var _fonts_utils = __w_pdfjs_require__(38); + +const getStdFontMap = (0, _core_utils.getLookupTableFactory)(function (t) { + t["Times-Roman"] = "Times-Roman"; + t.Helvetica = "Helvetica"; + t.Courier = "Courier"; + t.Symbol = "Symbol"; + t["Times-Bold"] = "Times-Bold"; + t["Helvetica-Bold"] = "Helvetica-Bold"; + t["Courier-Bold"] = "Courier-Bold"; + t.ZapfDingbats = "ZapfDingbats"; + t["Times-Italic"] = "Times-Italic"; + t["Helvetica-Oblique"] = "Helvetica-Oblique"; + t["Courier-Oblique"] = "Courier-Oblique"; + t["Times-BoldItalic"] = "Times-BoldItalic"; + t["Helvetica-BoldOblique"] = "Helvetica-BoldOblique"; + t["Courier-BoldOblique"] = "Courier-BoldOblique"; + t.ArialNarrow = "Helvetica"; + t["ArialNarrow-Bold"] = "Helvetica-Bold"; + t["ArialNarrow-BoldItalic"] = "Helvetica-BoldOblique"; + t["ArialNarrow-Italic"] = "Helvetica-Oblique"; + t.ArialBlack = "Helvetica"; + t["ArialBlack-Bold"] = "Helvetica-Bold"; + t["ArialBlack-BoldItalic"] = "Helvetica-BoldOblique"; + t["ArialBlack-Italic"] = "Helvetica-Oblique"; + t["Arial-Black"] = "Helvetica"; + t["Arial-Black-Bold"] = "Helvetica-Bold"; + t["Arial-Black-BoldItalic"] = "Helvetica-BoldOblique"; + t["Arial-Black-Italic"] = "Helvetica-Oblique"; + t.Arial = "Helvetica"; + t["Arial-Bold"] = "Helvetica-Bold"; + t["Arial-BoldItalic"] = "Helvetica-BoldOblique"; + t["Arial-Italic"] = "Helvetica-Oblique"; + t.ArialMT = "Helvetica"; + t["Arial-BoldItalicMT"] = "Helvetica-BoldOblique"; + t["Arial-BoldMT"] = "Helvetica-Bold"; + t["Arial-ItalicMT"] = "Helvetica-Oblique"; + t.ArialUnicodeMS = "Helvetica"; + t["ArialUnicodeMS-Bold"] = "Helvetica-Bold"; + t["ArialUnicodeMS-BoldItalic"] = "Helvetica-BoldOblique"; + t["ArialUnicodeMS-Italic"] = "Helvetica-Oblique"; + t["Courier-BoldItalic"] = "Courier-BoldOblique"; + t["Courier-Italic"] = "Courier-Oblique"; + t.CourierNew = "Courier"; + t["CourierNew-Bold"] = "Courier-Bold"; + t["CourierNew-BoldItalic"] = "Courier-BoldOblique"; + t["CourierNew-Italic"] = "Courier-Oblique"; + t["CourierNewPS-BoldItalicMT"] = "Courier-BoldOblique"; + t["CourierNewPS-BoldMT"] = "Courier-Bold"; + t["CourierNewPS-ItalicMT"] = "Courier-Oblique"; + t.CourierNewPSMT = "Courier"; + t["Helvetica-BoldItalic"] = "Helvetica-BoldOblique"; + t["Helvetica-Italic"] = "Helvetica-Oblique"; + t["Symbol-Bold"] = "Symbol"; + t["Symbol-BoldItalic"] = "Symbol"; + t["Symbol-Italic"] = "Symbol"; + t.TimesNewRoman = "Times-Roman"; + t["TimesNewRoman-Bold"] = "Times-Bold"; + t["TimesNewRoman-BoldItalic"] = "Times-BoldItalic"; + t["TimesNewRoman-Italic"] = "Times-Italic"; + t.TimesNewRomanPS = "Times-Roman"; + t["TimesNewRomanPS-Bold"] = "Times-Bold"; + t["TimesNewRomanPS-BoldItalic"] = "Times-BoldItalic"; + t["TimesNewRomanPS-BoldItalicMT"] = "Times-BoldItalic"; + t["TimesNewRomanPS-BoldMT"] = "Times-Bold"; + t["TimesNewRomanPS-Italic"] = "Times-Italic"; + t["TimesNewRomanPS-ItalicMT"] = "Times-Italic"; + t.TimesNewRomanPSMT = "Times-Roman"; + t["TimesNewRomanPSMT-Bold"] = "Times-Bold"; + t["TimesNewRomanPSMT-BoldItalic"] = "Times-BoldItalic"; + t["TimesNewRomanPSMT-Italic"] = "Times-Italic"; }); +exports.getStdFontMap = getStdFontMap; +const getFontNameToFileMap = (0, _core_utils.getLookupTableFactory)(function (t) { + t.Courier = "FoxitFixed.pfb"; + t["Courier-Bold"] = "FoxitFixedBold.pfb"; + t["Courier-BoldOblique"] = "FoxitFixedBoldItalic.pfb"; + t["Courier-Oblique"] = "FoxitFixedItalic.pfb"; + t.Helvetica = "FoxitSans.pfb"; + t["Helvetica-Bold"] = "FoxitSansBold.pfb"; + t["Helvetica-BoldOblique"] = "FoxitSansBoldItalic.pfb"; + t["Helvetica-Oblique"] = "FoxitSansItalic.pfb"; + t["Times-Roman"] = "FoxitSerif.pfb"; + t["Times-Bold"] = "FoxitSerifBold.pfb"; + t["Times-BoldItalic"] = "FoxitSerifBoldItalic.pfb"; + t["Times-Italic"] = "FoxitSerifItalic.pfb"; + t.Symbol = "FoxitSymbol.pfb"; + t.ZapfDingbats = "FoxitDingbats.pfb"; + t["LiberationSans-Regular"] = "LiberationSans-Regular.ttf"; + t["LiberationSans-Bold"] = "LiberationSans-Bold.ttf"; + t["LiberationSans-Italic"] = "LiberationSans-Italic.ttf"; + t["LiberationSans-BoldItalic"] = "LiberationSans-BoldItalic.ttf"; +}); +exports.getFontNameToFileMap = getFontNameToFileMap; +const getNonStdFontMap = (0, _core_utils.getLookupTableFactory)(function (t) { + t.Calibri = "Helvetica"; + t["Calibri-Bold"] = "Helvetica-Bold"; + t["Calibri-BoldItalic"] = "Helvetica-BoldOblique"; + t["Calibri-Italic"] = "Helvetica-Oblique"; + t.CenturyGothic = "Helvetica"; + t["CenturyGothic-Bold"] = "Helvetica-Bold"; + t["CenturyGothic-BoldItalic"] = "Helvetica-BoldOblique"; + t["CenturyGothic-Italic"] = "Helvetica-Oblique"; + t.ComicSansMS = "Comic Sans MS"; + t["ComicSansMS-Bold"] = "Comic Sans MS-Bold"; + t["ComicSansMS-BoldItalic"] = "Comic Sans MS-BoldItalic"; + t["ComicSansMS-Italic"] = "Comic Sans MS-Italic"; + t["ItcSymbol-Bold"] = "Helvetica-Bold"; + t["ItcSymbol-BoldItalic"] = "Helvetica-BoldOblique"; + t["ItcSymbol-Book"] = "Helvetica"; + t["ItcSymbol-BookItalic"] = "Helvetica-Oblique"; + t["ItcSymbol-Medium"] = "Helvetica"; + t["ItcSymbol-MediumItalic"] = "Helvetica-Oblique"; + t.LucidaConsole = "Courier"; + t["LucidaConsole-Bold"] = "Courier-Bold"; + t["LucidaConsole-BoldItalic"] = "Courier-BoldOblique"; + t["LucidaConsole-Italic"] = "Courier-Oblique"; + t["LucidaSans-Demi"] = "Helvetica-Bold"; + t["MS-Gothic"] = "MS Gothic"; + t["MS-Gothic-Bold"] = "MS Gothic-Bold"; + t["MS-Gothic-BoldItalic"] = "MS Gothic-BoldItalic"; + t["MS-Gothic-Italic"] = "MS Gothic-Italic"; + t["MS-Mincho"] = "MS Mincho"; + t["MS-Mincho-Bold"] = "MS Mincho-Bold"; + t["MS-Mincho-BoldItalic"] = "MS Mincho-BoldItalic"; + t["MS-Mincho-Italic"] = "MS Mincho-Italic"; + t["MS-PGothic"] = "MS PGothic"; + t["MS-PGothic-Bold"] = "MS PGothic-Bold"; + t["MS-PGothic-BoldItalic"] = "MS PGothic-BoldItalic"; + t["MS-PGothic-Italic"] = "MS PGothic-Italic"; + t["MS-PMincho"] = "MS PMincho"; + t["MS-PMincho-Bold"] = "MS PMincho-Bold"; + t["MS-PMincho-BoldItalic"] = "MS PMincho-BoldItalic"; + t["MS-PMincho-Italic"] = "MS PMincho-Italic"; + t.NuptialScript = "Times-Italic"; + t.SegoeUISymbol = "Helvetica"; + t.Wingdings = "ZapfDingbats"; + t["Wingdings-Regular"] = "ZapfDingbats"; +}); +exports.getNonStdFontMap = getNonStdFontMap; +const getSerifFonts = (0, _core_utils.getLookupTableFactory)(function (t) { + t["Adobe Jenson"] = true; + t["Adobe Text"] = true; + t.Albertus = true; + t.Aldus = true; + t.Alexandria = true; + t.Algerian = true; + t["American Typewriter"] = true; + t.Antiqua = true; + t.Apex = true; + t.Arno = true; + t.Aster = true; + t.Aurora = true; + t.Baskerville = true; + t.Bell = true; + t.Bembo = true; + t["Bembo Schoolbook"] = true; + t.Benguiat = true; + t["Berkeley Old Style"] = true; + t["Bernhard Modern"] = true; + t["Berthold City"] = true; + t.Bodoni = true; + t["Bauer Bodoni"] = true; + t["Book Antiqua"] = true; + t.Bookman = true; + t["Bordeaux Roman"] = true; + t["Californian FB"] = true; + t.Calisto = true; + t.Calvert = true; + t.Capitals = true; + t.Cambria = true; + t.Cartier = true; + t.Caslon = true; + t.Catull = true; + t.Centaur = true; + t["Century Old Style"] = true; + t["Century Schoolbook"] = true; + t.Chaparral = true; + t["Charis SIL"] = true; + t.Cheltenham = true; + t["Cholla Slab"] = true; + t.Clarendon = true; + t.Clearface = true; + t.Cochin = true; + t.Colonna = true; + t["Computer Modern"] = true; + t["Concrete Roman"] = true; + t.Constantia = true; + t["Cooper Black"] = true; + t.Corona = true; + t.Ecotype = true; + t.Egyptienne = true; + t.Elephant = true; + t.Excelsior = true; + t.Fairfield = true; + t["FF Scala"] = true; + t.Folkard = true; + t.Footlight = true; + t.FreeSerif = true; + t["Friz Quadrata"] = true; + t.Garamond = true; + t.Gentium = true; + t.Georgia = true; + t.Gloucester = true; + t["Goudy Old Style"] = true; + t["Goudy Schoolbook"] = true; + t["Goudy Pro Font"] = true; + t.Granjon = true; + t["Guardian Egyptian"] = true; + t.Heather = true; + t.Hercules = true; + t["High Tower Text"] = true; + t.Hiroshige = true; + t["Hoefler Text"] = true; + t["Humana Serif"] = true; + t.Imprint = true; + t["Ionic No. 5"] = true; + t.Janson = true; + t.Joanna = true; + t.Korinna = true; + t.Lexicon = true; + t.LiberationSerif = true; + t["Liberation Serif"] = true; + t["Linux Libertine"] = true; + t.Literaturnaya = true; + t.Lucida = true; + t["Lucida Bright"] = true; + t.Melior = true; + t.Memphis = true; + t.Miller = true; + t.Minion = true; + t.Modern = true; + t["Mona Lisa"] = true; + t["Mrs Eaves"] = true; + t["MS Serif"] = true; + t["Museo Slab"] = true; + t["New York"] = true; + t["Nimbus Roman"] = true; + t["NPS Rawlinson Roadway"] = true; + t.NuptialScript = true; + t.Palatino = true; + t.Perpetua = true; + t.Plantin = true; + t["Plantin Schoolbook"] = true; + t.Playbill = true; + t["Poor Richard"] = true; + t["Rawlinson Roadway"] = true; + t.Renault = true; + t.Requiem = true; + t.Rockwell = true; + t.Roman = true; + t["Rotis Serif"] = true; + t.Sabon = true; + t.Scala = true; + t.Seagull = true; + t.Sistina = true; + t.Souvenir = true; + t.STIX = true; + t["Stone Informal"] = true; + t["Stone Serif"] = true; + t.Sylfaen = true; + t.Times = true; + t.Trajan = true; + t["Trinité"] = true; + t["Trump Mediaeval"] = true; + t.Utopia = true; + t["Vale Type"] = true; + t["Bitstream Vera"] = true; + t["Vera Serif"] = true; + t.Versailles = true; + t.Wanted = true; + t.Weiss = true; + t["Wide Latin"] = true; + t.Windsor = true; + t.XITS = true; +}); +exports.getSerifFonts = getSerifFonts; +const getSymbolsFonts = (0, _core_utils.getLookupTableFactory)(function (t) { + t.Dingbats = true; + t.Symbol = true; + t.ZapfDingbats = true; +}); +exports.getSymbolsFonts = getSymbolsFonts; +const getGlyphMapForStandardFonts = (0, _core_utils.getLookupTableFactory)(function (t) { + t[2] = 10; + t[3] = 32; + t[4] = 33; + t[5] = 34; + t[6] = 35; + t[7] = 36; + t[8] = 37; + t[9] = 38; + t[10] = 39; + t[11] = 40; + t[12] = 41; + t[13] = 42; + t[14] = 43; + t[15] = 44; + t[16] = 45; + t[17] = 46; + t[18] = 47; + t[19] = 48; + t[20] = 49; + t[21] = 50; + t[22] = 51; + t[23] = 52; + t[24] = 53; + t[25] = 54; + t[26] = 55; + t[27] = 56; + t[28] = 57; + t[29] = 58; + t[30] = 894; + t[31] = 60; + t[32] = 61; + t[33] = 62; + t[34] = 63; + t[35] = 64; + t[36] = 65; + t[37] = 66; + t[38] = 67; + t[39] = 68; + t[40] = 69; + t[41] = 70; + t[42] = 71; + t[43] = 72; + t[44] = 73; + t[45] = 74; + t[46] = 75; + t[47] = 76; + t[48] = 77; + t[49] = 78; + t[50] = 79; + t[51] = 80; + t[52] = 81; + t[53] = 82; + t[54] = 83; + t[55] = 84; + t[56] = 85; + t[57] = 86; + t[58] = 87; + t[59] = 88; + t[60] = 89; + t[61] = 90; + t[62] = 91; + t[63] = 92; + t[64] = 93; + t[65] = 94; + t[66] = 95; + t[67] = 96; + t[68] = 97; + t[69] = 98; + t[70] = 99; + t[71] = 100; + t[72] = 101; + t[73] = 102; + t[74] = 103; + t[75] = 104; + t[76] = 105; + t[77] = 106; + t[78] = 107; + t[79] = 108; + t[80] = 109; + t[81] = 110; + t[82] = 111; + t[83] = 112; + t[84] = 113; + t[85] = 114; + t[86] = 115; + t[87] = 116; + t[88] = 117; + t[89] = 118; + t[90] = 119; + t[91] = 120; + t[92] = 121; + t[93] = 122; + t[94] = 123; + t[95] = 124; + t[96] = 125; + t[97] = 126; + t[98] = 196; + t[99] = 197; + t[100] = 199; + t[101] = 201; + t[102] = 209; + t[103] = 214; + t[104] = 220; + t[105] = 225; + t[106] = 224; + t[107] = 226; + t[108] = 228; + t[109] = 227; + t[110] = 229; + t[111] = 231; + t[112] = 233; + t[113] = 232; + t[114] = 234; + t[115] = 235; + t[116] = 237; + t[117] = 236; + t[118] = 238; + t[119] = 239; + t[120] = 241; + t[121] = 243; + t[122] = 242; + t[123] = 244; + t[124] = 246; + t[125] = 245; + t[126] = 250; + t[127] = 249; + t[128] = 251; + t[129] = 252; + t[130] = 8224; + t[131] = 176; + t[132] = 162; + t[133] = 163; + t[134] = 167; + t[135] = 8226; + t[136] = 182; + t[137] = 223; + t[138] = 174; + t[139] = 169; + t[140] = 8482; + t[141] = 180; + t[142] = 168; + t[143] = 8800; + t[144] = 198; + t[145] = 216; + t[146] = 8734; + t[147] = 177; + t[148] = 8804; + t[149] = 8805; + t[150] = 165; + t[151] = 181; + t[152] = 8706; + t[153] = 8721; + t[154] = 8719; + t[156] = 8747; + t[157] = 170; + t[158] = 186; + t[159] = 8486; + t[160] = 230; + t[161] = 248; + t[162] = 191; + t[163] = 161; + t[164] = 172; + t[165] = 8730; + t[166] = 402; + t[167] = 8776; + t[168] = 8710; + t[169] = 171; + t[170] = 187; + t[171] = 8230; + t[200] = 193; + t[203] = 205; + t[210] = 218; + t[223] = 711; + t[224] = 321; + t[225] = 322; + t[226] = 352; + t[227] = 353; + t[228] = 381; + t[229] = 382; + t[233] = 221; + t[234] = 253; + t[252] = 263; + t[253] = 268; + t[254] = 269; + t[258] = 258; + t[260] = 260; + t[261] = 261; + t[265] = 280; + t[266] = 281; + t[267] = 282; + t[268] = 283; + t[269] = 313; + t[275] = 323; + t[276] = 324; + t[278] = 328; + t[283] = 344; + t[284] = 345; + t[285] = 346; + t[286] = 347; + t[292] = 367; + t[295] = 377; + t[296] = 378; + t[298] = 380; + t[305] = 963; + t[306] = 964; + t[307] = 966; + t[308] = 8215; + t[309] = 8252; + t[310] = 8319; + t[311] = 8359; + t[312] = 8592; + t[313] = 8593; + t[337] = 9552; + t[493] = 1039; + t[494] = 1040; + t[672] = 1488; + t[673] = 1489; + t[674] = 1490; + t[675] = 1491; + t[676] = 1492; + t[677] = 1493; + t[678] = 1494; + t[679] = 1495; + t[680] = 1496; + t[681] = 1497; + t[682] = 1498; + t[683] = 1499; + t[684] = 1500; + t[685] = 1501; + t[686] = 1502; + t[687] = 1503; + t[688] = 1504; + t[689] = 1505; + t[690] = 1506; + t[691] = 1507; + t[692] = 1508; + t[693] = 1509; + t[694] = 1510; + t[695] = 1511; + t[696] = 1512; + t[697] = 1513; + t[698] = 1514; + t[705] = 1524; + t[706] = 8362; + t[710] = 64288; + t[711] = 64298; + t[759] = 1617; + t[761] = 1776; + t[763] = 1778; + t[775] = 1652; + t[777] = 1764; + t[778] = 1780; + t[779] = 1781; + t[780] = 1782; + t[782] = 771; + t[783] = 64726; + t[786] = 8363; + t[788] = 8532; + t[790] = 768; + t[791] = 769; + t[792] = 768; + t[795] = 803; + t[797] = 64336; + t[798] = 64337; + t[799] = 64342; + t[800] = 64343; + t[801] = 64344; + t[802] = 64345; + t[803] = 64362; + t[804] = 64363; + t[805] = 64364; + t[2424] = 7821; + t[2425] = 7822; + t[2426] = 7823; + t[2427] = 7824; + t[2428] = 7825; + t[2429] = 7826; + t[2430] = 7827; + t[2433] = 7682; + t[2678] = 8045; + t[2679] = 8046; + t[2830] = 1552; + t[2838] = 686; + t[2840] = 751; + t[2842] = 753; + t[2843] = 754; + t[2844] = 755; + t[2846] = 757; + t[2856] = 767; + t[2857] = 848; + t[2858] = 849; + t[2862] = 853; + t[2863] = 854; + t[2864] = 855; + t[2865] = 861; + t[2866] = 862; + t[2906] = 7460; + t[2908] = 7462; + t[2909] = 7463; + t[2910] = 7464; + t[2912] = 7466; + t[2913] = 7467; + t[2914] = 7468; + t[2916] = 7470; + t[2917] = 7471; + t[2918] = 7472; + t[2920] = 7474; + t[2921] = 7475; + t[2922] = 7476; + t[2924] = 7478; + t[2925] = 7479; + t[2926] = 7480; + t[2928] = 7482; + t[2929] = 7483; + t[2930] = 7484; + t[2932] = 7486; + t[2933] = 7487; + t[2934] = 7488; + t[2936] = 7490; + t[2937] = 7491; + t[2938] = 7492; + t[2940] = 7494; + t[2941] = 7495; + t[2942] = 7496; + t[2944] = 7498; + t[2946] = 7500; + t[2948] = 7502; + t[2950] = 7504; + t[2951] = 7505; + t[2952] = 7506; + t[2954] = 7508; + t[2955] = 7509; + t[2956] = 7510; + t[2958] = 7512; + t[2959] = 7513; + t[2960] = 7514; + t[2962] = 7516; + t[2963] = 7517; + t[2964] = 7518; + t[2966] = 7520; + t[2967] = 7521; + t[2968] = 7522; + t[2970] = 7524; + t[2971] = 7525; + t[2972] = 7526; + t[2974] = 7528; + t[2975] = 7529; + t[2976] = 7530; + t[2978] = 1537; + t[2979] = 1538; + t[2980] = 1539; + t[2982] = 1549; + t[2983] = 1551; + t[2984] = 1552; + t[2986] = 1554; + t[2987] = 1555; + t[2988] = 1556; + t[2990] = 1623; + t[2991] = 1624; + t[2995] = 1775; + t[2999] = 1791; + t[3002] = 64290; + t[3003] = 64291; + t[3004] = 64292; + t[3006] = 64294; + t[3007] = 64295; + t[3008] = 64296; + t[3011] = 1900; + t[3014] = 8223; + t[3015] = 8244; + t[3017] = 7532; + t[3018] = 7533; + t[3019] = 7534; + t[3075] = 7590; + t[3076] = 7591; + t[3079] = 7594; + t[3080] = 7595; + t[3083] = 7598; + t[3084] = 7599; + t[3087] = 7602; + t[3088] = 7603; + t[3091] = 7606; + t[3092] = 7607; + t[3095] = 7610; + t[3096] = 7611; + t[3099] = 7614; + t[3100] = 7615; + t[3103] = 7618; + t[3104] = 7619; + t[3107] = 8337; + t[3108] = 8338; + t[3116] = 1884; + t[3119] = 1885; + t[3120] = 1885; + t[3123] = 1886; + t[3124] = 1886; + t[3127] = 1887; + t[3128] = 1887; + t[3131] = 1888; + t[3132] = 1888; + t[3135] = 1889; + t[3136] = 1889; + t[3139] = 1890; + t[3140] = 1890; + t[3143] = 1891; + t[3144] = 1891; + t[3147] = 1892; + t[3148] = 1892; + t[3153] = 580; + t[3154] = 581; + t[3157] = 584; + t[3158] = 585; + t[3161] = 588; + t[3162] = 589; + t[3165] = 891; + t[3166] = 892; + t[3169] = 1274; + t[3170] = 1275; + t[3173] = 1278; + t[3174] = 1279; + t[3181] = 7622; + t[3182] = 7623; + t[3282] = 11799; + t[3316] = 578; + t[3379] = 42785; + t[3393] = 1159; + t[3416] = 8377; +}); +exports.getGlyphMapForStandardFonts = getGlyphMapForStandardFonts; +const getSupplementalGlyphMapForArialBlack = (0, _core_utils.getLookupTableFactory)(function (t) { + t[227] = 322; + t[264] = 261; + t[291] = 346; +}); +exports.getSupplementalGlyphMapForArialBlack = getSupplementalGlyphMapForArialBlack; +const getSupplementalGlyphMapForCalibri = (0, _core_utils.getLookupTableFactory)(function (t) { + t[1] = 32; + t[4] = 65; + t[6] = 193; + t[17] = 66; + t[18] = 67; + t[21] = 268; + t[24] = 68; + t[28] = 69; + t[30] = 201; + t[32] = 282; + t[38] = 70; + t[39] = 71; + t[44] = 72; + t[47] = 73; + t[49] = 205; + t[58] = 74; + t[60] = 75; + t[62] = 76; + t[68] = 77; + t[69] = 78; + t[75] = 79; + t[87] = 80; + t[89] = 81; + t[90] = 82; + t[92] = 344; + t[94] = 83; + t[97] = 352; + t[100] = 84; + t[104] = 85; + t[115] = 86; + t[116] = 87; + t[121] = 88; + t[122] = 89; + t[124] = 221; + t[127] = 90; + t[129] = 381; + t[258] = 97; + t[260] = 225; + t[268] = 261; + t[271] = 98; + t[272] = 99; + t[273] = 263; + t[275] = 269; + t[282] = 100; + t[286] = 101; + t[288] = 233; + t[290] = 283; + t[295] = 281; + t[296] = 102; + t[336] = 103; + t[346] = 104; + t[349] = 105; + t[351] = 237; + t[361] = 106; + t[364] = 107; + t[367] = 108; + t[371] = 322; + t[373] = 109; + t[374] = 110; + t[381] = 111; + t[383] = 243; + t[393] = 112; + t[395] = 113; + t[396] = 114; + t[398] = 345; + t[400] = 115; + t[401] = 347; + t[403] = 353; + t[410] = 116; + t[437] = 117; + t[448] = 118; + t[449] = 119; + t[454] = 120; + t[455] = 121; + t[457] = 253; + t[460] = 122; + t[462] = 382; + t[463] = 380; + t[853] = 44; + t[855] = 58; + t[856] = 46; + t[876] = 47; + t[878] = 45; + t[882] = 45; + t[894] = 40; + t[895] = 41; + t[896] = 91; + t[897] = 93; + t[923] = 64; + t[1004] = 48; + t[1005] = 49; + t[1006] = 50; + t[1007] = 51; + t[1008] = 52; + t[1009] = 53; + t[1010] = 54; + t[1011] = 55; + t[1012] = 56; + t[1013] = 57; + t[1081] = 37; + t[1085] = 43; + t[1086] = 45; +}); +exports.getSupplementalGlyphMapForCalibri = getSupplementalGlyphMapForCalibri; + +function getStandardFontName(name) { + const fontName = (0, _fonts_utils.normalizeFontName)(name); + const stdFontMap = getStdFontMap(); + return stdFontMap[fontName]; +} + +/***/ }), +/* 42 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.ToUnicodeMap = exports.IdentityToUnicodeMap = void 0; + +var _util = __w_pdfjs_require__(2); + +class ToUnicodeMap { + constructor(cmap = []) { + this._map = cmap; + } + + get length() { + return this._map.length; + } + + forEach(callback) { + for (const charCode in this._map) { + callback(charCode, this._map[charCode].charCodeAt(0)); + } + } + + has(i) { + return this._map[i] !== undefined; + } + + get(i) { + return this._map[i]; + } + + charCodeOf(value) { + const map = this._map; + + if (map.length <= 0x10000) { + return map.indexOf(value); + } + + for (const charCode in map) { + if (map[charCode] === value) { + return charCode | 0; + } + } + + return -1; + } + + amend(map) { + for (const charCode in map) { + this._map[charCode] = map[charCode]; + } + } + +} + +exports.ToUnicodeMap = ToUnicodeMap; + +class IdentityToUnicodeMap { + constructor(firstChar, lastChar) { + this.firstChar = firstChar; + this.lastChar = lastChar; + } + + get length() { + return this.lastChar + 1 - this.firstChar; + } + + forEach(callback) { + for (let i = this.firstChar, ii = this.lastChar; i <= ii; i++) { + callback(i, i); + } + } + + has(i) { + return this.firstChar <= i && i <= this.lastChar; + } + + get(i) { + if (this.firstChar <= i && i <= this.lastChar) { + return String.fromCharCode(i); + } + + return undefined; + } + + charCodeOf(v) { + return Number.isInteger(v) && v >= this.firstChar && v <= this.lastChar ? v : -1; + } + + amend(map) { + (0, _util.unreachable)("Should not call amend()"); + } + +} + +exports.IdentityToUnicodeMap = IdentityToUnicodeMap; + +/***/ }), +/* 43 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.CFFFont = void 0; + +var _cff_parser = __w_pdfjs_require__(35); + +var _fonts_utils = __w_pdfjs_require__(38); + +var _util = __w_pdfjs_require__(2); + +class CFFFont { + constructor(file, properties) { + this.properties = properties; + const parser = new _cff_parser.CFFParser(file, properties, _fonts_utils.SEAC_ANALYSIS_ENABLED); + this.cff = parser.parse(); + this.cff.duplicateFirstGlyph(); + const compiler = new _cff_parser.CFFCompiler(this.cff); + this.seacs = this.cff.seacs; + + try { + this.data = compiler.compile(); + } catch (e) { + (0, _util.warn)("Failed to compile font " + properties.loadedName); + this.data = file; + } + + this._createBuiltInEncoding(); + } + + get numGlyphs() { + return this.cff.charStrings.count; + } + + getCharset() { + return this.cff.charset.charset; + } + + getGlyphMapping() { + const cff = this.cff; + const properties = this.properties; + const charsets = cff.charset.charset; + let charCodeToGlyphId; + let glyphId; + + if (properties.composite) { + charCodeToGlyphId = Object.create(null); + let charCode; + + if (cff.isCIDFont) { + for (glyphId = 0; glyphId < charsets.length; glyphId++) { + const cid = charsets[glyphId]; + charCode = properties.cMap.charCodeOf(cid); + charCodeToGlyphId[charCode] = glyphId; + } + } else { + for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) { + charCode = properties.cMap.charCodeOf(glyphId); + charCodeToGlyphId[charCode] = glyphId; + } + } + + return charCodeToGlyphId; + } + + let encoding = cff.encoding ? cff.encoding.encoding : null; + + if (properties.isInternalFont) { + encoding = properties.defaultEncoding; + } + + charCodeToGlyphId = (0, _fonts_utils.type1FontGlyphMapping)(properties, encoding, charsets); + return charCodeToGlyphId; + } + + hasGlyphId(id) { + return this.cff.hasGlyphId(id); + } + + _createBuiltInEncoding() { + const { + charset, + encoding + } = this.cff; + + if (!charset || !encoding) { + return; + } + + const charsets = charset.charset, + encodings = encoding.encoding; + const map = []; + + for (const charCode in encodings) { + const glyphId = encodings[charCode]; + + if (glyphId >= 0) { + const glyphName = charsets[glyphId]; + + if (glyphName) { + map[charCode] = glyphName; + } + } + } + + if (map.length > 0) { + this.properties.builtInEncoding = map; + } + } + +} + +exports.CFFFont = CFFFont; + +/***/ }), +/* 44 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.FontRendererFactory = void 0; var _util = __w_pdfjs_require__(2); -var _cff_parser = __w_pdfjs_require__(31); +var _cff_parser = __w_pdfjs_require__(35); -var _glyphlist = __w_pdfjs_require__(34); +var _glyphlist = __w_pdfjs_require__(39); -var _encodings = __w_pdfjs_require__(33); +var _encodings = __w_pdfjs_require__(37); -var _stream = __w_pdfjs_require__(12); +var _stream = __w_pdfjs_require__(10); -var FontRendererFactory = function FontRendererFactoryClosure() { - function getLong(data, offset) { - return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; +function getUint32(data, offset) { + return (data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0; +} + +function getUint16(data, offset) { + return data[offset] << 8 | data[offset + 1]; +} + +function getInt16(data, offset) { + return (data[offset] << 24 | data[offset + 1] << 16) >> 16; +} + +function getInt8(data, offset) { + return data[offset] << 24 >> 24; +} + +function getFloat214(data, offset) { + return getInt16(data, offset) / 16384; +} + +function getSubroutineBias(subrs) { + const numSubrs = subrs.length; + let bias = 32768; + + if (numSubrs < 1240) { + bias = 107; + } else if (numSubrs < 33900) { + bias = 1131; } - function getUshort(data, offset) { - return data[offset] << 8 | data[offset + 1]; - } + return bias; +} - function getSubroutineBias(subrs) { - const numSubrs = subrs.length; - let bias = 32768; +function parseCmap(data, start, end) { + const offset = getUint16(data, start + 2) === 1 ? getUint32(data, start + 8) : getUint32(data, start + 16); + const format = getUint16(data, start + offset); + let ranges, p, i; - if (numSubrs < 1240) { - bias = 107; - } else if (numSubrs < 33900) { - bias = 1131; - } + if (format === 4) { + getUint16(data, start + offset + 2); + const segCount = getUint16(data, start + offset + 6) >> 1; + p = start + offset + 14; + ranges = []; - return bias; - } - - function parseCmap(data, start, end) { - var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) : getLong(data, start + 16); - var format = getUshort(data, start + offset); - var ranges, p, i; - - if (format === 4) { - getUshort(data, start + offset + 2); - var segCount = getUshort(data, start + offset + 6) >> 1; - p = start + offset + 14; - ranges = []; - - for (i = 0; i < segCount; i++, p += 2) { - ranges[i] = { - end: getUshort(data, p) - }; - } - - p += 2; - - for (i = 0; i < segCount; i++, p += 2) { - ranges[i].start = getUshort(data, p); - } - - for (i = 0; i < segCount; i++, p += 2) { - ranges[i].idDelta = getUshort(data, p); - } - - for (i = 0; i < segCount; i++, p += 2) { - var idOffset = getUshort(data, p); - - if (idOffset === 0) { - continue; - } - - ranges[i].ids = []; - - for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) { - ranges[i].ids[j] = getUshort(data, p + idOffset); - idOffset += 2; - } - } - - return ranges; - } else if (format === 12) { - getLong(data, start + offset + 4); - var groups = getLong(data, start + offset + 12); - p = start + offset + 16; - ranges = []; - - for (i = 0; i < groups; i++) { - ranges.push({ - start: getLong(data, p), - end: getLong(data, p + 4), - idDelta: getLong(data, p + 8) - getLong(data, p) - }); - p += 12; - } - - return ranges; - } - - throw new _util.FormatError(`unsupported cmap: ${format}`); - } - - function parseCff(data, start, end, seacAnalysisEnabled) { - var properties = {}; - var parser = new _cff_parser.CFFParser(new _stream.Stream(data, start, end - start), properties, seacAnalysisEnabled); - var cff = parser.parse(); - return { - glyphs: cff.charStrings.objects, - subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex && cff.topDict.privateDict.subrsIndex.objects, - gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects, - isCFFCIDFont: cff.isCIDFont, - fdSelect: cff.fdSelect, - fdArray: cff.fdArray - }; - } - - function parseGlyfTable(glyf, loca, isGlyphLocationsLong) { - var itemSize, itemDecode; - - if (isGlyphLocationsLong) { - itemSize = 4; - - itemDecode = function fontItemDecodeLong(data, offset) { - return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; + for (i = 0; i < segCount; i++, p += 2) { + ranges[i] = { + end: getUint16(data, p) }; + } + + p += 2; + + for (i = 0; i < segCount; i++, p += 2) { + ranges[i].start = getUint16(data, p); + } + + for (i = 0; i < segCount; i++, p += 2) { + ranges[i].idDelta = getUint16(data, p); + } + + for (i = 0; i < segCount; i++, p += 2) { + let idOffset = getUint16(data, p); + + if (idOffset === 0) { + continue; + } + + ranges[i].ids = []; + + for (let j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) { + ranges[i].ids[j] = getUint16(data, p + idOffset); + idOffset += 2; + } + } + + return ranges; + } else if (format === 12) { + const groups = getUint32(data, start + offset + 12); + p = start + offset + 16; + ranges = []; + + for (i = 0; i < groups; i++) { + start = getUint32(data, p); + ranges.push({ + start, + end: getUint32(data, p + 4), + idDelta: getUint32(data, p + 8) - start + }); + p += 12; + } + + return ranges; + } + + throw new _util.FormatError(`unsupported cmap: ${format}`); +} + +function parseCff(data, start, end, seacAnalysisEnabled) { + const properties = {}; + const parser = new _cff_parser.CFFParser(new _stream.Stream(data, start, end - start), properties, seacAnalysisEnabled); + const cff = parser.parse(); + return { + glyphs: cff.charStrings.objects, + subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex && cff.topDict.privateDict.subrsIndex.objects, + gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects, + isCFFCIDFont: cff.isCIDFont, + fdSelect: cff.fdSelect, + fdArray: cff.fdArray + }; +} + +function parseGlyfTable(glyf, loca, isGlyphLocationsLong) { + let itemSize, itemDecode; + + if (isGlyphLocationsLong) { + itemSize = 4; + itemDecode = getUint32; + } else { + itemSize = 2; + + itemDecode = (data, offset) => 2 * getUint16(data, offset); + } + + const glyphs = []; + let startOffset = itemDecode(loca, 0); + + for (let j = itemSize; j < loca.length; j += itemSize) { + const endOffset = itemDecode(loca, j); + glyphs.push(glyf.subarray(startOffset, endOffset)); + startOffset = endOffset; + } + + return glyphs; +} + +function lookupCmap(ranges, unicode) { + const code = unicode.codePointAt(0); + let gid = 0, + l = 0, + r = ranges.length - 1; + + while (l < r) { + const c = l + r + 1 >> 1; + + if (code < ranges[c].start) { + r = c - 1; } else { - itemSize = 2; - - itemDecode = function fontItemDecode(data, offset) { - return data[offset] << 9 | data[offset + 1] << 1; - }; + l = c; } - - var glyphs = []; - var startOffset = itemDecode(loca, 0); - - for (var j = itemSize; j < loca.length; j += itemSize) { - var endOffset = itemDecode(loca, j); - glyphs.push(glyf.subarray(startOffset, endOffset)); - startOffset = endOffset; - } - - return glyphs; } - function lookupCmap(ranges, unicode) { - var code = unicode.codePointAt(0), - gid = 0; - var l = 0, - r = ranges.length - 1; - - while (l < r) { - var c = l + r + 1 >> 1; - - if (code < ranges[c].start) { - r = c - 1; - } else { - l = c; - } - } - - if (ranges[l].start <= code && code <= ranges[l].end) { - gid = ranges[l].idDelta + (ranges[l].ids ? ranges[l].ids[code - ranges[l].start] : code) & 0xffff; - } - - return { - charCode: code, - glyphId: gid - }; + if (ranges[l].start <= code && code <= ranges[l].end) { + gid = ranges[l].idDelta + (ranges[l].ids ? ranges[l].ids[code - ranges[l].start] : code) & 0xffff; } - function compileGlyf(code, cmds, font) { - function moveTo(x, y) { - cmds.push({ - cmd: "moveTo", - args: [x, y] - }); - } + return { + charCode: code, + glyphId: gid + }; +} - function lineTo(x, y) { - cmds.push({ - cmd: "lineTo", - args: [x, y] - }); - } +function compileGlyf(code, cmds, font) { + function moveTo(x, y) { + cmds.push({ + cmd: "moveTo", + args: [x, y] + }); + } - function quadraticCurveTo(xa, ya, x, y) { - cmds.push({ - cmd: "quadraticCurveTo", - args: [xa, ya, x, y] - }); - } + function lineTo(x, y) { + cmds.push({ + cmd: "lineTo", + args: [x, y] + }); + } - var i = 0; - var numberOfContours = (code[i] << 24 | code[i + 1] << 16) >> 16; - var flags; - var x = 0, - y = 0; - i += 10; + function quadraticCurveTo(xa, ya, x, y) { + cmds.push({ + cmd: "quadraticCurveTo", + args: [xa, ya, x, y] + }); + } + + let i = 0; + const numberOfContours = getInt16(code, i); + let flags; + let x = 0, + y = 0; + i += 10; + + if (numberOfContours < 0) { + do { + flags = getUint16(code, i); + const glyphIndex = getUint16(code, i + 2); + i += 4; + let arg1, arg2; + + if (flags & 0x01) { + if (flags & 0x02) { + arg1 = getInt16(code, i); + arg2 = getInt16(code, i + 2); + } else { + arg1 = getUint16(code, i); + arg2 = getUint16(code, i + 2); + } - if (numberOfContours < 0) { - do { - flags = code[i] << 8 | code[i + 1]; - var glyphIndex = code[i + 2] << 8 | code[i + 3]; i += 4; - var arg1, arg2; - - if (flags & 0x01) { - arg1 = (code[i] << 24 | code[i + 1] << 16) >> 16; - arg2 = (code[i + 2] << 24 | code[i + 3] << 16) >> 16; - i += 4; + } else { + if (flags & 0x02) { + arg1 = getInt8(code, i++); + arg2 = getInt8(code, i++); } else { arg1 = code[i++]; arg2 = code[i++]; } + } - if (flags & 0x02) { - x = arg1; - y = arg2; - } else { - x = 0; - y = 0; - } + if (flags & 0x02) { + x = arg1; + y = arg2; + } else { + x = 0; + y = 0; + } - var scaleX = 1, - scaleY = 1, - scale01 = 0, - scale10 = 0; + let scaleX = 1, + scaleY = 1, + scale01 = 0, + scale10 = 0; - if (flags & 0x08) { - scaleX = scaleY = (code[i] << 24 | code[i + 1] << 16) / 1073741824; - i += 2; - } else if (flags & 0x40) { - scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824; - scaleY = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824; - i += 4; - } else if (flags & 0x80) { - scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824; - scale01 = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824; - scale10 = (code[i + 4] << 24 | code[i + 5] << 16) / 1073741824; - scaleY = (code[i + 6] << 24 | code[i + 7] << 16) / 1073741824; - i += 8; - } - - var subglyph = font.glyphs[glyphIndex]; - - if (subglyph) { - cmds.push({ - cmd: "save" - }); - cmds.push({ - cmd: "transform", - args: [scaleX, scale01, scale10, scaleY, x, y] - }); - compileGlyf(subglyph, cmds, font); - cmds.push({ - cmd: "restore" - }); - } - } while (flags & 0x20); - } else { - var endPtsOfContours = []; - var j, jj; - - for (j = 0; j < numberOfContours; j++) { - endPtsOfContours.push(code[i] << 8 | code[i + 1]); + if (flags & 0x08) { + scaleX = scaleY = getFloat214(code, i); i += 2; + } else if (flags & 0x40) { + scaleX = getFloat214(code, i); + scaleY = getFloat214(code, i + 2); + i += 4; + } else if (flags & 0x80) { + scaleX = getFloat214(code, i); + scale01 = getFloat214(code, i + 2); + scale10 = getFloat214(code, i + 4); + scaleY = getFloat214(code, i + 6); + i += 8; } - var instructionLength = code[i] << 8 | code[i + 1]; - i += 2 + instructionLength; - var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1; - var points = []; + const subglyph = font.glyphs[glyphIndex]; - while (points.length < numberOfPoints) { - flags = code[i++]; - var repeat = 1; + if (subglyph) { + cmds.push({ + cmd: "save" + }, { + cmd: "transform", + args: [scaleX, scale01, scale10, scaleY, x, y] + }); - if (flags & 0x08) { - repeat += code[i++]; - } + if (!(flags & 0x02)) {} - while (repeat-- > 0) { - points.push({ - flags - }); - } + compileGlyf(subglyph, cmds, font); + cmds.push({ + cmd: "restore" + }); + } + } while (flags & 0x20); + } else { + const endPtsOfContours = []; + let j, jj; + + for (j = 0; j < numberOfContours; j++) { + endPtsOfContours.push(getUint16(code, i)); + i += 2; + } + + const instructionLength = getUint16(code, i); + i += 2 + instructionLength; + const numberOfPoints = endPtsOfContours.at(-1) + 1; + const points = []; + + while (points.length < numberOfPoints) { + flags = code[i++]; + let repeat = 1; + + if (flags & 0x08) { + repeat += code[i++]; } - for (j = 0; j < numberOfPoints; j++) { - switch (points[j].flags & 0x12) { - case 0x00: - x += (code[i] << 24 | code[i + 1] << 16) >> 16; - i += 2; - break; + while (repeat-- > 0) { + points.push({ + flags + }); + } + } - case 0x02: - x -= code[i++]; - break; + for (j = 0; j < numberOfPoints; j++) { + switch (points[j].flags & 0x12) { + case 0x00: + x += getInt16(code, i); + i += 2; + break; - case 0x12: - x += code[i++]; - break; - } + case 0x02: + x -= code[i++]; + break; - points[j].x = x; + case 0x12: + x += code[i++]; + break; } - for (j = 0; j < numberOfPoints; j++) { - switch (points[j].flags & 0x24) { - case 0x00: - y += (code[i] << 24 | code[i + 1] << 16) >> 16; - i += 2; - break; + points[j].x = x; + } - case 0x04: - y -= code[i++]; - break; + for (j = 0; j < numberOfPoints; j++) { + switch (points[j].flags & 0x24) { + case 0x00: + y += getInt16(code, i); + i += 2; + break; - case 0x24: - y += code[i++]; - break; - } + case 0x04: + y -= code[i++]; + break; - points[j].y = y; + case 0x24: + y += code[i++]; + break; } - var startPoint = 0; + points[j].y = y; + } - for (i = 0; i < numberOfContours; i++) { - var endPoint = endPtsOfContours[i]; - var contour = points.slice(startPoint, endPoint + 1); + let startPoint = 0; - if (contour[0].flags & 1) { - contour.push(contour[0]); - } else if (contour[contour.length - 1].flags & 1) { - contour.unshift(contour[contour.length - 1]); + for (i = 0; i < numberOfContours; i++) { + const endPoint = endPtsOfContours[i]; + const contour = points.slice(startPoint, endPoint + 1); + + if (contour[0].flags & 1) { + contour.push(contour[0]); + } else if (contour.at(-1).flags & 1) { + contour.unshift(contour.at(-1)); + } else { + const p = { + flags: 1, + x: (contour[0].x + contour.at(-1).x) / 2, + y: (contour[0].y + contour.at(-1).y) / 2 + }; + contour.unshift(p); + contour.push(p); + } + + moveTo(contour[0].x, contour[0].y); + + for (j = 1, jj = contour.length; j < jj; j++) { + if (contour[j].flags & 1) { + lineTo(contour[j].x, contour[j].y); + } else if (contour[j + 1].flags & 1) { + quadraticCurveTo(contour[j].x, contour[j].y, contour[j + 1].x, contour[j + 1].y); + j++; } else { - var p = { - flags: 1, - x: (contour[0].x + contour[contour.length - 1].x) / 2, - y: (contour[0].y + contour[contour.length - 1].y) / 2 - }; - contour.unshift(p); - contour.push(p); + quadraticCurveTo(contour[j].x, contour[j].y, (contour[j].x + contour[j + 1].x) / 2, (contour[j].y + contour[j + 1].y) / 2); } - - moveTo(contour[0].x, contour[0].y); - - for (j = 1, jj = contour.length; j < jj; j++) { - if (contour[j].flags & 1) { - lineTo(contour[j].x, contour[j].y); - } else if (contour[j + 1].flags & 1) { - quadraticCurveTo(contour[j].x, contour[j].y, contour[j + 1].x, contour[j + 1].y); - j++; - } else { - quadraticCurveTo(contour[j].x, contour[j].y, (contour[j].x + contour[j + 1].x) / 2, (contour[j].y + contour[j + 1].y) / 2); - } - } - - startPoint = endPoint + 1; } + + startPoint = endPoint + 1; } } +} - function compileCharString(charStringCode, cmds, font, glyphId) { - function moveTo(x, y) { - cmds.push({ - cmd: "moveTo", - args: [x, y] - }); - } +function compileCharString(charStringCode, cmds, font, glyphId) { + function moveTo(x, y) { + cmds.push({ + cmd: "moveTo", + args: [x, y] + }); + } - function lineTo(x, y) { - cmds.push({ - cmd: "lineTo", - args: [x, y] - }); - } + function lineTo(x, y) { + cmds.push({ + cmd: "lineTo", + args: [x, y] + }); + } - function bezierCurveTo(x1, y1, x2, y2, x, y) { - cmds.push({ - cmd: "bezierCurveTo", - args: [x1, y1, x2, y2, x, y] - }); - } + function bezierCurveTo(x1, y1, x2, y2, x, y) { + cmds.push({ + cmd: "bezierCurveTo", + args: [x1, y1, x2, y2, x, y] + }); + } - var stack = []; - var x = 0, - y = 0; - var stems = 0; + const stack = []; + let x = 0, + y = 0; + let stems = 0; - function parse(code) { - var i = 0; + function parse(code) { + let i = 0; - while (i < code.length) { - var stackClean = false; - var v = code[i++]; - var xa, xb, ya, yb, y1, y2, y3, n, subrCode; + while (i < code.length) { + let stackClean = false; + let v = code[i++]; + let xa, xb, ya, yb, y1, y2, y3, n, subrCode; - switch (v) { - case 1: - stems += stack.length >> 1; - stackClean = true; - break; + switch (v) { + case 1: + stems += stack.length >> 1; + stackClean = true; + break; - case 3: - stems += stack.length >> 1; - stackClean = true; - break; + case 3: + stems += stack.length >> 1; + stackClean = true; + break; - case 4: - y += stack.pop(); - moveTo(x, y); - stackClean = true; - break; - - case 5: - while (stack.length > 0) { - x += stack.shift(); - y += stack.shift(); - lineTo(x, y); - } - - break; - - case 6: - while (stack.length > 0) { - x += stack.shift(); - lineTo(x, y); - - if (stack.length === 0) { - break; - } - - y += stack.shift(); - lineTo(x, y); - } - - break; - - case 7: - while (stack.length > 0) { - y += stack.shift(); - lineTo(x, y); - - if (stack.length === 0) { - break; - } - - x += stack.shift(); - lineTo(x, y); - } - - break; - - case 8: - while (stack.length > 0) { - xa = x + stack.shift(); - ya = y + stack.shift(); - xb = xa + stack.shift(); - yb = ya + stack.shift(); - x = xb + stack.shift(); - y = yb + stack.shift(); - bezierCurveTo(xa, ya, xb, yb, x, y); - } - - break; - - case 10: - n = stack.pop(); - subrCode = null; - - if (font.isCFFCIDFont) { - const fdIndex = font.fdSelect.getFDIndex(glyphId); - - if (fdIndex >= 0 && fdIndex < font.fdArray.length) { - const fontDict = font.fdArray[fdIndex]; - let subrs; - - if (fontDict.privateDict && fontDict.privateDict.subrsIndex) { - subrs = fontDict.privateDict.subrsIndex.objects; - } - - if (subrs) { - n += getSubroutineBias(subrs); - subrCode = subrs[n]; - } - } else { - (0, _util.warn)("Invalid fd index for glyph index."); - } - } else { - subrCode = font.subrs[n + font.subrsBias]; - } - - if (subrCode) { - parse(subrCode); - } - - break; - - case 11: - return; - - case 12: - v = code[i++]; - - switch (v) { - case 34: - xa = x + stack.shift(); - xb = xa + stack.shift(); - y1 = y + stack.shift(); - x = xb + stack.shift(); - bezierCurveTo(xa, y, xb, y1, x, y1); - xa = x + stack.shift(); - xb = xa + stack.shift(); - x = xb + stack.shift(); - bezierCurveTo(xa, y1, xb, y, x, y); - break; - - case 35: - xa = x + stack.shift(); - ya = y + stack.shift(); - xb = xa + stack.shift(); - yb = ya + stack.shift(); - x = xb + stack.shift(); - y = yb + stack.shift(); - bezierCurveTo(xa, ya, xb, yb, x, y); - xa = x + stack.shift(); - ya = y + stack.shift(); - xb = xa + stack.shift(); - yb = ya + stack.shift(); - x = xb + stack.shift(); - y = yb + stack.shift(); - bezierCurveTo(xa, ya, xb, yb, x, y); - stack.pop(); - break; - - case 36: - xa = x + stack.shift(); - y1 = y + stack.shift(); - xb = xa + stack.shift(); - y2 = y1 + stack.shift(); - x = xb + stack.shift(); - bezierCurveTo(xa, y1, xb, y2, x, y2); - xa = x + stack.shift(); - xb = xa + stack.shift(); - y3 = y2 + stack.shift(); - x = xb + stack.shift(); - bezierCurveTo(xa, y2, xb, y3, x, y); - break; - - case 37: - var x0 = x, - y0 = y; - xa = x + stack.shift(); - ya = y + stack.shift(); - xb = xa + stack.shift(); - yb = ya + stack.shift(); - x = xb + stack.shift(); - y = yb + stack.shift(); - bezierCurveTo(xa, ya, xb, yb, x, y); - xa = x + stack.shift(); - ya = y + stack.shift(); - xb = xa + stack.shift(); - yb = ya + stack.shift(); - x = xb; - y = yb; - - if (Math.abs(x - x0) > Math.abs(y - y0)) { - x += stack.shift(); - } else { - y += stack.shift(); - } - - bezierCurveTo(xa, ya, xb, yb, x, y); - break; - - default: - throw new _util.FormatError(`unknown operator: 12 ${v}`); - } - - break; - - case 14: - if (stack.length >= 4) { - var achar = stack.pop(); - var bchar = stack.pop(); - y = stack.pop(); - x = stack.pop(); - cmds.push({ - cmd: "save" - }); - cmds.push({ - cmd: "translate", - args: [x, y] - }); - var cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[achar]])); - compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId); - cmds.push({ - cmd: "restore" - }); - cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[bchar]])); - compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId); - } - - return; - - case 18: - stems += stack.length >> 1; - stackClean = true; - break; - - case 19: - stems += stack.length >> 1; - i += stems + 7 >> 3; - stackClean = true; - break; - - case 20: - stems += stack.length >> 1; - i += stems + 7 >> 3; - stackClean = true; - break; - - case 21: - y += stack.pop(); - x += stack.pop(); - moveTo(x, y); - stackClean = true; - break; - - case 22: - x += stack.pop(); - moveTo(x, y); - stackClean = true; - break; - - case 23: - stems += stack.length >> 1; - stackClean = true; - break; - - case 24: - while (stack.length > 2) { - xa = x + stack.shift(); - ya = y + stack.shift(); - xb = xa + stack.shift(); - yb = ya + stack.shift(); - x = xb + stack.shift(); - y = yb + stack.shift(); - bezierCurveTo(xa, ya, xb, yb, x, y); - } + case 4: + y += stack.pop(); + moveTo(x, y); + stackClean = true; + break; + case 5: + while (stack.length > 0) { x += stack.shift(); y += stack.shift(); lineTo(x, y); - break; + } - case 25: - while (stack.length > 6) { - x += stack.shift(); - y += stack.shift(); - lineTo(x, y); + break; + + case 6: + while (stack.length > 0) { + x += stack.shift(); + lineTo(x, y); + + if (stack.length === 0) { + break; } + y += stack.shift(); + lineTo(x, y); + } + + break; + + case 7: + while (stack.length > 0) { + y += stack.shift(); + lineTo(x, y); + + if (stack.length === 0) { + break; + } + + x += stack.shift(); + lineTo(x, y); + } + + break; + + case 8: + while (stack.length > 0) { xa = x + stack.shift(); ya = y + stack.shift(); xb = xa + stack.shift(); @@ -39283,3962 +44028,527 @@ var FontRendererFactory = function FontRendererFactoryClosure() { x = xb + stack.shift(); y = yb + stack.shift(); bezierCurveTo(xa, ya, xb, yb, x, y); - break; + } - case 26: - if (stack.length % 2) { - x += stack.shift(); + break; + + case 10: + n = stack.pop(); + subrCode = null; + + if (font.isCFFCIDFont) { + const fdIndex = font.fdSelect.getFDIndex(glyphId); + + if (fdIndex >= 0 && fdIndex < font.fdArray.length) { + const fontDict = font.fdArray[fdIndex]; + let subrs; + + if (fontDict.privateDict && fontDict.privateDict.subrsIndex) { + subrs = fontDict.privateDict.subrsIndex.objects; + } + + if (subrs) { + n += getSubroutineBias(subrs); + subrCode = subrs[n]; + } + } else { + (0, _util.warn)("Invalid fd index for glyph index."); } + } else { + subrCode = font.subrs[n + font.subrsBias]; + } - while (stack.length > 0) { - xa = x; + if (subrCode) { + parse(subrCode); + } + + break; + + case 11: + return; + + case 12: + v = code[i++]; + + switch (v) { + case 34: + xa = x + stack.shift(); + xb = xa + stack.shift(); + y1 = y + stack.shift(); + x = xb + stack.shift(); + bezierCurveTo(xa, y, xb, y1, x, y1); + xa = x + stack.shift(); + xb = xa + stack.shift(); + x = xb + stack.shift(); + bezierCurveTo(xa, y1, xb, y, x, y); + break; + + case 35: + xa = x + stack.shift(); + ya = y + stack.shift(); + xb = xa + stack.shift(); + yb = ya + stack.shift(); + x = xb + stack.shift(); + y = yb + stack.shift(); + bezierCurveTo(xa, ya, xb, yb, x, y); + xa = x + stack.shift(); + ya = y + stack.shift(); + xb = xa + stack.shift(); + yb = ya + stack.shift(); + x = xb + stack.shift(); + y = yb + stack.shift(); + bezierCurveTo(xa, ya, xb, yb, x, y); + stack.pop(); + break; + + case 36: + xa = x + stack.shift(); + y1 = y + stack.shift(); + xb = xa + stack.shift(); + y2 = y1 + stack.shift(); + x = xb + stack.shift(); + bezierCurveTo(xa, y1, xb, y2, x, y2); + xa = x + stack.shift(); + xb = xa + stack.shift(); + y3 = y2 + stack.shift(); + x = xb + stack.shift(); + bezierCurveTo(xa, y2, xb, y3, x, y); + break; + + case 37: + const x0 = x, + y0 = y; + xa = x + stack.shift(); + ya = y + stack.shift(); + xb = xa + stack.shift(); + yb = ya + stack.shift(); + x = xb + stack.shift(); + y = yb + stack.shift(); + bezierCurveTo(xa, ya, xb, yb, x, y); + xa = x + stack.shift(); ya = y + stack.shift(); xb = xa + stack.shift(); yb = ya + stack.shift(); x = xb; - y = yb + stack.shift(); - bezierCurveTo(xa, ya, xb, yb, x, y); - } - - break; - - case 27: - if (stack.length % 2) { - y += stack.shift(); - } - - while (stack.length > 0) { - xa = x + stack.shift(); - ya = y; - xb = xa + stack.shift(); - yb = ya + stack.shift(); - x = xb + stack.shift(); y = yb; - bezierCurveTo(xa, ya, xb, yb, x, y); - } - break; - - case 28: - stack.push((code[i] << 24 | code[i + 1] << 16) >> 16); - i += 2; - break; - - case 29: - n = stack.pop() + font.gsubrsBias; - subrCode = font.gsubrs[n]; - - if (subrCode) { - parse(subrCode); - } - - break; - - case 30: - while (stack.length > 0) { - xa = x; - ya = y + stack.shift(); - xb = xa + stack.shift(); - yb = ya + stack.shift(); - x = xb + stack.shift(); - y = yb + (stack.length === 1 ? stack.shift() : 0); - bezierCurveTo(xa, ya, xb, yb, x, y); - - if (stack.length === 0) { - break; + if (Math.abs(x - x0) > Math.abs(y - y0)) { + x += stack.shift(); + } else { + y += stack.shift(); } - xa = x + stack.shift(); - ya = y; - xb = xa + stack.shift(); - yb = ya + stack.shift(); - y = yb + stack.shift(); - x = xb + (stack.length === 1 ? stack.shift() : 0); bezierCurveTo(xa, ya, xb, yb, x, y); + break; + + default: + throw new _util.FormatError(`unknown operator: 12 ${v}`); + } + + break; + + case 14: + if (stack.length >= 4) { + const achar = stack.pop(); + const bchar = stack.pop(); + y = stack.pop(); + x = stack.pop(); + cmds.push({ + cmd: "save" + }, { + cmd: "translate", + args: [x, y] + }); + let cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[achar]])); + compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId); + cmds.push({ + cmd: "restore" + }); + cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[bchar]])); + compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId); + } + + return; + + case 18: + stems += stack.length >> 1; + stackClean = true; + break; + + case 19: + stems += stack.length >> 1; + i += stems + 7 >> 3; + stackClean = true; + break; + + case 20: + stems += stack.length >> 1; + i += stems + 7 >> 3; + stackClean = true; + break; + + case 21: + y += stack.pop(); + x += stack.pop(); + moveTo(x, y); + stackClean = true; + break; + + case 22: + x += stack.pop(); + moveTo(x, y); + stackClean = true; + break; + + case 23: + stems += stack.length >> 1; + stackClean = true; + break; + + case 24: + while (stack.length > 2) { + xa = x + stack.shift(); + ya = y + stack.shift(); + xb = xa + stack.shift(); + yb = ya + stack.shift(); + x = xb + stack.shift(); + y = yb + stack.shift(); + bezierCurveTo(xa, ya, xb, yb, x, y); + } + + x += stack.shift(); + y += stack.shift(); + lineTo(x, y); + break; + + case 25: + while (stack.length > 6) { + x += stack.shift(); + y += stack.shift(); + lineTo(x, y); + } + + xa = x + stack.shift(); + ya = y + stack.shift(); + xb = xa + stack.shift(); + yb = ya + stack.shift(); + x = xb + stack.shift(); + y = yb + stack.shift(); + bezierCurveTo(xa, ya, xb, yb, x, y); + break; + + case 26: + if (stack.length % 2) { + x += stack.shift(); + } + + while (stack.length > 0) { + xa = x; + ya = y + stack.shift(); + xb = xa + stack.shift(); + yb = ya + stack.shift(); + x = xb; + y = yb + stack.shift(); + bezierCurveTo(xa, ya, xb, yb, x, y); + } + + break; + + case 27: + if (stack.length % 2) { + y += stack.shift(); + } + + while (stack.length > 0) { + xa = x + stack.shift(); + ya = y; + xb = xa + stack.shift(); + yb = ya + stack.shift(); + x = xb + stack.shift(); + y = yb; + bezierCurveTo(xa, ya, xb, yb, x, y); + } + + break; + + case 28: + stack.push((code[i] << 24 | code[i + 1] << 16) >> 16); + i += 2; + break; + + case 29: + n = stack.pop() + font.gsubrsBias; + subrCode = font.gsubrs[n]; + + if (subrCode) { + parse(subrCode); + } + + break; + + case 30: + while (stack.length > 0) { + xa = x; + ya = y + stack.shift(); + xb = xa + stack.shift(); + yb = ya + stack.shift(); + x = xb + stack.shift(); + y = yb + (stack.length === 1 ? stack.shift() : 0); + bezierCurveTo(xa, ya, xb, yb, x, y); + + if (stack.length === 0) { + break; } - break; + xa = x + stack.shift(); + ya = y; + xb = xa + stack.shift(); + yb = ya + stack.shift(); + y = yb + stack.shift(); + x = xb + (stack.length === 1 ? stack.shift() : 0); + bezierCurveTo(xa, ya, xb, yb, x, y); + } - case 31: - while (stack.length > 0) { - xa = x + stack.shift(); - ya = y; - xb = xa + stack.shift(); - yb = ya + stack.shift(); - y = yb + stack.shift(); - x = xb + (stack.length === 1 ? stack.shift() : 0); - bezierCurveTo(xa, ya, xb, yb, x, y); + break; - if (stack.length === 0) { - break; - } + case 31: + while (stack.length > 0) { + xa = x + stack.shift(); + ya = y; + xb = xa + stack.shift(); + yb = ya + stack.shift(); + y = yb + stack.shift(); + x = xb + (stack.length === 1 ? stack.shift() : 0); + bezierCurveTo(xa, ya, xb, yb, x, y); - xa = x; - ya = y + stack.shift(); - xb = xa + stack.shift(); - yb = ya + stack.shift(); - x = xb + stack.shift(); - y = yb + (stack.length === 1 ? stack.shift() : 0); - bezierCurveTo(xa, ya, xb, yb, x, y); + if (stack.length === 0) { + break; } - break; + xa = x; + ya = y + stack.shift(); + xb = xa + stack.shift(); + yb = ya + stack.shift(); + x = xb + stack.shift(); + y = yb + (stack.length === 1 ? stack.shift() : 0); + bezierCurveTo(xa, ya, xb, yb, x, y); + } - default: - if (v < 32) { - throw new _util.FormatError(`unknown operator: ${v}`); - } + break; - if (v < 247) { - stack.push(v - 139); - } else if (v < 251) { - stack.push((v - 247) * 256 + code[i++] + 108); - } else if (v < 255) { - stack.push(-(v - 251) * 256 - code[i++] - 108); - } else { - stack.push((code[i] << 24 | code[i + 1] << 16 | code[i + 2] << 8 | code[i + 3]) / 65536); - i += 4; - } + default: + if (v < 32) { + throw new _util.FormatError(`unknown operator: ${v}`); + } - break; - } + if (v < 247) { + stack.push(v - 139); + } else if (v < 251) { + stack.push((v - 247) * 256 + code[i++] + 108); + } else if (v < 255) { + stack.push(-(v - 251) * 256 - code[i++] - 108); + } else { + stack.push((code[i] << 24 | code[i + 1] << 16 | code[i + 2] << 8 | code[i + 3]) / 65536); + i += 4; + } - if (stackClean) { - stack.length = 0; - } + break; + } + + if (stackClean) { + stack.length = 0; } } - - parse(charStringCode); } - const NOOP = []; + parse(charStringCode); +} - class CompiledFont { - constructor(fontMatrix) { - if (this.constructor === CompiledFont) { - (0, _util.unreachable)("Cannot initialize CompiledFont."); - } +const NOOP = []; - this.fontMatrix = fontMatrix; - this.compiledGlyphs = Object.create(null); - this.compiledCharCodeToGlyphId = Object.create(null); +class CompiledFont { + constructor(fontMatrix) { + if (this.constructor === CompiledFont) { + (0, _util.unreachable)("Cannot initialize CompiledFont."); } - getPathJs(unicode) { - const cmap = lookupCmap(this.cmap, unicode); - let fn = this.compiledGlyphs[cmap.glyphId]; + this.fontMatrix = fontMatrix; + this.compiledGlyphs = Object.create(null); + this.compiledCharCodeToGlyphId = Object.create(null); + } - if (!fn) { - fn = this.compileGlyph(this.glyphs[cmap.glyphId], cmap.glyphId); - this.compiledGlyphs[cmap.glyphId] = fn; - } + getPathJs(unicode) { + const { + charCode, + glyphId + } = lookupCmap(this.cmap, unicode); + let fn = this.compiledGlyphs[glyphId]; - if (this.compiledCharCodeToGlyphId[cmap.charCode] === undefined) { - this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId; - } + if (!fn) { + try { + fn = this.compileGlyph(this.glyphs[glyphId], glyphId); + this.compiledGlyphs[glyphId] = fn; + } catch (ex) { + this.compiledGlyphs[glyphId] = NOOP; - return fn; - } - - compileGlyph(code, glyphId) { - if (!code || code.length === 0 || code[0] === 14) { - return NOOP; - } - - let fontMatrix = this.fontMatrix; - - if (this.isCFFCIDFont) { - const fdIndex = this.fdSelect.getFDIndex(glyphId); - - if (fdIndex >= 0 && fdIndex < this.fdArray.length) { - const fontDict = this.fdArray[fdIndex]; - fontMatrix = fontDict.getByName("FontMatrix") || _util.FONT_IDENTITY_MATRIX; - } else { - (0, _util.warn)("Invalid fd index for glyph index."); + if (this.compiledCharCodeToGlyphId[charCode] === undefined) { + this.compiledCharCodeToGlyphId[charCode] = glyphId; } + + throw ex; } - - const cmds = []; - cmds.push({ - cmd: "save" - }); - cmds.push({ - cmd: "transform", - args: fontMatrix.slice() - }); - cmds.push({ - cmd: "scale", - args: ["size", "-size"] - }); - this.compileGlyphImpl(code, cmds, glyphId); - cmds.push({ - cmd: "restore" - }); - return cmds; } - compileGlyphImpl() { - (0, _util.unreachable)("Children classes should implement this."); - } - - hasBuiltPath(unicode) { - const cmap = lookupCmap(this.cmap, unicode); - return this.compiledGlyphs[cmap.glyphId] !== undefined && this.compiledCharCodeToGlyphId[cmap.charCode] !== undefined; + if (this.compiledCharCodeToGlyphId[charCode] === undefined) { + this.compiledCharCodeToGlyphId[charCode] = glyphId; } + return fn; } - class TrueTypeCompiled extends CompiledFont { - constructor(glyphs, cmap, fontMatrix) { - super(fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0]); - this.glyphs = glyphs; - this.cmap = cmap; + compileGlyph(code, glyphId) { + if (!code || code.length === 0 || code[0] === 14) { + return NOOP; } - compileGlyphImpl(code, cmds) { - compileGlyf(code, cmds, this); + let fontMatrix = this.fontMatrix; + + if (this.isCFFCIDFont) { + const fdIndex = this.fdSelect.getFDIndex(glyphId); + + if (fdIndex >= 0 && fdIndex < this.fdArray.length) { + const fontDict = this.fdArray[fdIndex]; + fontMatrix = fontDict.getByName("FontMatrix") || _util.FONT_IDENTITY_MATRIX; + } else { + (0, _util.warn)("Invalid fd index for glyph index."); + } } + const cmds = [{ + cmd: "save" + }, { + cmd: "transform", + args: fontMatrix.slice() + }, { + cmd: "scale", + args: ["size", "-size"] + }]; + this.compileGlyphImpl(code, cmds, glyphId); + cmds.push({ + cmd: "restore" + }); + return cmds; } - class Type2Compiled extends CompiledFont { - constructor(cffInfo, cmap, fontMatrix, glyphNameMap) { - super(fontMatrix || [0.001, 0, 0, 0.001, 0, 0]); - this.glyphs = cffInfo.glyphs; - this.gsubrs = cffInfo.gsubrs || []; - this.subrs = cffInfo.subrs || []; - this.cmap = cmap; - this.glyphNameMap = glyphNameMap || (0, _glyphlist.getGlyphsUnicode)(); - this.gsubrsBias = getSubroutineBias(this.gsubrs); - this.subrsBias = getSubroutineBias(this.subrs); - this.isCFFCIDFont = cffInfo.isCFFCIDFont; - this.fdSelect = cffInfo.fdSelect; - this.fdArray = cffInfo.fdArray; - } - - compileGlyphImpl(code, cmds, glyphId) { - compileCharString(code, cmds, this, glyphId); - } - + compileGlyphImpl() { + (0, _util.unreachable)("Children classes should implement this."); } - return { - create: function FontRendererFactory_create(font, seacAnalysisEnabled) { - var data = new Uint8Array(font.data); - var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm; - var numTables = getUshort(data, 4); + hasBuiltPath(unicode) { + const { + charCode, + glyphId + } = lookupCmap(this.cmap, unicode); + return this.compiledGlyphs[glyphId] !== undefined && this.compiledCharCodeToGlyphId[charCode] !== undefined; + } - for (var i = 0, p = 12; i < numTables; i++, p += 16) { - var tag = (0, _util.bytesToString)(data.subarray(p, p + 4)); - var offset = getLong(data, p + 8); - var length = getLong(data, p + 12); +} - switch (tag) { - case "cmap": - cmap = parseCmap(data, offset, offset + length); - break; +class TrueTypeCompiled extends CompiledFont { + constructor(glyphs, cmap, fontMatrix) { + super(fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0]); + this.glyphs = glyphs; + this.cmap = cmap; + } - case "glyf": - glyf = data.subarray(offset, offset + length); - break; + compileGlyphImpl(code, cmds) { + compileGlyf(code, cmds, this); + } - case "loca": - loca = data.subarray(offset, offset + length); - break; +} - case "head": - unitsPerEm = getUshort(data, offset + 18); - indexToLocFormat = getUshort(data, offset + 50); - break; +class Type2Compiled extends CompiledFont { + constructor(cffInfo, cmap, fontMatrix, glyphNameMap) { + super(fontMatrix || [0.001, 0, 0, 0.001, 0, 0]); + this.glyphs = cffInfo.glyphs; + this.gsubrs = cffInfo.gsubrs || []; + this.subrs = cffInfo.subrs || []; + this.cmap = cmap; + this.glyphNameMap = glyphNameMap || (0, _glyphlist.getGlyphsUnicode)(); + this.gsubrsBias = getSubroutineBias(this.gsubrs); + this.subrsBias = getSubroutineBias(this.subrs); + this.isCFFCIDFont = cffInfo.isCFFCIDFont; + this.fdSelect = cffInfo.fdSelect; + this.fdArray = cffInfo.fdArray; + } - case "CFF ": - cff = parseCff(data, offset, offset + length, seacAnalysisEnabled); - break; - } + compileGlyphImpl(code, cmds, glyphId) { + compileCharString(code, cmds, this, glyphId); + } + +} + +class FontRendererFactory { + static create(font, seacAnalysisEnabled) { + const data = new Uint8Array(font.data); + let cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm; + const numTables = getUint16(data, 4); + + for (let i = 0, p = 12; i < numTables; i++, p += 16) { + const tag = (0, _util.bytesToString)(data.subarray(p, p + 4)); + const offset = getUint32(data, p + 8); + const length = getUint32(data, p + 12); + + switch (tag) { + case "cmap": + cmap = parseCmap(data, offset, offset + length); + break; + + case "glyf": + glyf = data.subarray(offset, offset + length); + break; + + case "loca": + loca = data.subarray(offset, offset + length); + break; + + case "head": + unitsPerEm = getUint16(data, offset + 18); + indexToLocFormat = getUint16(data, offset + 50); + break; + + case "CFF ": + cff = parseCff(data, offset, offset + length, seacAnalysisEnabled); + break; } - - if (glyf) { - var fontMatrix = !unitsPerEm ? font.fontMatrix : [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]; - return new TrueTypeCompiled(parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix); - } - - return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap); } - }; -}(); + + if (glyf) { + const fontMatrix = !unitsPerEm ? font.fontMatrix : [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]; + return new TrueTypeCompiled(parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix); + } + + return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap); + } + +} exports.FontRendererFactory = FontRendererFactory; /***/ }), -/* 38 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 45 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.Type1Parser = void 0; +})); +exports.getMetrics = exports.getFontBasicMetrics = void 0; -var _encodings = __w_pdfjs_require__(33); +var _core_utils = __w_pdfjs_require__(6); -var _core_utils = __w_pdfjs_require__(8); - -var _stream = __w_pdfjs_require__(12); - -var _util = __w_pdfjs_require__(2); - -var HINTING_ENABLED = false; - -var Type1CharString = function Type1CharStringClosure() { - var COMMAND_MAP = { - hstem: [1], - vstem: [3], - vmoveto: [4], - rlineto: [5], - hlineto: [6], - vlineto: [7], - rrcurveto: [8], - callsubr: [10], - flex: [12, 35], - drop: [12, 18], - endchar: [14], - rmoveto: [21], - hmoveto: [22], - vhcurveto: [30], - hvcurveto: [31] - }; - - function Type1CharString() { - this.width = 0; - this.lsb = 0; - this.flexing = false; - this.output = []; - this.stack = []; - } - - Type1CharString.prototype = { - convert: function Type1CharString_convert(encoded, subrs, seacAnalysisEnabled) { - var count = encoded.length; - var error = false; - var wx, sbx, subrNumber; - - for (var i = 0; i < count; i++) { - var value = encoded[i]; - - if (value < 32) { - if (value === 12) { - value = (value << 8) + encoded[++i]; - } - - switch (value) { - case 1: - if (!HINTING_ENABLED) { - this.stack = []; - break; - } - - error = this.executeCommand(2, COMMAND_MAP.hstem); - break; - - case 3: - if (!HINTING_ENABLED) { - this.stack = []; - break; - } - - error = this.executeCommand(2, COMMAND_MAP.vstem); - break; - - case 4: - if (this.flexing) { - if (this.stack.length < 1) { - error = true; - break; - } - - var dy = this.stack.pop(); - this.stack.push(0, dy); - break; - } - - error = this.executeCommand(1, COMMAND_MAP.vmoveto); - break; - - case 5: - error = this.executeCommand(2, COMMAND_MAP.rlineto); - break; - - case 6: - error = this.executeCommand(1, COMMAND_MAP.hlineto); - break; - - case 7: - error = this.executeCommand(1, COMMAND_MAP.vlineto); - break; - - case 8: - error = this.executeCommand(6, COMMAND_MAP.rrcurveto); - break; - - case 9: - this.stack = []; - break; - - case 10: - if (this.stack.length < 1) { - error = true; - break; - } - - subrNumber = this.stack.pop(); - - if (!subrs[subrNumber]) { - error = true; - break; - } - - error = this.convert(subrs[subrNumber], subrs, seacAnalysisEnabled); - break; - - case 11: - return error; - - case 13: - if (this.stack.length < 2) { - error = true; - break; - } - - wx = this.stack.pop(); - sbx = this.stack.pop(); - this.lsb = sbx; - this.width = wx; - this.stack.push(wx, sbx); - error = this.executeCommand(2, COMMAND_MAP.hmoveto); - break; - - case 14: - this.output.push(COMMAND_MAP.endchar[0]); - break; - - case 21: - if (this.flexing) { - break; - } - - error = this.executeCommand(2, COMMAND_MAP.rmoveto); - break; - - case 22: - if (this.flexing) { - this.stack.push(0); - break; - } - - error = this.executeCommand(1, COMMAND_MAP.hmoveto); - break; - - case 30: - error = this.executeCommand(4, COMMAND_MAP.vhcurveto); - break; - - case 31: - error = this.executeCommand(4, COMMAND_MAP.hvcurveto); - break; - - case (12 << 8) + 0: - this.stack = []; - break; - - case (12 << 8) + 1: - if (!HINTING_ENABLED) { - this.stack = []; - break; - } - - error = this.executeCommand(2, COMMAND_MAP.vstem); - break; - - case (12 << 8) + 2: - if (!HINTING_ENABLED) { - this.stack = []; - break; - } - - error = this.executeCommand(2, COMMAND_MAP.hstem); - break; - - case (12 << 8) + 6: - if (seacAnalysisEnabled) { - const asb = this.stack[this.stack.length - 5]; - this.seac = this.stack.splice(-4, 4); - this.seac[0] += this.lsb - asb; - error = this.executeCommand(0, COMMAND_MAP.endchar); - } else { - error = this.executeCommand(4, COMMAND_MAP.endchar); - } - - break; - - case (12 << 8) + 7: - if (this.stack.length < 4) { - error = true; - break; - } - - this.stack.pop(); - wx = this.stack.pop(); - var sby = this.stack.pop(); - sbx = this.stack.pop(); - this.lsb = sbx; - this.width = wx; - this.stack.push(wx, sbx, sby); - error = this.executeCommand(3, COMMAND_MAP.rmoveto); - break; - - case (12 << 8) + 12: - if (this.stack.length < 2) { - error = true; - break; - } - - var num2 = this.stack.pop(); - var num1 = this.stack.pop(); - this.stack.push(num1 / num2); - break; - - case (12 << 8) + 16: - if (this.stack.length < 2) { - error = true; - break; - } - - subrNumber = this.stack.pop(); - var numArgs = this.stack.pop(); - - if (subrNumber === 0 && numArgs === 3) { - var flexArgs = this.stack.splice(this.stack.length - 17, 17); - this.stack.push(flexArgs[2] + flexArgs[0], flexArgs[3] + flexArgs[1], flexArgs[4], flexArgs[5], flexArgs[6], flexArgs[7], flexArgs[8], flexArgs[9], flexArgs[10], flexArgs[11], flexArgs[12], flexArgs[13], flexArgs[14]); - error = this.executeCommand(13, COMMAND_MAP.flex, true); - this.flexing = false; - this.stack.push(flexArgs[15], flexArgs[16]); - } else if (subrNumber === 1 && numArgs === 0) { - this.flexing = true; - } - - break; - - case (12 << 8) + 17: - break; - - case (12 << 8) + 33: - this.stack = []; - break; - - default: - (0, _util.warn)('Unknown type 1 charstring command of "' + value + '"'); - break; - } - - if (error) { - break; - } - - continue; - } else if (value <= 246) { - value = value - 139; - } else if (value <= 250) { - value = (value - 247) * 256 + encoded[++i] + 108; - } else if (value <= 254) { - value = -((value - 251) * 256) - encoded[++i] - 108; - } else { - value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 | (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0; - } - - this.stack.push(value); - } - - return error; - }, - - executeCommand(howManyArgs, command, keepStack) { - var stackLength = this.stack.length; - - if (howManyArgs > stackLength) { - return true; - } - - var start = stackLength - howManyArgs; - - for (var i = start; i < stackLength; i++) { - var value = this.stack[i]; - - if (Number.isInteger(value)) { - this.output.push(28, value >> 8 & 0xff, value & 0xff); - } else { - value = 65536 * value | 0; - this.output.push(255, value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff); - } - } - - this.output.push.apply(this.output, command); - - if (keepStack) { - this.stack.splice(start, howManyArgs); - } else { - this.stack.length = 0; - } - - return false; - } - - }; - return Type1CharString; -}(); - -var Type1Parser = function Type1ParserClosure() { - var EEXEC_ENCRYPT_KEY = 55665; - var CHAR_STRS_ENCRYPT_KEY = 4330; - - function isHexDigit(code) { - return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102; - } - - function decrypt(data, key, discardNumber) { - if (discardNumber >= data.length) { - return new Uint8Array(0); - } - - var r = key | 0, - c1 = 52845, - c2 = 22719, - i, - j; - - for (i = 0; i < discardNumber; i++) { - r = (data[i] + r) * c1 + c2 & (1 << 16) - 1; - } - - var count = data.length - discardNumber; - var decrypted = new Uint8Array(count); - - for (i = discardNumber, j = 0; j < count; i++, j++) { - var value = data[i]; - decrypted[j] = value ^ r >> 8; - r = (value + r) * c1 + c2 & (1 << 16) - 1; - } - - return decrypted; - } - - function decryptAscii(data, key, discardNumber) { - var r = key | 0, - c1 = 52845, - c2 = 22719; - var count = data.length, - maybeLength = count >>> 1; - var decrypted = new Uint8Array(maybeLength); - var i, j; - - for (i = 0, j = 0; i < count; i++) { - var digit1 = data[i]; - - if (!isHexDigit(digit1)) { - continue; - } - - i++; - var digit2; - - while (i < count && !isHexDigit(digit2 = data[i])) { - i++; - } - - if (i < count) { - var value = parseInt(String.fromCharCode(digit1, digit2), 16); - decrypted[j++] = value ^ r >> 8; - r = (value + r) * c1 + c2 & (1 << 16) - 1; - } - } - - return decrypted.slice(discardNumber, j); - } - - function isSpecial(c) { - return c === 0x2f || c === 0x5b || c === 0x5d || c === 0x7b || c === 0x7d || c === 0x28 || c === 0x29; - } - - function Type1Parser(stream, encrypted, seacAnalysisEnabled) { - if (encrypted) { - var data = stream.getBytes(); - var isBinary = !((isHexDigit(data[0]) || (0, _core_utils.isWhiteSpace)(data[0])) && isHexDigit(data[1]) && isHexDigit(data[2]) && isHexDigit(data[3]) && isHexDigit(data[4]) && isHexDigit(data[5]) && isHexDigit(data[6]) && isHexDigit(data[7])); - stream = new _stream.Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) : decryptAscii(data, EEXEC_ENCRYPT_KEY, 4)); - } - - this.seacAnalysisEnabled = !!seacAnalysisEnabled; - this.stream = stream; - this.nextChar(); - } - - Type1Parser.prototype = { - readNumberArray: function Type1Parser_readNumberArray() { - this.getToken(); - var array = []; - - while (true) { - var token = this.getToken(); - - if (token === null || token === "]" || token === "}") { - break; - } - - array.push(parseFloat(token || 0)); - } - - return array; - }, - readNumber: function Type1Parser_readNumber() { - var token = this.getToken(); - return parseFloat(token || 0); - }, - readInt: function Type1Parser_readInt() { - var token = this.getToken(); - return parseInt(token || 0, 10) | 0; - }, - readBoolean: function Type1Parser_readBoolean() { - var token = this.getToken(); - return token === "true" ? 1 : 0; - }, - nextChar: function Type1_nextChar() { - return this.currentChar = this.stream.getByte(); - }, - getToken: function Type1Parser_getToken() { - var comment = false; - var ch = this.currentChar; - - while (true) { - if (ch === -1) { - return null; - } - - if (comment) { - if (ch === 0x0a || ch === 0x0d) { - comment = false; - } - } else if (ch === 0x25) { - comment = true; - } else if (!(0, _core_utils.isWhiteSpace)(ch)) { - break; - } - - ch = this.nextChar(); - } - - if (isSpecial(ch)) { - this.nextChar(); - return String.fromCharCode(ch); - } - - var token = ""; - - do { - token += String.fromCharCode(ch); - ch = this.nextChar(); - } while (ch >= 0 && !(0, _core_utils.isWhiteSpace)(ch) && !isSpecial(ch)); - - return token; - }, - readCharStrings: function Type1Parser_readCharStrings(bytes, lenIV) { - if (lenIV === -1) { - return bytes; - } - - return decrypt(bytes, CHAR_STRS_ENCRYPT_KEY, lenIV); - }, - extractFontProgram: function Type1Parser_extractFontProgram(properties) { - var stream = this.stream; - var subrs = [], - charstrings = []; - var privateData = Object.create(null); - privateData.lenIV = 4; - var program = { - subrs: [], - charstrings: [], - properties: { - privateData - } - }; - var token, length, data, lenIV, encoded; - - while ((token = this.getToken()) !== null) { - if (token !== "/") { - continue; - } - - token = this.getToken(); - - switch (token) { - case "CharStrings": - this.getToken(); - this.getToken(); - this.getToken(); - this.getToken(); - - while (true) { - token = this.getToken(); - - if (token === null || token === "end") { - break; - } - - if (token !== "/") { - continue; - } - - var glyph = this.getToken(); - length = this.readInt(); - this.getToken(); - data = length > 0 ? stream.getBytes(length) : new Uint8Array(0); - lenIV = program.properties.privateData.lenIV; - encoded = this.readCharStrings(data, lenIV); - this.nextChar(); - token = this.getToken(); - - if (token === "noaccess") { - this.getToken(); - } - - charstrings.push({ - glyph, - encoded - }); - } - - break; - - case "Subrs": - this.readInt(); - this.getToken(); - - while (this.getToken() === "dup") { - const index = this.readInt(); - length = this.readInt(); - this.getToken(); - data = length > 0 ? stream.getBytes(length) : new Uint8Array(0); - lenIV = program.properties.privateData.lenIV; - encoded = this.readCharStrings(data, lenIV); - this.nextChar(); - token = this.getToken(); - - if (token === "noaccess") { - this.getToken(); - } - - subrs[index] = encoded; - } - - break; - - case "BlueValues": - case "OtherBlues": - case "FamilyBlues": - case "FamilyOtherBlues": - var blueArray = this.readNumberArray(); - - if (blueArray.length > 0 && blueArray.length % 2 === 0 && HINTING_ENABLED) { - program.properties.privateData[token] = blueArray; - } - - break; - - case "StemSnapH": - case "StemSnapV": - program.properties.privateData[token] = this.readNumberArray(); - break; - - case "StdHW": - case "StdVW": - program.properties.privateData[token] = this.readNumberArray()[0]; - break; - - case "BlueShift": - case "lenIV": - case "BlueFuzz": - case "BlueScale": - case "LanguageGroup": - case "ExpansionFactor": - program.properties.privateData[token] = this.readNumber(); - break; - - case "ForceBold": - program.properties.privateData[token] = this.readBoolean(); - break; - } - } - - for (var i = 0; i < charstrings.length; i++) { - glyph = charstrings[i].glyph; - encoded = charstrings[i].encoded; - var charString = new Type1CharString(); - var error = charString.convert(encoded, subrs, this.seacAnalysisEnabled); - var output = charString.output; - - if (error) { - output = [14]; - } - - const charStringObject = { - glyphName: glyph, - charstring: output, - width: charString.width, - lsb: charString.lsb, - seac: charString.seac - }; - - if (glyph === ".notdef") { - program.charstrings.unshift(charStringObject); - } else { - program.charstrings.push(charStringObject); - } - - if (properties.builtInEncoding) { - const index = properties.builtInEncoding.indexOf(glyph); - - if (index > -1 && properties.widths[index] === undefined && index >= properties.firstChar && index <= properties.lastChar) { - properties.widths[index] = charString.width; - } - } - } - - return program; - }, - extractFontHeader: function Type1Parser_extractFontHeader(properties) { - var token; - - while ((token = this.getToken()) !== null) { - if (token !== "/") { - continue; - } - - token = this.getToken(); - - switch (token) { - case "FontMatrix": - var matrix = this.readNumberArray(); - properties.fontMatrix = matrix; - break; - - case "Encoding": - var encodingArg = this.getToken(); - var encoding; - - if (!/^\d+$/.test(encodingArg)) { - encoding = (0, _encodings.getEncoding)(encodingArg); - } else { - encoding = []; - var size = parseInt(encodingArg, 10) | 0; - this.getToken(); - - for (var j = 0; j < size; j++) { - token = this.getToken(); - - while (token !== "dup" && token !== "def") { - token = this.getToken(); - - if (token === null) { - return; - } - } - - if (token === "def") { - break; - } - - var index = this.readInt(); - this.getToken(); - var glyph = this.getToken(); - encoding[index] = glyph; - this.getToken(); - } - } - - properties.builtInEncoding = encoding; - break; - - case "FontBBox": - var fontBBox = this.readNumberArray(); - properties.ascent = Math.max(fontBBox[3], fontBBox[1]); - properties.descent = Math.min(fontBBox[1], fontBBox[3]); - properties.ascentScaled = true; - break; - } - } - } - }; - return Type1Parser; -}(); - -exports.Type1Parser = Type1Parser; - -/***/ }), -/* 39 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getTilingPatternIR = getTilingPatternIR; -exports.Pattern = void 0; - -var _util = __w_pdfjs_require__(2); - -var _colorspace = __w_pdfjs_require__(23); - -var _primitives = __w_pdfjs_require__(5); - -var _core_utils = __w_pdfjs_require__(8); - -var ShadingType = { - FUNCTION_BASED: 1, - AXIAL: 2, - RADIAL: 3, - FREE_FORM_MESH: 4, - LATTICE_FORM_MESH: 5, - COONS_PATCH_MESH: 6, - TENSOR_PATCH_MESH: 7 -}; - -var Pattern = function PatternClosure() { - function Pattern() { - (0, _util.unreachable)("should not call Pattern constructor"); - } - - Pattern.prototype = { - getPattern: function Pattern_getPattern(ctx) { - (0, _util.unreachable)(`Should not call Pattern.getStyle: ${ctx}`); - } - }; - - Pattern.parseShading = function (shading, matrix, xref, res, handler, pdfFunctionFactory, localColorSpaceCache) { - var dict = (0, _primitives.isStream)(shading) ? shading.dict : shading; - var type = dict.get("ShadingType"); - - try { - switch (type) { - case ShadingType.AXIAL: - case ShadingType.RADIAL: - return new Shadings.RadialAxial(dict, matrix, xref, res, pdfFunctionFactory, localColorSpaceCache); - - case ShadingType.FREE_FORM_MESH: - case ShadingType.LATTICE_FORM_MESH: - case ShadingType.COONS_PATCH_MESH: - case ShadingType.TENSOR_PATCH_MESH: - return new Shadings.Mesh(shading, matrix, xref, res, pdfFunctionFactory, localColorSpaceCache); - - default: - throw new _util.FormatError("Unsupported ShadingType: " + type); - } - } catch (ex) { - if (ex instanceof _core_utils.MissingDataException) { - throw ex; - } - - handler.send("UnsupportedFeature", { - featureId: _util.UNSUPPORTED_FEATURES.shadingPattern - }); - (0, _util.warn)(ex); - return new Shadings.Dummy(); - } - }; - - return Pattern; -}(); - -exports.Pattern = Pattern; -var Shadings = {}; -Shadings.SMALL_NUMBER = 1e-6; - -Shadings.RadialAxial = function RadialAxialClosure() { - function RadialAxial(dict, matrix, xref, resources, pdfFunctionFactory, localColorSpaceCache) { - this.matrix = matrix; - this.coordsArr = dict.getArray("Coords"); - this.shadingType = dict.get("ShadingType"); - this.type = "Pattern"; - - const cs = _colorspace.ColorSpace.parse({ - cs: dict.getRaw("ColorSpace") || dict.getRaw("CS"), - xref, - resources, - pdfFunctionFactory, - localColorSpaceCache - }); - - this.cs = cs; - const bbox = dict.getArray("BBox"); - - if (Array.isArray(bbox) && bbox.length === 4) { - this.bbox = _util.Util.normalizeRect(bbox); - } else { - this.bbox = null; - } - - var t0 = 0.0, - t1 = 1.0; - - if (dict.has("Domain")) { - var domainArr = dict.getArray("Domain"); - t0 = domainArr[0]; - t1 = domainArr[1]; - } - - var extendStart = false, - extendEnd = false; - - if (dict.has("Extend")) { - var extendArr = dict.getArray("Extend"); - extendStart = extendArr[0]; - extendEnd = extendArr[1]; - } - - if (this.shadingType === ShadingType.RADIAL && (!extendStart || !extendEnd)) { - var x1 = this.coordsArr[0]; - var y1 = this.coordsArr[1]; - var r1 = this.coordsArr[2]; - var x2 = this.coordsArr[3]; - var y2 = this.coordsArr[4]; - var r2 = this.coordsArr[5]; - var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); - - if (r1 <= r2 + distance && r2 <= r1 + distance) { - (0, _util.warn)("Unsupported radial gradient."); - } - } - - this.extendStart = extendStart; - this.extendEnd = extendEnd; - var fnObj = dict.getRaw("Function"); - var fn = pdfFunctionFactory.createFromArray(fnObj); - const NUMBER_OF_SAMPLES = 10; - const step = (t1 - t0) / NUMBER_OF_SAMPLES; - var colorStops = this.colorStops = []; - - if (t0 >= t1 || step <= 0) { - (0, _util.info)("Bad shading domain."); - return; - } - - var color = new Float32Array(cs.numComps), - ratio = new Float32Array(1); - var rgbColor; - - for (let i = 0; i <= NUMBER_OF_SAMPLES; i++) { - ratio[0] = t0 + i * step; - fn(ratio, 0, color, 0); - rgbColor = cs.getRgb(color, 0); - - var cssColor = _util.Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]); - - colorStops.push([i / NUMBER_OF_SAMPLES, cssColor]); - } - - var background = "transparent"; - - if (dict.has("Background")) { - rgbColor = cs.getRgb(dict.get("Background"), 0); - background = _util.Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]); - } - - if (!extendStart) { - colorStops.unshift([0, background]); - colorStops[1][0] += Shadings.SMALL_NUMBER; - } - - if (!extendEnd) { - colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER; - colorStops.push([1, background]); - } - - this.colorStops = colorStops; - } - - RadialAxial.prototype = { - getIR: function RadialAxial_getIR() { - var coordsArr = this.coordsArr; - var shadingType = this.shadingType; - var type, p0, p1, r0, r1; - - if (shadingType === ShadingType.AXIAL) { - p0 = [coordsArr[0], coordsArr[1]]; - p1 = [coordsArr[2], coordsArr[3]]; - r0 = null; - r1 = null; - type = "axial"; - } else if (shadingType === ShadingType.RADIAL) { - p0 = [coordsArr[0], coordsArr[1]]; - p1 = [coordsArr[3], coordsArr[4]]; - r0 = coordsArr[2]; - r1 = coordsArr[5]; - type = "radial"; - } else { - (0, _util.unreachable)(`getPattern type unknown: ${shadingType}`); - } - - var matrix = this.matrix; - - if (matrix) { - p0 = _util.Util.applyTransform(p0, matrix); - p1 = _util.Util.applyTransform(p1, matrix); - - if (shadingType === ShadingType.RADIAL) { - var scale = _util.Util.singularValueDecompose2dScale(matrix); - - r0 *= scale[0]; - r1 *= scale[1]; - } - } - - return ["RadialAxial", type, this.bbox, this.colorStops, p0, p1, r0, r1]; - } - }; - return RadialAxial; -}(); - -Shadings.Mesh = function MeshClosure() { - function MeshStreamReader(stream, context) { - this.stream = stream; - this.context = context; - this.buffer = 0; - this.bufferLength = 0; - var numComps = context.numComps; - this.tmpCompsBuf = new Float32Array(numComps); - var csNumComps = context.colorSpace.numComps; - this.tmpCsCompsBuf = context.colorFn ? new Float32Array(csNumComps) : this.tmpCompsBuf; - } - - MeshStreamReader.prototype = { - get hasData() { - if (this.stream.end) { - return this.stream.pos < this.stream.end; - } - - if (this.bufferLength > 0) { - return true; - } - - var nextByte = this.stream.getByte(); - - if (nextByte < 0) { - return false; - } - - this.buffer = nextByte; - this.bufferLength = 8; - return true; - }, - - readBits: function MeshStreamReader_readBits(n) { - var buffer = this.buffer; - var bufferLength = this.bufferLength; - - if (n === 32) { - if (bufferLength === 0) { - return (this.stream.getByte() << 24 | this.stream.getByte() << 16 | this.stream.getByte() << 8 | this.stream.getByte()) >>> 0; - } - - buffer = buffer << 24 | this.stream.getByte() << 16 | this.stream.getByte() << 8 | this.stream.getByte(); - var nextByte = this.stream.getByte(); - this.buffer = nextByte & (1 << bufferLength) - 1; - return (buffer << 8 - bufferLength | (nextByte & 0xff) >> bufferLength) >>> 0; - } - - if (n === 8 && bufferLength === 0) { - return this.stream.getByte(); - } - - while (bufferLength < n) { - buffer = buffer << 8 | this.stream.getByte(); - bufferLength += 8; - } - - bufferLength -= n; - this.bufferLength = bufferLength; - this.buffer = buffer & (1 << bufferLength) - 1; - return buffer >> bufferLength; - }, - align: function MeshStreamReader_align() { - this.buffer = 0; - this.bufferLength = 0; - }, - readFlag: function MeshStreamReader_readFlag() { - return this.readBits(this.context.bitsPerFlag); - }, - readCoordinate: function MeshStreamReader_readCoordinate() { - var bitsPerCoordinate = this.context.bitsPerCoordinate; - var xi = this.readBits(bitsPerCoordinate); - var yi = this.readBits(bitsPerCoordinate); - var decode = this.context.decode; - var scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) : 2.3283064365386963e-10; - return [xi * scale * (decode[1] - decode[0]) + decode[0], yi * scale * (decode[3] - decode[2]) + decode[2]]; - }, - readComponents: function MeshStreamReader_readComponents() { - var numComps = this.context.numComps; - var bitsPerComponent = this.context.bitsPerComponent; - var scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) : 2.3283064365386963e-10; - var decode = this.context.decode; - var components = this.tmpCompsBuf; - - for (var i = 0, j = 4; i < numComps; i++, j += 2) { - var ci = this.readBits(bitsPerComponent); - components[i] = ci * scale * (decode[j + 1] - decode[j]) + decode[j]; - } - - var color = this.tmpCsCompsBuf; - - if (this.context.colorFn) { - this.context.colorFn(components, 0, color, 0); - } - - return this.context.colorSpace.getRgb(color, 0); - } - }; - - function decodeType4Shading(mesh, reader) { - var coords = mesh.coords; - var colors = mesh.colors; - var operators = []; - var ps = []; - var verticesLeft = 0; - - while (reader.hasData) { - var f = reader.readFlag(); - var coord = reader.readCoordinate(); - var color = reader.readComponents(); - - if (verticesLeft === 0) { - if (!(0 <= f && f <= 2)) { - throw new _util.FormatError("Unknown type4 flag"); - } - - switch (f) { - case 0: - verticesLeft = 3; - break; - - case 1: - ps.push(ps[ps.length - 2], ps[ps.length - 1]); - verticesLeft = 1; - break; - - case 2: - ps.push(ps[ps.length - 3], ps[ps.length - 1]); - verticesLeft = 1; - break; - } - - operators.push(f); - } - - ps.push(coords.length); - coords.push(coord); - colors.push(color); - verticesLeft--; - reader.align(); - } - - mesh.figures.push({ - type: "triangles", - coords: new Int32Array(ps), - colors: new Int32Array(ps) - }); - } - - function decodeType5Shading(mesh, reader, verticesPerRow) { - var coords = mesh.coords; - var colors = mesh.colors; - var ps = []; - - while (reader.hasData) { - var coord = reader.readCoordinate(); - var color = reader.readComponents(); - ps.push(coords.length); - coords.push(coord); - colors.push(color); - } - - mesh.figures.push({ - type: "lattice", - coords: new Int32Array(ps), - colors: new Int32Array(ps), - verticesPerRow - }); - } - - var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3; - var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20; - var TRIANGLE_DENSITY = 20; - - var getB = function getBClosure() { - function buildB(count) { - var lut = []; - - for (var i = 0; i <= count; i++) { - var t = i / count, - t_ = 1 - t; - lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_, 3 * t * t * t_, t * t * t])); - } - - return lut; - } - - var cache = []; - return function getB(count) { - if (!cache[count]) { - cache[count] = buildB(count); - } - - return cache[count]; - }; - }(); - - function buildFigureFromPatch(mesh, index) { - var figure = mesh.figures[index]; - (0, _util.assert)(figure.type === "patch", "Unexpected patch mesh figure"); - var coords = mesh.coords, - colors = mesh.colors; - var pi = figure.coords; - var ci = figure.colors; - var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0], coords[pi[12]][0], coords[pi[15]][0]); - var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1], coords[pi[12]][1], coords[pi[15]][1]); - var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0], coords[pi[12]][0], coords[pi[15]][0]); - var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1], coords[pi[12]][1], coords[pi[15]][1]); - var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY / (mesh.bounds[2] - mesh.bounds[0])); - splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT, Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy)); - var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY / (mesh.bounds[3] - mesh.bounds[1])); - splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT, Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy)); - var verticesPerRow = splitXBy + 1; - var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow); - var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow); - var k = 0; - var cl = new Uint8Array(3), - cr = new Uint8Array(3); - var c0 = colors[ci[0]], - c1 = colors[ci[1]], - c2 = colors[ci[2]], - c3 = colors[ci[3]]; - var bRow = getB(splitYBy), - bCol = getB(splitXBy); - - for (var row = 0; row <= splitYBy; row++) { - cl[0] = (c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy | 0; - cl[1] = (c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy | 0; - cl[2] = (c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy | 0; - cr[0] = (c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy | 0; - cr[1] = (c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy | 0; - cr[2] = (c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy | 0; - - for (var col = 0; col <= splitXBy; col++, k++) { - if ((row === 0 || row === splitYBy) && (col === 0 || col === splitXBy)) { - continue; - } - - var x = 0, - y = 0; - var q = 0; - - for (var i = 0; i <= 3; i++) { - for (var j = 0; j <= 3; j++, q++) { - var m = bRow[row][i] * bCol[col][j]; - x += coords[pi[q]][0] * m; - y += coords[pi[q]][1] * m; - } - } - - figureCoords[k] = coords.length; - coords.push([x, y]); - figureColors[k] = colors.length; - var newColor = new Uint8Array(3); - newColor[0] = (cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy | 0; - newColor[1] = (cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy | 0; - newColor[2] = (cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy | 0; - colors.push(newColor); - } - } - - figureCoords[0] = pi[0]; - figureColors[0] = ci[0]; - figureCoords[splitXBy] = pi[3]; - figureColors[splitXBy] = ci[1]; - figureCoords[verticesPerRow * splitYBy] = pi[12]; - figureColors[verticesPerRow * splitYBy] = ci[2]; - figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15]; - figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3]; - mesh.figures[index] = { - type: "lattice", - coords: figureCoords, - colors: figureColors, - verticesPerRow - }; - } - - function decodeType6Shading(mesh, reader) { - var coords = mesh.coords; - var colors = mesh.colors; - var ps = new Int32Array(16); - var cs = new Int32Array(4); - - while (reader.hasData) { - var f = reader.readFlag(); - - if (!(0 <= f && f <= 3)) { - throw new _util.FormatError("Unknown type6 flag"); - } - - var i, ii; - var pi = coords.length; - - for (i = 0, ii = f !== 0 ? 8 : 12; i < ii; i++) { - coords.push(reader.readCoordinate()); - } - - var ci = colors.length; - - for (i = 0, ii = f !== 0 ? 2 : 4; i < ii; i++) { - colors.push(reader.readComponents()); - } - - var tmp1, tmp2, tmp3, tmp4; - - switch (f) { - case 0: - ps[12] = pi + 3; - ps[13] = pi + 4; - ps[14] = pi + 5; - ps[15] = pi + 6; - ps[8] = pi + 2; - ps[11] = pi + 7; - ps[4] = pi + 1; - ps[7] = pi + 8; - ps[0] = pi; - ps[1] = pi + 11; - ps[2] = pi + 10; - ps[3] = pi + 9; - cs[2] = ci + 1; - cs[3] = ci + 2; - cs[0] = ci; - cs[1] = ci + 3; - break; - - case 1: - tmp1 = ps[12]; - tmp2 = ps[13]; - tmp3 = ps[14]; - tmp4 = ps[15]; - ps[12] = tmp4; - ps[13] = pi + 0; - ps[14] = pi + 1; - ps[15] = pi + 2; - ps[8] = tmp3; - ps[11] = pi + 3; - ps[4] = tmp2; - ps[7] = pi + 4; - ps[0] = tmp1; - ps[1] = pi + 7; - ps[2] = pi + 6; - ps[3] = pi + 5; - tmp1 = cs[2]; - tmp2 = cs[3]; - cs[2] = tmp2; - cs[3] = ci; - cs[0] = tmp1; - cs[1] = ci + 1; - break; - - case 2: - tmp1 = ps[15]; - tmp2 = ps[11]; - ps[12] = ps[3]; - ps[13] = pi + 0; - ps[14] = pi + 1; - ps[15] = pi + 2; - ps[8] = ps[7]; - ps[11] = pi + 3; - ps[4] = tmp2; - ps[7] = pi + 4; - ps[0] = tmp1; - ps[1] = pi + 7; - ps[2] = pi + 6; - ps[3] = pi + 5; - tmp1 = cs[3]; - cs[2] = cs[1]; - cs[3] = ci; - cs[0] = tmp1; - cs[1] = ci + 1; - break; - - case 3: - ps[12] = ps[0]; - ps[13] = pi + 0; - ps[14] = pi + 1; - ps[15] = pi + 2; - ps[8] = ps[1]; - ps[11] = pi + 3; - ps[4] = ps[2]; - ps[7] = pi + 4; - ps[0] = ps[3]; - ps[1] = pi + 7; - ps[2] = pi + 6; - ps[3] = pi + 5; - cs[2] = cs[0]; - cs[3] = ci; - cs[0] = cs[1]; - cs[1] = ci + 1; - break; - } - - ps[5] = coords.length; - coords.push([(-4 * coords[ps[0]][0] - coords[ps[15]][0] + 6 * (coords[ps[4]][0] + coords[ps[1]][0]) - 2 * (coords[ps[12]][0] + coords[ps[3]][0]) + 3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9, (-4 * coords[ps[0]][1] - coords[ps[15]][1] + 6 * (coords[ps[4]][1] + coords[ps[1]][1]) - 2 * (coords[ps[12]][1] + coords[ps[3]][1]) + 3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9]); - ps[6] = coords.length; - coords.push([(-4 * coords[ps[3]][0] - coords[ps[12]][0] + 6 * (coords[ps[2]][0] + coords[ps[7]][0]) - 2 * (coords[ps[0]][0] + coords[ps[15]][0]) + 3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9, (-4 * coords[ps[3]][1] - coords[ps[12]][1] + 6 * (coords[ps[2]][1] + coords[ps[7]][1]) - 2 * (coords[ps[0]][1] + coords[ps[15]][1]) + 3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9]); - ps[9] = coords.length; - coords.push([(-4 * coords[ps[12]][0] - coords[ps[3]][0] + 6 * (coords[ps[8]][0] + coords[ps[13]][0]) - 2 * (coords[ps[0]][0] + coords[ps[15]][0]) + 3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9, (-4 * coords[ps[12]][1] - coords[ps[3]][1] + 6 * (coords[ps[8]][1] + coords[ps[13]][1]) - 2 * (coords[ps[0]][1] + coords[ps[15]][1]) + 3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9]); - ps[10] = coords.length; - coords.push([(-4 * coords[ps[15]][0] - coords[ps[0]][0] + 6 * (coords[ps[11]][0] + coords[ps[14]][0]) - 2 * (coords[ps[12]][0] + coords[ps[3]][0]) + 3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9, (-4 * coords[ps[15]][1] - coords[ps[0]][1] + 6 * (coords[ps[11]][1] + coords[ps[14]][1]) - 2 * (coords[ps[12]][1] + coords[ps[3]][1]) + 3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9]); - mesh.figures.push({ - type: "patch", - coords: new Int32Array(ps), - colors: new Int32Array(cs) - }); - } - } - - function decodeType7Shading(mesh, reader) { - var coords = mesh.coords; - var colors = mesh.colors; - var ps = new Int32Array(16); - var cs = new Int32Array(4); - - while (reader.hasData) { - var f = reader.readFlag(); - - if (!(0 <= f && f <= 3)) { - throw new _util.FormatError("Unknown type7 flag"); - } - - var i, ii; - var pi = coords.length; - - for (i = 0, ii = f !== 0 ? 12 : 16; i < ii; i++) { - coords.push(reader.readCoordinate()); - } - - var ci = colors.length; - - for (i = 0, ii = f !== 0 ? 2 : 4; i < ii; i++) { - colors.push(reader.readComponents()); - } - - var tmp1, tmp2, tmp3, tmp4; - - switch (f) { - case 0: - ps[12] = pi + 3; - ps[13] = pi + 4; - ps[14] = pi + 5; - ps[15] = pi + 6; - ps[8] = pi + 2; - ps[9] = pi + 13; - ps[10] = pi + 14; - ps[11] = pi + 7; - ps[4] = pi + 1; - ps[5] = pi + 12; - ps[6] = pi + 15; - ps[7] = pi + 8; - ps[0] = pi; - ps[1] = pi + 11; - ps[2] = pi + 10; - ps[3] = pi + 9; - cs[2] = ci + 1; - cs[3] = ci + 2; - cs[0] = ci; - cs[1] = ci + 3; - break; - - case 1: - tmp1 = ps[12]; - tmp2 = ps[13]; - tmp3 = ps[14]; - tmp4 = ps[15]; - ps[12] = tmp4; - ps[13] = pi + 0; - ps[14] = pi + 1; - ps[15] = pi + 2; - ps[8] = tmp3; - ps[9] = pi + 9; - ps[10] = pi + 10; - ps[11] = pi + 3; - ps[4] = tmp2; - ps[5] = pi + 8; - ps[6] = pi + 11; - ps[7] = pi + 4; - ps[0] = tmp1; - ps[1] = pi + 7; - ps[2] = pi + 6; - ps[3] = pi + 5; - tmp1 = cs[2]; - tmp2 = cs[3]; - cs[2] = tmp2; - cs[3] = ci; - cs[0] = tmp1; - cs[1] = ci + 1; - break; - - case 2: - tmp1 = ps[15]; - tmp2 = ps[11]; - ps[12] = ps[3]; - ps[13] = pi + 0; - ps[14] = pi + 1; - ps[15] = pi + 2; - ps[8] = ps[7]; - ps[9] = pi + 9; - ps[10] = pi + 10; - ps[11] = pi + 3; - ps[4] = tmp2; - ps[5] = pi + 8; - ps[6] = pi + 11; - ps[7] = pi + 4; - ps[0] = tmp1; - ps[1] = pi + 7; - ps[2] = pi + 6; - ps[3] = pi + 5; - tmp1 = cs[3]; - cs[2] = cs[1]; - cs[3] = ci; - cs[0] = tmp1; - cs[1] = ci + 1; - break; - - case 3: - ps[12] = ps[0]; - ps[13] = pi + 0; - ps[14] = pi + 1; - ps[15] = pi + 2; - ps[8] = ps[1]; - ps[9] = pi + 9; - ps[10] = pi + 10; - ps[11] = pi + 3; - ps[4] = ps[2]; - ps[5] = pi + 8; - ps[6] = pi + 11; - ps[7] = pi + 4; - ps[0] = ps[3]; - ps[1] = pi + 7; - ps[2] = pi + 6; - ps[3] = pi + 5; - cs[2] = cs[0]; - cs[3] = ci; - cs[0] = cs[1]; - cs[1] = ci + 1; - break; - } - - mesh.figures.push({ - type: "patch", - coords: new Int32Array(ps), - colors: new Int32Array(cs) - }); - } - } - - function updateBounds(mesh) { - var minX = mesh.coords[0][0], - minY = mesh.coords[0][1], - maxX = minX, - maxY = minY; - - for (var i = 1, ii = mesh.coords.length; i < ii; i++) { - var x = mesh.coords[i][0], - y = mesh.coords[i][1]; - minX = minX > x ? x : minX; - minY = minY > y ? y : minY; - maxX = maxX < x ? x : maxX; - maxY = maxY < y ? y : maxY; - } - - mesh.bounds = [minX, minY, maxX, maxY]; - } - - function packData(mesh) { - var i, ii, j, jj; - var coords = mesh.coords; - var coordsPacked = new Float32Array(coords.length * 2); - - for (i = 0, j = 0, ii = coords.length; i < ii; i++) { - var xy = coords[i]; - coordsPacked[j++] = xy[0]; - coordsPacked[j++] = xy[1]; - } - - mesh.coords = coordsPacked; - var colors = mesh.colors; - var colorsPacked = new Uint8Array(colors.length * 3); - - for (i = 0, j = 0, ii = colors.length; i < ii; i++) { - var c = colors[i]; - colorsPacked[j++] = c[0]; - colorsPacked[j++] = c[1]; - colorsPacked[j++] = c[2]; - } - - mesh.colors = colorsPacked; - var figures = mesh.figures; - - for (i = 0, ii = figures.length; i < ii; i++) { - var figure = figures[i], - ps = figure.coords, - cs = figure.colors; - - for (j = 0, jj = ps.length; j < jj; j++) { - ps[j] *= 2; - cs[j] *= 3; - } - } - } - - function Mesh(stream, matrix, xref, resources, pdfFunctionFactory, localColorSpaceCache) { - if (!(0, _primitives.isStream)(stream)) { - throw new _util.FormatError("Mesh data is not a stream"); - } - - var dict = stream.dict; - this.matrix = matrix; - this.shadingType = dict.get("ShadingType"); - this.type = "Pattern"; - const bbox = dict.getArray("BBox"); - - if (Array.isArray(bbox) && bbox.length === 4) { - this.bbox = _util.Util.normalizeRect(bbox); - } else { - this.bbox = null; - } - - const cs = _colorspace.ColorSpace.parse({ - cs: dict.getRaw("ColorSpace") || dict.getRaw("CS"), - xref, - resources, - pdfFunctionFactory, - localColorSpaceCache - }); - - this.cs = cs; - this.background = dict.has("Background") ? cs.getRgb(dict.get("Background"), 0) : null; - var fnObj = dict.getRaw("Function"); - var fn = fnObj ? pdfFunctionFactory.createFromArray(fnObj) : null; - this.coords = []; - this.colors = []; - this.figures = []; - var decodeContext = { - bitsPerCoordinate: dict.get("BitsPerCoordinate"), - bitsPerComponent: dict.get("BitsPerComponent"), - bitsPerFlag: dict.get("BitsPerFlag"), - decode: dict.getArray("Decode"), - colorFn: fn, - colorSpace: cs, - numComps: fn ? 1 : cs.numComps - }; - var reader = new MeshStreamReader(stream, decodeContext); - var patchMesh = false; - - switch (this.shadingType) { - case ShadingType.FREE_FORM_MESH: - decodeType4Shading(this, reader); - break; - - case ShadingType.LATTICE_FORM_MESH: - var verticesPerRow = dict.get("VerticesPerRow") | 0; - - if (verticesPerRow < 2) { - throw new _util.FormatError("Invalid VerticesPerRow"); - } - - decodeType5Shading(this, reader, verticesPerRow); - break; - - case ShadingType.COONS_PATCH_MESH: - decodeType6Shading(this, reader); - patchMesh = true; - break; - - case ShadingType.TENSOR_PATCH_MESH: - decodeType7Shading(this, reader); - patchMesh = true; - break; - - default: - (0, _util.unreachable)("Unsupported mesh type."); - break; - } - - if (patchMesh) { - updateBounds(this); - - for (var i = 0, ii = this.figures.length; i < ii; i++) { - buildFigureFromPatch(this, i); - } - } - - updateBounds(this); - packData(this); - } - - Mesh.prototype = { - getIR: function Mesh_getIR() { - return ["Mesh", this.shadingType, this.coords, this.colors, this.figures, this.bounds, this.matrix, this.bbox, this.background]; - } - }; - return Mesh; -}(); - -Shadings.Dummy = function DummyClosure() { - function Dummy() { - this.type = "Pattern"; - } - - Dummy.prototype = { - getIR: function Dummy_getIR() { - return ["Dummy"]; - } - }; - return Dummy; -}(); - -function getTilingPatternIR(operatorList, dict, args) { - const matrix = dict.getArray("Matrix"); - - const bbox = _util.Util.normalizeRect(dict.getArray("BBox")); - - const xstep = dict.get("XStep"); - const ystep = dict.get("YStep"); - const paintType = dict.get("PaintType"); - const tilingType = dict.get("TilingType"); - - if (bbox[2] - bbox[0] === 0 || bbox[3] - bbox[1] === 0) { - throw new _util.FormatError(`Invalid getTilingPatternIR /BBox array: [${bbox}].`); - } - - return ["TilingPattern", args, operatorList, matrix, bbox, xstep, ystep, paintType, tilingType]; -} - -/***/ }), -/* 40 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.isPDFFunction = isPDFFunction; -exports.PostScriptCompiler = exports.PostScriptEvaluator = exports.PDFFunctionFactory = void 0; - -var _primitives = __w_pdfjs_require__(5); - -var _util = __w_pdfjs_require__(2); - -var _ps_parser = __w_pdfjs_require__(41); - -var _image_utils = __w_pdfjs_require__(24); - -class PDFFunctionFactory { - constructor({ - xref, - isEvalSupported = true - }) { - this.xref = xref; - this.isEvalSupported = isEvalSupported !== false; - this._localFunctionCache = null; - } - - create(fn) { - const cachedFunction = this.getCached(fn); - - if (cachedFunction) { - return cachedFunction; - } - - const parsedFunction = PDFFunction.parse({ - xref: this.xref, - isEvalSupported: this.isEvalSupported, - fn: fn instanceof _primitives.Ref ? this.xref.fetch(fn) : fn - }); - - this._cache(fn, parsedFunction); - - return parsedFunction; - } - - createFromArray(fnObj) { - const cachedFunction = this.getCached(fnObj); - - if (cachedFunction) { - return cachedFunction; - } - - const parsedFunction = PDFFunction.parseArray({ - xref: this.xref, - isEvalSupported: this.isEvalSupported, - fnObj: fnObj instanceof _primitives.Ref ? this.xref.fetch(fnObj) : fnObj - }); - - this._cache(fnObj, parsedFunction); - - return parsedFunction; - } - - getCached(cacheKey) { - let fnRef; - - if (cacheKey instanceof _primitives.Ref) { - fnRef = cacheKey; - } else if (cacheKey instanceof _primitives.Dict) { - fnRef = cacheKey.objId; - } else if ((0, _primitives.isStream)(cacheKey)) { - fnRef = cacheKey.dict && cacheKey.dict.objId; - } - - if (fnRef) { - if (!this._localFunctionCache) { - this._localFunctionCache = new _image_utils.LocalFunctionCache(); - } - - const localFunction = this._localFunctionCache.getByRef(fnRef); - - if (localFunction) { - return localFunction; - } - } - - return null; - } - - _cache(cacheKey, parsedFunction) { - if (!parsedFunction) { - throw new Error('PDFFunctionFactory._cache - expected "parsedFunction" argument.'); - } - - let fnRef; - - if (cacheKey instanceof _primitives.Ref) { - fnRef = cacheKey; - } else if (cacheKey instanceof _primitives.Dict) { - fnRef = cacheKey.objId; - } else if ((0, _primitives.isStream)(cacheKey)) { - fnRef = cacheKey.dict && cacheKey.dict.objId; - } - - if (fnRef) { - if (!this._localFunctionCache) { - this._localFunctionCache = new _image_utils.LocalFunctionCache(); - } - - this._localFunctionCache.set(null, fnRef, parsedFunction); - } - } - -} - -exports.PDFFunctionFactory = PDFFunctionFactory; - -function toNumberArray(arr) { - if (!Array.isArray(arr)) { - return null; - } - - const length = arr.length; - - for (let i = 0; i < length; i++) { - if (typeof arr[i] !== "number") { - const result = new Array(length); - - for (let j = 0; j < length; j++) { - result[j] = +arr[j]; - } - - return result; - } - } - - return arr; -} - -var PDFFunction = function PDFFunctionClosure() { - const CONSTRUCT_SAMPLED = 0; - const CONSTRUCT_INTERPOLATED = 2; - const CONSTRUCT_STICHED = 3; - const CONSTRUCT_POSTSCRIPT = 4; - return { - getSampleArray(size, outputSize, bps, stream) { - var i, ii; - var length = 1; - - for (i = 0, ii = size.length; i < ii; i++) { - length *= size[i]; - } - - length *= outputSize; - var array = new Array(length); - var codeSize = 0; - var codeBuf = 0; - var sampleMul = 1.0 / (2.0 ** bps - 1); - var strBytes = stream.getBytes((length * bps + 7) / 8); - var strIdx = 0; - - for (i = 0; i < length; i++) { - while (codeSize < bps) { - codeBuf <<= 8; - codeBuf |= strBytes[strIdx++]; - codeSize += 8; - } - - codeSize -= bps; - array[i] = (codeBuf >> codeSize) * sampleMul; - codeBuf &= (1 << codeSize) - 1; - } - - return array; - }, - - getIR({ - xref, - isEvalSupported, - fn - }) { - var dict = fn.dict; - - if (!dict) { - dict = fn; - } - - var types = [this.constructSampled, null, this.constructInterpolated, this.constructStiched, this.constructPostScript]; - var typeNum = dict.get("FunctionType"); - var typeFn = types[typeNum]; - - if (!typeFn) { - throw new _util.FormatError("Unknown type of function"); - } - - return typeFn.call(this, { - xref, - isEvalSupported, - fn, - dict - }); - }, - - fromIR({ - xref, - isEvalSupported, - IR - }) { - var type = IR[0]; - - switch (type) { - case CONSTRUCT_SAMPLED: - return this.constructSampledFromIR({ - xref, - isEvalSupported, - IR - }); - - case CONSTRUCT_INTERPOLATED: - return this.constructInterpolatedFromIR({ - xref, - isEvalSupported, - IR - }); - - case CONSTRUCT_STICHED: - return this.constructStichedFromIR({ - xref, - isEvalSupported, - IR - }); - - default: - return this.constructPostScriptFromIR({ - xref, - isEvalSupported, - IR - }); - } - }, - - parse({ - xref, - isEvalSupported, - fn - }) { - const IR = this.getIR({ - xref, - isEvalSupported, - fn - }); - return this.fromIR({ - xref, - isEvalSupported, - IR - }); - }, - - parseArray({ - xref, - isEvalSupported, - fnObj - }) { - if (!Array.isArray(fnObj)) { - return this.parse({ - xref, - isEvalSupported, - fn: fnObj - }); - } - - var fnArray = []; - - for (var j = 0, jj = fnObj.length; j < jj; j++) { - fnArray.push(this.parse({ - xref, - isEvalSupported, - fn: xref.fetchIfRef(fnObj[j]) - })); - } - - return function (src, srcOffset, dest, destOffset) { - for (var i = 0, ii = fnArray.length; i < ii; i++) { - fnArray[i](src, srcOffset, dest, destOffset + i); - } - }; - }, - - constructSampled({ - xref, - isEvalSupported, - fn, - dict - }) { - function toMultiArray(arr) { - var inputLength = arr.length; - var out = []; - var index = 0; - - for (var i = 0; i < inputLength; i += 2) { - out[index] = [arr[i], arr[i + 1]]; - ++index; - } - - return out; - } - - var domain = toNumberArray(dict.getArray("Domain")); - var range = toNumberArray(dict.getArray("Range")); - - if (!domain || !range) { - throw new _util.FormatError("No domain or range"); - } - - var inputSize = domain.length / 2; - var outputSize = range.length / 2; - domain = toMultiArray(domain); - range = toMultiArray(range); - var size = toNumberArray(dict.getArray("Size")); - var bps = dict.get("BitsPerSample"); - var order = dict.get("Order") || 1; - - if (order !== 1) { - (0, _util.info)("No support for cubic spline interpolation: " + order); - } - - var encode = toNumberArray(dict.getArray("Encode")); - - if (!encode) { - encode = []; - - for (var i = 0; i < inputSize; ++i) { - encode.push([0, size[i] - 1]); - } - } else { - encode = toMultiArray(encode); - } - - var decode = toNumberArray(dict.getArray("Decode")); - - if (!decode) { - decode = range; - } else { - decode = toMultiArray(decode); - } - - var samples = this.getSampleArray(size, outputSize, bps, fn); - return [CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size, outputSize, 2 ** bps - 1, range]; - }, - - constructSampledFromIR({ - xref, - isEvalSupported, - IR - }) { - function interpolate(x, xmin, xmax, ymin, ymax) { - return ymin + (x - xmin) * ((ymax - ymin) / (xmax - xmin)); - } - - return function constructSampledFromIRResult(src, srcOffset, dest, destOffset) { - var m = IR[1]; - var domain = IR[2]; - var encode = IR[3]; - var decode = IR[4]; - var samples = IR[5]; - var size = IR[6]; - var n = IR[7]; - var range = IR[9]; - var cubeVertices = 1 << m; - var cubeN = new Float64Array(cubeVertices); - var cubeVertex = new Uint32Array(cubeVertices); - var i, j; - - for (j = 0; j < cubeVertices; j++) { - cubeN[j] = 1; - } - - var k = n, - pos = 1; - - for (i = 0; i < m; ++i) { - var domain_2i = domain[i][0]; - var domain_2i_1 = domain[i][1]; - var xi = Math.min(Math.max(src[srcOffset + i], domain_2i), domain_2i_1); - var e = interpolate(xi, domain_2i, domain_2i_1, encode[i][0], encode[i][1]); - var size_i = size[i]; - e = Math.min(Math.max(e, 0), size_i - 1); - var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; - var n0 = e0 + 1 - e; - var n1 = e - e0; - var offset0 = e0 * k; - var offset1 = offset0 + k; - - for (j = 0; j < cubeVertices; j++) { - if (j & pos) { - cubeN[j] *= n1; - cubeVertex[j] += offset1; - } else { - cubeN[j] *= n0; - cubeVertex[j] += offset0; - } - } - - k *= size_i; - pos <<= 1; - } - - for (j = 0; j < n; ++j) { - var rj = 0; - - for (i = 0; i < cubeVertices; i++) { - rj += samples[cubeVertex[i] + j] * cubeN[i]; - } - - rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]); - dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]), range[j][1]); - } - }; - }, - - constructInterpolated({ - xref, - isEvalSupported, - fn, - dict - }) { - var c0 = toNumberArray(dict.getArray("C0")) || [0]; - var c1 = toNumberArray(dict.getArray("C1")) || [1]; - var n = dict.get("N"); - var length = c0.length; - var diff = []; - - for (var i = 0; i < length; ++i) { - diff.push(c1[i] - c0[i]); - } - - return [CONSTRUCT_INTERPOLATED, c0, diff, n]; - }, - - constructInterpolatedFromIR({ - xref, - isEvalSupported, - IR - }) { - var c0 = IR[1]; - var diff = IR[2]; - var n = IR[3]; - var length = diff.length; - return function constructInterpolatedFromIRResult(src, srcOffset, dest, destOffset) { - var x = n === 1 ? src[srcOffset] : src[srcOffset] ** n; - - for (var j = 0; j < length; ++j) { - dest[destOffset + j] = c0[j] + x * diff[j]; - } - }; - }, - - constructStiched({ - xref, - isEvalSupported, - fn, - dict - }) { - var domain = toNumberArray(dict.getArray("Domain")); - - if (!domain) { - throw new _util.FormatError("No domain"); - } - - var inputSize = domain.length / 2; - - if (inputSize !== 1) { - throw new _util.FormatError("Bad domain for stiched function"); - } - - var fnRefs = dict.get("Functions"); - var fns = []; - - for (var i = 0, ii = fnRefs.length; i < ii; ++i) { - fns.push(this.parse({ - xref, - isEvalSupported, - fn: xref.fetchIfRef(fnRefs[i]) - })); - } - - var bounds = toNumberArray(dict.getArray("Bounds")); - var encode = toNumberArray(dict.getArray("Encode")); - return [CONSTRUCT_STICHED, domain, bounds, encode, fns]; - }, - - constructStichedFromIR({ - xref, - isEvalSupported, - IR - }) { - var domain = IR[1]; - var bounds = IR[2]; - var encode = IR[3]; - var fns = IR[4]; - var tmpBuf = new Float32Array(1); - return function constructStichedFromIRResult(src, srcOffset, dest, destOffset) { - var clip = function constructStichedFromIRClip(v, min, max) { - if (v > max) { - v = max; - } else if (v < min) { - v = min; - } - - return v; - }; - - var v = clip(src[srcOffset], domain[0], domain[1]); - - for (var i = 0, ii = bounds.length; i < ii; ++i) { - if (v < bounds[i]) { - break; - } - } - - var dmin = domain[0]; - - if (i > 0) { - dmin = bounds[i - 1]; - } - - var dmax = domain[1]; - - if (i < bounds.length) { - dmax = bounds[i]; - } - - var rmin = encode[2 * i]; - var rmax = encode[2 * i + 1]; - tmpBuf[0] = dmin === dmax ? rmin : rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin); - fns[i](tmpBuf, 0, dest, destOffset); - }; - }, - - constructPostScript({ - xref, - isEvalSupported, - fn, - dict - }) { - var domain = toNumberArray(dict.getArray("Domain")); - var range = toNumberArray(dict.getArray("Range")); - - if (!domain) { - throw new _util.FormatError("No domain."); - } - - if (!range) { - throw new _util.FormatError("No range."); - } - - var lexer = new _ps_parser.PostScriptLexer(fn); - var parser = new _ps_parser.PostScriptParser(lexer); - var code = parser.parse(); - return [CONSTRUCT_POSTSCRIPT, domain, range, code]; - }, - - constructPostScriptFromIR({ - xref, - isEvalSupported, - IR - }) { - var domain = IR[1]; - var range = IR[2]; - var code = IR[3]; - - if (isEvalSupported && _util.IsEvalSupportedCached.value) { - const compiled = new PostScriptCompiler().compile(code, domain, range); - - if (compiled) { - return new Function("src", "srcOffset", "dest", "destOffset", compiled); - } - } - - (0, _util.info)("Unable to compile PS function"); - var numOutputs = range.length >> 1; - var numInputs = domain.length >> 1; - var evaluator = new PostScriptEvaluator(code); - var cache = Object.create(null); - var MAX_CACHE_SIZE = 2048 * 4; - var cache_available = MAX_CACHE_SIZE; - var tmpBuf = new Float32Array(numInputs); - return function constructPostScriptFromIRResult(src, srcOffset, dest, destOffset) { - var i, value; - var key = ""; - var input = tmpBuf; - - for (i = 0; i < numInputs; i++) { - value = src[srcOffset + i]; - input[i] = value; - key += value + "_"; - } - - var cachedValue = cache[key]; - - if (cachedValue !== undefined) { - dest.set(cachedValue, destOffset); - return; - } - - var output = new Float32Array(numOutputs); - var stack = evaluator.execute(input); - var stackIndex = stack.length - numOutputs; - - for (i = 0; i < numOutputs; i++) { - value = stack[stackIndex + i]; - var bound = range[i * 2]; - - if (value < bound) { - value = bound; - } else { - bound = range[i * 2 + 1]; - - if (value > bound) { - value = bound; - } - } - - output[i] = value; - } - - if (cache_available > 0) { - cache_available--; - cache[key] = output; - } - - dest.set(output, destOffset); - }; - } - - }; -}(); - -function isPDFFunction(v) { - var fnDict; - - if (typeof v !== "object") { - return false; - } else if ((0, _primitives.isDict)(v)) { - fnDict = v; - } else if ((0, _primitives.isStream)(v)) { - fnDict = v.dict; - } else { - return false; - } - - return fnDict.has("FunctionType"); -} - -var PostScriptStack = function PostScriptStackClosure() { - var MAX_STACK_SIZE = 100; - - function PostScriptStack(initialStack) { - this.stack = !initialStack ? [] : Array.prototype.slice.call(initialStack, 0); - } - - PostScriptStack.prototype = { - push: function PostScriptStack_push(value) { - if (this.stack.length >= MAX_STACK_SIZE) { - throw new Error("PostScript function stack overflow."); - } - - this.stack.push(value); - }, - pop: function PostScriptStack_pop() { - if (this.stack.length <= 0) { - throw new Error("PostScript function stack underflow."); - } - - return this.stack.pop(); - }, - copy: function PostScriptStack_copy(n) { - if (this.stack.length + n >= MAX_STACK_SIZE) { - throw new Error("PostScript function stack overflow."); - } - - var stack = this.stack; - - for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) { - stack.push(stack[i]); - } - }, - index: function PostScriptStack_index(n) { - this.push(this.stack[this.stack.length - n - 1]); - }, - roll: function PostScriptStack_roll(n, p) { - var stack = this.stack; - var l = stack.length - n; - var r = stack.length - 1, - c = l + (p - Math.floor(p / n) * n), - i, - j, - t; - - for (i = l, j = r; i < j; i++, j--) { - t = stack[i]; - stack[i] = stack[j]; - stack[j] = t; - } - - for (i = l, j = c - 1; i < j; i++, j--) { - t = stack[i]; - stack[i] = stack[j]; - stack[j] = t; - } - - for (i = c, j = r; i < j; i++, j--) { - t = stack[i]; - stack[i] = stack[j]; - stack[j] = t; - } - } - }; - return PostScriptStack; -}(); - -var PostScriptEvaluator = function PostScriptEvaluatorClosure() { - function PostScriptEvaluator(operators) { - this.operators = operators; - } - - PostScriptEvaluator.prototype = { - execute: function PostScriptEvaluator_execute(initialStack) { - var stack = new PostScriptStack(initialStack); - var counter = 0; - var operators = this.operators; - var length = operators.length; - var operator, a, b; - - while (counter < length) { - operator = operators[counter++]; - - if (typeof operator === "number") { - stack.push(operator); - continue; - } - - switch (operator) { - case "jz": - b = stack.pop(); - a = stack.pop(); - - if (!a) { - counter = b; - } - - break; - - case "j": - a = stack.pop(); - counter = a; - break; - - case "abs": - a = stack.pop(); - stack.push(Math.abs(a)); - break; - - case "add": - b = stack.pop(); - a = stack.pop(); - stack.push(a + b); - break; - - case "and": - b = stack.pop(); - a = stack.pop(); - - if ((0, _util.isBool)(a) && (0, _util.isBool)(b)) { - stack.push(a && b); - } else { - stack.push(a & b); - } - - break; - - case "atan": - a = stack.pop(); - stack.push(Math.atan(a)); - break; - - case "bitshift": - b = stack.pop(); - a = stack.pop(); - - if (a > 0) { - stack.push(a << b); - } else { - stack.push(a >> b); - } - - break; - - case "ceiling": - a = stack.pop(); - stack.push(Math.ceil(a)); - break; - - case "copy": - a = stack.pop(); - stack.copy(a); - break; - - case "cos": - a = stack.pop(); - stack.push(Math.cos(a)); - break; - - case "cvi": - a = stack.pop() | 0; - stack.push(a); - break; - - case "cvr": - break; - - case "div": - b = stack.pop(); - a = stack.pop(); - stack.push(a / b); - break; - - case "dup": - stack.copy(1); - break; - - case "eq": - b = stack.pop(); - a = stack.pop(); - stack.push(a === b); - break; - - case "exch": - stack.roll(2, 1); - break; - - case "exp": - b = stack.pop(); - a = stack.pop(); - stack.push(a ** b); - break; - - case "false": - stack.push(false); - break; - - case "floor": - a = stack.pop(); - stack.push(Math.floor(a)); - break; - - case "ge": - b = stack.pop(); - a = stack.pop(); - stack.push(a >= b); - break; - - case "gt": - b = stack.pop(); - a = stack.pop(); - stack.push(a > b); - break; - - case "idiv": - b = stack.pop(); - a = stack.pop(); - stack.push(a / b | 0); - break; - - case "index": - a = stack.pop(); - stack.index(a); - break; - - case "le": - b = stack.pop(); - a = stack.pop(); - stack.push(a <= b); - break; - - case "ln": - a = stack.pop(); - stack.push(Math.log(a)); - break; - - case "log": - a = stack.pop(); - stack.push(Math.log(a) / Math.LN10); - break; - - case "lt": - b = stack.pop(); - a = stack.pop(); - stack.push(a < b); - break; - - case "mod": - b = stack.pop(); - a = stack.pop(); - stack.push(a % b); - break; - - case "mul": - b = stack.pop(); - a = stack.pop(); - stack.push(a * b); - break; - - case "ne": - b = stack.pop(); - a = stack.pop(); - stack.push(a !== b); - break; - - case "neg": - a = stack.pop(); - stack.push(-a); - break; - - case "not": - a = stack.pop(); - - if ((0, _util.isBool)(a)) { - stack.push(!a); - } else { - stack.push(~a); - } - - break; - - case "or": - b = stack.pop(); - a = stack.pop(); - - if ((0, _util.isBool)(a) && (0, _util.isBool)(b)) { - stack.push(a || b); - } else { - stack.push(a | b); - } - - break; - - case "pop": - stack.pop(); - break; - - case "roll": - b = stack.pop(); - a = stack.pop(); - stack.roll(a, b); - break; - - case "round": - a = stack.pop(); - stack.push(Math.round(a)); - break; - - case "sin": - a = stack.pop(); - stack.push(Math.sin(a)); - break; - - case "sqrt": - a = stack.pop(); - stack.push(Math.sqrt(a)); - break; - - case "sub": - b = stack.pop(); - a = stack.pop(); - stack.push(a - b); - break; - - case "true": - stack.push(true); - break; - - case "truncate": - a = stack.pop(); - a = a < 0 ? Math.ceil(a) : Math.floor(a); - stack.push(a); - break; - - case "xor": - b = stack.pop(); - a = stack.pop(); - - if ((0, _util.isBool)(a) && (0, _util.isBool)(b)) { - stack.push(a !== b); - } else { - stack.push(a ^ b); - } - - break; - - default: - throw new _util.FormatError(`Unknown operator ${operator}`); - } - } - - return stack.stack; - } - }; - return PostScriptEvaluator; -}(); - -exports.PostScriptEvaluator = PostScriptEvaluator; - -var PostScriptCompiler = function PostScriptCompilerClosure() { - function AstNode(type) { - this.type = type; - } - - AstNode.prototype.visit = function (visitor) { - (0, _util.unreachable)("abstract method"); - }; - - function AstArgument(index, min, max) { - AstNode.call(this, "args"); - this.index = index; - this.min = min; - this.max = max; - } - - AstArgument.prototype = Object.create(AstNode.prototype); - - AstArgument.prototype.visit = function (visitor) { - visitor.visitArgument(this); - }; - - function AstLiteral(number) { - AstNode.call(this, "literal"); - this.number = number; - this.min = number; - this.max = number; - } - - AstLiteral.prototype = Object.create(AstNode.prototype); - - AstLiteral.prototype.visit = function (visitor) { - visitor.visitLiteral(this); - }; - - function AstBinaryOperation(op, arg1, arg2, min, max) { - AstNode.call(this, "binary"); - this.op = op; - this.arg1 = arg1; - this.arg2 = arg2; - this.min = min; - this.max = max; - } - - AstBinaryOperation.prototype = Object.create(AstNode.prototype); - - AstBinaryOperation.prototype.visit = function (visitor) { - visitor.visitBinaryOperation(this); - }; - - function AstMin(arg, max) { - AstNode.call(this, "max"); - this.arg = arg; - this.min = arg.min; - this.max = max; - } - - AstMin.prototype = Object.create(AstNode.prototype); - - AstMin.prototype.visit = function (visitor) { - visitor.visitMin(this); - }; - - function AstVariable(index, min, max) { - AstNode.call(this, "var"); - this.index = index; - this.min = min; - this.max = max; - } - - AstVariable.prototype = Object.create(AstNode.prototype); - - AstVariable.prototype.visit = function (visitor) { - visitor.visitVariable(this); - }; - - function AstVariableDefinition(variable, arg) { - AstNode.call(this, "definition"); - this.variable = variable; - this.arg = arg; - } - - AstVariableDefinition.prototype = Object.create(AstNode.prototype); - - AstVariableDefinition.prototype.visit = function (visitor) { - visitor.visitVariableDefinition(this); - }; - - function ExpressionBuilderVisitor() { - this.parts = []; - } - - ExpressionBuilderVisitor.prototype = { - visitArgument(arg) { - this.parts.push("Math.max(", arg.min, ", Math.min(", arg.max, ", src[srcOffset + ", arg.index, "]))"); - }, - - visitVariable(variable) { - this.parts.push("v", variable.index); - }, - - visitLiteral(literal) { - this.parts.push(literal.number); - }, - - visitBinaryOperation(operation) { - this.parts.push("("); - operation.arg1.visit(this); - this.parts.push(" ", operation.op, " "); - operation.arg2.visit(this); - this.parts.push(")"); - }, - - visitVariableDefinition(definition) { - this.parts.push("var "); - definition.variable.visit(this); - this.parts.push(" = "); - definition.arg.visit(this); - this.parts.push(";"); - }, - - visitMin(max) { - this.parts.push("Math.min("); - max.arg.visit(this); - this.parts.push(", ", max.max, ")"); - }, - - toString() { - return this.parts.join(""); - } - - }; - - function buildAddOperation(num1, num2) { - if (num2.type === "literal" && num2.number === 0) { - return num1; - } - - if (num1.type === "literal" && num1.number === 0) { - return num2; - } - - if (num2.type === "literal" && num1.type === "literal") { - return new AstLiteral(num1.number + num2.number); - } - - return new AstBinaryOperation("+", num1, num2, num1.min + num2.min, num1.max + num2.max); - } - - function buildMulOperation(num1, num2) { - if (num2.type === "literal") { - if (num2.number === 0) { - return new AstLiteral(0); - } else if (num2.number === 1) { - return num1; - } else if (num1.type === "literal") { - return new AstLiteral(num1.number * num2.number); - } - } - - if (num1.type === "literal") { - if (num1.number === 0) { - return new AstLiteral(0); - } else if (num1.number === 1) { - return num2; - } - } - - var min = Math.min(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max); - var max = Math.max(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max); - return new AstBinaryOperation("*", num1, num2, min, max); - } - - function buildSubOperation(num1, num2) { - if (num2.type === "literal") { - if (num2.number === 0) { - return num1; - } else if (num1.type === "literal") { - return new AstLiteral(num1.number - num2.number); - } - } - - if (num2.type === "binary" && num2.op === "-" && num1.type === "literal" && num1.number === 1 && num2.arg1.type === "literal" && num2.arg1.number === 1) { - return num2.arg2; - } - - return new AstBinaryOperation("-", num1, num2, num1.min - num2.max, num1.max - num2.min); - } - - function buildMinOperation(num1, max) { - if (num1.min >= max) { - return new AstLiteral(max); - } else if (num1.max <= max) { - return num1; - } - - return new AstMin(num1, max); - } - - function PostScriptCompiler() {} - - PostScriptCompiler.prototype = { - compile: function PostScriptCompiler_compile(code, domain, range) { - var stack = []; - var instructions = []; - var inputSize = domain.length >> 1, - outputSize = range.length >> 1; - var lastRegister = 0; - var n, j; - var num1, num2, ast1, ast2, tmpVar, item; - - for (let i = 0; i < inputSize; i++) { - stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1])); - } - - for (let i = 0, ii = code.length; i < ii; i++) { - item = code[i]; - - if (typeof item === "number") { - stack.push(new AstLiteral(item)); - continue; - } - - switch (item) { - case "add": - if (stack.length < 2) { - return null; - } - - num2 = stack.pop(); - num1 = stack.pop(); - stack.push(buildAddOperation(num1, num2)); - break; - - case "cvr": - if (stack.length < 1) { - return null; - } - - break; - - case "mul": - if (stack.length < 2) { - return null; - } - - num2 = stack.pop(); - num1 = stack.pop(); - stack.push(buildMulOperation(num1, num2)); - break; - - case "sub": - if (stack.length < 2) { - return null; - } - - num2 = stack.pop(); - num1 = stack.pop(); - stack.push(buildSubOperation(num1, num2)); - break; - - case "exch": - if (stack.length < 2) { - return null; - } - - ast1 = stack.pop(); - ast2 = stack.pop(); - stack.push(ast1, ast2); - break; - - case "pop": - if (stack.length < 1) { - return null; - } - - stack.pop(); - break; - - case "index": - if (stack.length < 1) { - return null; - } - - num1 = stack.pop(); - - if (num1.type !== "literal") { - return null; - } - - n = num1.number; - - if (n < 0 || !Number.isInteger(n) || stack.length < n) { - return null; - } - - ast1 = stack[stack.length - n - 1]; - - if (ast1.type === "literal" || ast1.type === "var") { - stack.push(ast1); - break; - } - - tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max); - stack[stack.length - n - 1] = tmpVar; - stack.push(tmpVar); - instructions.push(new AstVariableDefinition(tmpVar, ast1)); - break; - - case "dup": - if (stack.length < 1) { - return null; - } - - if (typeof code[i + 1] === "number" && code[i + 2] === "gt" && code[i + 3] === i + 7 && code[i + 4] === "jz" && code[i + 5] === "pop" && code[i + 6] === code[i + 1]) { - num1 = stack.pop(); - stack.push(buildMinOperation(num1, code[i + 1])); - i += 6; - break; - } - - ast1 = stack[stack.length - 1]; - - if (ast1.type === "literal" || ast1.type === "var") { - stack.push(ast1); - break; - } - - tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max); - stack[stack.length - 1] = tmpVar; - stack.push(tmpVar); - instructions.push(new AstVariableDefinition(tmpVar, ast1)); - break; - - case "roll": - if (stack.length < 2) { - return null; - } - - num2 = stack.pop(); - num1 = stack.pop(); - - if (num2.type !== "literal" || num1.type !== "literal") { - return null; - } - - j = num2.number; - n = num1.number; - - if (n <= 0 || !Number.isInteger(n) || !Number.isInteger(j) || stack.length < n) { - return null; - } - - j = (j % n + n) % n; - - if (j === 0) { - break; - } - - Array.prototype.push.apply(stack, stack.splice(stack.length - n, n - j)); - break; - - default: - return null; - } - } - - if (stack.length !== outputSize) { - return null; - } - - var result = []; - instructions.forEach(function (instruction) { - var statementBuilder = new ExpressionBuilderVisitor(); - instruction.visit(statementBuilder); - result.push(statementBuilder.toString()); - }); - stack.forEach(function (expr, i) { - var statementBuilder = new ExpressionBuilderVisitor(); - expr.visit(statementBuilder); - var min = range[i * 2], - max = range[i * 2 + 1]; - var out = [statementBuilder.toString()]; - - if (min > expr.min) { - out.unshift("Math.max(", min, ", "); - out.push(")"); - } - - if (max < expr.max) { - out.unshift("Math.min(", max, ", "); - out.push(")"); - } - - out.unshift("dest[destOffset + ", i, "] = "); - out.push(";"); - result.push(out.join("")); - }); - return result.join("\n"); - } - }; - return PostScriptCompiler; -}(); - -exports.PostScriptCompiler = PostScriptCompiler; - -/***/ }), -/* 41 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.PostScriptParser = exports.PostScriptLexer = void 0; - -var _util = __w_pdfjs_require__(2); - -var _primitives = __w_pdfjs_require__(5); - -var _core_utils = __w_pdfjs_require__(8); - -class PostScriptParser { - constructor(lexer) { - this.lexer = lexer; - this.operators = []; - this.token = null; - this.prev = null; - } - - nextToken() { - this.prev = this.token; - this.token = this.lexer.getToken(); - } - - accept(type) { - if (this.token.type === type) { - this.nextToken(); - return true; - } - - return false; - } - - expect(type) { - if (this.accept(type)) { - return true; - } - - throw new _util.FormatError(`Unexpected symbol: found ${this.token.type} expected ${type}.`); - } - - parse() { - this.nextToken(); - this.expect(PostScriptTokenTypes.LBRACE); - this.parseBlock(); - this.expect(PostScriptTokenTypes.RBRACE); - return this.operators; - } - - parseBlock() { - while (true) { - if (this.accept(PostScriptTokenTypes.NUMBER)) { - this.operators.push(this.prev.value); - } else if (this.accept(PostScriptTokenTypes.OPERATOR)) { - this.operators.push(this.prev.value); - } else if (this.accept(PostScriptTokenTypes.LBRACE)) { - this.parseCondition(); - } else { - return; - } - } - } - - parseCondition() { - const conditionLocation = this.operators.length; - this.operators.push(null, null); - this.parseBlock(); - this.expect(PostScriptTokenTypes.RBRACE); - - if (this.accept(PostScriptTokenTypes.IF)) { - this.operators[conditionLocation] = this.operators.length; - this.operators[conditionLocation + 1] = "jz"; - } else if (this.accept(PostScriptTokenTypes.LBRACE)) { - const jumpLocation = this.operators.length; - this.operators.push(null, null); - const endOfTrue = this.operators.length; - this.parseBlock(); - this.expect(PostScriptTokenTypes.RBRACE); - this.expect(PostScriptTokenTypes.IFELSE); - this.operators[jumpLocation] = this.operators.length; - this.operators[jumpLocation + 1] = "j"; - this.operators[conditionLocation] = endOfTrue; - this.operators[conditionLocation + 1] = "jz"; - } else { - throw new _util.FormatError("PS Function: error parsing conditional."); - } - } - -} - -exports.PostScriptParser = PostScriptParser; -const PostScriptTokenTypes = { - LBRACE: 0, - RBRACE: 1, - NUMBER: 2, - OPERATOR: 3, - IF: 4, - IFELSE: 5 -}; - -const PostScriptToken = function PostScriptTokenClosure() { - const opCache = Object.create(null); - - class PostScriptToken { - constructor(type, value) { - this.type = type; - this.value = value; - } - - static getOperator(op) { - const opValue = opCache[op]; - - if (opValue) { - return opValue; - } - - return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op); - } - - static get LBRACE() { - return (0, _util.shadow)(this, "LBRACE", new PostScriptToken(PostScriptTokenTypes.LBRACE, "{")); - } - - static get RBRACE() { - return (0, _util.shadow)(this, "RBRACE", new PostScriptToken(PostScriptTokenTypes.RBRACE, "}")); - } - - static get IF() { - return (0, _util.shadow)(this, "IF", new PostScriptToken(PostScriptTokenTypes.IF, "IF")); - } - - static get IFELSE() { - return (0, _util.shadow)(this, "IFELSE", new PostScriptToken(PostScriptTokenTypes.IFELSE, "IFELSE")); - } - - } - - return PostScriptToken; -}(); - -class PostScriptLexer { - constructor(stream) { - this.stream = stream; - this.nextChar(); - this.strBuf = []; - } - - nextChar() { - return this.currentChar = this.stream.getByte(); - } - - getToken() { - let comment = false; - let ch = this.currentChar; - - while (true) { - if (ch < 0) { - return _primitives.EOF; - } - - if (comment) { - if (ch === 0x0a || ch === 0x0d) { - comment = false; - } - } else if (ch === 0x25) { - comment = true; - } else if (!(0, _core_utils.isWhiteSpace)(ch)) { - break; - } - - ch = this.nextChar(); - } - - switch (ch | 0) { - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x2b: - case 0x2d: - case 0x2e: - return new PostScriptToken(PostScriptTokenTypes.NUMBER, this.getNumber()); - - case 0x7b: - this.nextChar(); - return PostScriptToken.LBRACE; - - case 0x7d: - this.nextChar(); - return PostScriptToken.RBRACE; - } - - const strBuf = this.strBuf; - strBuf.length = 0; - strBuf[0] = String.fromCharCode(ch); - - while ((ch = this.nextChar()) >= 0 && (ch >= 0x41 && ch <= 0x5a || ch >= 0x61 && ch <= 0x7a)) { - strBuf.push(String.fromCharCode(ch)); - } - - const str = strBuf.join(""); - - switch (str.toLowerCase()) { - case "if": - return PostScriptToken.IF; - - case "ifelse": - return PostScriptToken.IFELSE; - - default: - return PostScriptToken.getOperator(str); - } - } - - getNumber() { - let ch = this.currentChar; - const strBuf = this.strBuf; - strBuf.length = 0; - strBuf[0] = String.fromCharCode(ch); - - while ((ch = this.nextChar()) >= 0) { - if (ch >= 0x30 && ch <= 0x39 || ch === 0x2d || ch === 0x2e) { - strBuf.push(String.fromCharCode(ch)); - } else { - break; - } - } - - const value = parseFloat(strBuf.join("")); - - if (isNaN(value)) { - throw new _util.FormatError(`Invalid floating point number: ${value}`); - } - - return value; - } - -} - -exports.PostScriptLexer = PostScriptLexer; - -/***/ }), -/* 42 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.bidi = bidi; - -var _util = __w_pdfjs_require__(2); - -var baseTypes = ["BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "S", "B", "S", "WS", "B", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "B", "B", "B", "S", "WS", "ON", "ON", "ET", "ET", "ET", "ON", "ON", "ON", "ON", "ON", "ES", "CS", "ES", "CS", "CS", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "CS", "ON", "ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "ON", "ON", "ON", "BN", "BN", "BN", "BN", "BN", "BN", "B", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "CS", "ON", "ET", "ET", "ET", "ET", "ON", "ON", "ON", "ON", "L", "ON", "ON", "BN", "ON", "ON", "ET", "ET", "EN", "EN", "ON", "L", "ON", "ON", "ON", "EN", "L", "ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "L", "L", "L", "L", "L", "L", "L", "L"]; -var arabicTypes = ["AN", "AN", "AN", "AN", "AN", "AN", "ON", "ON", "AL", "ET", "ET", "AL", "CS", "AL", "ON", "ON", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "ET", "AN", "AN", "AL", "AL", "AL", "NSM", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AN", "ON", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "NSM", "NSM", "ON", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "AL", "AL", "AL", "AL", "AL", "AL"]; - -function isOdd(i) { - return (i & 1) !== 0; -} - -function isEven(i) { - return (i & 1) === 0; -} - -function findUnequal(arr, start, value) { - for (var j = start, jj = arr.length; j < jj; ++j) { - if (arr[j] !== value) { - return j; - } - } - - return j; -} - -function setValues(arr, start, end, value) { - for (var j = start; j < end; ++j) { - arr[j] = value; - } -} - -function reverseValues(arr, start, end) { - for (var i = start, j = end - 1; i < j; ++i, --j) { - var temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; - } -} - -function createBidiText(str, isLTR, vertical = false) { - let dir = "ltr"; - - if (vertical) { - dir = "ttb"; - } else if (!isLTR) { - dir = "rtl"; - } - - return { - str, - dir - }; -} - -var chars = []; -var types = []; - -function bidi(str, startLevel, vertical) { - var isLTR = true; - var strLength = str.length; - - if (strLength === 0 || vertical) { - return createBidiText(str, isLTR, vertical); - } - - chars.length = strLength; - types.length = strLength; - var numBidi = 0; - var i, ii; - - for (i = 0; i < strLength; ++i) { - chars[i] = str.charAt(i); - var charCode = str.charCodeAt(i); - var charType = "L"; - - if (charCode <= 0x00ff) { - charType = baseTypes[charCode]; - } else if (0x0590 <= charCode && charCode <= 0x05f4) { - charType = "R"; - } else if (0x0600 <= charCode && charCode <= 0x06ff) { - charType = arabicTypes[charCode & 0xff]; - - if (!charType) { - (0, _util.warn)("Bidi: invalid Unicode character " + charCode.toString(16)); - } - } else if (0x0700 <= charCode && charCode <= 0x08ac) { - charType = "AL"; - } - - if (charType === "R" || charType === "AL" || charType === "AN") { - numBidi++; - } - - types[i] = charType; - } - - if (numBidi === 0) { - isLTR = true; - return createBidiText(str, isLTR); - } - - if (startLevel === -1) { - if (numBidi / strLength < 0.3) { - isLTR = true; - startLevel = 0; - } else { - isLTR = false; - startLevel = 1; - } - } - - var levels = []; - - for (i = 0; i < strLength; ++i) { - levels[i] = startLevel; - } - - var e = isOdd(startLevel) ? "R" : "L"; - var sor = e; - var eor = sor; - var lastType = sor; - - for (i = 0; i < strLength; ++i) { - if (types[i] === "NSM") { - types[i] = lastType; - } else { - lastType = types[i]; - } - } - - lastType = sor; - var t; - - for (i = 0; i < strLength; ++i) { - t = types[i]; - - if (t === "EN") { - types[i] = lastType === "AL" ? "AN" : "EN"; - } else if (t === "R" || t === "L" || t === "AL") { - lastType = t; - } - } - - for (i = 0; i < strLength; ++i) { - t = types[i]; - - if (t === "AL") { - types[i] = "R"; - } - } - - for (i = 1; i < strLength - 1; ++i) { - if (types[i] === "ES" && types[i - 1] === "EN" && types[i + 1] === "EN") { - types[i] = "EN"; - } - - if (types[i] === "CS" && (types[i - 1] === "EN" || types[i - 1] === "AN") && types[i + 1] === types[i - 1]) { - types[i] = types[i - 1]; - } - } - - for (i = 0; i < strLength; ++i) { - if (types[i] === "EN") { - var j; - - for (j = i - 1; j >= 0; --j) { - if (types[j] !== "ET") { - break; - } - - types[j] = "EN"; - } - - for (j = i + 1; j < strLength; ++j) { - if (types[j] !== "ET") { - break; - } - - types[j] = "EN"; - } - } - } - - for (i = 0; i < strLength; ++i) { - t = types[i]; - - if (t === "WS" || t === "ES" || t === "ET" || t === "CS") { - types[i] = "ON"; - } - } - - lastType = sor; - - for (i = 0; i < strLength; ++i) { - t = types[i]; - - if (t === "EN") { - types[i] = lastType === "L" ? "L" : "EN"; - } else if (t === "R" || t === "L") { - lastType = t; - } - } - - for (i = 0; i < strLength; ++i) { - if (types[i] === "ON") { - var end = findUnequal(types, i + 1, "ON"); - var before = sor; - - if (i > 0) { - before = types[i - 1]; - } - - var after = eor; - - if (end + 1 < strLength) { - after = types[end + 1]; - } - - if (before !== "L") { - before = "R"; - } - - if (after !== "L") { - after = "R"; - } - - if (before === after) { - setValues(types, i, end, before); - } - - i = end - 1; - } - } - - for (i = 0; i < strLength; ++i) { - if (types[i] === "ON") { - types[i] = e; - } - } - - for (i = 0; i < strLength; ++i) { - t = types[i]; - - if (isEven(levels[i])) { - if (t === "R") { - levels[i] += 1; - } else if (t === "AN" || t === "EN") { - levels[i] += 2; - } - } else { - if (t === "L" || t === "AN" || t === "EN") { - levels[i] += 1; - } - } - } - - var highestLevel = -1; - var lowestOddLevel = 99; - var level; - - for (i = 0, ii = levels.length; i < ii; ++i) { - level = levels[i]; - - if (highestLevel < level) { - highestLevel = level; - } - - if (lowestOddLevel > level && isOdd(level)) { - lowestOddLevel = level; - } - } - - for (level = highestLevel; level >= lowestOddLevel; --level) { - var start = -1; - - for (i = 0, ii = levels.length; i < ii; ++i) { - if (levels[i] < level) { - if (start >= 0) { - reverseValues(chars, start, i); - start = -1; - } - } else if (start < 0) { - start = i; - } - } - - if (start >= 0) { - reverseValues(chars, start, levels.length); - } - } - - for (i = 0, ii = chars.length; i < ii; ++i) { - var ch = chars[i]; - - if (ch === "<" || ch === ">") { - chars[i] = ""; - } - } - - return createBidiText(chars.join(""), isLTR); -} - -/***/ }), -/* 43 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getMetrics = void 0; - -var _core_utils = __w_pdfjs_require__(8); - -var getMetrics = (0, _core_utils.getLookupTableFactory)(function (t) { +const getMetrics = (0, _core_utils.getLookupTableFactory)(function (t) { t.Courier = 600; t["Courier-Bold"] = 600; t["Courier-BoldOblique"] = 600; @@ -46177,17 +47487,5560 @@ var getMetrics = (0, _core_utils.getLookupTableFactory)(function (t) { }); }); exports.getMetrics = getMetrics; +const getFontBasicMetrics = (0, _core_utils.getLookupTableFactory)(function (t) { + t.Courier = { + ascent: 629, + descent: -157, + capHeight: 562, + xHeight: -426 + }; + t["Courier-Bold"] = { + ascent: 629, + descent: -157, + capHeight: 562, + xHeight: 439 + }; + t["Courier-Oblique"] = { + ascent: 629, + descent: -157, + capHeight: 562, + xHeight: 426 + }; + t["Courier-BoldOblique"] = { + ascent: 629, + descent: -157, + capHeight: 562, + xHeight: 426 + }; + t.Helvetica = { + ascent: 718, + descent: -207, + capHeight: 718, + xHeight: 523 + }; + t["Helvetica-Bold"] = { + ascent: 718, + descent: -207, + capHeight: 718, + xHeight: 532 + }; + t["Helvetica-Oblique"] = { + ascent: 718, + descent: -207, + capHeight: 718, + xHeight: 523 + }; + t["Helvetica-BoldOblique"] = { + ascent: 718, + descent: -207, + capHeight: 718, + xHeight: 532 + }; + t["Times-Roman"] = { + ascent: 683, + descent: -217, + capHeight: 662, + xHeight: 450 + }; + t["Times-Bold"] = { + ascent: 683, + descent: -217, + capHeight: 676, + xHeight: 461 + }; + t["Times-Italic"] = { + ascent: 683, + descent: -217, + capHeight: 653, + xHeight: 441 + }; + t["Times-BoldItalic"] = { + ascent: 683, + descent: -217, + capHeight: 669, + xHeight: 462 + }; + t.Symbol = { + ascent: Math.NaN, + descent: Math.NaN, + capHeight: Math.NaN, + xHeight: Math.NaN + }; + t.ZapfDingbats = { + ascent: Math.NaN, + descent: Math.NaN, + capHeight: Math.NaN, + xHeight: Math.NaN + }; +}); +exports.getFontBasicMetrics = getFontBasicMetrics; /***/ }), -/* 44 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 46 */ +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true +})); +exports.GlyfTable = void 0; +const ON_CURVE_POINT = 1 << 0; +const X_SHORT_VECTOR = 1 << 1; +const Y_SHORT_VECTOR = 1 << 2; +const REPEAT_FLAG = 1 << 3; +const X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR = 1 << 4; +const Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR = 1 << 5; +const OVERLAP_SIMPLE = 1 << 6; +const ARG_1_AND_2_ARE_WORDS = 1 << 0; +const ARGS_ARE_XY_VALUES = 1 << 1; +const WE_HAVE_A_SCALE = 1 << 3; +const MORE_COMPONENTS = 1 << 5; +const WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6; +const WE_HAVE_A_TWO_BY_TWO = 1 << 7; +const WE_HAVE_INSTRUCTIONS = 1 << 8; + +class GlyfTable { + constructor({ + glyfTable, + isGlyphLocationsLong, + locaTable, + numGlyphs + }) { + this.glyphs = []; + const loca = new DataView(locaTable.buffer, locaTable.byteOffset, locaTable.byteLength); + const glyf = new DataView(glyfTable.buffer, glyfTable.byteOffset, glyfTable.byteLength); + const offsetSize = isGlyphLocationsLong ? 4 : 2; + let prev = isGlyphLocationsLong ? loca.getUint32(0) : 2 * loca.getUint16(0); + let pos = 0; + + for (let i = 0; i < numGlyphs; i++) { + pos += offsetSize; + const next = isGlyphLocationsLong ? loca.getUint32(pos) : 2 * loca.getUint16(pos); + + if (next === prev) { + this.glyphs.push(new Glyph({})); + continue; + } + + const glyph = Glyph.parse(prev, glyf); + this.glyphs.push(glyph); + prev = next; + } + } + + getSize() { + return this.glyphs.reduce((a, g) => { + const size = g.getSize(); + return a + (size + 3 & ~3); + }, 0); + } + + write() { + const totalSize = this.getSize(); + const glyfTable = new DataView(new ArrayBuffer(totalSize)); + const isLocationLong = totalSize > 0x1fffe; + const offsetSize = isLocationLong ? 4 : 2; + const locaTable = new DataView(new ArrayBuffer((this.glyphs.length + 1) * offsetSize)); + + if (isLocationLong) { + locaTable.setUint32(0, 0); + } else { + locaTable.setUint16(0, 0); + } + + let pos = 0; + let locaIndex = 0; + + for (const glyph of this.glyphs) { + pos += glyph.write(pos, glyfTable); + pos = pos + 3 & ~3; + locaIndex += offsetSize; + + if (isLocationLong) { + locaTable.setUint32(locaIndex, pos); + } else { + locaTable.setUint16(locaIndex, pos >> 1); + } + } + + return { + isLocationLong, + loca: new Uint8Array(locaTable.buffer), + glyf: new Uint8Array(glyfTable.buffer) + }; + } + + scale(factors) { + for (let i = 0, ii = this.glyphs.length; i < ii; i++) { + this.glyphs[i].scale(factors[i]); + } + } + +} + +exports.GlyfTable = GlyfTable; + +class Glyph { + constructor({ + header = null, + simple = null, + composites = null + }) { + this.header = header; + this.simple = simple; + this.composites = composites; + } + + static parse(pos, glyf) { + const [read, header] = GlyphHeader.parse(pos, glyf); + pos += read; + + if (header.numberOfContours < 0) { + const composites = []; + + while (true) { + const [n, composite] = CompositeGlyph.parse(pos, glyf); + pos += n; + composites.push(composite); + + if (!(composite.flags & MORE_COMPONENTS)) { + break; + } + } + + return new Glyph({ + header, + composites + }); + } + + const simple = SimpleGlyph.parse(pos, glyf, header.numberOfContours); + return new Glyph({ + header, + simple + }); + } + + getSize() { + if (!this.header) { + return 0; + } + + const size = this.simple ? this.simple.getSize() : this.composites.reduce((a, c) => a + c.getSize(), 0); + return this.header.getSize() + size; + } + + write(pos, buf) { + if (!this.header) { + return 0; + } + + const spos = pos; + pos += this.header.write(pos, buf); + + if (this.simple) { + pos += this.simple.write(pos, buf); + } else { + for (const composite of this.composites) { + pos += composite.write(pos, buf); + } + } + + return pos - spos; + } + + scale(factor) { + if (!this.header) { + return; + } + + const xMiddle = (this.header.xMin + this.header.xMax) / 2; + this.header.scale(xMiddle, factor); + + if (this.simple) { + this.simple.scale(xMiddle, factor); + } else { + for (const composite of this.composites) { + composite.scale(xMiddle, factor); + } + } + } + +} + +class GlyphHeader { + constructor({ + numberOfContours, + xMin, + yMin, + xMax, + yMax + }) { + this.numberOfContours = numberOfContours; + this.xMin = xMin; + this.yMin = yMin; + this.xMax = xMax; + this.yMax = yMax; + } + + static parse(pos, glyf) { + return [10, new GlyphHeader({ + numberOfContours: glyf.getInt16(pos), + xMin: glyf.getInt16(pos + 2), + yMin: glyf.getInt16(pos + 4), + xMax: glyf.getInt16(pos + 6), + yMax: glyf.getInt16(pos + 8) + })]; + } + + getSize() { + return 10; + } + + write(pos, buf) { + buf.setInt16(pos, this.numberOfContours); + buf.setInt16(pos + 2, this.xMin); + buf.setInt16(pos + 4, this.yMin); + buf.setInt16(pos + 6, this.xMax); + buf.setInt16(pos + 8, this.yMax); + return 10; + } + + scale(x, factor) { + this.xMin = Math.round(x + (this.xMin - x) * factor); + this.xMax = Math.round(x + (this.xMax - x) * factor); + } + +} + +class Contour { + constructor({ + flags, + xCoordinates, + yCoordinates + }) { + this.xCoordinates = xCoordinates; + this.yCoordinates = yCoordinates; + this.flags = flags; + } + +} + +class SimpleGlyph { + constructor({ + contours, + instructions + }) { + this.contours = contours; + this.instructions = instructions; + } + + static parse(pos, glyf, numberOfContours) { + const endPtsOfContours = []; + + for (let i = 0; i < numberOfContours; i++) { + const endPt = glyf.getUint16(pos); + pos += 2; + endPtsOfContours.push(endPt); + } + + const numberOfPt = endPtsOfContours[numberOfContours - 1] + 1; + const instructionLength = glyf.getUint16(pos); + pos += 2; + const instructions = new Uint8Array(glyf).slice(pos, pos + instructionLength); + pos += instructionLength; + const flags = []; + + for (let i = 0; i < numberOfPt; pos++, i++) { + let flag = glyf.getUint8(pos); + flags.push(flag); + + if (flag & REPEAT_FLAG) { + const count = glyf.getUint8(++pos); + flag ^= REPEAT_FLAG; + + for (let m = 0; m < count; m++) { + flags.push(flag); + } + + i += count; + } + } + + const allXCoordinates = []; + let xCoordinates = []; + let yCoordinates = []; + let pointFlags = []; + const contours = []; + let endPtsOfContoursIndex = 0; + let lastCoordinate = 0; + + for (let i = 0; i < numberOfPt; i++) { + const flag = flags[i]; + + if (flag & X_SHORT_VECTOR) { + const x = glyf.getUint8(pos++); + lastCoordinate += flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR ? x : -x; + xCoordinates.push(lastCoordinate); + } else if (flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) { + xCoordinates.push(lastCoordinate); + } else { + lastCoordinate += glyf.getInt16(pos); + pos += 2; + xCoordinates.push(lastCoordinate); + } + + if (endPtsOfContours[endPtsOfContoursIndex] === i) { + endPtsOfContoursIndex++; + allXCoordinates.push(xCoordinates); + xCoordinates = []; + } + } + + lastCoordinate = 0; + endPtsOfContoursIndex = 0; + + for (let i = 0; i < numberOfPt; i++) { + const flag = flags[i]; + + if (flag & Y_SHORT_VECTOR) { + const y = glyf.getUint8(pos++); + lastCoordinate += flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR ? y : -y; + yCoordinates.push(lastCoordinate); + } else if (flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) { + yCoordinates.push(lastCoordinate); + } else { + lastCoordinate += glyf.getInt16(pos); + pos += 2; + yCoordinates.push(lastCoordinate); + } + + pointFlags.push(flag & ON_CURVE_POINT | flag & OVERLAP_SIMPLE); + + if (endPtsOfContours[endPtsOfContoursIndex] === i) { + xCoordinates = allXCoordinates[endPtsOfContoursIndex]; + endPtsOfContoursIndex++; + contours.push(new Contour({ + flags: pointFlags, + xCoordinates, + yCoordinates + })); + yCoordinates = []; + pointFlags = []; + } + } + + return new SimpleGlyph({ + contours, + instructions + }); + } + + getSize() { + let size = this.contours.length * 2 + 2 + this.instructions.length; + let lastX = 0; + let lastY = 0; + + for (const contour of this.contours) { + size += contour.flags.length; + + for (let i = 0, ii = contour.xCoordinates.length; i < ii; i++) { + const x = contour.xCoordinates[i]; + const y = contour.yCoordinates[i]; + let abs = Math.abs(x - lastX); + + if (abs > 255) { + size += 2; + } else if (abs > 0) { + size += 1; + } + + lastX = x; + abs = Math.abs(y - lastY); + + if (abs > 255) { + size += 2; + } else if (abs > 0) { + size += 1; + } + + lastY = y; + } + } + + return size; + } + + write(pos, buf) { + const spos = pos; + const xCoordinates = []; + const yCoordinates = []; + const flags = []; + let lastX = 0; + let lastY = 0; + + for (const contour of this.contours) { + for (let i = 0, ii = contour.xCoordinates.length; i < ii; i++) { + let flag = contour.flags[i]; + const x = contour.xCoordinates[i]; + let delta = x - lastX; + + if (delta === 0) { + flag |= X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR; + xCoordinates.push(0); + } else { + const abs = Math.abs(delta); + + if (abs <= 255) { + flag |= delta >= 0 ? X_SHORT_VECTOR | X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR : X_SHORT_VECTOR; + xCoordinates.push(abs); + } else { + xCoordinates.push(delta); + } + } + + lastX = x; + const y = contour.yCoordinates[i]; + delta = y - lastY; + + if (delta === 0) { + flag |= Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR; + yCoordinates.push(0); + } else { + const abs = Math.abs(delta); + + if (abs <= 255) { + flag |= delta >= 0 ? Y_SHORT_VECTOR | Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR : Y_SHORT_VECTOR; + yCoordinates.push(abs); + } else { + yCoordinates.push(delta); + } + } + + lastY = y; + flags.push(flag); + } + + buf.setUint16(pos, xCoordinates.length - 1); + pos += 2; + } + + buf.setUint16(pos, this.instructions.length); + pos += 2; + + if (this.instructions.length) { + new Uint8Array(buf.buffer, 0, buf.buffer.byteLength).set(this.instructions, pos); + pos += this.instructions.length; + } + + for (const flag of flags) { + buf.setUint8(pos++, flag); + } + + for (let i = 0, ii = xCoordinates.length; i < ii; i++) { + const x = xCoordinates[i]; + const flag = flags[i]; + + if (flag & X_SHORT_VECTOR) { + buf.setUint8(pos++, x); + } else if (!(flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR)) { + buf.setInt16(pos, x); + pos += 2; + } + } + + for (let i = 0, ii = yCoordinates.length; i < ii; i++) { + const y = yCoordinates[i]; + const flag = flags[i]; + + if (flag & Y_SHORT_VECTOR) { + buf.setUint8(pos++, y); + } else if (!(flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR)) { + buf.setInt16(pos, y); + pos += 2; + } + } + + return pos - spos; + } + + scale(x, factor) { + for (const contour of this.contours) { + if (contour.xCoordinates.length === 0) { + continue; + } + + for (let i = 0, ii = contour.xCoordinates.length; i < ii; i++) { + contour.xCoordinates[i] = Math.round(x + (contour.xCoordinates[i] - x) * factor); + } + } + } + +} + +class CompositeGlyph { + constructor({ + flags, + glyphIndex, + argument1, + argument2, + transf, + instructions + }) { + this.flags = flags; + this.glyphIndex = glyphIndex; + this.argument1 = argument1; + this.argument2 = argument2; + this.transf = transf; + this.instructions = instructions; + } + + static parse(pos, glyf) { + const spos = pos; + const transf = []; + let flags = glyf.getUint16(pos); + const glyphIndex = glyf.getUint16(pos + 2); + pos += 4; + let argument1, argument2; + + if (flags & ARG_1_AND_2_ARE_WORDS) { + if (flags & ARGS_ARE_XY_VALUES) { + argument1 = glyf.getInt16(pos); + argument2 = glyf.getInt16(pos + 2); + } else { + argument1 = glyf.getUint16(pos); + argument2 = glyf.getUint16(pos + 2); + } + + pos += 4; + flags ^= ARG_1_AND_2_ARE_WORDS; + } else { + if (flags & ARGS_ARE_XY_VALUES) { + argument1 = glyf.getInt8(pos); + argument2 = glyf.getInt8(pos + 1); + } else { + argument1 = glyf.getUint8(pos); + argument2 = glyf.getUint8(pos + 1); + } + + pos += 2; + } + + if (flags & WE_HAVE_A_SCALE) { + transf.push(glyf.getUint16(pos)); + pos += 2; + } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { + transf.push(glyf.getUint16(pos), glyf.getUint16(pos + 2)); + pos += 4; + } else if (flags & WE_HAVE_A_TWO_BY_TWO) { + transf.push(glyf.getUint16(pos), glyf.getUint16(pos + 2), glyf.getUint16(pos + 4), glyf.getUint16(pos + 6)); + pos += 8; + } + + let instructions = null; + + if (flags & WE_HAVE_INSTRUCTIONS) { + const instructionLength = glyf.getUint16(pos); + pos += 2; + instructions = new Uint8Array(glyf).slice(pos, pos + instructionLength); + pos += instructionLength; + } + + return [pos - spos, new CompositeGlyph({ + flags, + glyphIndex, + argument1, + argument2, + transf, + instructions + })]; + } + + getSize() { + let size = 2 + 2 + this.transf.length * 2; + + if (this.flags & WE_HAVE_INSTRUCTIONS) { + size += 2 + this.instructions.length; + } + + size += 2; + + if (this.flags & 2) { + if (!(this.argument1 >= -128 && this.argument1 <= 127 && this.argument2 >= -128 && this.argument2 <= 127)) { + size += 2; + } + } else { + if (!(this.argument1 >= 0 && this.argument1 <= 255 && this.argument2 >= 0 && this.argument2 <= 255)) { + size += 2; + } + } + + return size; + } + + write(pos, buf) { + const spos = pos; + + if (this.flags & ARGS_ARE_XY_VALUES) { + if (!(this.argument1 >= -128 && this.argument1 <= 127 && this.argument2 >= -128 && this.argument2 <= 127)) { + this.flags |= ARG_1_AND_2_ARE_WORDS; + } + } else { + if (!(this.argument1 >= 0 && this.argument1 <= 255 && this.argument2 >= 0 && this.argument2 <= 255)) { + this.flags |= ARG_1_AND_2_ARE_WORDS; + } + } + + buf.setUint16(pos, this.flags); + buf.setUint16(pos + 2, this.glyphIndex); + pos += 4; + + if (this.flags & ARG_1_AND_2_ARE_WORDS) { + if (this.flags & ARGS_ARE_XY_VALUES) { + buf.setInt16(pos, this.argument1); + buf.setInt16(pos + 2, this.argument2); + } else { + buf.setUint16(pos, this.argument1); + buf.setUint16(pos + 2, this.argument2); + } + + pos += 4; + } else { + buf.setUint8(pos, this.argument1); + buf.setUint8(pos + 1, this.argument2); + pos += 2; + } + + if (this.flags & WE_HAVE_INSTRUCTIONS) { + buf.setUint16(pos, this.instructions.length); + pos += 2; + + if (this.instructions.length) { + new Uint8Array(buf.buffer, 0, buf.buffer.byteLength).set(this.instructions, pos); + pos += this.instructions.length; + } + } + + return pos - spos; + } + + scale(x, factor) {} + +} + +/***/ }), +/* 47 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.OpenTypeFileBuilder = void 0; + +var _core_utils = __w_pdfjs_require__(6); + +var _util = __w_pdfjs_require__(2); + +function writeInt16(dest, offset, num) { + dest[offset] = num >> 8 & 0xff; + dest[offset + 1] = num & 0xff; +} + +function writeInt32(dest, offset, num) { + dest[offset] = num >> 24 & 0xff; + dest[offset + 1] = num >> 16 & 0xff; + dest[offset + 2] = num >> 8 & 0xff; + dest[offset + 3] = num & 0xff; +} + +function writeData(dest, offset, data) { + if (data instanceof Uint8Array) { + dest.set(data, offset); + } else if (typeof data === "string") { + for (let i = 0, ii = data.length; i < ii; i++) { + dest[offset++] = data.charCodeAt(i) & 0xff; + } + } else { + for (let i = 0, ii = data.length; i < ii; i++) { + dest[offset++] = data[i] & 0xff; + } + } +} + +const OTF_HEADER_SIZE = 12; +const OTF_TABLE_ENTRY_SIZE = 16; + +class OpenTypeFileBuilder { + constructor(sfnt) { + this.sfnt = sfnt; + this.tables = Object.create(null); + } + + static getSearchParams(entriesCount, entrySize) { + let maxPower2 = 1, + log2 = 0; + + while ((maxPower2 ^ entriesCount) > maxPower2) { + maxPower2 <<= 1; + log2++; + } + + const searchRange = maxPower2 * entrySize; + return { + range: searchRange, + entry: log2, + rangeShift: entrySize * entriesCount - searchRange + }; + } + + toArray() { + let sfnt = this.sfnt; + const tables = this.tables; + const tablesNames = Object.keys(tables); + tablesNames.sort(); + const numTables = tablesNames.length; + let i, j, jj, table, tableName; + let offset = OTF_HEADER_SIZE + numTables * OTF_TABLE_ENTRY_SIZE; + const tableOffsets = [offset]; + + for (i = 0; i < numTables; i++) { + table = tables[tablesNames[i]]; + const paddedLength = (table.length + 3 & ~3) >>> 0; + offset += paddedLength; + tableOffsets.push(offset); + } + + const file = new Uint8Array(offset); + + for (i = 0; i < numTables; i++) { + table = tables[tablesNames[i]]; + writeData(file, tableOffsets[i], table); + } + + if (sfnt === "true") { + sfnt = (0, _util.string32)(0x00010000); + } + + file[0] = sfnt.charCodeAt(0) & 0xff; + file[1] = sfnt.charCodeAt(1) & 0xff; + file[2] = sfnt.charCodeAt(2) & 0xff; + file[3] = sfnt.charCodeAt(3) & 0xff; + writeInt16(file, 4, numTables); + const searchParams = OpenTypeFileBuilder.getSearchParams(numTables, 16); + writeInt16(file, 6, searchParams.range); + writeInt16(file, 8, searchParams.entry); + writeInt16(file, 10, searchParams.rangeShift); + offset = OTF_HEADER_SIZE; + + for (i = 0; i < numTables; i++) { + tableName = tablesNames[i]; + file[offset] = tableName.charCodeAt(0) & 0xff; + file[offset + 1] = tableName.charCodeAt(1) & 0xff; + file[offset + 2] = tableName.charCodeAt(2) & 0xff; + file[offset + 3] = tableName.charCodeAt(3) & 0xff; + let checksum = 0; + + for (j = tableOffsets[i], jj = tableOffsets[i + 1]; j < jj; j += 4) { + const quad = (0, _core_utils.readUint32)(file, j); + checksum = checksum + quad >>> 0; + } + + writeInt32(file, offset + 4, checksum); + writeInt32(file, offset + 8, tableOffsets[i]); + writeInt32(file, offset + 12, tables[tableName].length); + offset += OTF_TABLE_ENTRY_SIZE; + } + + return file; + } + + addTable(tag, data) { + if (tag in this.tables) { + throw new Error("Table " + tag + " already exists"); + } + + this.tables[tag] = data; + } + +} + +exports.OpenTypeFileBuilder = OpenTypeFileBuilder; + +/***/ }), +/* 48 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Type1Font = void 0; + +var _cff_parser = __w_pdfjs_require__(35); + +var _fonts_utils = __w_pdfjs_require__(38); + +var _core_utils = __w_pdfjs_require__(6); + +var _stream = __w_pdfjs_require__(10); + +var _type1_parser = __w_pdfjs_require__(49); + +var _util = __w_pdfjs_require__(2); + +function findBlock(streamBytes, signature, startIndex) { + const streamBytesLength = streamBytes.length; + const signatureLength = signature.length; + const scanLength = streamBytesLength - signatureLength; + let i = startIndex, + found = false; + + while (i < scanLength) { + let j = 0; + + while (j < signatureLength && streamBytes[i + j] === signature[j]) { + j++; + } + + if (j >= signatureLength) { + i += j; + + while (i < streamBytesLength && (0, _core_utils.isWhiteSpace)(streamBytes[i])) { + i++; + } + + found = true; + break; + } + + i++; + } + + return { + found, + length: i + }; +} + +function getHeaderBlock(stream, suggestedLength) { + const EEXEC_SIGNATURE = [0x65, 0x65, 0x78, 0x65, 0x63]; + const streamStartPos = stream.pos; + let headerBytes, headerBytesLength, block; + + try { + headerBytes = stream.getBytes(suggestedLength); + headerBytesLength = headerBytes.length; + } catch (ex) {} + + if (headerBytesLength === suggestedLength) { + block = findBlock(headerBytes, EEXEC_SIGNATURE, suggestedLength - 2 * EEXEC_SIGNATURE.length); + + if (block.found && block.length === suggestedLength) { + return { + stream: new _stream.Stream(headerBytes), + length: suggestedLength + }; + } + } + + (0, _util.warn)('Invalid "Length1" property in Type1 font -- trying to recover.'); + stream.pos = streamStartPos; + const SCAN_BLOCK_LENGTH = 2048; + let actualLength; + + while (true) { + const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH); + block = findBlock(scanBytes, EEXEC_SIGNATURE, 0); + + if (block.length === 0) { + break; + } + + stream.pos += block.length; + + if (block.found) { + actualLength = stream.pos - streamStartPos; + break; + } + } + + stream.pos = streamStartPos; + + if (actualLength) { + return { + stream: new _stream.Stream(stream.getBytes(actualLength)), + length: actualLength + }; + } + + (0, _util.warn)('Unable to recover "Length1" property in Type1 font -- using as is.'); + return { + stream: new _stream.Stream(stream.getBytes(suggestedLength)), + length: suggestedLength + }; +} + +function getEexecBlock(stream, suggestedLength) { + const eexecBytes = stream.getBytes(); + return { + stream: new _stream.Stream(eexecBytes), + length: eexecBytes.length + }; +} + +class Type1Font { + constructor(name, file, properties) { + const PFB_HEADER_SIZE = 6; + let headerBlockLength = properties.length1; + let eexecBlockLength = properties.length2; + let pfbHeader = file.peekBytes(PFB_HEADER_SIZE); + const pfbHeaderPresent = pfbHeader[0] === 0x80 && pfbHeader[1] === 0x01; + + if (pfbHeaderPresent) { + file.skip(PFB_HEADER_SIZE); + headerBlockLength = pfbHeader[5] << 24 | pfbHeader[4] << 16 | pfbHeader[3] << 8 | pfbHeader[2]; + } + + const headerBlock = getHeaderBlock(file, headerBlockLength); + const headerBlockParser = new _type1_parser.Type1Parser(headerBlock.stream, false, _fonts_utils.SEAC_ANALYSIS_ENABLED); + headerBlockParser.extractFontHeader(properties); + + if (pfbHeaderPresent) { + pfbHeader = file.getBytes(PFB_HEADER_SIZE); + eexecBlockLength = pfbHeader[5] << 24 | pfbHeader[4] << 16 | pfbHeader[3] << 8 | pfbHeader[2]; + } + + const eexecBlock = getEexecBlock(file, eexecBlockLength); + const eexecBlockParser = new _type1_parser.Type1Parser(eexecBlock.stream, true, _fonts_utils.SEAC_ANALYSIS_ENABLED); + const data = eexecBlockParser.extractFontProgram(properties); + + for (const key in data.properties) { + properties[key] = data.properties[key]; + } + + const charstrings = data.charstrings; + const type2Charstrings = this.getType2Charstrings(charstrings); + const subrs = this.getType2Subrs(data.subrs); + this.charstrings = charstrings; + this.data = this.wrap(name, type2Charstrings, this.charstrings, subrs, properties); + this.seacs = this.getSeacs(data.charstrings); + } + + get numGlyphs() { + return this.charstrings.length + 1; + } + + getCharset() { + const charset = [".notdef"]; + + for (const { + glyphName + } of this.charstrings) { + charset.push(glyphName); + } + + return charset; + } + + getGlyphMapping(properties) { + const charstrings = this.charstrings; + + if (properties.composite) { + const charCodeToGlyphId = Object.create(null); + + for (let glyphId = 0, charstringsLen = charstrings.length; glyphId < charstringsLen; glyphId++) { + const charCode = properties.cMap.charCodeOf(glyphId); + charCodeToGlyphId[charCode] = glyphId + 1; + } + + return charCodeToGlyphId; + } + + const glyphNames = [".notdef"]; + let builtInEncoding, glyphId; + + for (glyphId = 0; glyphId < charstrings.length; glyphId++) { + glyphNames.push(charstrings[glyphId].glyphName); + } + + const encoding = properties.builtInEncoding; + + if (encoding) { + builtInEncoding = Object.create(null); + + for (const charCode in encoding) { + glyphId = glyphNames.indexOf(encoding[charCode]); + + if (glyphId >= 0) { + builtInEncoding[charCode] = glyphId; + } + } + } + + return (0, _fonts_utils.type1FontGlyphMapping)(properties, builtInEncoding, glyphNames); + } + + hasGlyphId(id) { + if (id < 0 || id >= this.numGlyphs) { + return false; + } + + if (id === 0) { + return true; + } + + const glyph = this.charstrings[id - 1]; + return glyph.charstring.length > 0; + } + + getSeacs(charstrings) { + const seacMap = []; + + for (let i = 0, ii = charstrings.length; i < ii; i++) { + const charstring = charstrings[i]; + + if (charstring.seac) { + seacMap[i + 1] = charstring.seac; + } + } + + return seacMap; + } + + getType2Charstrings(type1Charstrings) { + const type2Charstrings = []; + + for (let i = 0, ii = type1Charstrings.length; i < ii; i++) { + type2Charstrings.push(type1Charstrings[i].charstring); + } + + return type2Charstrings; + } + + getType2Subrs(type1Subrs) { + let bias = 0; + const count = type1Subrs.length; + + if (count < 1133) { + bias = 107; + } else if (count < 33769) { + bias = 1131; + } else { + bias = 32768; + } + + const type2Subrs = []; + let i; + + for (i = 0; i < bias; i++) { + type2Subrs.push([0x0b]); + } + + for (i = 0; i < count; i++) { + type2Subrs.push(type1Subrs[i]); + } + + return type2Subrs; + } + + wrap(name, glyphs, charstrings, subrs, properties) { + const cff = new _cff_parser.CFF(); + cff.header = new _cff_parser.CFFHeader(1, 0, 4, 4); + cff.names = [name]; + const topDict = new _cff_parser.CFFTopDict(); + topDict.setByName("version", 391); + topDict.setByName("Notice", 392); + topDict.setByName("FullName", 393); + topDict.setByName("FamilyName", 394); + topDict.setByName("Weight", 395); + topDict.setByName("Encoding", null); + topDict.setByName("FontMatrix", properties.fontMatrix); + topDict.setByName("FontBBox", properties.bbox); + topDict.setByName("charset", null); + topDict.setByName("CharStrings", null); + topDict.setByName("Private", null); + cff.topDict = topDict; + const strings = new _cff_parser.CFFStrings(); + strings.add("Version 0.11"); + strings.add("See original notice"); + strings.add(name); + strings.add(name); + strings.add("Medium"); + cff.strings = strings; + cff.globalSubrIndex = new _cff_parser.CFFIndex(); + const count = glyphs.length; + const charsetArray = [".notdef"]; + let i, ii; + + for (i = 0; i < count; i++) { + const glyphName = charstrings[i].glyphName; + + const index = _cff_parser.CFFStandardStrings.indexOf(glyphName); + + if (index === -1) { + strings.add(glyphName); + } + + charsetArray.push(glyphName); + } + + cff.charset = new _cff_parser.CFFCharset(false, 0, charsetArray); + const charStringsIndex = new _cff_parser.CFFIndex(); + charStringsIndex.add([0x8b, 0x0e]); + + for (i = 0; i < count; i++) { + charStringsIndex.add(glyphs[i]); + } + + cff.charStrings = charStringsIndex; + const privateDict = new _cff_parser.CFFPrivateDict(); + privateDict.setByName("Subrs", null); + const fields = ["BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StemSnapH", "StemSnapV", "BlueShift", "BlueFuzz", "BlueScale", "LanguageGroup", "ExpansionFactor", "ForceBold", "StdHW", "StdVW"]; + + for (i = 0, ii = fields.length; i < ii; i++) { + const field = fields[i]; + + if (!(field in properties.privateData)) { + continue; + } + + const value = properties.privateData[field]; + + if (Array.isArray(value)) { + for (let j = value.length - 1; j > 0; j--) { + value[j] -= value[j - 1]; + } + } + + privateDict.setByName(field, value); + } + + cff.topDict.privateDict = privateDict; + const subrIndex = new _cff_parser.CFFIndex(); + + for (i = 0, ii = subrs.length; i < ii; i++) { + subrIndex.add(subrs[i]); + } + + privateDict.subrsIndex = subrIndex; + const compiler = new _cff_parser.CFFCompiler(cff); + return compiler.compile(); + } + +} + +exports.Type1Font = Type1Font; + +/***/ }), +/* 49 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Type1Parser = void 0; + +var _encodings = __w_pdfjs_require__(37); + +var _core_utils = __w_pdfjs_require__(6); + +var _stream = __w_pdfjs_require__(10); + +var _util = __w_pdfjs_require__(2); + +const HINTING_ENABLED = false; +const COMMAND_MAP = { + hstem: [1], + vstem: [3], + vmoveto: [4], + rlineto: [5], + hlineto: [6], + vlineto: [7], + rrcurveto: [8], + callsubr: [10], + flex: [12, 35], + drop: [12, 18], + endchar: [14], + rmoveto: [21], + hmoveto: [22], + vhcurveto: [30], + hvcurveto: [31] +}; + +class Type1CharString { + constructor() { + this.width = 0; + this.lsb = 0; + this.flexing = false; + this.output = []; + this.stack = []; + } + + convert(encoded, subrs, seacAnalysisEnabled) { + const count = encoded.length; + let error = false; + let wx, sbx, subrNumber; + + for (let i = 0; i < count; i++) { + let value = encoded[i]; + + if (value < 32) { + if (value === 12) { + value = (value << 8) + encoded[++i]; + } + + switch (value) { + case 1: + if (!HINTING_ENABLED) { + this.stack = []; + break; + } + + error = this.executeCommand(2, COMMAND_MAP.hstem); + break; + + case 3: + if (!HINTING_ENABLED) { + this.stack = []; + break; + } + + error = this.executeCommand(2, COMMAND_MAP.vstem); + break; + + case 4: + if (this.flexing) { + if (this.stack.length < 1) { + error = true; + break; + } + + const dy = this.stack.pop(); + this.stack.push(0, dy); + break; + } + + error = this.executeCommand(1, COMMAND_MAP.vmoveto); + break; + + case 5: + error = this.executeCommand(2, COMMAND_MAP.rlineto); + break; + + case 6: + error = this.executeCommand(1, COMMAND_MAP.hlineto); + break; + + case 7: + error = this.executeCommand(1, COMMAND_MAP.vlineto); + break; + + case 8: + error = this.executeCommand(6, COMMAND_MAP.rrcurveto); + break; + + case 9: + this.stack = []; + break; + + case 10: + if (this.stack.length < 1) { + error = true; + break; + } + + subrNumber = this.stack.pop(); + + if (!subrs[subrNumber]) { + error = true; + break; + } + + error = this.convert(subrs[subrNumber], subrs, seacAnalysisEnabled); + break; + + case 11: + return error; + + case 13: + if (this.stack.length < 2) { + error = true; + break; + } + + wx = this.stack.pop(); + sbx = this.stack.pop(); + this.lsb = sbx; + this.width = wx; + this.stack.push(wx, sbx); + error = this.executeCommand(2, COMMAND_MAP.hmoveto); + break; + + case 14: + this.output.push(COMMAND_MAP.endchar[0]); + break; + + case 21: + if (this.flexing) { + break; + } + + error = this.executeCommand(2, COMMAND_MAP.rmoveto); + break; + + case 22: + if (this.flexing) { + this.stack.push(0); + break; + } + + error = this.executeCommand(1, COMMAND_MAP.hmoveto); + break; + + case 30: + error = this.executeCommand(4, COMMAND_MAP.vhcurveto); + break; + + case 31: + error = this.executeCommand(4, COMMAND_MAP.hvcurveto); + break; + + case (12 << 8) + 0: + this.stack = []; + break; + + case (12 << 8) + 1: + if (!HINTING_ENABLED) { + this.stack = []; + break; + } + + error = this.executeCommand(2, COMMAND_MAP.vstem); + break; + + case (12 << 8) + 2: + if (!HINTING_ENABLED) { + this.stack = []; + break; + } + + error = this.executeCommand(2, COMMAND_MAP.hstem); + break; + + case (12 << 8) + 6: + if (seacAnalysisEnabled) { + const asb = this.stack.at(-5); + this.seac = this.stack.splice(-4, 4); + this.seac[0] += this.lsb - asb; + error = this.executeCommand(0, COMMAND_MAP.endchar); + } else { + error = this.executeCommand(4, COMMAND_MAP.endchar); + } + + break; + + case (12 << 8) + 7: + if (this.stack.length < 4) { + error = true; + break; + } + + this.stack.pop(); + wx = this.stack.pop(); + const sby = this.stack.pop(); + sbx = this.stack.pop(); + this.lsb = sbx; + this.width = wx; + this.stack.push(wx, sbx, sby); + error = this.executeCommand(3, COMMAND_MAP.rmoveto); + break; + + case (12 << 8) + 12: + if (this.stack.length < 2) { + error = true; + break; + } + + const num2 = this.stack.pop(); + const num1 = this.stack.pop(); + this.stack.push(num1 / num2); + break; + + case (12 << 8) + 16: + if (this.stack.length < 2) { + error = true; + break; + } + + subrNumber = this.stack.pop(); + const numArgs = this.stack.pop(); + + if (subrNumber === 0 && numArgs === 3) { + const flexArgs = this.stack.splice(this.stack.length - 17, 17); + this.stack.push(flexArgs[2] + flexArgs[0], flexArgs[3] + flexArgs[1], flexArgs[4], flexArgs[5], flexArgs[6], flexArgs[7], flexArgs[8], flexArgs[9], flexArgs[10], flexArgs[11], flexArgs[12], flexArgs[13], flexArgs[14]); + error = this.executeCommand(13, COMMAND_MAP.flex, true); + this.flexing = false; + this.stack.push(flexArgs[15], flexArgs[16]); + } else if (subrNumber === 1 && numArgs === 0) { + this.flexing = true; + } + + break; + + case (12 << 8) + 17: + break; + + case (12 << 8) + 33: + this.stack = []; + break; + + default: + (0, _util.warn)('Unknown type 1 charstring command of "' + value + '"'); + break; + } + + if (error) { + break; + } + + continue; + } else if (value <= 246) { + value -= 139; + } else if (value <= 250) { + value = (value - 247) * 256 + encoded[++i] + 108; + } else if (value <= 254) { + value = -((value - 251) * 256) - encoded[++i] - 108; + } else { + value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 | (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0; + } + + this.stack.push(value); + } + + return error; + } + + executeCommand(howManyArgs, command, keepStack) { + const stackLength = this.stack.length; + + if (howManyArgs > stackLength) { + return true; + } + + const start = stackLength - howManyArgs; + + for (let i = start; i < stackLength; i++) { + let value = this.stack[i]; + + if (Number.isInteger(value)) { + this.output.push(28, value >> 8 & 0xff, value & 0xff); + } else { + value = 65536 * value | 0; + this.output.push(255, value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff); + } + } + + this.output.push(...command); + + if (keepStack) { + this.stack.splice(start, howManyArgs); + } else { + this.stack.length = 0; + } + + return false; + } + +} + +const EEXEC_ENCRYPT_KEY = 55665; +const CHAR_STRS_ENCRYPT_KEY = 4330; + +function isHexDigit(code) { + return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102; +} + +function decrypt(data, key, discardNumber) { + if (discardNumber >= data.length) { + return new Uint8Array(0); + } + + const c1 = 52845, + c2 = 22719; + let r = key | 0, + i, + j; + + for (i = 0; i < discardNumber; i++) { + r = (data[i] + r) * c1 + c2 & (1 << 16) - 1; + } + + const count = data.length - discardNumber; + const decrypted = new Uint8Array(count); + + for (i = discardNumber, j = 0; j < count; i++, j++) { + const value = data[i]; + decrypted[j] = value ^ r >> 8; + r = (value + r) * c1 + c2 & (1 << 16) - 1; + } + + return decrypted; +} + +function decryptAscii(data, key, discardNumber) { + const c1 = 52845, + c2 = 22719; + let r = key | 0; + const count = data.length, + maybeLength = count >>> 1; + const decrypted = new Uint8Array(maybeLength); + let i, j; + + for (i = 0, j = 0; i < count; i++) { + const digit1 = data[i]; + + if (!isHexDigit(digit1)) { + continue; + } + + i++; + let digit2; + + while (i < count && !isHexDigit(digit2 = data[i])) { + i++; + } + + if (i < count) { + const value = parseInt(String.fromCharCode(digit1, digit2), 16); + decrypted[j++] = value ^ r >> 8; + r = (value + r) * c1 + c2 & (1 << 16) - 1; + } + } + + return decrypted.slice(discardNumber, j); +} + +function isSpecial(c) { + return c === 0x2f || c === 0x5b || c === 0x5d || c === 0x7b || c === 0x7d || c === 0x28 || c === 0x29; +} + +class Type1Parser { + constructor(stream, encrypted, seacAnalysisEnabled) { + if (encrypted) { + const data = stream.getBytes(); + const isBinary = !((isHexDigit(data[0]) || (0, _core_utils.isWhiteSpace)(data[0])) && isHexDigit(data[1]) && isHexDigit(data[2]) && isHexDigit(data[3]) && isHexDigit(data[4]) && isHexDigit(data[5]) && isHexDigit(data[6]) && isHexDigit(data[7])); + stream = new _stream.Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) : decryptAscii(data, EEXEC_ENCRYPT_KEY, 4)); + } + + this.seacAnalysisEnabled = !!seacAnalysisEnabled; + this.stream = stream; + this.nextChar(); + } + + readNumberArray() { + this.getToken(); + const array = []; + + while (true) { + const token = this.getToken(); + + if (token === null || token === "]" || token === "}") { + break; + } + + array.push(parseFloat(token || 0)); + } + + return array; + } + + readNumber() { + const token = this.getToken(); + return parseFloat(token || 0); + } + + readInt() { + const token = this.getToken(); + return parseInt(token || 0, 10) | 0; + } + + readBoolean() { + const token = this.getToken(); + return token === "true" ? 1 : 0; + } + + nextChar() { + return this.currentChar = this.stream.getByte(); + } + + prevChar() { + this.stream.skip(-2); + return this.currentChar = this.stream.getByte(); + } + + getToken() { + let comment = false; + let ch = this.currentChar; + + while (true) { + if (ch === -1) { + return null; + } + + if (comment) { + if (ch === 0x0a || ch === 0x0d) { + comment = false; + } + } else if (ch === 0x25) { + comment = true; + } else if (!(0, _core_utils.isWhiteSpace)(ch)) { + break; + } + + ch = this.nextChar(); + } + + if (isSpecial(ch)) { + this.nextChar(); + return String.fromCharCode(ch); + } + + let token = ""; + + do { + token += String.fromCharCode(ch); + ch = this.nextChar(); + } while (ch >= 0 && !(0, _core_utils.isWhiteSpace)(ch) && !isSpecial(ch)); + + return token; + } + + readCharStrings(bytes, lenIV) { + if (lenIV === -1) { + return bytes; + } + + return decrypt(bytes, CHAR_STRS_ENCRYPT_KEY, lenIV); + } + + extractFontProgram(properties) { + const stream = this.stream; + const subrs = [], + charstrings = []; + const privateData = Object.create(null); + privateData.lenIV = 4; + const program = { + subrs: [], + charstrings: [], + properties: { + privateData + } + }; + let token, length, data, lenIV; + + while ((token = this.getToken()) !== null) { + if (token !== "/") { + continue; + } + + token = this.getToken(); + + switch (token) { + case "CharStrings": + this.getToken(); + this.getToken(); + this.getToken(); + this.getToken(); + + while (true) { + token = this.getToken(); + + if (token === null || token === "end") { + break; + } + + if (token !== "/") { + continue; + } + + const glyph = this.getToken(); + length = this.readInt(); + this.getToken(); + data = length > 0 ? stream.getBytes(length) : new Uint8Array(0); + lenIV = program.properties.privateData.lenIV; + const encoded = this.readCharStrings(data, lenIV); + this.nextChar(); + token = this.getToken(); + + if (token === "noaccess") { + this.getToken(); + } else if (token === "/") { + this.prevChar(); + } + + charstrings.push({ + glyph, + encoded + }); + } + + break; + + case "Subrs": + this.readInt(); + this.getToken(); + + while (this.getToken() === "dup") { + const index = this.readInt(); + length = this.readInt(); + this.getToken(); + data = length > 0 ? stream.getBytes(length) : new Uint8Array(0); + lenIV = program.properties.privateData.lenIV; + const encoded = this.readCharStrings(data, lenIV); + this.nextChar(); + token = this.getToken(); + + if (token === "noaccess") { + this.getToken(); + } + + subrs[index] = encoded; + } + + break; + + case "BlueValues": + case "OtherBlues": + case "FamilyBlues": + case "FamilyOtherBlues": + const blueArray = this.readNumberArray(); + + if (blueArray.length > 0 && blueArray.length % 2 === 0 && HINTING_ENABLED) { + program.properties.privateData[token] = blueArray; + } + + break; + + case "StemSnapH": + case "StemSnapV": + program.properties.privateData[token] = this.readNumberArray(); + break; + + case "StdHW": + case "StdVW": + program.properties.privateData[token] = this.readNumberArray()[0]; + break; + + case "BlueShift": + case "lenIV": + case "BlueFuzz": + case "BlueScale": + case "LanguageGroup": + case "ExpansionFactor": + program.properties.privateData[token] = this.readNumber(); + break; + + case "ForceBold": + program.properties.privateData[token] = this.readBoolean(); + break; + } + } + + for (const { + encoded, + glyph + } of charstrings) { + const charString = new Type1CharString(); + const error = charString.convert(encoded, subrs, this.seacAnalysisEnabled); + let output = charString.output; + + if (error) { + output = [14]; + } + + const charStringObject = { + glyphName: glyph, + charstring: output, + width: charString.width, + lsb: charString.lsb, + seac: charString.seac + }; + + if (glyph === ".notdef") { + program.charstrings.unshift(charStringObject); + } else { + program.charstrings.push(charStringObject); + } + + if (properties.builtInEncoding) { + const index = properties.builtInEncoding.indexOf(glyph); + + if (index > -1 && properties.widths[index] === undefined && index >= properties.firstChar && index <= properties.lastChar) { + properties.widths[index] = charString.width; + } + } + } + + return program; + } + + extractFontHeader(properties) { + let token; + + while ((token = this.getToken()) !== null) { + if (token !== "/") { + continue; + } + + token = this.getToken(); + + switch (token) { + case "FontMatrix": + const matrix = this.readNumberArray(); + properties.fontMatrix = matrix; + break; + + case "Encoding": + const encodingArg = this.getToken(); + let encoding; + + if (!/^\d+$/.test(encodingArg)) { + encoding = (0, _encodings.getEncoding)(encodingArg); + } else { + encoding = []; + const size = parseInt(encodingArg, 10) | 0; + this.getToken(); + + for (let j = 0; j < size; j++) { + token = this.getToken(); + + while (token !== "dup" && token !== "def") { + token = this.getToken(); + + if (token === null) { + return; + } + } + + if (token === "def") { + break; + } + + const index = this.readInt(); + this.getToken(); + const glyph = this.getToken(); + encoding[index] = glyph; + this.getToken(); + } + } + + properties.builtInEncoding = encoding; + break; + + case "FontBBox": + const fontBBox = this.readNumberArray(); + properties.ascent = Math.max(fontBBox[3], fontBBox[1]); + properties.descent = Math.min(fontBBox[1], fontBBox[3]); + properties.ascentScaled = true; + break; + } + } + } + +} + +exports.Type1Parser = Type1Parser; + +/***/ }), +/* 50 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Pattern = void 0; +exports.getTilingPatternIR = getTilingPatternIR; + +var _util = __w_pdfjs_require__(2); + +var _base_stream = __w_pdfjs_require__(7); + +var _colorspace = __w_pdfjs_require__(14); + +var _core_utils = __w_pdfjs_require__(6); + +const ShadingType = { + FUNCTION_BASED: 1, + AXIAL: 2, + RADIAL: 3, + FREE_FORM_MESH: 4, + LATTICE_FORM_MESH: 5, + COONS_PATCH_MESH: 6, + TENSOR_PATCH_MESH: 7 +}; + +class Pattern { + constructor() { + (0, _util.unreachable)("Cannot initialize Pattern."); + } + + static parseShading(shading, xref, res, handler, pdfFunctionFactory, localColorSpaceCache) { + const dict = shading instanceof _base_stream.BaseStream ? shading.dict : shading; + const type = dict.get("ShadingType"); + + try { + switch (type) { + case ShadingType.AXIAL: + case ShadingType.RADIAL: + return new RadialAxialShading(dict, xref, res, pdfFunctionFactory, localColorSpaceCache); + + case ShadingType.FREE_FORM_MESH: + case ShadingType.LATTICE_FORM_MESH: + case ShadingType.COONS_PATCH_MESH: + case ShadingType.TENSOR_PATCH_MESH: + return new MeshShading(shading, xref, res, pdfFunctionFactory, localColorSpaceCache); + + default: + throw new _util.FormatError("Unsupported ShadingType: " + type); + } + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + handler.send("UnsupportedFeature", { + featureId: _util.UNSUPPORTED_FEATURES.shadingPattern + }); + (0, _util.warn)(ex); + return new DummyShading(); + } + } + +} + +exports.Pattern = Pattern; + +class BaseShading { + static get SMALL_NUMBER() { + return (0, _util.shadow)(this, "SMALL_NUMBER", 1e-6); + } + + constructor() { + if (this.constructor === BaseShading) { + (0, _util.unreachable)("Cannot initialize BaseShading."); + } + } + + getIR() { + (0, _util.unreachable)("Abstract method `getIR` called."); + } + +} + +class RadialAxialShading extends BaseShading { + constructor(dict, xref, resources, pdfFunctionFactory, localColorSpaceCache) { + super(); + this.coordsArr = dict.getArray("Coords"); + this.shadingType = dict.get("ShadingType"); + + const cs = _colorspace.ColorSpace.parse({ + cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"), + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache + }); + + const bbox = dict.getArray("BBox"); + + if (Array.isArray(bbox) && bbox.length === 4) { + this.bbox = _util.Util.normalizeRect(bbox); + } else { + this.bbox = null; + } + + let t0 = 0.0, + t1 = 1.0; + + if (dict.has("Domain")) { + const domainArr = dict.getArray("Domain"); + t0 = domainArr[0]; + t1 = domainArr[1]; + } + + let extendStart = false, + extendEnd = false; + + if (dict.has("Extend")) { + const extendArr = dict.getArray("Extend"); + extendStart = extendArr[0]; + extendEnd = extendArr[1]; + } + + if (this.shadingType === ShadingType.RADIAL && (!extendStart || !extendEnd)) { + const [x1, y1, r1, x2, y2, r2] = this.coordsArr; + const distance = Math.hypot(x1 - x2, y1 - y2); + + if (r1 <= r2 + distance && r2 <= r1 + distance) { + (0, _util.warn)("Unsupported radial gradient."); + } + } + + this.extendStart = extendStart; + this.extendEnd = extendEnd; + const fnObj = dict.getRaw("Function"); + const fn = pdfFunctionFactory.createFromArray(fnObj); + const NUMBER_OF_SAMPLES = 10; + const step = (t1 - t0) / NUMBER_OF_SAMPLES; + const colorStops = this.colorStops = []; + + if (t0 >= t1 || step <= 0) { + (0, _util.info)("Bad shading domain."); + return; + } + + const color = new Float32Array(cs.numComps), + ratio = new Float32Array(1); + let rgbColor; + + for (let i = 0; i <= NUMBER_OF_SAMPLES; i++) { + ratio[0] = t0 + i * step; + fn(ratio, 0, color, 0); + rgbColor = cs.getRgb(color, 0); + + const cssColor = _util.Util.makeHexColor(rgbColor[0], rgbColor[1], rgbColor[2]); + + colorStops.push([i / NUMBER_OF_SAMPLES, cssColor]); + } + + let background = "transparent"; + + if (dict.has("Background")) { + rgbColor = cs.getRgb(dict.get("Background"), 0); + background = _util.Util.makeHexColor(rgbColor[0], rgbColor[1], rgbColor[2]); + } + + if (!extendStart) { + colorStops.unshift([0, background]); + colorStops[1][0] += BaseShading.SMALL_NUMBER; + } + + if (!extendEnd) { + colorStops.at(-1)[0] -= BaseShading.SMALL_NUMBER; + colorStops.push([1, background]); + } + + this.colorStops = colorStops; + } + + getIR() { + const coordsArr = this.coordsArr; + const shadingType = this.shadingType; + let type, p0, p1, r0, r1; + + if (shadingType === ShadingType.AXIAL) { + p0 = [coordsArr[0], coordsArr[1]]; + p1 = [coordsArr[2], coordsArr[3]]; + r0 = null; + r1 = null; + type = "axial"; + } else if (shadingType === ShadingType.RADIAL) { + p0 = [coordsArr[0], coordsArr[1]]; + p1 = [coordsArr[3], coordsArr[4]]; + r0 = coordsArr[2]; + r1 = coordsArr[5]; + type = "radial"; + } else { + (0, _util.unreachable)(`getPattern type unknown: ${shadingType}`); + } + + return ["RadialAxial", type, this.bbox, this.colorStops, p0, p1, r0, r1]; + } + +} + +class MeshStreamReader { + constructor(stream, context) { + this.stream = stream; + this.context = context; + this.buffer = 0; + this.bufferLength = 0; + const numComps = context.numComps; + this.tmpCompsBuf = new Float32Array(numComps); + const csNumComps = context.colorSpace.numComps; + this.tmpCsCompsBuf = context.colorFn ? new Float32Array(csNumComps) : this.tmpCompsBuf; + } + + get hasData() { + if (this.stream.end) { + return this.stream.pos < this.stream.end; + } + + if (this.bufferLength > 0) { + return true; + } + + const nextByte = this.stream.getByte(); + + if (nextByte < 0) { + return false; + } + + this.buffer = nextByte; + this.bufferLength = 8; + return true; + } + + readBits(n) { + let buffer = this.buffer; + let bufferLength = this.bufferLength; + + if (n === 32) { + if (bufferLength === 0) { + return (this.stream.getByte() << 24 | this.stream.getByte() << 16 | this.stream.getByte() << 8 | this.stream.getByte()) >>> 0; + } + + buffer = buffer << 24 | this.stream.getByte() << 16 | this.stream.getByte() << 8 | this.stream.getByte(); + const nextByte = this.stream.getByte(); + this.buffer = nextByte & (1 << bufferLength) - 1; + return (buffer << 8 - bufferLength | (nextByte & 0xff) >> bufferLength) >>> 0; + } + + if (n === 8 && bufferLength === 0) { + return this.stream.getByte(); + } + + while (bufferLength < n) { + buffer = buffer << 8 | this.stream.getByte(); + bufferLength += 8; + } + + bufferLength -= n; + this.bufferLength = bufferLength; + this.buffer = buffer & (1 << bufferLength) - 1; + return buffer >> bufferLength; + } + + align() { + this.buffer = 0; + this.bufferLength = 0; + } + + readFlag() { + return this.readBits(this.context.bitsPerFlag); + } + + readCoordinate() { + const bitsPerCoordinate = this.context.bitsPerCoordinate; + const xi = this.readBits(bitsPerCoordinate); + const yi = this.readBits(bitsPerCoordinate); + const decode = this.context.decode; + const scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) : 2.3283064365386963e-10; + return [xi * scale * (decode[1] - decode[0]) + decode[0], yi * scale * (decode[3] - decode[2]) + decode[2]]; + } + + readComponents() { + const numComps = this.context.numComps; + const bitsPerComponent = this.context.bitsPerComponent; + const scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) : 2.3283064365386963e-10; + const decode = this.context.decode; + const components = this.tmpCompsBuf; + + for (let i = 0, j = 4; i < numComps; i++, j += 2) { + const ci = this.readBits(bitsPerComponent); + components[i] = ci * scale * (decode[j + 1] - decode[j]) + decode[j]; + } + + const color = this.tmpCsCompsBuf; + + if (this.context.colorFn) { + this.context.colorFn(components, 0, color, 0); + } + + return this.context.colorSpace.getRgb(color, 0); + } + +} + +const getB = function getBClosure() { + function buildB(count) { + const lut = []; + + for (let i = 0; i <= count; i++) { + const t = i / count, + t_ = 1 - t; + lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_, 3 * t * t * t_, t * t * t])); + } + + return lut; + } + + const cache = []; + return function (count) { + if (!cache[count]) { + cache[count] = buildB(count); + } + + return cache[count]; + }; +}(); + +class MeshShading extends BaseShading { + static get MIN_SPLIT_PATCH_CHUNKS_AMOUNT() { + return (0, _util.shadow)(this, "MIN_SPLIT_PATCH_CHUNKS_AMOUNT", 3); + } + + static get MAX_SPLIT_PATCH_CHUNKS_AMOUNT() { + return (0, _util.shadow)(this, "MAX_SPLIT_PATCH_CHUNKS_AMOUNT", 20); + } + + static get TRIANGLE_DENSITY() { + return (0, _util.shadow)(this, "TRIANGLE_DENSITY", 20); + } + + constructor(stream, xref, resources, pdfFunctionFactory, localColorSpaceCache) { + super(); + + if (!(stream instanceof _base_stream.BaseStream)) { + throw new _util.FormatError("Mesh data is not a stream"); + } + + const dict = stream.dict; + this.shadingType = dict.get("ShadingType"); + const bbox = dict.getArray("BBox"); + + if (Array.isArray(bbox) && bbox.length === 4) { + this.bbox = _util.Util.normalizeRect(bbox); + } else { + this.bbox = null; + } + + const cs = _colorspace.ColorSpace.parse({ + cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"), + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache + }); + + this.background = dict.has("Background") ? cs.getRgb(dict.get("Background"), 0) : null; + const fnObj = dict.getRaw("Function"); + const fn = fnObj ? pdfFunctionFactory.createFromArray(fnObj) : null; + this.coords = []; + this.colors = []; + this.figures = []; + const decodeContext = { + bitsPerCoordinate: dict.get("BitsPerCoordinate"), + bitsPerComponent: dict.get("BitsPerComponent"), + bitsPerFlag: dict.get("BitsPerFlag"), + decode: dict.getArray("Decode"), + colorFn: fn, + colorSpace: cs, + numComps: fn ? 1 : cs.numComps + }; + const reader = new MeshStreamReader(stream, decodeContext); + let patchMesh = false; + + switch (this.shadingType) { + case ShadingType.FREE_FORM_MESH: + this._decodeType4Shading(reader); + + break; + + case ShadingType.LATTICE_FORM_MESH: + const verticesPerRow = dict.get("VerticesPerRow") | 0; + + if (verticesPerRow < 2) { + throw new _util.FormatError("Invalid VerticesPerRow"); + } + + this._decodeType5Shading(reader, verticesPerRow); + + break; + + case ShadingType.COONS_PATCH_MESH: + this._decodeType6Shading(reader); + + patchMesh = true; + break; + + case ShadingType.TENSOR_PATCH_MESH: + this._decodeType7Shading(reader); + + patchMesh = true; + break; + + default: + (0, _util.unreachable)("Unsupported mesh type."); + break; + } + + if (patchMesh) { + this._updateBounds(); + + for (let i = 0, ii = this.figures.length; i < ii; i++) { + this._buildFigureFromPatch(i); + } + } + + this._updateBounds(); + + this._packData(); + } + + _decodeType4Shading(reader) { + const coords = this.coords; + const colors = this.colors; + const operators = []; + const ps = []; + let verticesLeft = 0; + + while (reader.hasData) { + const f = reader.readFlag(); + const coord = reader.readCoordinate(); + const color = reader.readComponents(); + + if (verticesLeft === 0) { + if (!(0 <= f && f <= 2)) { + throw new _util.FormatError("Unknown type4 flag"); + } + + switch (f) { + case 0: + verticesLeft = 3; + break; + + case 1: + ps.push(ps.at(-2), ps.at(-1)); + verticesLeft = 1; + break; + + case 2: + ps.push(ps.at(-3), ps.at(-1)); + verticesLeft = 1; + break; + } + + operators.push(f); + } + + ps.push(coords.length); + coords.push(coord); + colors.push(color); + verticesLeft--; + reader.align(); + } + + this.figures.push({ + type: "triangles", + coords: new Int32Array(ps), + colors: new Int32Array(ps) + }); + } + + _decodeType5Shading(reader, verticesPerRow) { + const coords = this.coords; + const colors = this.colors; + const ps = []; + + while (reader.hasData) { + const coord = reader.readCoordinate(); + const color = reader.readComponents(); + ps.push(coords.length); + coords.push(coord); + colors.push(color); + } + + this.figures.push({ + type: "lattice", + coords: new Int32Array(ps), + colors: new Int32Array(ps), + verticesPerRow + }); + } + + _decodeType6Shading(reader) { + const coords = this.coords; + const colors = this.colors; + const ps = new Int32Array(16); + const cs = new Int32Array(4); + + while (reader.hasData) { + const f = reader.readFlag(); + + if (!(0 <= f && f <= 3)) { + throw new _util.FormatError("Unknown type6 flag"); + } + + const pi = coords.length; + + for (let i = 0, ii = f !== 0 ? 8 : 12; i < ii; i++) { + coords.push(reader.readCoordinate()); + } + + const ci = colors.length; + + for (let i = 0, ii = f !== 0 ? 2 : 4; i < ii; i++) { + colors.push(reader.readComponents()); + } + + let tmp1, tmp2, tmp3, tmp4; + + switch (f) { + case 0: + ps[12] = pi + 3; + ps[13] = pi + 4; + ps[14] = pi + 5; + ps[15] = pi + 6; + ps[8] = pi + 2; + ps[11] = pi + 7; + ps[4] = pi + 1; + ps[7] = pi + 8; + ps[0] = pi; + ps[1] = pi + 11; + ps[2] = pi + 10; + ps[3] = pi + 9; + cs[2] = ci + 1; + cs[3] = ci + 2; + cs[0] = ci; + cs[1] = ci + 3; + break; + + case 1: + tmp1 = ps[12]; + tmp2 = ps[13]; + tmp3 = ps[14]; + tmp4 = ps[15]; + ps[12] = tmp4; + ps[13] = pi + 0; + ps[14] = pi + 1; + ps[15] = pi + 2; + ps[8] = tmp3; + ps[11] = pi + 3; + ps[4] = tmp2; + ps[7] = pi + 4; + ps[0] = tmp1; + ps[1] = pi + 7; + ps[2] = pi + 6; + ps[3] = pi + 5; + tmp1 = cs[2]; + tmp2 = cs[3]; + cs[2] = tmp2; + cs[3] = ci; + cs[0] = tmp1; + cs[1] = ci + 1; + break; + + case 2: + tmp1 = ps[15]; + tmp2 = ps[11]; + ps[12] = ps[3]; + ps[13] = pi + 0; + ps[14] = pi + 1; + ps[15] = pi + 2; + ps[8] = ps[7]; + ps[11] = pi + 3; + ps[4] = tmp2; + ps[7] = pi + 4; + ps[0] = tmp1; + ps[1] = pi + 7; + ps[2] = pi + 6; + ps[3] = pi + 5; + tmp1 = cs[3]; + cs[2] = cs[1]; + cs[3] = ci; + cs[0] = tmp1; + cs[1] = ci + 1; + break; + + case 3: + ps[12] = ps[0]; + ps[13] = pi + 0; + ps[14] = pi + 1; + ps[15] = pi + 2; + ps[8] = ps[1]; + ps[11] = pi + 3; + ps[4] = ps[2]; + ps[7] = pi + 4; + ps[0] = ps[3]; + ps[1] = pi + 7; + ps[2] = pi + 6; + ps[3] = pi + 5; + cs[2] = cs[0]; + cs[3] = ci; + cs[0] = cs[1]; + cs[1] = ci + 1; + break; + } + + ps[5] = coords.length; + coords.push([(-4 * coords[ps[0]][0] - coords[ps[15]][0] + 6 * (coords[ps[4]][0] + coords[ps[1]][0]) - 2 * (coords[ps[12]][0] + coords[ps[3]][0]) + 3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9, (-4 * coords[ps[0]][1] - coords[ps[15]][1] + 6 * (coords[ps[4]][1] + coords[ps[1]][1]) - 2 * (coords[ps[12]][1] + coords[ps[3]][1]) + 3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9]); + ps[6] = coords.length; + coords.push([(-4 * coords[ps[3]][0] - coords[ps[12]][0] + 6 * (coords[ps[2]][0] + coords[ps[7]][0]) - 2 * (coords[ps[0]][0] + coords[ps[15]][0]) + 3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9, (-4 * coords[ps[3]][1] - coords[ps[12]][1] + 6 * (coords[ps[2]][1] + coords[ps[7]][1]) - 2 * (coords[ps[0]][1] + coords[ps[15]][1]) + 3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9]); + ps[9] = coords.length; + coords.push([(-4 * coords[ps[12]][0] - coords[ps[3]][0] + 6 * (coords[ps[8]][0] + coords[ps[13]][0]) - 2 * (coords[ps[0]][0] + coords[ps[15]][0]) + 3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9, (-4 * coords[ps[12]][1] - coords[ps[3]][1] + 6 * (coords[ps[8]][1] + coords[ps[13]][1]) - 2 * (coords[ps[0]][1] + coords[ps[15]][1]) + 3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9]); + ps[10] = coords.length; + coords.push([(-4 * coords[ps[15]][0] - coords[ps[0]][0] + 6 * (coords[ps[11]][0] + coords[ps[14]][0]) - 2 * (coords[ps[12]][0] + coords[ps[3]][0]) + 3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9, (-4 * coords[ps[15]][1] - coords[ps[0]][1] + 6 * (coords[ps[11]][1] + coords[ps[14]][1]) - 2 * (coords[ps[12]][1] + coords[ps[3]][1]) + 3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9]); + this.figures.push({ + type: "patch", + coords: new Int32Array(ps), + colors: new Int32Array(cs) + }); + } + } + + _decodeType7Shading(reader) { + const coords = this.coords; + const colors = this.colors; + const ps = new Int32Array(16); + const cs = new Int32Array(4); + + while (reader.hasData) { + const f = reader.readFlag(); + + if (!(0 <= f && f <= 3)) { + throw new _util.FormatError("Unknown type7 flag"); + } + + const pi = coords.length; + + for (let i = 0, ii = f !== 0 ? 12 : 16; i < ii; i++) { + coords.push(reader.readCoordinate()); + } + + const ci = colors.length; + + for (let i = 0, ii = f !== 0 ? 2 : 4; i < ii; i++) { + colors.push(reader.readComponents()); + } + + let tmp1, tmp2, tmp3, tmp4; + + switch (f) { + case 0: + ps[12] = pi + 3; + ps[13] = pi + 4; + ps[14] = pi + 5; + ps[15] = pi + 6; + ps[8] = pi + 2; + ps[9] = pi + 13; + ps[10] = pi + 14; + ps[11] = pi + 7; + ps[4] = pi + 1; + ps[5] = pi + 12; + ps[6] = pi + 15; + ps[7] = pi + 8; + ps[0] = pi; + ps[1] = pi + 11; + ps[2] = pi + 10; + ps[3] = pi + 9; + cs[2] = ci + 1; + cs[3] = ci + 2; + cs[0] = ci; + cs[1] = ci + 3; + break; + + case 1: + tmp1 = ps[12]; + tmp2 = ps[13]; + tmp3 = ps[14]; + tmp4 = ps[15]; + ps[12] = tmp4; + ps[13] = pi + 0; + ps[14] = pi + 1; + ps[15] = pi + 2; + ps[8] = tmp3; + ps[9] = pi + 9; + ps[10] = pi + 10; + ps[11] = pi + 3; + ps[4] = tmp2; + ps[5] = pi + 8; + ps[6] = pi + 11; + ps[7] = pi + 4; + ps[0] = tmp1; + ps[1] = pi + 7; + ps[2] = pi + 6; + ps[3] = pi + 5; + tmp1 = cs[2]; + tmp2 = cs[3]; + cs[2] = tmp2; + cs[3] = ci; + cs[0] = tmp1; + cs[1] = ci + 1; + break; + + case 2: + tmp1 = ps[15]; + tmp2 = ps[11]; + ps[12] = ps[3]; + ps[13] = pi + 0; + ps[14] = pi + 1; + ps[15] = pi + 2; + ps[8] = ps[7]; + ps[9] = pi + 9; + ps[10] = pi + 10; + ps[11] = pi + 3; + ps[4] = tmp2; + ps[5] = pi + 8; + ps[6] = pi + 11; + ps[7] = pi + 4; + ps[0] = tmp1; + ps[1] = pi + 7; + ps[2] = pi + 6; + ps[3] = pi + 5; + tmp1 = cs[3]; + cs[2] = cs[1]; + cs[3] = ci; + cs[0] = tmp1; + cs[1] = ci + 1; + break; + + case 3: + ps[12] = ps[0]; + ps[13] = pi + 0; + ps[14] = pi + 1; + ps[15] = pi + 2; + ps[8] = ps[1]; + ps[9] = pi + 9; + ps[10] = pi + 10; + ps[11] = pi + 3; + ps[4] = ps[2]; + ps[5] = pi + 8; + ps[6] = pi + 11; + ps[7] = pi + 4; + ps[0] = ps[3]; + ps[1] = pi + 7; + ps[2] = pi + 6; + ps[3] = pi + 5; + cs[2] = cs[0]; + cs[3] = ci; + cs[0] = cs[1]; + cs[1] = ci + 1; + break; + } + + this.figures.push({ + type: "patch", + coords: new Int32Array(ps), + colors: new Int32Array(cs) + }); + } + } + + _buildFigureFromPatch(index) { + const figure = this.figures[index]; + (0, _util.assert)(figure.type === "patch", "Unexpected patch mesh figure"); + const coords = this.coords, + colors = this.colors; + const pi = figure.coords; + const ci = figure.colors; + const figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0], coords[pi[12]][0], coords[pi[15]][0]); + const figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1], coords[pi[12]][1], coords[pi[15]][1]); + const figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0], coords[pi[12]][0], coords[pi[15]][0]); + const figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1], coords[pi[12]][1], coords[pi[15]][1]); + let splitXBy = Math.ceil((figureMaxX - figureMinX) * MeshShading.TRIANGLE_DENSITY / (this.bounds[2] - this.bounds[0])); + splitXBy = Math.max(MeshShading.MIN_SPLIT_PATCH_CHUNKS_AMOUNT, Math.min(MeshShading.MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy)); + let splitYBy = Math.ceil((figureMaxY - figureMinY) * MeshShading.TRIANGLE_DENSITY / (this.bounds[3] - this.bounds[1])); + splitYBy = Math.max(MeshShading.MIN_SPLIT_PATCH_CHUNKS_AMOUNT, Math.min(MeshShading.MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy)); + const verticesPerRow = splitXBy + 1; + const figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow); + const figureColors = new Int32Array((splitYBy + 1) * verticesPerRow); + let k = 0; + const cl = new Uint8Array(3), + cr = new Uint8Array(3); + const c0 = colors[ci[0]], + c1 = colors[ci[1]], + c2 = colors[ci[2]], + c3 = colors[ci[3]]; + const bRow = getB(splitYBy), + bCol = getB(splitXBy); + + for (let row = 0; row <= splitYBy; row++) { + cl[0] = (c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy | 0; + cl[1] = (c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy | 0; + cl[2] = (c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy | 0; + cr[0] = (c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy | 0; + cr[1] = (c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy | 0; + cr[2] = (c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy | 0; + + for (let col = 0; col <= splitXBy; col++, k++) { + if ((row === 0 || row === splitYBy) && (col === 0 || col === splitXBy)) { + continue; + } + + let x = 0, + y = 0; + let q = 0; + + for (let i = 0; i <= 3; i++) { + for (let j = 0; j <= 3; j++, q++) { + const m = bRow[row][i] * bCol[col][j]; + x += coords[pi[q]][0] * m; + y += coords[pi[q]][1] * m; + } + } + + figureCoords[k] = coords.length; + coords.push([x, y]); + figureColors[k] = colors.length; + const newColor = new Uint8Array(3); + newColor[0] = (cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy | 0; + newColor[1] = (cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy | 0; + newColor[2] = (cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy | 0; + colors.push(newColor); + } + } + + figureCoords[0] = pi[0]; + figureColors[0] = ci[0]; + figureCoords[splitXBy] = pi[3]; + figureColors[splitXBy] = ci[1]; + figureCoords[verticesPerRow * splitYBy] = pi[12]; + figureColors[verticesPerRow * splitYBy] = ci[2]; + figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15]; + figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3]; + this.figures[index] = { + type: "lattice", + coords: figureCoords, + colors: figureColors, + verticesPerRow + }; + } + + _updateBounds() { + let minX = this.coords[0][0], + minY = this.coords[0][1], + maxX = minX, + maxY = minY; + + for (let i = 1, ii = this.coords.length; i < ii; i++) { + const x = this.coords[i][0], + y = this.coords[i][1]; + minX = minX > x ? x : minX; + minY = minY > y ? y : minY; + maxX = maxX < x ? x : maxX; + maxY = maxY < y ? y : maxY; + } + + this.bounds = [minX, minY, maxX, maxY]; + } + + _packData() { + let i, ii, j, jj; + const coords = this.coords; + const coordsPacked = new Float32Array(coords.length * 2); + + for (i = 0, j = 0, ii = coords.length; i < ii; i++) { + const xy = coords[i]; + coordsPacked[j++] = xy[0]; + coordsPacked[j++] = xy[1]; + } + + this.coords = coordsPacked; + const colors = this.colors; + const colorsPacked = new Uint8Array(colors.length * 3); + + for (i = 0, j = 0, ii = colors.length; i < ii; i++) { + const c = colors[i]; + colorsPacked[j++] = c[0]; + colorsPacked[j++] = c[1]; + colorsPacked[j++] = c[2]; + } + + this.colors = colorsPacked; + const figures = this.figures; + + for (i = 0, ii = figures.length; i < ii; i++) { + const figure = figures[i], + ps = figure.coords, + cs = figure.colors; + + for (j = 0, jj = ps.length; j < jj; j++) { + ps[j] *= 2; + cs[j] *= 3; + } + } + } + + getIR() { + return ["Mesh", this.shadingType, this.coords, this.colors, this.figures, this.bounds, this.bbox, this.background]; + } + +} + +class DummyShading extends BaseShading { + getIR() { + return ["Dummy"]; + } + +} + +function getTilingPatternIR(operatorList, dict, color) { + const matrix = dict.getArray("Matrix"); + + const bbox = _util.Util.normalizeRect(dict.getArray("BBox")); + + const xstep = dict.get("XStep"); + const ystep = dict.get("YStep"); + const paintType = dict.get("PaintType"); + const tilingType = dict.get("TilingType"); + + if (bbox[2] - bbox[0] === 0 || bbox[3] - bbox[1] === 0) { + throw new _util.FormatError(`Invalid getTilingPatternIR /BBox array: [${bbox}].`); + } + + return ["TilingPattern", color, operatorList, matrix, bbox, xstep, ystep, paintType, tilingType]; +} + +/***/ }), +/* 51 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.getXfaFontDict = getXfaFontDict; +exports.getXfaFontName = getXfaFontName; + +var _calibri_factors = __w_pdfjs_require__(52); + +var _primitives = __w_pdfjs_require__(5); + +var _helvetica_factors = __w_pdfjs_require__(53); + +var _liberationsans_widths = __w_pdfjs_require__(54); + +var _myriadpro_factors = __w_pdfjs_require__(55); + +var _segoeui_factors = __w_pdfjs_require__(56); + +var _core_utils = __w_pdfjs_require__(6); + +var _fonts_utils = __w_pdfjs_require__(38); + +const getXFAFontMap = (0, _core_utils.getLookupTableFactory)(function (t) { + t["MyriadPro-Regular"] = t["PdfJS-Fallback-Regular"] = { + name: "LiberationSans-Regular", + factors: _myriadpro_factors.MyriadProRegularFactors, + baseWidths: _liberationsans_widths.LiberationSansRegularWidths, + baseMapping: _liberationsans_widths.LiberationSansRegularMapping, + metrics: _myriadpro_factors.MyriadProRegularMetrics + }; + t["MyriadPro-Bold"] = t["PdfJS-Fallback-Bold"] = { + name: "LiberationSans-Bold", + factors: _myriadpro_factors.MyriadProBoldFactors, + baseWidths: _liberationsans_widths.LiberationSansBoldWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldMapping, + metrics: _myriadpro_factors.MyriadProBoldMetrics + }; + t["MyriadPro-It"] = t["MyriadPro-Italic"] = t["PdfJS-Fallback-Italic"] = { + name: "LiberationSans-Italic", + factors: _myriadpro_factors.MyriadProItalicFactors, + baseWidths: _liberationsans_widths.LiberationSansItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansItalicMapping, + metrics: _myriadpro_factors.MyriadProItalicMetrics + }; + t["MyriadPro-BoldIt"] = t["MyriadPro-BoldItalic"] = t["PdfJS-Fallback-BoldItalic"] = { + name: "LiberationSans-BoldItalic", + factors: _myriadpro_factors.MyriadProBoldItalicFactors, + baseWidths: _liberationsans_widths.LiberationSansBoldItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldItalicMapping, + metrics: _myriadpro_factors.MyriadProBoldItalicMetrics + }; + t.ArialMT = t.Arial = t["Arial-Regular"] = { + name: "LiberationSans-Regular", + baseWidths: _liberationsans_widths.LiberationSansRegularWidths, + baseMapping: _liberationsans_widths.LiberationSansRegularMapping + }; + t["Arial-BoldMT"] = t["Arial-Bold"] = { + name: "LiberationSans-Bold", + baseWidths: _liberationsans_widths.LiberationSansBoldWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldMapping + }; + t["Arial-ItalicMT"] = t["Arial-Italic"] = { + name: "LiberationSans-Italic", + baseWidths: _liberationsans_widths.LiberationSansItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansItalicMapping + }; + t["Arial-BoldItalicMT"] = t["Arial-BoldItalic"] = { + name: "LiberationSans-BoldItalic", + baseWidths: _liberationsans_widths.LiberationSansBoldItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldItalicMapping + }; + t["Calibri-Regular"] = { + name: "LiberationSans-Regular", + factors: _calibri_factors.CalibriRegularFactors, + baseWidths: _liberationsans_widths.LiberationSansRegularWidths, + baseMapping: _liberationsans_widths.LiberationSansRegularMapping, + metrics: _calibri_factors.CalibriRegularMetrics + }; + t["Calibri-Bold"] = { + name: "LiberationSans-Bold", + factors: _calibri_factors.CalibriBoldFactors, + baseWidths: _liberationsans_widths.LiberationSansBoldWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldMapping, + metrics: _calibri_factors.CalibriBoldMetrics + }; + t["Calibri-Italic"] = { + name: "LiberationSans-Italic", + factors: _calibri_factors.CalibriItalicFactors, + baseWidths: _liberationsans_widths.LiberationSansItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansItalicMapping, + metrics: _calibri_factors.CalibriItalicMetrics + }; + t["Calibri-BoldItalic"] = { + name: "LiberationSans-BoldItalic", + factors: _calibri_factors.CalibriBoldItalicFactors, + baseWidths: _liberationsans_widths.LiberationSansBoldItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldItalicMapping, + metrics: _calibri_factors.CalibriBoldItalicMetrics + }; + t["Segoeui-Regular"] = { + name: "LiberationSans-Regular", + factors: _segoeui_factors.SegoeuiRegularFactors, + baseWidths: _liberationsans_widths.LiberationSansRegularWidths, + baseMapping: _liberationsans_widths.LiberationSansRegularMapping, + metrics: _segoeui_factors.SegoeuiRegularMetrics + }; + t["Segoeui-Bold"] = { + name: "LiberationSans-Bold", + factors: _segoeui_factors.SegoeuiBoldFactors, + baseWidths: _liberationsans_widths.LiberationSansBoldWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldMapping, + metrics: _segoeui_factors.SegoeuiBoldMetrics + }; + t["Segoeui-Italic"] = { + name: "LiberationSans-Italic", + factors: _segoeui_factors.SegoeuiItalicFactors, + baseWidths: _liberationsans_widths.LiberationSansItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansItalicMapping, + metrics: _segoeui_factors.SegoeuiItalicMetrics + }; + t["Segoeui-BoldItalic"] = { + name: "LiberationSans-BoldItalic", + factors: _segoeui_factors.SegoeuiBoldItalicFactors, + baseWidths: _liberationsans_widths.LiberationSansBoldItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldItalicMapping, + metrics: _segoeui_factors.SegoeuiBoldItalicMetrics + }; + t["Helvetica-Regular"] = t.Helvetica = { + name: "LiberationSans-Regular", + factors: _helvetica_factors.HelveticaRegularFactors, + baseWidths: _liberationsans_widths.LiberationSansRegularWidths, + baseMapping: _liberationsans_widths.LiberationSansRegularMapping, + metrics: _helvetica_factors.HelveticaRegularMetrics + }; + t["Helvetica-Bold"] = { + name: "LiberationSans-Bold", + factors: _helvetica_factors.HelveticaBoldFactors, + baseWidths: _liberationsans_widths.LiberationSansBoldWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldMapping, + metrics: _helvetica_factors.HelveticaBoldMetrics + }; + t["Helvetica-Italic"] = { + name: "LiberationSans-Italic", + factors: _helvetica_factors.HelveticaItalicFactors, + baseWidths: _liberationsans_widths.LiberationSansItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansItalicMapping, + metrics: _helvetica_factors.HelveticaItalicMetrics + }; + t["Helvetica-BoldItalic"] = { + name: "LiberationSans-BoldItalic", + factors: _helvetica_factors.HelveticaBoldItalicFactors, + baseWidths: _liberationsans_widths.LiberationSansBoldItalicWidths, + baseMapping: _liberationsans_widths.LiberationSansBoldItalicMapping, + metrics: _helvetica_factors.HelveticaBoldItalicMetrics + }; }); + +function getXfaFontName(name) { + const fontName = (0, _fonts_utils.normalizeFontName)(name); + const fontMap = getXFAFontMap(); + return fontMap[fontName]; +} + +function getXfaFontWidths(name) { + const info = getXfaFontName(name); + + if (!info) { + return null; + } + + const { + baseWidths, + baseMapping, + factors + } = info; + let rescaledBaseWidths; + + if (!factors) { + rescaledBaseWidths = baseWidths; + } else { + rescaledBaseWidths = baseWidths.map((w, i) => w * factors[i]); + } + + let currentCode = -2; + let currentArray; + const newWidths = []; + + for (const [unicode, glyphIndex] of baseMapping.map((charUnicode, index) => [charUnicode, index]).sort(([unicode1], [unicode2]) => unicode1 - unicode2)) { + if (unicode === -1) { + continue; + } + + if (unicode === currentCode + 1) { + currentArray.push(rescaledBaseWidths[glyphIndex]); + currentCode += 1; + } else { + currentCode = unicode; + currentArray = [rescaledBaseWidths[glyphIndex]]; + newWidths.push(unicode, currentArray); + } + } + + return newWidths; +} + +function getXfaFontDict(name) { + const widths = getXfaFontWidths(name); + const dict = new _primitives.Dict(null); + dict.set("BaseFont", _primitives.Name.get(name)); + dict.set("Type", _primitives.Name.get("Font")); + dict.set("Subtype", _primitives.Name.get("CIDFontType2")); + dict.set("Encoding", _primitives.Name.get("Identity-H")); + dict.set("CIDToGIDMap", _primitives.Name.get("Identity")); + dict.set("W", widths); + dict.set("FirstChar", widths[0]); + dict.set("LastChar", widths.at(-2) + widths.at(-1).length - 1); + const descriptor = new _primitives.Dict(null); + dict.set("FontDescriptor", descriptor); + const systemInfo = new _primitives.Dict(null); + systemInfo.set("Ordering", "Identity"); + systemInfo.set("Registry", "Adobe"); + systemInfo.set("Supplement", 0); + dict.set("CIDSystemInfo", systemInfo); + return dict; +} + +/***/ }), +/* 52 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.CalibriRegularMetrics = exports.CalibriRegularFactors = exports.CalibriItalicMetrics = exports.CalibriItalicFactors = exports.CalibriBoldMetrics = exports.CalibriBoldItalicMetrics = exports.CalibriBoldItalicFactors = exports.CalibriBoldFactors = void 0; +const CalibriBoldFactors = [1.3877, 1, 1, 1, 0.97801, 0.92482, 0.89552, 0.91133, 0.81988, 0.97566, 0.98152, 0.93548, 0.93548, 1.2798, 0.85284, 0.92794, 1, 0.96134, 1.54657, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.82845, 0.82845, 0.85284, 0.85284, 0.85284, 0.75859, 0.92138, 0.83908, 0.7762, 0.73293, 0.87289, 0.73133, 0.7514, 0.81921, 0.87356, 0.95958, 0.59526, 0.75727, 0.69225, 1.04924, 0.9121, 0.86943, 0.79795, 0.88198, 0.77958, 0.70864, 0.81055, 0.90399, 0.88653, 0.96017, 0.82577, 0.77892, 0.78257, 0.97507, 1.54657, 0.97507, 0.85284, 0.89552, 0.90176, 0.88762, 0.8785, 0.75241, 0.8785, 0.90518, 0.95015, 0.77618, 0.8785, 0.88401, 0.91916, 0.86304, 0.88401, 0.91488, 0.8785, 0.8801, 0.8785, 0.8785, 0.91343, 0.7173, 1.04106, 0.8785, 0.85075, 0.95794, 0.82616, 0.85162, 0.79492, 0.88331, 1.69808, 0.88331, 0.85284, 0.97801, 0.89552, 0.91133, 0.89552, 0.91133, 1.7801, 0.89552, 1.24487, 1.13254, 1.12401, 0.96839, 0.85284, 0.68787, 0.70645, 0.85592, 0.90747, 1.01466, 1.0088, 0.90323, 1, 1.07463, 1, 0.91056, 0.75806, 1.19118, 0.96839, 0.78864, 0.82845, 0.84133, 0.75859, 0.83908, 0.83908, 0.83908, 0.83908, 0.83908, 0.83908, 0.77539, 0.73293, 0.73133, 0.73133, 0.73133, 0.73133, 0.95958, 0.95958, 0.95958, 0.95958, 0.88506, 0.9121, 0.86943, 0.86943, 0.86943, 0.86943, 0.86943, 0.85284, 0.87508, 0.90399, 0.90399, 0.90399, 0.90399, 0.77892, 0.79795, 0.90807, 0.88762, 0.88762, 0.88762, 0.88762, 0.88762, 0.88762, 0.8715, 0.75241, 0.90518, 0.90518, 0.90518, 0.90518, 0.88401, 0.88401, 0.88401, 0.88401, 0.8785, 0.8785, 0.8801, 0.8801, 0.8801, 0.8801, 0.8801, 0.90747, 0.89049, 0.8785, 0.8785, 0.8785, 0.8785, 0.85162, 0.8785, 0.85162, 0.83908, 0.88762, 0.83908, 0.88762, 0.83908, 0.88762, 0.73293, 0.75241, 0.73293, 0.75241, 0.73293, 0.75241, 0.73293, 0.75241, 0.87289, 0.83016, 0.88506, 0.93125, 0.73133, 0.90518, 0.73133, 0.90518, 0.73133, 0.90518, 0.73133, 0.90518, 0.73133, 0.90518, 0.81921, 0.77618, 0.81921, 0.77618, 0.81921, 0.77618, 1, 1, 0.87356, 0.8785, 0.91075, 0.89608, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.76229, 0.90167, 0.59526, 0.91916, 1, 1, 0.86304, 0.69225, 0.88401, 1, 1, 0.70424, 0.79468, 0.91926, 0.88175, 0.70823, 0.94903, 0.9121, 0.8785, 1, 1, 0.9121, 0.8785, 0.87802, 0.88656, 0.8785, 0.86943, 0.8801, 0.86943, 0.8801, 0.86943, 0.8801, 0.87402, 0.89291, 0.77958, 0.91343, 1, 1, 0.77958, 0.91343, 0.70864, 0.7173, 0.70864, 0.7173, 0.70864, 0.7173, 0.70864, 0.7173, 1, 1, 0.81055, 0.75841, 0.81055, 1.06452, 0.90399, 0.8785, 0.90399, 0.8785, 0.90399, 0.8785, 0.90399, 0.8785, 0.90399, 0.8785, 0.90399, 0.8785, 0.96017, 0.95794, 0.77892, 0.85162, 0.77892, 0.78257, 0.79492, 0.78257, 0.79492, 0.78257, 0.79492, 0.9297, 0.56892, 0.83908, 0.88762, 0.77539, 0.8715, 0.87508, 0.89049, 1, 1, 0.81055, 1.04106, 1.20528, 1.20528, 1, 1.15543, 0.70674, 0.98387, 0.94721, 1.33431, 1.45894, 0.95161, 1.06303, 0.83908, 0.80352, 0.57184, 0.6965, 0.56289, 0.82001, 0.56029, 0.81235, 1.02988, 0.83908, 0.7762, 0.68156, 0.80367, 0.73133, 0.78257, 0.87356, 0.86943, 0.95958, 0.75727, 0.89019, 1.04924, 0.9121, 0.7648, 0.86943, 0.87356, 0.79795, 0.78275, 0.81055, 0.77892, 0.9762, 0.82577, 0.99819, 0.84896, 0.95958, 0.77892, 0.96108, 1.01407, 0.89049, 1.02988, 0.94211, 0.96108, 0.8936, 0.84021, 0.87842, 0.96399, 0.79109, 0.89049, 1.00813, 1.02988, 0.86077, 0.87445, 0.92099, 0.84723, 0.86513, 0.8801, 0.75638, 0.85714, 0.78216, 0.79586, 0.87965, 0.94211, 0.97747, 0.78287, 0.97926, 0.84971, 1.02988, 0.94211, 0.8801, 0.94211, 0.84971, 0.73133, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90264, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90518, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90548, 1, 1, 1, 1, 1, 1, 0.96017, 0.95794, 0.96017, 0.95794, 0.96017, 0.95794, 0.77892, 0.85162, 1, 1, 0.89552, 0.90527, 1, 0.90363, 0.92794, 0.92794, 0.92794, 0.92794, 0.87012, 0.87012, 0.87012, 0.89552, 0.89552, 1.42259, 0.71143, 1.06152, 1, 1, 1.03372, 1.03372, 0.97171, 1.4956, 2.2807, 0.93835, 0.83406, 0.91133, 0.84107, 0.91133, 1, 1, 1, 0.72021, 1, 1.23108, 0.83489, 0.88525, 0.88525, 0.81499, 0.90527, 1.81055, 0.90527, 1.81055, 1.31006, 1.53711, 0.94434, 1.08696, 1, 0.95018, 0.77192, 0.85284, 0.90747, 1.17534, 0.69825, 0.9716, 1.37077, 0.90747, 0.90747, 0.85356, 0.90747, 0.90747, 1.44947, 0.85284, 0.8941, 0.8941, 0.70572, 0.8, 0.70572, 0.70572, 0.70572, 0.70572, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.99862, 0.99862, 1, 1, 1, 1, 1, 1.08004, 0.91027, 1, 1, 1, 0.99862, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90727, 0.90727, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.CalibriBoldFactors = CalibriBoldFactors; +const CalibriBoldMetrics = { + lineHeight: 1.2207, + lineGap: 0.2207 +}; +exports.CalibriBoldMetrics = CalibriBoldMetrics; +const CalibriBoldItalicFactors = [1.3877, 1, 1, 1, 0.97801, 0.92482, 0.89552, 0.91133, 0.81988, 0.97566, 0.98152, 0.93548, 0.93548, 1.2798, 0.85284, 0.92794, 1, 0.96134, 1.56239, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.82845, 0.82845, 0.85284, 0.85284, 0.85284, 0.75859, 0.92138, 0.83908, 0.7762, 0.71805, 0.87289, 0.73133, 0.7514, 0.81921, 0.87356, 0.95958, 0.59526, 0.75727, 0.69225, 1.04924, 0.90872, 0.85938, 0.79795, 0.87068, 0.77958, 0.69766, 0.81055, 0.90399, 0.88653, 0.96068, 0.82577, 0.77892, 0.78257, 0.97507, 1.529, 0.97507, 0.85284, 0.89552, 0.90176, 0.94908, 0.86411, 0.74012, 0.86411, 0.88323, 0.95015, 0.86411, 0.86331, 0.88401, 0.91916, 0.86304, 0.88401, 0.9039, 0.86331, 0.86331, 0.86411, 0.86411, 0.90464, 0.70852, 1.04106, 0.86331, 0.84372, 0.95794, 0.82616, 0.84548, 0.79492, 0.88331, 1.69808, 0.88331, 0.85284, 0.97801, 0.89552, 0.91133, 0.89552, 0.91133, 1.7801, 0.89552, 1.24487, 1.13254, 1.19129, 0.96839, 0.85284, 0.68787, 0.70645, 0.85592, 0.90747, 1.01466, 1.0088, 0.90323, 1, 1.07463, 1, 0.91056, 0.75806, 1.19118, 0.96839, 0.78864, 0.82845, 0.84133, 0.75859, 0.83908, 0.83908, 0.83908, 0.83908, 0.83908, 0.83908, 0.77539, 0.71805, 0.73133, 0.73133, 0.73133, 0.73133, 0.95958, 0.95958, 0.95958, 0.95958, 0.88506, 0.90872, 0.85938, 0.85938, 0.85938, 0.85938, 0.85938, 0.85284, 0.87068, 0.90399, 0.90399, 0.90399, 0.90399, 0.77892, 0.79795, 0.90807, 0.94908, 0.94908, 0.94908, 0.94908, 0.94908, 0.94908, 0.85887, 0.74012, 0.88323, 0.88323, 0.88323, 0.88323, 0.88401, 0.88401, 0.88401, 0.88401, 0.8785, 0.86331, 0.86331, 0.86331, 0.86331, 0.86331, 0.86331, 0.90747, 0.89049, 0.86331, 0.86331, 0.86331, 0.86331, 0.84548, 0.86411, 0.84548, 0.83908, 0.94908, 0.83908, 0.94908, 0.83908, 0.94908, 0.71805, 0.74012, 0.71805, 0.74012, 0.71805, 0.74012, 0.71805, 0.74012, 0.87289, 0.79538, 0.88506, 0.92726, 0.73133, 0.88323, 0.73133, 0.88323, 0.73133, 0.88323, 0.73133, 0.88323, 0.73133, 0.88323, 0.81921, 0.86411, 0.81921, 0.86411, 0.81921, 0.86411, 1, 1, 0.87356, 0.86331, 0.91075, 0.8777, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.76467, 0.90167, 0.59526, 0.91916, 1, 1, 0.86304, 0.69225, 0.88401, 1, 1, 0.70424, 0.77312, 0.91926, 0.88175, 0.70823, 0.94903, 0.90872, 0.86331, 1, 1, 0.90872, 0.86331, 0.86906, 0.88116, 0.86331, 0.85938, 0.86331, 0.85938, 0.86331, 0.85938, 0.86331, 0.87402, 0.86549, 0.77958, 0.90464, 1, 1, 0.77958, 0.90464, 0.69766, 0.70852, 0.69766, 0.70852, 0.69766, 0.70852, 0.69766, 0.70852, 1, 1, 0.81055, 0.75841, 0.81055, 1.06452, 0.90399, 0.86331, 0.90399, 0.86331, 0.90399, 0.86331, 0.90399, 0.86331, 0.90399, 0.86331, 0.90399, 0.86331, 0.96068, 0.95794, 0.77892, 0.84548, 0.77892, 0.78257, 0.79492, 0.78257, 0.79492, 0.78257, 0.79492, 0.9297, 0.56892, 0.83908, 0.94908, 0.77539, 0.85887, 0.87068, 0.89049, 1, 1, 0.81055, 1.04106, 1.20528, 1.20528, 1, 1.15543, 0.70088, 0.98387, 0.94721, 1.33431, 1.45894, 0.95161, 1.48387, 0.83908, 0.80352, 0.57118, 0.6965, 0.56347, 0.79179, 0.55853, 0.80346, 1.02988, 0.83908, 0.7762, 0.67174, 0.86036, 0.73133, 0.78257, 0.87356, 0.86441, 0.95958, 0.75727, 0.89019, 1.04924, 0.90872, 0.74889, 0.85938, 0.87891, 0.79795, 0.7957, 0.81055, 0.77892, 0.97447, 0.82577, 0.97466, 0.87179, 0.95958, 0.77892, 0.94252, 0.95612, 0.8753, 1.02988, 0.92733, 0.94252, 0.87411, 0.84021, 0.8728, 0.95612, 0.74081, 0.8753, 1.02189, 1.02988, 0.84814, 0.87445, 0.91822, 0.84723, 0.85668, 0.86331, 0.81344, 0.87581, 0.76422, 0.82046, 0.96057, 0.92733, 0.99375, 0.78022, 0.95452, 0.86015, 1.02988, 0.92733, 0.86331, 0.92733, 0.86015, 0.73133, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90631, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.88323, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.85174, 1, 1, 1, 1, 1, 1, 0.96068, 0.95794, 0.96068, 0.95794, 0.96068, 0.95794, 0.77892, 0.84548, 1, 1, 0.89552, 0.90527, 1, 0.90363, 0.92794, 0.92794, 0.92794, 0.89807, 0.87012, 0.87012, 0.87012, 0.89552, 0.89552, 1.42259, 0.71094, 1.06152, 1, 1, 1.03372, 1.03372, 0.97171, 1.4956, 2.2807, 0.92972, 0.83406, 0.91133, 0.83326, 0.91133, 1, 1, 1, 0.72021, 1, 1.23108, 0.83489, 0.88525, 0.88525, 0.81499, 0.90616, 1.81055, 0.90527, 1.81055, 1.3107, 1.53711, 0.94434, 1.08696, 1, 0.95018, 0.77192, 0.85284, 0.90747, 1.17534, 0.69825, 0.9716, 1.37077, 0.90747, 0.90747, 0.85356, 0.90747, 0.90747, 1.44947, 0.85284, 0.8941, 0.8941, 0.70572, 0.8, 0.70572, 0.70572, 0.70572, 0.70572, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.99862, 0.99862, 1, 1, 1, 1, 1, 1.08004, 0.91027, 1, 1, 1, 0.99862, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90727, 0.90727, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.CalibriBoldItalicFactors = CalibriBoldItalicFactors; +const CalibriBoldItalicMetrics = { + lineHeight: 1.2207, + lineGap: 0.2207 +}; +exports.CalibriBoldItalicMetrics = CalibriBoldItalicMetrics; +const CalibriItalicFactors = [1.3877, 1, 1, 1, 1.17223, 1.1293, 0.89552, 0.91133, 0.80395, 1.02269, 1.15601, 0.91056, 0.91056, 1.2798, 0.85284, 0.89807, 1, 0.90861, 1.39543, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.96309, 0.96309, 0.85284, 0.85284, 0.85284, 0.83319, 0.88071, 0.8675, 0.81552, 0.72346, 0.85193, 0.73206, 0.7522, 0.81105, 0.86275, 0.90685, 0.6377, 0.77892, 0.75593, 1.02638, 0.89249, 0.84118, 0.77452, 0.85374, 0.75186, 0.67789, 0.79776, 0.88844, 0.85066, 0.94309, 0.77818, 0.7306, 0.76659, 1.10369, 1.38313, 1.10369, 1.06139, 0.89552, 0.8739, 0.9245, 0.9245, 0.83203, 0.9245, 0.85865, 1.09842, 0.9245, 0.9245, 1.03297, 1.07692, 0.90918, 1.03297, 0.94959, 0.9245, 0.92274, 0.9245, 0.9245, 1.02933, 0.77832, 1.20562, 0.9245, 0.8916, 0.98986, 0.86621, 0.89453, 0.79004, 0.94152, 1.77256, 0.94152, 0.85284, 0.97801, 0.89552, 0.91133, 0.89552, 0.91133, 1.91729, 0.89552, 1.17889, 1.13254, 1.16359, 0.92098, 0.85284, 0.68787, 0.71353, 0.84737, 0.90747, 1.0088, 1.0044, 0.87683, 1, 1.09091, 1, 0.92229, 0.739, 1.15642, 0.92098, 0.76288, 0.80504, 0.80972, 0.75859, 0.8675, 0.8675, 0.8675, 0.8675, 0.8675, 0.8675, 0.76318, 0.72346, 0.73206, 0.73206, 0.73206, 0.73206, 0.90685, 0.90685, 0.90685, 0.90685, 0.86477, 0.89249, 0.84118, 0.84118, 0.84118, 0.84118, 0.84118, 0.85284, 0.84557, 0.88844, 0.88844, 0.88844, 0.88844, 0.7306, 0.77452, 0.86331, 0.9245, 0.9245, 0.9245, 0.9245, 0.9245, 0.9245, 0.84843, 0.83203, 0.85865, 0.85865, 0.85865, 0.85865, 0.82601, 0.82601, 0.82601, 0.82601, 0.94469, 0.9245, 0.92274, 0.92274, 0.92274, 0.92274, 0.92274, 0.90747, 0.86651, 0.9245, 0.9245, 0.9245, 0.9245, 0.89453, 0.9245, 0.89453, 0.8675, 0.9245, 0.8675, 0.9245, 0.8675, 0.9245, 0.72346, 0.83203, 0.72346, 0.83203, 0.72346, 0.83203, 0.72346, 0.83203, 0.85193, 0.8875, 0.86477, 0.99034, 0.73206, 0.85865, 0.73206, 0.85865, 0.73206, 0.85865, 0.73206, 0.85865, 0.73206, 0.85865, 0.81105, 0.9245, 0.81105, 0.9245, 0.81105, 0.9245, 1, 1, 0.86275, 0.9245, 0.90872, 0.93591, 0.90685, 0.82601, 0.90685, 0.82601, 0.90685, 0.82601, 0.90685, 1.03297, 0.90685, 0.82601, 0.77896, 1.05611, 0.6377, 1.07692, 1, 1, 0.90918, 0.75593, 1.03297, 1, 1, 0.76032, 0.9375, 0.98156, 0.93407, 0.77261, 1.11429, 0.89249, 0.9245, 1, 1, 0.89249, 0.9245, 0.92534, 0.86698, 0.9245, 0.84118, 0.92274, 0.84118, 0.92274, 0.84118, 0.92274, 0.8667, 0.86291, 0.75186, 1.02933, 1, 1, 0.75186, 1.02933, 0.67789, 0.77832, 0.67789, 0.77832, 0.67789, 0.77832, 0.67789, 0.77832, 1, 1, 0.79776, 0.97655, 0.79776, 1.23023, 0.88844, 0.9245, 0.88844, 0.9245, 0.88844, 0.9245, 0.88844, 0.9245, 0.88844, 0.9245, 0.88844, 0.9245, 0.94309, 0.98986, 0.7306, 0.89453, 0.7306, 0.76659, 0.79004, 0.76659, 0.79004, 0.76659, 0.79004, 1.09231, 0.54873, 0.8675, 0.9245, 0.76318, 0.84843, 0.84557, 0.86651, 1, 1, 0.79776, 1.20562, 1.18622, 1.18622, 1, 1.1437, 0.67009, 0.96334, 0.93695, 1.35191, 1.40909, 0.95161, 1.48387, 0.8675, 0.90861, 0.6192, 0.7363, 0.64824, 0.82411, 0.56321, 0.85696, 1.23516, 0.8675, 0.81552, 0.7286, 0.84134, 0.73206, 0.76659, 0.86275, 0.84369, 0.90685, 0.77892, 0.85871, 1.02638, 0.89249, 0.75828, 0.84118, 0.85984, 0.77452, 0.76466, 0.79776, 0.7306, 0.90782, 0.77818, 0.903, 0.87291, 0.90685, 0.7306, 0.99058, 1.03667, 0.94635, 1.23516, 0.9849, 0.99058, 0.92393, 0.8916, 0.942, 1.03667, 0.75026, 0.94635, 1.0297, 1.23516, 0.90918, 0.94048, 0.98217, 0.89746, 0.84153, 0.92274, 0.82507, 0.88832, 0.84438, 0.88178, 1.03525, 0.9849, 1.00225, 0.78086, 0.97248, 0.89404, 1.23516, 0.9849, 0.92274, 0.9849, 0.89404, 0.73206, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.89693, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.85865, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90933, 1, 1, 1, 1, 1, 1, 0.94309, 0.98986, 0.94309, 0.98986, 0.94309, 0.98986, 0.7306, 0.89453, 1, 1, 0.89552, 0.90527, 1, 0.90186, 1.12308, 1.12308, 1.12308, 1.12308, 1.2566, 1.2566, 1.2566, 0.89552, 0.89552, 1.42259, 0.68994, 1.03809, 1, 1, 1.0176, 1.0176, 1.11523, 1.4956, 2.01462, 0.97858, 0.82616, 0.91133, 0.83437, 0.91133, 1, 1, 1, 0.70508, 1, 1.23108, 0.79801, 0.84426, 0.84426, 0.774, 0.90572, 1.81055, 0.90749, 1.81055, 1.28809, 1.55469, 0.94434, 1.07806, 1, 0.97094, 0.7589, 0.85284, 0.90747, 1.19658, 0.69825, 0.97622, 1.33512, 0.90747, 0.90747, 0.85284, 0.90747, 0.90747, 1.44947, 0.85284, 0.8941, 0.8941, 0.70572, 0.8, 0.70572, 0.70572, 0.70572, 0.70572, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.99862, 0.99862, 1, 1, 1, 1, 1, 1.0336, 0.91027, 1, 1, 1, 0.99862, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.05859, 1.05859, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.CalibriItalicFactors = CalibriItalicFactors; +const CalibriItalicMetrics = { + lineHeight: 1.2207, + lineGap: 0.2207 +}; +exports.CalibriItalicMetrics = CalibriItalicMetrics; +const CalibriRegularFactors = [1.3877, 1, 1, 1, 1.17223, 1.1293, 0.89552, 0.91133, 0.80395, 1.02269, 1.15601, 0.91056, 0.91056, 1.2798, 0.85284, 0.89807, 1, 0.90861, 1.39016, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.96309, 0.96309, 0.85284, 0.85284, 0.85284, 0.83319, 0.88071, 0.8675, 0.81552, 0.73834, 0.85193, 0.73206, 0.7522, 0.81105, 0.86275, 0.90685, 0.6377, 0.77892, 0.75593, 1.02638, 0.89385, 0.85122, 0.77452, 0.86503, 0.75186, 0.68887, 0.79776, 0.88844, 0.85066, 0.94258, 0.77818, 0.7306, 0.76659, 1.10369, 1.39016, 1.10369, 1.06139, 0.89552, 0.8739, 0.86128, 0.94469, 0.8457, 0.94469, 0.89464, 1.09842, 0.84636, 0.94469, 1.03297, 1.07692, 0.90918, 1.03297, 0.95897, 0.94469, 0.9482, 0.94469, 0.94469, 1.04692, 0.78223, 1.20562, 0.94469, 0.90332, 0.98986, 0.86621, 0.90527, 0.79004, 0.94152, 1.77256, 0.94152, 0.85284, 0.97801, 0.89552, 0.91133, 0.89552, 0.91133, 1.91729, 0.89552, 1.17889, 1.13254, 1.08707, 0.92098, 0.85284, 0.68787, 0.71353, 0.84737, 0.90747, 1.0088, 1.0044, 0.87683, 1, 1.09091, 1, 0.92229, 0.739, 1.15642, 0.92098, 0.76288, 0.80504, 0.80972, 0.75859, 0.8675, 0.8675, 0.8675, 0.8675, 0.8675, 0.8675, 0.76318, 0.73834, 0.73206, 0.73206, 0.73206, 0.73206, 0.90685, 0.90685, 0.90685, 0.90685, 0.86477, 0.89385, 0.85122, 0.85122, 0.85122, 0.85122, 0.85122, 0.85284, 0.85311, 0.88844, 0.88844, 0.88844, 0.88844, 0.7306, 0.77452, 0.86331, 0.86128, 0.86128, 0.86128, 0.86128, 0.86128, 0.86128, 0.8693, 0.8457, 0.89464, 0.89464, 0.89464, 0.89464, 0.82601, 0.82601, 0.82601, 0.82601, 0.94469, 0.94469, 0.9482, 0.9482, 0.9482, 0.9482, 0.9482, 0.90747, 0.86651, 0.94469, 0.94469, 0.94469, 0.94469, 0.90527, 0.94469, 0.90527, 0.8675, 0.86128, 0.8675, 0.86128, 0.8675, 0.86128, 0.73834, 0.8457, 0.73834, 0.8457, 0.73834, 0.8457, 0.73834, 0.8457, 0.85193, 0.92454, 0.86477, 0.9921, 0.73206, 0.89464, 0.73206, 0.89464, 0.73206, 0.89464, 0.73206, 0.89464, 0.73206, 0.89464, 0.81105, 0.84636, 0.81105, 0.84636, 0.81105, 0.84636, 1, 1, 0.86275, 0.94469, 0.90872, 0.95786, 0.90685, 0.82601, 0.90685, 0.82601, 0.90685, 0.82601, 0.90685, 1.03297, 0.90685, 0.82601, 0.77741, 1.05611, 0.6377, 1.07692, 1, 1, 0.90918, 0.75593, 1.03297, 1, 1, 0.76032, 0.90452, 0.98156, 1.11842, 0.77261, 1.11429, 0.89385, 0.94469, 1, 1, 0.89385, 0.94469, 0.95877, 0.86901, 0.94469, 0.85122, 0.9482, 0.85122, 0.9482, 0.85122, 0.9482, 0.8667, 0.90016, 0.75186, 1.04692, 1, 1, 0.75186, 1.04692, 0.68887, 0.78223, 0.68887, 0.78223, 0.68887, 0.78223, 0.68887, 0.78223, 1, 1, 0.79776, 0.92188, 0.79776, 1.23023, 0.88844, 0.94469, 0.88844, 0.94469, 0.88844, 0.94469, 0.88844, 0.94469, 0.88844, 0.94469, 0.88844, 0.94469, 0.94258, 0.98986, 0.7306, 0.90527, 0.7306, 0.76659, 0.79004, 0.76659, 0.79004, 0.76659, 0.79004, 1.09231, 0.54873, 0.8675, 0.86128, 0.76318, 0.8693, 0.85311, 0.86651, 1, 1, 0.79776, 1.20562, 1.18622, 1.18622, 1, 1.1437, 0.67742, 0.96334, 0.93695, 1.35191, 1.40909, 0.95161, 1.48387, 0.86686, 0.90861, 0.62267, 0.74359, 0.65649, 0.85498, 0.56963, 0.88254, 1.23516, 0.8675, 0.81552, 0.75443, 0.84503, 0.73206, 0.76659, 0.86275, 0.85122, 0.90685, 0.77892, 0.85746, 1.02638, 0.89385, 0.75657, 0.85122, 0.86275, 0.77452, 0.74171, 0.79776, 0.7306, 0.95165, 0.77818, 0.89772, 0.88831, 0.90685, 0.7306, 0.98142, 1.02191, 0.96576, 1.23516, 0.99018, 0.98142, 0.9236, 0.89258, 0.94035, 1.02191, 0.78848, 0.96576, 0.9561, 1.23516, 0.90918, 0.92578, 0.95424, 0.89746, 0.83969, 0.9482, 0.80113, 0.89442, 0.85208, 0.86155, 0.98022, 0.99018, 1.00452, 0.81209, 0.99247, 0.89181, 1.23516, 0.99018, 0.9482, 0.99018, 0.89181, 0.73206, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.88844, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.89464, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.96766, 1, 1, 1, 1, 1, 1, 0.94258, 0.98986, 0.94258, 0.98986, 0.94258, 0.98986, 0.7306, 0.90527, 1, 1, 0.89552, 0.90527, 1, 0.90186, 1.12308, 1.12308, 1.12308, 1.12308, 1.2566, 1.2566, 1.2566, 0.89552, 0.89552, 1.42259, 0.69043, 1.03809, 1, 1, 1.0176, 1.0176, 1.11523, 1.4956, 2.01462, 0.99331, 0.82616, 0.91133, 0.84286, 0.91133, 1, 1, 1, 0.70508, 1, 1.23108, 0.79801, 0.84426, 0.84426, 0.774, 0.90527, 1.81055, 0.90527, 1.81055, 1.28809, 1.55469, 0.94434, 1.07806, 1, 0.97094, 0.7589, 0.85284, 0.90747, 1.19658, 0.69825, 0.97622, 1.33512, 0.90747, 0.90747, 0.85356, 0.90747, 0.90747, 1.44947, 0.85284, 0.8941, 0.8941, 0.70572, 0.8, 0.70572, 0.70572, 0.70572, 0.70572, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.99862, 0.99862, 1, 1, 1, 1, 1, 1.0336, 0.91027, 1, 1, 1, 0.99862, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.05859, 1.05859, 1, 1, 1, 1.07185, 0.99413, 0.96334, 1.08065, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.CalibriRegularFactors = CalibriRegularFactors; +const CalibriRegularMetrics = { + lineHeight: 1.2207, + lineGap: 0.2207 +}; +exports.CalibriRegularMetrics = CalibriRegularMetrics; + +/***/ }), +/* 53 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.HelveticaRegularMetrics = exports.HelveticaRegularFactors = exports.HelveticaItalicMetrics = exports.HelveticaItalicFactors = exports.HelveticaBoldMetrics = exports.HelveticaBoldItalicMetrics = exports.HelveticaBoldItalicFactors = exports.HelveticaBoldFactors = void 0; +const HelveticaBoldFactors = [0.76116, 1, 1, 1.0006, 0.99998, 0.99974, 0.99973, 0.99973, 0.99982, 0.99977, 1.00087, 0.99998, 0.99998, 0.99959, 1.00003, 1.0006, 0.99998, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99998, 1, 1.00003, 1.00003, 1.00003, 1.00026, 0.9999, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00026, 1.00022, 0.99977, 1.0006, 0.99973, 0.99977, 1.00026, 0.99999, 0.99977, 1.00022, 1.00001, 1.00022, 0.99977, 1.00001, 1.00026, 0.99977, 1.00001, 1.00016, 1.00001, 1.00001, 1.00026, 0.99998, 1.0006, 0.99998, 1.00003, 0.99973, 0.99998, 0.99973, 1.00026, 0.99973, 1.00026, 0.99973, 0.99998, 1.00026, 1.00026, 1.0006, 1.0006, 0.99973, 1.0006, 0.99982, 1.00026, 1.00026, 1.00026, 1.00026, 0.99959, 0.99973, 0.99998, 1.00026, 0.99973, 1.00022, 0.99973, 0.99973, 1, 0.99959, 1.00077, 0.99959, 1.00003, 0.99998, 0.99973, 0.99973, 0.99973, 0.99973, 1.00077, 0.99973, 0.99998, 1.00025, 0.99968, 0.99973, 1.00003, 1.00025, 0.60299, 1.00024, 1.06409, 1, 1, 0.99998, 1, 0.99973, 1.0006, 0.99998, 1, 0.99936, 0.99973, 1.00002, 1.00002, 1.00002, 1.00026, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 1, 0.99977, 1.00001, 1.00001, 1.00001, 1.00001, 1.0006, 1.0006, 1.0006, 1.0006, 0.99977, 0.99977, 1.00022, 1.00022, 1.00022, 1.00022, 1.00022, 1.00003, 1.00022, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00001, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99982, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.06409, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 0.99973, 1.00026, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 1.03374, 0.99977, 1.00026, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.00042, 0.99973, 0.99973, 1.0006, 0.99977, 0.99973, 0.99973, 1.00026, 1.0006, 1.00026, 1.0006, 1.00026, 1.03828, 1.00026, 0.99999, 1.00026, 1.0006, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.9993, 0.9998, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1, 1.00016, 0.99977, 0.99959, 0.99977, 0.99959, 0.99977, 0.99959, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00026, 0.99998, 1.00026, 0.8121, 1.00026, 0.99998, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 1.00016, 1.00022, 1.00001, 0.99973, 1.00001, 1.00026, 1, 1.00026, 1, 1.00026, 1, 1.0006, 0.99973, 0.99977, 0.99973, 1, 0.99982, 1.00022, 1.00026, 1.00001, 0.99973, 1.00026, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 1.00034, 0.99977, 1, 0.99997, 1.00026, 1.00078, 1.00036, 0.99973, 1.00013, 1.0006, 0.99977, 0.99977, 0.99988, 0.85148, 1.00001, 1.00026, 0.99977, 1.00022, 1.0006, 0.99977, 1.00001, 0.99999, 0.99977, 1.00069, 1.00022, 0.99977, 1.00001, 0.99984, 1.00026, 1.00001, 1.00024, 1.00001, 0.9999, 1, 1.0006, 1.00001, 1.00041, 0.99962, 1.00026, 1.0006, 0.99995, 1.00041, 0.99942, 0.99973, 0.99927, 1.00082, 0.99902, 1.00026, 1.00087, 1.0006, 1.00069, 0.99973, 0.99867, 0.99973, 0.9993, 1.00026, 1.00049, 1.00056, 1, 0.99988, 0.99935, 0.99995, 0.99954, 1.00055, 0.99945, 1.00032, 1.0006, 0.99995, 1.00026, 0.99995, 1.00032, 1.00001, 1.00008, 0.99971, 1.00019, 0.9994, 1.00001, 1.0006, 1.00044, 0.99973, 1.00023, 1.00047, 1, 0.99942, 0.99561, 0.99989, 1.00035, 0.99977, 1.00035, 0.99977, 1.00019, 0.99944, 1.00001, 1.00021, 0.99926, 1.00035, 1.00035, 0.99942, 1.00048, 0.99999, 0.99977, 1.00022, 1.00035, 1.00001, 0.99977, 1.00026, 0.99989, 1.00057, 1.00001, 0.99936, 1.00052, 1.00012, 0.99996, 1.00043, 1, 1.00035, 0.9994, 0.99976, 1.00035, 0.99973, 1.00052, 1.00041, 1.00119, 1.00037, 0.99973, 1.00002, 0.99986, 1.00041, 1.00041, 0.99902, 0.9996, 1.00034, 0.99999, 1.00026, 0.99999, 1.00026, 0.99973, 1.00052, 0.99973, 1, 0.99973, 1.00041, 1.00075, 0.9994, 1.0003, 0.99999, 1, 1.00041, 0.99955, 1, 0.99915, 0.99973, 0.99973, 1.00026, 1.00119, 0.99955, 0.99973, 1.0006, 0.99911, 1.0006, 1.00026, 0.99972, 1.00026, 0.99902, 1.00041, 0.99973, 0.99999, 1, 1, 1.00038, 1.0005, 1.00016, 1.00022, 1.00016, 1.00022, 1.00016, 1.00022, 1.00001, 0.99973, 1, 1, 0.99973, 1, 1, 0.99955, 1.0006, 1.0006, 1.0006, 1.0006, 1, 1, 1, 0.99973, 0.99973, 0.99972, 1, 1, 1.00106, 0.99999, 0.99998, 0.99998, 0.99999, 0.99998, 1.66475, 1, 0.99973, 0.99973, 1.00023, 0.99973, 0.99971, 1.00047, 1.00023, 1, 0.99991, 0.99984, 1.00002, 1.00002, 1.00002, 1.00002, 1, 1, 1, 1, 1, 1, 1, 0.99972, 1, 1.20985, 1.39713, 1.00003, 1.00031, 1.00015, 1, 0.99561, 1.00027, 1.00031, 1.00031, 0.99915, 1.00031, 1.00031, 0.99999, 1.00003, 0.99999, 0.99999, 1.41144, 1.6, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.40579, 1.40579, 1.36625, 0.99999, 1, 0.99861, 0.99861, 1, 1.00026, 1.00026, 1.00026, 1.00026, 0.99972, 0.99999, 0.99999, 0.99999, 0.99999, 1.40483, 1, 0.99977, 1.00054, 1, 1, 0.99953, 0.99962, 1.00042, 0.9995, 1, 1, 1, 1, 1, 1, 1, 1, 0.99998, 0.99998, 0.99998, 0.99998, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.HelveticaBoldFactors = HelveticaBoldFactors; +const HelveticaBoldMetrics = { + lineHeight: 1.2, + lineGap: 0.2 +}; +exports.HelveticaBoldMetrics = HelveticaBoldMetrics; +const HelveticaBoldItalicFactors = [0.76116, 1, 1, 1.0006, 0.99998, 0.99974, 0.99973, 0.99973, 0.99982, 0.99977, 1.00087, 0.99998, 0.99998, 0.99959, 1.00003, 1.0006, 0.99998, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99998, 1, 1.00003, 1.00003, 1.00003, 1.00026, 0.9999, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00026, 1.00022, 0.99977, 1.0006, 0.99973, 0.99977, 1.00026, 0.99999, 0.99977, 1.00022, 1.00001, 1.00022, 0.99977, 1.00001, 1.00026, 0.99977, 1.00001, 1.00016, 1.00001, 1.00001, 1.00026, 0.99998, 1.0006, 0.99998, 1.00003, 0.99973, 0.99998, 0.99973, 1.00026, 0.99973, 1.00026, 0.99973, 0.99998, 1.00026, 1.00026, 1.0006, 1.0006, 0.99973, 1.0006, 0.99982, 1.00026, 1.00026, 1.00026, 1.00026, 0.99959, 0.99973, 0.99998, 1.00026, 0.99973, 1.00022, 0.99973, 0.99973, 1, 0.99959, 1.00077, 0.99959, 1.00003, 0.99998, 0.99973, 0.99973, 0.99973, 0.99973, 1.00077, 0.99973, 0.99998, 1.00025, 0.99968, 0.99973, 1.00003, 1.00025, 0.60299, 1.00024, 1.06409, 1, 1, 0.99998, 1, 0.99973, 1.0006, 0.99998, 1, 0.99936, 0.99973, 1.00002, 1.00002, 1.00002, 1.00026, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 1, 0.99977, 1.00001, 1.00001, 1.00001, 1.00001, 1.0006, 1.0006, 1.0006, 1.0006, 0.99977, 0.99977, 1.00022, 1.00022, 1.00022, 1.00022, 1.00022, 1.00003, 1.00022, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00001, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99982, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.06409, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 0.99973, 1.00026, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 1.0044, 0.99977, 1.00026, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 0.99971, 0.99973, 0.99973, 1.0006, 0.99977, 0.99973, 0.99973, 1.00026, 1.0006, 1.00026, 1.0006, 1.00026, 1.01011, 1.00026, 0.99999, 1.00026, 1.0006, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.9993, 0.9998, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1, 1.00016, 0.99977, 0.99959, 0.99977, 0.99959, 0.99977, 0.99959, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00026, 0.99998, 1.00026, 0.8121, 1.00026, 0.99998, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 1.00016, 1.00022, 1.00001, 0.99973, 1.00001, 1.00026, 1, 1.00026, 1, 1.00026, 1, 1.0006, 0.99973, 0.99977, 0.99973, 1, 0.99982, 1.00022, 1.00026, 1.00001, 0.99973, 1.00026, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99977, 1, 1, 1.00026, 0.99969, 0.99972, 0.99981, 0.9998, 1.0006, 0.99977, 0.99977, 1.00022, 0.91155, 1.00001, 1.00026, 0.99977, 1.00022, 1.0006, 0.99977, 1.00001, 0.99999, 0.99977, 0.99966, 1.00022, 1.00032, 1.00001, 0.99944, 1.00026, 1.00001, 0.99968, 1.00001, 1.00047, 1, 1.0006, 1.00001, 0.99981, 1.00101, 1.00026, 1.0006, 0.99948, 0.99981, 1.00064, 0.99973, 0.99942, 1.00101, 1.00061, 1.00026, 1.00069, 1.0006, 1.00014, 0.99973, 1.01322, 0.99973, 1.00065, 1.00026, 1.00012, 0.99923, 1, 1.00064, 1.00076, 0.99948, 1.00055, 1.00063, 1.00007, 0.99943, 1.0006, 0.99948, 1.00026, 0.99948, 0.99943, 1.00001, 1.00001, 1.00029, 1.00038, 1.00035, 1.00001, 1.0006, 1.0006, 0.99973, 0.99978, 1.00001, 1.00057, 0.99989, 0.99967, 0.99964, 0.99967, 0.99977, 0.99999, 0.99977, 1.00038, 0.99977, 1.00001, 0.99973, 1.00066, 0.99967, 0.99967, 1.00041, 0.99998, 0.99999, 0.99977, 1.00022, 0.99967, 1.00001, 0.99977, 1.00026, 0.99964, 1.00031, 1.00001, 0.99999, 0.99999, 1, 1.00023, 1, 1, 0.99999, 1.00035, 1.00001, 0.99999, 0.99973, 0.99977, 0.99999, 1.00058, 0.99973, 0.99973, 0.99955, 0.9995, 1.00026, 1.00026, 1.00032, 0.99989, 1.00034, 0.99999, 1.00026, 1.00026, 1.00026, 0.99973, 0.45998, 0.99973, 1.00026, 0.99973, 1.00001, 0.99999, 0.99982, 0.99994, 0.99996, 1, 1.00042, 1.00044, 1.00029, 1.00023, 0.99973, 0.99973, 1.00026, 0.99949, 1.00002, 0.99973, 1.0006, 1.0006, 1.0006, 0.99975, 1.00026, 1.00026, 1.00032, 0.98685, 0.99973, 1.00026, 1, 1, 0.99966, 1.00044, 1.00016, 1.00022, 1.00016, 1.00022, 1.00016, 1.00022, 1.00001, 0.99973, 1, 1, 0.99973, 1, 1, 0.99955, 1.0006, 1.0006, 1.0006, 1.0006, 1, 1, 1, 0.99973, 0.99973, 0.99972, 1, 1, 1.00106, 0.99999, 0.99998, 0.99998, 0.99999, 0.99998, 1.66475, 1, 0.99973, 0.99973, 1, 0.99973, 0.99971, 0.99978, 1, 1, 0.99991, 0.99984, 1.00002, 1.00002, 1.00002, 1.00002, 1.00098, 1, 1, 1, 1.00049, 1, 1, 0.99972, 1, 1.20985, 1.39713, 1.00003, 1.00031, 1.00015, 1, 0.99561, 1.00027, 1.00031, 1.00031, 0.99915, 1.00031, 1.00031, 0.99999, 1.00003, 0.99999, 0.99999, 1.41144, 1.6, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.40579, 1.40579, 1.36625, 0.99999, 1, 0.99861, 0.99861, 1, 1.00026, 1.00026, 1.00026, 1.00026, 0.99972, 0.99999, 0.99999, 0.99999, 0.99999, 1.40483, 1, 0.99977, 1.00054, 1, 1, 0.99953, 0.99962, 1.00042, 0.9995, 1, 1, 1, 1, 1, 1, 1, 1, 0.99998, 0.99998, 0.99998, 0.99998, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.HelveticaBoldItalicFactors = HelveticaBoldItalicFactors; +const HelveticaBoldItalicMetrics = { + lineHeight: 1.35, + lineGap: 0.2 +}; +exports.HelveticaBoldItalicMetrics = HelveticaBoldItalicMetrics; +const HelveticaItalicFactors = [0.76116, 1, 1, 1.0006, 1.0006, 1.00006, 0.99973, 0.99973, 0.99982, 1.00001, 1.00043, 0.99998, 0.99998, 0.99959, 1.00003, 1.0006, 0.99998, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1, 1.00003, 1.00003, 1.00003, 0.99973, 0.99987, 1.00001, 1.00001, 0.99977, 0.99977, 1.00001, 1.00026, 1.00022, 0.99977, 1.0006, 1, 1.00001, 0.99973, 0.99999, 0.99977, 1.00022, 1.00001, 1.00022, 0.99977, 1.00001, 1.00026, 0.99977, 1.00001, 1.00016, 1.00001, 1.00001, 1.00026, 1.0006, 1.0006, 1.0006, 0.99949, 0.99973, 0.99998, 0.99973, 0.99973, 1, 0.99973, 0.99973, 1.0006, 0.99973, 0.99973, 0.99924, 0.99924, 1, 0.99924, 0.99999, 0.99973, 0.99973, 0.99973, 0.99973, 0.99998, 1, 1.0006, 0.99973, 1, 0.99977, 1, 1, 1, 1.00005, 1.0009, 1.00005, 1.00003, 0.99998, 0.99973, 0.99973, 0.99973, 0.99973, 1.0009, 0.99973, 0.99998, 1.00025, 0.99968, 0.99973, 1.00003, 1.00025, 0.60299, 1.00024, 1.06409, 1, 1, 0.99998, 1, 0.9998, 1.0006, 0.99998, 1, 0.99936, 0.99973, 1.00002, 1.00002, 1.00002, 1.00026, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1, 0.99977, 1.00001, 1.00001, 1.00001, 1.00001, 1.0006, 1.0006, 1.0006, 1.0006, 0.99977, 0.99977, 1.00022, 1.00022, 1.00022, 1.00022, 1.00022, 1.00003, 1.00022, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00001, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99982, 1, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.06409, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 1, 0.99973, 1, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 0.99977, 1, 0.99977, 1, 0.99977, 1, 0.99977, 1, 0.99977, 1.0288, 0.99977, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 0.99924, 1.0006, 1.0006, 0.99946, 1.00034, 1, 0.99924, 1.00001, 1, 1, 0.99973, 0.99924, 0.99973, 0.99924, 0.99973, 1.06311, 0.99973, 1.00024, 0.99973, 0.99924, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.00041, 0.9998, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1, 1.00016, 0.99977, 0.99998, 0.99977, 0.99998, 0.99977, 0.99998, 1.00001, 1, 1.00001, 1, 1.00001, 1, 1.00001, 1, 1.00026, 1.0006, 1.00026, 0.89547, 1.00026, 1.0006, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.00016, 0.99977, 1.00001, 1, 1.00001, 1.00026, 1, 1.00026, 1, 1.00026, 1, 0.99924, 0.99973, 1.00001, 0.99973, 1, 0.99982, 1.00022, 1.00026, 1.00001, 1, 1.00026, 1.0006, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 1.00001, 1, 1.00054, 0.99977, 1.00084, 1.00007, 0.99973, 1.00013, 0.99924, 1.00001, 1.00001, 0.99945, 0.91221, 1.00001, 1.00026, 0.99977, 1.00022, 1.0006, 1.00001, 1.00001, 0.99999, 0.99977, 0.99933, 1.00022, 1.00054, 1.00001, 1.00065, 1.00026, 1.00001, 1.0001, 1.00001, 1.00052, 1, 1.0006, 1.00001, 0.99945, 0.99897, 0.99968, 0.99924, 1.00036, 0.99945, 0.99949, 1, 1.0006, 0.99897, 0.99918, 0.99968, 0.99911, 0.99924, 1, 0.99962, 1.01487, 1, 1.0005, 0.99973, 1.00012, 1.00043, 1, 0.99995, 0.99994, 1.00036, 0.99947, 1.00019, 1.00063, 1.00025, 0.99924, 1.00036, 0.99973, 1.00036, 1.00025, 1.00001, 1.00001, 1.00027, 1.0001, 1.00068, 1.00001, 1.0006, 1.0006, 1, 1.00008, 0.99957, 0.99972, 0.9994, 0.99954, 0.99975, 1.00051, 1.00001, 1.00019, 1.00001, 1.0001, 0.99986, 1.00001, 1.00001, 1.00038, 0.99954, 0.99954, 0.9994, 1.00066, 0.99999, 0.99977, 1.00022, 1.00054, 1.00001, 0.99977, 1.00026, 0.99975, 1.0001, 1.00001, 0.99993, 0.9995, 0.99955, 1.00016, 0.99978, 0.99974, 1.00019, 1.00022, 0.99955, 1.00053, 0.99973, 1.00089, 1.00005, 0.99967, 1.00048, 0.99973, 1.00002, 1.00034, 0.99973, 0.99973, 0.99964, 1.00006, 1.00066, 0.99947, 0.99973, 0.98894, 0.99973, 1, 0.44898, 1, 0.99946, 1, 1.00039, 1.00082, 0.99991, 0.99991, 0.99985, 1.00022, 1.00023, 1.00061, 1.00006, 0.99966, 0.99973, 0.99973, 0.99973, 1.00019, 1.0008, 1, 0.99924, 0.99924, 0.99924, 0.99983, 1.00044, 0.99973, 0.99964, 0.98332, 1, 0.99973, 1, 1, 0.99962, 0.99895, 1.00016, 0.99977, 1.00016, 0.99977, 1.00016, 0.99977, 1.00001, 1, 1, 1, 0.99973, 1, 1, 0.99955, 0.99924, 0.99924, 0.99924, 0.99924, 0.99998, 0.99998, 0.99998, 0.99973, 0.99973, 0.99972, 1, 1, 1.00267, 0.99999, 0.99998, 0.99998, 1, 0.99998, 1.66475, 1, 0.99973, 0.99973, 1.00023, 0.99973, 1.00423, 0.99925, 0.99999, 1, 0.99991, 0.99984, 1.00002, 1.00002, 1.00002, 1.00002, 1.00049, 1, 1.00245, 1, 1, 1, 1, 0.96329, 1, 1.20985, 1.39713, 1.00003, 0.8254, 1.00015, 1, 1.00035, 1.00027, 1.00031, 1.00031, 1.00003, 1.00031, 1.00031, 0.99999, 1.00003, 0.99999, 0.99999, 1.41144, 1.6, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.40579, 1.40579, 1.36625, 0.99999, 1, 0.99861, 0.99861, 1, 1.00026, 1.00026, 1.00026, 1.00026, 0.95317, 0.99999, 0.99999, 0.99999, 0.99999, 1.40483, 1, 0.99977, 1.00054, 1, 1, 0.99953, 0.99962, 1.00042, 0.9995, 1, 1, 1, 1, 1, 1, 1, 1, 0.99998, 0.99998, 0.99998, 0.99998, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.HelveticaItalicFactors = HelveticaItalicFactors; +const HelveticaItalicMetrics = { + lineHeight: 1.35, + lineGap: 0.2 +}; +exports.HelveticaItalicMetrics = HelveticaItalicMetrics; +const HelveticaRegularFactors = [0.76116, 1, 1, 1.0006, 1.0006, 1.00006, 0.99973, 0.99973, 0.99982, 1.00001, 1.00043, 0.99998, 0.99998, 0.99959, 1.00003, 1.0006, 0.99998, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1, 1.00003, 1.00003, 1.00003, 0.99973, 0.99987, 1.00001, 1.00001, 0.99977, 0.99977, 1.00001, 1.00026, 1.00022, 0.99977, 1.0006, 1, 1.00001, 0.99973, 0.99999, 0.99977, 1.00022, 1.00001, 1.00022, 0.99977, 1.00001, 1.00026, 0.99977, 1.00001, 1.00016, 1.00001, 1.00001, 1.00026, 1.0006, 1.0006, 1.0006, 0.99949, 0.99973, 0.99998, 0.99973, 0.99973, 1, 0.99973, 0.99973, 1.0006, 0.99973, 0.99973, 0.99924, 0.99924, 1, 0.99924, 0.99999, 0.99973, 0.99973, 0.99973, 0.99973, 0.99998, 1, 1.0006, 0.99973, 1, 0.99977, 1, 1, 1, 1.00005, 1.0009, 1.00005, 1.00003, 0.99998, 0.99973, 0.99973, 0.99973, 0.99973, 1.0009, 0.99973, 0.99998, 1.00025, 0.99968, 0.99973, 1.00003, 1.00025, 0.60299, 1.00024, 1.06409, 1, 1, 0.99998, 1, 0.9998, 1.0006, 0.99998, 1, 0.99936, 0.99973, 1.00002, 1.00002, 1.00002, 1.00026, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1, 0.99977, 1.00001, 1.00001, 1.00001, 1.00001, 1.0006, 1.0006, 1.0006, 1.0006, 0.99977, 0.99977, 1.00022, 1.00022, 1.00022, 1.00022, 1.00022, 1.00003, 1.00022, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00001, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99982, 1, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.06409, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 1, 0.99973, 1, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 0.99977, 1, 0.99977, 1, 0.99977, 1, 0.99977, 1, 0.99977, 1.04596, 0.99977, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 0.99924, 1.0006, 1.0006, 1.00019, 1.00034, 1, 0.99924, 1.00001, 1, 1, 0.99973, 0.99924, 0.99973, 0.99924, 0.99973, 1.02572, 0.99973, 1.00005, 0.99973, 0.99924, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99999, 0.9998, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1, 1.00016, 0.99977, 0.99998, 0.99977, 0.99998, 0.99977, 0.99998, 1.00001, 1, 1.00001, 1, 1.00001, 1, 1.00001, 1, 1.00026, 1.0006, 1.00026, 0.84533, 1.00026, 1.0006, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.00016, 0.99977, 1.00001, 1, 1.00001, 1.00026, 1, 1.00026, 1, 1.00026, 1, 0.99924, 0.99973, 1.00001, 0.99973, 1, 0.99982, 1.00022, 1.00026, 1.00001, 1, 1.00026, 1.0006, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99928, 1, 0.99977, 1.00013, 1.00055, 0.99947, 0.99945, 0.99941, 0.99924, 1.00001, 1.00001, 1.0004, 0.91621, 1.00001, 1.00026, 0.99977, 1.00022, 1.0006, 1.00001, 1.00005, 0.99999, 0.99977, 1.00015, 1.00022, 0.99977, 1.00001, 0.99973, 1.00026, 1.00001, 1.00019, 1.00001, 0.99946, 1, 1.0006, 1.00001, 0.99978, 1.00045, 0.99973, 0.99924, 1.00023, 0.99978, 0.99966, 1, 1.00065, 1.00045, 1.00019, 0.99973, 0.99973, 0.99924, 1, 1, 0.96499, 1, 1.00055, 0.99973, 1.00008, 1.00027, 1, 0.9997, 0.99995, 1.00023, 0.99933, 1.00019, 1.00015, 1.00031, 0.99924, 1.00023, 0.99973, 1.00023, 1.00031, 1.00001, 0.99928, 1.00029, 1.00092, 1.00035, 1.00001, 1.0006, 1.0006, 1, 0.99988, 0.99975, 1, 1.00082, 0.99561, 0.9996, 1.00035, 1.00001, 0.99962, 1.00001, 1.00092, 0.99964, 1.00001, 0.99963, 0.99999, 1.00035, 1.00035, 1.00082, 0.99962, 0.99999, 0.99977, 1.00022, 1.00035, 1.00001, 0.99977, 1.00026, 0.9996, 0.99967, 1.00001, 1.00034, 1.00074, 1.00054, 1.00053, 1.00063, 0.99971, 0.99962, 1.00035, 0.99975, 0.99977, 0.99973, 1.00043, 0.99953, 1.0007, 0.99915, 0.99973, 1.00008, 0.99892, 1.00073, 1.00073, 1.00114, 0.99915, 1.00073, 0.99955, 0.99973, 1.00092, 0.99973, 1, 0.99998, 1, 1.0003, 1, 1.00043, 1.00001, 0.99969, 1.0003, 1, 1.00035, 1.00001, 0.9995, 1, 1.00092, 0.99973, 0.99973, 0.99973, 1.0007, 0.9995, 1, 0.99924, 1.0006, 0.99924, 0.99972, 1.00062, 0.99973, 1.00114, 1.00073, 1, 0.99955, 1, 1, 1.00047, 0.99968, 1.00016, 0.99977, 1.00016, 0.99977, 1.00016, 0.99977, 1.00001, 1, 1, 1, 0.99973, 1, 1, 0.99955, 0.99924, 0.99924, 0.99924, 0.99924, 0.99998, 0.99998, 0.99998, 0.99973, 0.99973, 0.99972, 1, 1, 1.00267, 0.99999, 0.99998, 0.99998, 1, 0.99998, 1.66475, 1, 0.99973, 0.99973, 1.00023, 0.99973, 0.99971, 0.99925, 1.00023, 1, 0.99991, 0.99984, 1.00002, 1.00002, 1.00002, 1.00002, 1, 1, 1, 1, 1, 1, 1, 0.96329, 1, 1.20985, 1.39713, 1.00003, 0.8254, 1.00015, 1, 1.00035, 1.00027, 1.00031, 1.00031, 0.99915, 1.00031, 1.00031, 0.99999, 1.00003, 0.99999, 0.99999, 1.41144, 1.6, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.40579, 1.40579, 1.36625, 0.99999, 1, 0.99861, 0.99861, 1, 1.00026, 1.00026, 1.00026, 1.00026, 0.95317, 0.99999, 0.99999, 0.99999, 0.99999, 1.40483, 1, 0.99977, 1.00054, 1, 1, 0.99953, 0.99962, 1.00042, 0.9995, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.HelveticaRegularFactors = HelveticaRegularFactors; +const HelveticaRegularMetrics = { + lineHeight: 1.2, + lineGap: 0.2 +}; +exports.HelveticaRegularMetrics = HelveticaRegularMetrics; + +/***/ }), +/* 54 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.LiberationSansRegularWidths = exports.LiberationSansRegularMapping = exports.LiberationSansItalicWidths = exports.LiberationSansItalicMapping = exports.LiberationSansBoldWidths = exports.LiberationSansBoldMapping = exports.LiberationSansBoldItalicWidths = exports.LiberationSansBoldItalicMapping = void 0; +const LiberationSansBoldWidths = [365, 0, 333, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 737, 552, 400, 549, 333, 333, 333, 576, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 549, 611, 611, 611, 611, 611, 556, 611, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 719, 722, 611, 667, 556, 667, 556, 667, 556, 667, 556, 667, 556, 778, 611, 778, 611, 778, 611, 778, 611, 722, 611, 722, 611, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 785, 556, 556, 278, 722, 556, 556, 611, 278, 611, 278, 611, 385, 611, 479, 611, 278, 722, 611, 722, 611, 722, 611, 708, 723, 611, 778, 611, 778, 611, 778, 611, 1000, 944, 722, 389, 722, 389, 722, 389, 667, 556, 667, 556, 667, 556, 667, 556, 611, 333, 611, 479, 611, 333, 722, 611, 722, 611, 722, 611, 722, 611, 722, 611, 722, 611, 944, 778, 667, 556, 667, 611, 500, 611, 500, 611, 500, 278, 556, 722, 556, 1000, 889, 778, 611, 667, 556, 611, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 465, 722, 333, 853, 906, 474, 825, 927, 838, 278, 722, 722, 601, 719, 667, 611, 722, 778, 278, 722, 667, 833, 722, 644, 778, 722, 667, 600, 611, 667, 821, 667, 809, 802, 278, 667, 615, 451, 611, 278, 582, 615, 610, 556, 606, 475, 460, 611, 541, 278, 558, 556, 612, 556, 445, 611, 766, 619, 520, 684, 446, 582, 715, 576, 753, 845, 278, 582, 611, 582, 845, 667, 669, 885, 567, 711, 667, 278, 276, 556, 1094, 1062, 875, 610, 722, 622, 719, 722, 719, 722, 567, 712, 667, 904, 626, 719, 719, 610, 702, 833, 722, 778, 719, 667, 722, 611, 622, 854, 667, 730, 703, 1005, 1019, 870, 979, 719, 711, 1031, 719, 556, 618, 615, 417, 635, 556, 709, 497, 615, 615, 500, 635, 740, 604, 611, 604, 611, 556, 490, 556, 875, 556, 615, 581, 833, 844, 729, 854, 615, 552, 854, 583, 556, 556, 611, 417, 552, 556, 278, 281, 278, 969, 906, 611, 500, 615, 556, 604, 778, 611, 487, 447, 944, 778, 944, 778, 944, 778, 667, 556, 333, 333, 556, 1000, 1000, 552, 278, 278, 278, 278, 500, 500, 500, 556, 556, 350, 1000, 1000, 240, 479, 333, 333, 604, 333, 167, 396, 556, 556, 1094, 556, 885, 489, 1115, 1000, 768, 600, 834, 834, 834, 834, 1000, 500, 1000, 500, 1000, 500, 500, 494, 612, 823, 713, 584, 549, 713, 979, 722, 274, 549, 549, 583, 549, 549, 604, 584, 604, 604, 708, 625, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 729, 604, 604, 354, 354, 1000, 990, 990, 990, 990, 494, 604, 604, 604, 604, 354, 1021, 1052, 917, 750, 750, 531, 656, 594, 510, 500, 750, 750, 611, 611, 333, 333, 333, 333, 333, 333, 333, 333, 222, 222, 333, 333, 333, 333, 333, 333, 333, 333]; +exports.LiberationSansBoldWidths = LiberationSansBoldWidths; +const LiberationSansBoldMapping = [-1, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 402, 506, 507, 508, 509, 510, 511, 536, 537, 538, 539, 710, 711, 713, 728, 729, 730, 731, 732, 733, 900, 901, 902, 903, 904, 905, 906, 908, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1138, 1139, 1168, 1169, 7808, 7809, 7810, 7811, 7812, 7813, 7922, 7923, 8208, 8209, 8211, 8212, 8213, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 8222, 8224, 8225, 8226, 8230, 8240, 8242, 8243, 8249, 8250, 8252, 8254, 8260, 8319, 8355, 8356, 8359, 8364, 8453, 8467, 8470, 8482, 8486, 8494, 8539, 8540, 8541, 8542, 8592, 8593, 8594, 8595, 8596, 8597, 8616, 8706, 8710, 8719, 8721, 8722, 8730, 8734, 8735, 8745, 8747, 8776, 8800, 8801, 8804, 8805, 8962, 8976, 8992, 8993, 9472, 9474, 9484, 9488, 9492, 9496, 9500, 9508, 9516, 9524, 9532, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9600, 9604, 9608, 9612, 9616, 9617, 9618, 9619, 9632, 9633, 9642, 9643, 9644, 9650, 9658, 9660, 9668, 9674, 9675, 9679, 9688, 9689, 9702, 9786, 9787, 9788, 9792, 9794, 9824, 9827, 9829, 9830, 9834, 9835, 9836, 61441, 61442, 61445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]; +exports.LiberationSansBoldMapping = LiberationSansBoldMapping; +const LiberationSansBoldItalicWidths = [365, 0, 333, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 737, 552, 400, 549, 333, 333, 333, 576, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 549, 611, 611, 611, 611, 611, 556, 611, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 740, 722, 611, 667, 556, 667, 556, 667, 556, 667, 556, 667, 556, 778, 611, 778, 611, 778, 611, 778, 611, 722, 611, 722, 611, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 782, 556, 556, 278, 722, 556, 556, 611, 278, 611, 278, 611, 396, 611, 479, 611, 278, 722, 611, 722, 611, 722, 611, 708, 723, 611, 778, 611, 778, 611, 778, 611, 1000, 944, 722, 389, 722, 389, 722, 389, 667, 556, 667, 556, 667, 556, 667, 556, 611, 333, 611, 479, 611, 333, 722, 611, 722, 611, 722, 611, 722, 611, 722, 611, 722, 611, 944, 778, 667, 556, 667, 611, 500, 611, 500, 611, 500, 278, 556, 722, 556, 1000, 889, 778, 611, 667, 556, 611, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 722, 333, 854, 906, 473, 844, 930, 847, 278, 722, 722, 610, 671, 667, 611, 722, 778, 278, 722, 667, 833, 722, 657, 778, 718, 667, 590, 611, 667, 822, 667, 829, 781, 278, 667, 620, 479, 611, 278, 591, 620, 621, 556, 610, 479, 492, 611, 558, 278, 566, 556, 603, 556, 450, 611, 712, 605, 532, 664, 409, 591, 704, 578, 773, 834, 278, 591, 611, 591, 834, 667, 667, 886, 614, 719, 667, 278, 278, 556, 1094, 1042, 854, 622, 719, 677, 719, 722, 708, 722, 614, 722, 667, 927, 643, 719, 719, 615, 687, 833, 722, 778, 719, 667, 722, 611, 677, 781, 667, 729, 708, 979, 989, 854, 1000, 708, 719, 1042, 729, 556, 619, 604, 534, 618, 556, 736, 510, 611, 611, 507, 622, 740, 604, 611, 611, 611, 556, 889, 556, 885, 556, 646, 583, 889, 935, 707, 854, 594, 552, 865, 589, 556, 556, 611, 469, 563, 556, 278, 278, 278, 969, 906, 611, 507, 619, 556, 611, 778, 611, 575, 467, 944, 778, 944, 778, 944, 778, 667, 556, 333, 333, 556, 1000, 1000, 552, 278, 278, 278, 278, 500, 500, 500, 556, 556, 350, 1000, 1000, 240, 479, 333, 333, 604, 333, 167, 396, 556, 556, 1104, 556, 885, 516, 1146, 1000, 768, 600, 834, 834, 834, 834, 999, 500, 1000, 500, 1000, 500, 500, 494, 612, 823, 713, 584, 549, 713, 979, 722, 274, 549, 549, 583, 549, 549, 604, 584, 604, 604, 708, 625, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 729, 604, 604, 354, 354, 1000, 990, 990, 990, 990, 494, 604, 604, 604, 604, 354, 1021, 1052, 917, 750, 750, 531, 656, 594, 510, 500, 750, 750, 611, 611, 333, 333, 333, 333, 333, 333, 333, 333, 222, 222, 333, 333, 333, 333, 333, 333, 333, 333]; +exports.LiberationSansBoldItalicWidths = LiberationSansBoldItalicWidths; +const LiberationSansBoldItalicMapping = [-1, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 402, 506, 507, 508, 509, 510, 511, 536, 537, 538, 539, 710, 711, 713, 728, 729, 730, 731, 732, 733, 900, 901, 902, 903, 904, 905, 906, 908, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1138, 1139, 1168, 1169, 7808, 7809, 7810, 7811, 7812, 7813, 7922, 7923, 8208, 8209, 8211, 8212, 8213, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 8222, 8224, 8225, 8226, 8230, 8240, 8242, 8243, 8249, 8250, 8252, 8254, 8260, 8319, 8355, 8356, 8359, 8364, 8453, 8467, 8470, 8482, 8486, 8494, 8539, 8540, 8541, 8542, 8592, 8593, 8594, 8595, 8596, 8597, 8616, 8706, 8710, 8719, 8721, 8722, 8730, 8734, 8735, 8745, 8747, 8776, 8800, 8801, 8804, 8805, 8962, 8976, 8992, 8993, 9472, 9474, 9484, 9488, 9492, 9496, 9500, 9508, 9516, 9524, 9532, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9600, 9604, 9608, 9612, 9616, 9617, 9618, 9619, 9632, 9633, 9642, 9643, 9644, 9650, 9658, 9660, 9668, 9674, 9675, 9679, 9688, 9689, 9702, 9786, 9787, 9788, 9792, 9794, 9824, 9827, 9829, 9830, 9834, 9835, 9836, 61441, 61442, 61445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]; +exports.LiberationSansBoldItalicMapping = LiberationSansBoldItalicMapping; +const LiberationSansItalicWidths = [365, 0, 333, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 737, 552, 400, 549, 333, 333, 333, 576, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 549, 611, 556, 556, 556, 556, 500, 556, 500, 667, 556, 667, 556, 667, 556, 722, 500, 722, 500, 722, 500, 722, 500, 722, 625, 722, 556, 667, 556, 667, 556, 667, 556, 667, 556, 667, 556, 778, 556, 778, 556, 778, 556, 778, 556, 722, 556, 722, 556, 278, 278, 278, 278, 278, 278, 278, 222, 278, 278, 733, 444, 500, 222, 667, 500, 500, 556, 222, 556, 222, 556, 281, 556, 400, 556, 222, 722, 556, 722, 556, 722, 556, 615, 723, 556, 778, 556, 778, 556, 778, 556, 1000, 944, 722, 333, 722, 333, 722, 333, 667, 500, 667, 500, 667, 500, 667, 500, 611, 278, 611, 354, 611, 278, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 944, 722, 667, 500, 667, 611, 500, 611, 500, 611, 500, 222, 556, 667, 556, 1000, 889, 778, 611, 667, 500, 611, 278, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 667, 278, 789, 846, 389, 794, 865, 775, 222, 667, 667, 570, 671, 667, 611, 722, 778, 278, 667, 667, 833, 722, 648, 778, 725, 667, 600, 611, 667, 837, 667, 831, 761, 278, 667, 570, 439, 555, 222, 550, 570, 571, 500, 556, 439, 463, 555, 542, 222, 500, 492, 548, 500, 447, 556, 670, 573, 486, 603, 374, 550, 652, 546, 728, 779, 222, 550, 556, 550, 779, 667, 667, 843, 544, 708, 667, 278, 278, 500, 1066, 982, 844, 589, 715, 639, 724, 667, 651, 667, 544, 704, 667, 917, 614, 715, 715, 589, 686, 833, 722, 778, 725, 667, 722, 611, 639, 795, 667, 727, 673, 920, 923, 805, 886, 651, 694, 1022, 682, 556, 562, 522, 493, 553, 556, 688, 465, 556, 556, 472, 564, 686, 550, 556, 556, 556, 500, 833, 500, 835, 500, 572, 518, 830, 851, 621, 736, 526, 492, 752, 534, 556, 556, 556, 378, 496, 500, 222, 222, 222, 910, 828, 556, 472, 565, 500, 556, 778, 556, 492, 339, 944, 722, 944, 722, 944, 722, 667, 500, 333, 333, 556, 1000, 1000, 552, 222, 222, 222, 222, 333, 333, 333, 556, 556, 350, 1000, 1000, 188, 354, 333, 333, 500, 333, 167, 365, 556, 556, 1094, 556, 885, 323, 1083, 1000, 768, 600, 834, 834, 834, 834, 1000, 500, 998, 500, 1000, 500, 500, 494, 612, 823, 713, 584, 549, 713, 979, 719, 274, 549, 549, 584, 549, 549, 604, 584, 604, 604, 708, 625, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 729, 604, 604, 354, 354, 1000, 990, 990, 990, 990, 494, 604, 604, 604, 604, 354, 1021, 1052, 917, 750, 750, 531, 656, 594, 510, 500, 750, 750, 500, 500, 333, 333, 333, 333, 333, 333, 333, 333, 222, 222, 294, 294, 324, 324, 316, 328, 398, 285]; +exports.LiberationSansItalicWidths = LiberationSansItalicWidths; +const LiberationSansItalicMapping = [-1, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 402, 506, 507, 508, 509, 510, 511, 536, 537, 538, 539, 710, 711, 713, 728, 729, 730, 731, 732, 733, 900, 901, 902, 903, 904, 905, 906, 908, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1138, 1139, 1168, 1169, 7808, 7809, 7810, 7811, 7812, 7813, 7922, 7923, 8208, 8209, 8211, 8212, 8213, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 8222, 8224, 8225, 8226, 8230, 8240, 8242, 8243, 8249, 8250, 8252, 8254, 8260, 8319, 8355, 8356, 8359, 8364, 8453, 8467, 8470, 8482, 8486, 8494, 8539, 8540, 8541, 8542, 8592, 8593, 8594, 8595, 8596, 8597, 8616, 8706, 8710, 8719, 8721, 8722, 8730, 8734, 8735, 8745, 8747, 8776, 8800, 8801, 8804, 8805, 8962, 8976, 8992, 8993, 9472, 9474, 9484, 9488, 9492, 9496, 9500, 9508, 9516, 9524, 9532, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9600, 9604, 9608, 9612, 9616, 9617, 9618, 9619, 9632, 9633, 9642, 9643, 9644, 9650, 9658, 9660, 9668, 9674, 9675, 9679, 9688, 9689, 9702, 9786, 9787, 9788, 9792, 9794, 9824, 9827, 9829, 9830, 9834, 9835, 9836, 61441, 61442, 61445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]; +exports.LiberationSansItalicMapping = LiberationSansItalicMapping; +const LiberationSansRegularWidths = [365, 0, 333, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 737, 552, 400, 549, 333, 333, 333, 576, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 549, 611, 556, 556, 556, 556, 500, 556, 500, 667, 556, 667, 556, 667, 556, 722, 500, 722, 500, 722, 500, 722, 500, 722, 615, 722, 556, 667, 556, 667, 556, 667, 556, 667, 556, 667, 556, 778, 556, 778, 556, 778, 556, 778, 556, 722, 556, 722, 556, 278, 278, 278, 278, 278, 278, 278, 222, 278, 278, 735, 444, 500, 222, 667, 500, 500, 556, 222, 556, 222, 556, 292, 556, 334, 556, 222, 722, 556, 722, 556, 722, 556, 604, 723, 556, 778, 556, 778, 556, 778, 556, 1000, 944, 722, 333, 722, 333, 722, 333, 667, 500, 667, 500, 667, 500, 667, 500, 611, 278, 611, 375, 611, 278, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 944, 722, 667, 500, 667, 611, 500, 611, 500, 611, 500, 222, 556, 667, 556, 1000, 889, 778, 611, 667, 500, 611, 278, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 667, 278, 784, 838, 384, 774, 855, 752, 222, 667, 667, 551, 668, 667, 611, 722, 778, 278, 667, 668, 833, 722, 650, 778, 722, 667, 618, 611, 667, 798, 667, 835, 748, 278, 667, 578, 446, 556, 222, 547, 578, 575, 500, 557, 446, 441, 556, 556, 222, 500, 500, 576, 500, 448, 556, 690, 569, 482, 617, 395, 547, 648, 525, 713, 781, 222, 547, 556, 547, 781, 667, 667, 865, 542, 719, 667, 278, 278, 500, 1057, 1010, 854, 583, 722, 635, 719, 667, 656, 667, 542, 677, 667, 923, 604, 719, 719, 583, 656, 833, 722, 778, 719, 667, 722, 611, 635, 760, 667, 740, 667, 917, 938, 792, 885, 656, 719, 1010, 722, 556, 573, 531, 365, 583, 556, 669, 458, 559, 559, 438, 583, 688, 552, 556, 542, 556, 500, 458, 500, 823, 500, 573, 521, 802, 823, 625, 719, 521, 510, 750, 542, 556, 556, 556, 365, 510, 500, 222, 278, 222, 906, 812, 556, 438, 559, 500, 552, 778, 556, 489, 411, 944, 722, 944, 722, 944, 722, 667, 500, 333, 333, 556, 1000, 1000, 552, 222, 222, 222, 222, 333, 333, 333, 556, 556, 350, 1000, 1000, 188, 354, 333, 333, 500, 333, 167, 365, 556, 556, 1094, 556, 885, 323, 1073, 1000, 768, 600, 834, 834, 834, 834, 1000, 500, 1000, 500, 1000, 500, 500, 494, 612, 823, 713, 584, 549, 713, 979, 719, 274, 549, 549, 583, 549, 549, 604, 584, 604, 604, 708, 625, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 729, 604, 604, 354, 354, 1000, 990, 990, 990, 990, 494, 604, 604, 604, 604, 354, 1021, 1052, 917, 750, 750, 531, 656, 594, 510, 500, 750, 750, 500, 500, 333, 333, 333, 333, 333, 333, 333, 333, 222, 222, 294, 294, 324, 324, 316, 328, 398, 285]; +exports.LiberationSansRegularWidths = LiberationSansRegularWidths; +const LiberationSansRegularMapping = [-1, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 402, 506, 507, 508, 509, 510, 511, 536, 537, 538, 539, 710, 711, 713, 728, 729, 730, 731, 732, 733, 900, 901, 902, 903, 904, 905, 906, 908, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1138, 1139, 1168, 1169, 7808, 7809, 7810, 7811, 7812, 7813, 7922, 7923, 8208, 8209, 8211, 8212, 8213, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 8222, 8224, 8225, 8226, 8230, 8240, 8242, 8243, 8249, 8250, 8252, 8254, 8260, 8319, 8355, 8356, 8359, 8364, 8453, 8467, 8470, 8482, 8486, 8494, 8539, 8540, 8541, 8542, 8592, 8593, 8594, 8595, 8596, 8597, 8616, 8706, 8710, 8719, 8721, 8722, 8730, 8734, 8735, 8745, 8747, 8776, 8800, 8801, 8804, 8805, 8962, 8976, 8992, 8993, 9472, 9474, 9484, 9488, 9492, 9496, 9500, 9508, 9516, 9524, 9532, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9600, 9604, 9608, 9612, 9616, 9617, 9618, 9619, 9632, 9633, 9642, 9643, 9644, 9650, 9658, 9660, 9668, 9674, 9675, 9679, 9688, 9689, 9702, 9786, 9787, 9788, 9792, 9794, 9824, 9827, 9829, 9830, 9834, 9835, 9836, 61441, 61442, 61445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]; +exports.LiberationSansRegularMapping = LiberationSansRegularMapping; + +/***/ }), +/* 55 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.MyriadProRegularMetrics = exports.MyriadProRegularFactors = exports.MyriadProItalicMetrics = exports.MyriadProItalicFactors = exports.MyriadProBoldMetrics = exports.MyriadProBoldItalicMetrics = exports.MyriadProBoldItalicFactors = exports.MyriadProBoldFactors = void 0; +const MyriadProBoldFactors = [1.36898, 1, 1, 0.72706, 0.80479, 0.83734, 0.98894, 0.99793, 0.9897, 0.93884, 0.86209, 0.94292, 0.94292, 1.16661, 1.02058, 0.93582, 0.96694, 0.93582, 1.19137, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.78076, 0.78076, 1.02058, 1.02058, 1.02058, 0.72851, 0.78966, 0.90838, 0.83637, 0.82391, 0.96376, 0.80061, 0.86275, 0.8768, 0.95407, 1.0258, 0.73901, 0.85022, 0.83655, 1.0156, 0.95546, 0.92179, 0.87107, 0.92179, 0.82114, 0.8096, 0.89713, 0.94438, 0.95353, 0.94083, 0.91905, 0.90406, 0.9446, 0.94292, 1.18777, 0.94292, 1.02058, 0.89903, 0.90088, 0.94938, 0.97898, 0.81093, 0.97571, 0.94938, 1.024, 0.9577, 0.95933, 0.98621, 1.0474, 0.97455, 0.98981, 0.9672, 0.95933, 0.9446, 0.97898, 0.97407, 0.97646, 0.78036, 1.10208, 0.95442, 0.95298, 0.97579, 0.9332, 0.94039, 0.938, 0.80687, 1.01149, 0.80687, 1.02058, 0.80479, 0.99793, 0.99793, 0.99793, 0.99793, 1.01149, 1.00872, 0.90088, 0.91882, 1.0213, 0.8361, 1.02058, 0.62295, 0.54324, 0.89022, 1.08595, 1, 1, 0.90088, 1, 0.97455, 0.93582, 0.90088, 1, 1.05686, 0.8361, 0.99642, 0.99642, 0.99642, 0.72851, 0.90838, 0.90838, 0.90838, 0.90838, 0.90838, 0.90838, 0.868, 0.82391, 0.80061, 0.80061, 0.80061, 0.80061, 1.0258, 1.0258, 1.0258, 1.0258, 0.97484, 0.95546, 0.92179, 0.92179, 0.92179, 0.92179, 0.92179, 1.02058, 0.92179, 0.94438, 0.94438, 0.94438, 0.94438, 0.90406, 0.86958, 0.98225, 0.94938, 0.94938, 0.94938, 0.94938, 0.94938, 0.94938, 0.9031, 0.81093, 0.94938, 0.94938, 0.94938, 0.94938, 0.98621, 0.98621, 0.98621, 0.98621, 0.93969, 0.95933, 0.9446, 0.9446, 0.9446, 0.9446, 0.9446, 1.08595, 0.9446, 0.95442, 0.95442, 0.95442, 0.95442, 0.94039, 0.97898, 0.94039, 0.90838, 0.94938, 0.90838, 0.94938, 0.90838, 0.94938, 0.82391, 0.81093, 0.82391, 0.81093, 0.82391, 0.81093, 0.82391, 0.81093, 0.96376, 0.84313, 0.97484, 0.97571, 0.80061, 0.94938, 0.80061, 0.94938, 0.80061, 0.94938, 0.80061, 0.94938, 0.80061, 0.94938, 0.8768, 0.9577, 0.8768, 0.9577, 0.8768, 0.9577, 1, 1, 0.95407, 0.95933, 0.97069, 0.95933, 1.0258, 0.98621, 1.0258, 0.98621, 1.0258, 0.98621, 1.0258, 0.98621, 1.0258, 0.98621, 0.887, 1.01591, 0.73901, 1.0474, 1, 1, 0.97455, 0.83655, 0.98981, 1, 1, 0.83655, 0.73977, 0.83655, 0.73903, 0.84638, 1.033, 0.95546, 0.95933, 1, 1, 0.95546, 0.95933, 0.8271, 0.95417, 0.95933, 0.92179, 0.9446, 0.92179, 0.9446, 0.92179, 0.9446, 0.936, 0.91964, 0.82114, 0.97646, 1, 1, 0.82114, 0.97646, 0.8096, 0.78036, 0.8096, 0.78036, 1, 1, 0.8096, 0.78036, 1, 1, 0.89713, 0.77452, 0.89713, 1.10208, 0.94438, 0.95442, 0.94438, 0.95442, 0.94438, 0.95442, 0.94438, 0.95442, 0.94438, 0.95442, 0.94438, 0.95442, 0.94083, 0.97579, 0.90406, 0.94039, 0.90406, 0.9446, 0.938, 0.9446, 0.938, 0.9446, 0.938, 1, 0.99793, 0.90838, 0.94938, 0.868, 0.9031, 0.92179, 0.9446, 1, 1, 0.89713, 1.10208, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90989, 0.9358, 0.91945, 0.83181, 0.75261, 0.87992, 0.82976, 0.96034, 0.83689, 0.97268, 1.0078, 0.90838, 0.83637, 0.8019, 0.90157, 0.80061, 0.9446, 0.95407, 0.92436, 1.0258, 0.85022, 0.97153, 1.0156, 0.95546, 0.89192, 0.92179, 0.92361, 0.87107, 0.96318, 0.89713, 0.93704, 0.95638, 0.91905, 0.91709, 0.92796, 1.0258, 0.93704, 0.94836, 1.0373, 0.95933, 1.0078, 0.95871, 0.94836, 0.96174, 0.92601, 0.9498, 0.98607, 0.95776, 0.95933, 1.05453, 1.0078, 0.98275, 0.9314, 0.95617, 0.91701, 1.05993, 0.9446, 0.78367, 0.9553, 1, 0.86832, 1.0128, 0.95871, 0.99394, 0.87548, 0.96361, 0.86774, 1.0078, 0.95871, 0.9446, 0.95871, 0.86774, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.94083, 0.97579, 0.94083, 0.97579, 0.94083, 0.97579, 0.90406, 0.94039, 0.96694, 1, 0.89903, 1, 1, 1, 0.93582, 0.93582, 0.93582, 1, 0.908, 0.908, 0.918, 0.94219, 0.94219, 0.96544, 1, 1.285, 1, 1, 0.81079, 0.81079, 1, 1, 0.74854, 1, 1, 1, 1, 0.99793, 1, 1, 1, 0.65, 1, 1.36145, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.17173, 1, 0.80535, 0.76169, 1.02058, 1.0732, 1.05486, 1, 1, 1.30692, 1.08595, 1.08595, 1, 1.08595, 1.08595, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.16161, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.MyriadProBoldFactors = MyriadProBoldFactors; +const MyriadProBoldMetrics = { + lineHeight: 1.2, + lineGap: 0.2 +}; +exports.MyriadProBoldMetrics = MyriadProBoldMetrics; +const MyriadProBoldItalicFactors = [1.36898, 1, 1, 0.66227, 0.80779, 0.81625, 0.97276, 0.97276, 0.97733, 0.92222, 0.83266, 0.94292, 0.94292, 1.16148, 1.02058, 0.93582, 0.96694, 0.93582, 1.17337, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.78076, 0.78076, 1.02058, 1.02058, 1.02058, 0.71541, 0.76813, 0.85576, 0.80591, 0.80729, 0.94299, 0.77512, 0.83655, 0.86523, 0.92222, 0.98621, 0.71743, 0.81698, 0.79726, 0.98558, 0.92222, 0.90637, 0.83809, 0.90637, 0.80729, 0.76463, 0.86275, 0.90699, 0.91605, 0.9154, 0.85308, 0.85458, 0.90531, 0.94292, 1.21296, 0.94292, 1.02058, 0.89903, 1.18616, 0.99613, 0.91677, 0.78216, 0.91677, 0.90083, 0.98796, 0.9135, 0.92168, 0.95381, 0.98981, 0.95298, 0.95381, 0.93459, 0.92168, 0.91513, 0.92004, 0.91677, 0.95077, 0.748, 1.04502, 0.91677, 0.92061, 0.94236, 0.89544, 0.89364, 0.9, 0.80687, 0.8578, 0.80687, 1.02058, 0.80779, 0.97276, 0.97276, 0.97276, 0.97276, 0.8578, 0.99973, 1.18616, 0.91339, 1.08074, 0.82891, 1.02058, 0.55509, 0.71526, 0.89022, 1.08595, 1, 1, 1.18616, 1, 0.96736, 0.93582, 1.18616, 1, 1.04864, 0.82711, 0.99043, 0.99043, 0.99043, 0.71541, 0.85576, 0.85576, 0.85576, 0.85576, 0.85576, 0.85576, 0.845, 0.80729, 0.77512, 0.77512, 0.77512, 0.77512, 0.98621, 0.98621, 0.98621, 0.98621, 0.95961, 0.92222, 0.90637, 0.90637, 0.90637, 0.90637, 0.90637, 1.02058, 0.90251, 0.90699, 0.90699, 0.90699, 0.90699, 0.85458, 0.83659, 0.94951, 0.99613, 0.99613, 0.99613, 0.99613, 0.99613, 0.99613, 0.85811, 0.78216, 0.90083, 0.90083, 0.90083, 0.90083, 0.95381, 0.95381, 0.95381, 0.95381, 0.9135, 0.92168, 0.91513, 0.91513, 0.91513, 0.91513, 0.91513, 1.08595, 0.91677, 0.91677, 0.91677, 0.91677, 0.91677, 0.89364, 0.92332, 0.89364, 0.85576, 0.99613, 0.85576, 0.99613, 0.85576, 0.99613, 0.80729, 0.78216, 0.80729, 0.78216, 0.80729, 0.78216, 0.80729, 0.78216, 0.94299, 0.76783, 0.95961, 0.91677, 0.77512, 0.90083, 0.77512, 0.90083, 0.77512, 0.90083, 0.77512, 0.90083, 0.77512, 0.90083, 0.86523, 0.9135, 0.86523, 0.9135, 0.86523, 0.9135, 1, 1, 0.92222, 0.92168, 0.92222, 0.92168, 0.98621, 0.95381, 0.98621, 0.95381, 0.98621, 0.95381, 0.98621, 0.95381, 0.98621, 0.95381, 0.86036, 0.97096, 0.71743, 0.98981, 1, 1, 0.95298, 0.79726, 0.95381, 1, 1, 0.79726, 0.6894, 0.79726, 0.74321, 0.81691, 1.0006, 0.92222, 0.92168, 1, 1, 0.92222, 0.92168, 0.79464, 0.92098, 0.92168, 0.90637, 0.91513, 0.90637, 0.91513, 0.90637, 0.91513, 0.909, 0.87514, 0.80729, 0.95077, 1, 1, 0.80729, 0.95077, 0.76463, 0.748, 0.76463, 0.748, 1, 1, 0.76463, 0.748, 1, 1, 0.86275, 0.72651, 0.86275, 1.04502, 0.90699, 0.91677, 0.90699, 0.91677, 0.90699, 0.91677, 0.90699, 0.91677, 0.90699, 0.91677, 0.90699, 0.91677, 0.9154, 0.94236, 0.85458, 0.89364, 0.85458, 0.90531, 0.9, 0.90531, 0.9, 0.90531, 0.9, 1, 0.97276, 0.85576, 0.99613, 0.845, 0.85811, 0.90251, 0.91677, 1, 1, 0.86275, 1.04502, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.00899, 1.30628, 0.85576, 0.80178, 0.66862, 0.7927, 0.69323, 0.88127, 0.72459, 0.89711, 0.95381, 0.85576, 0.80591, 0.7805, 0.94729, 0.77512, 0.90531, 0.92222, 0.90637, 0.98621, 0.81698, 0.92655, 0.98558, 0.92222, 0.85359, 0.90637, 0.90976, 0.83809, 0.94523, 0.86275, 0.83509, 0.93157, 0.85308, 0.83392, 0.92346, 0.98621, 0.83509, 0.92886, 0.91324, 0.92168, 0.95381, 0.90646, 0.92886, 0.90557, 0.86847, 0.90276, 0.91324, 0.86842, 0.92168, 0.99531, 0.95381, 0.9224, 0.85408, 0.92699, 0.86847, 1.0051, 0.91513, 0.80487, 0.93481, 1, 0.88159, 1.05214, 0.90646, 0.97355, 0.81539, 0.89398, 0.85923, 0.95381, 0.90646, 0.91513, 0.90646, 0.85923, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9154, 0.94236, 0.9154, 0.94236, 0.9154, 0.94236, 0.85458, 0.89364, 0.96694, 1, 0.89903, 1, 1, 1, 0.91782, 0.91782, 0.91782, 1, 0.896, 0.896, 0.896, 0.9332, 0.9332, 0.95973, 1, 1.26, 1, 1, 0.80479, 0.80178, 1, 1, 0.85633, 1, 1, 1, 1, 0.97276, 1, 1, 1, 0.698, 1, 1.36145, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.14542, 1, 0.79199, 0.78694, 1.02058, 1.03493, 1.05486, 1, 1, 1.23026, 1.08595, 1.08595, 1, 1.08595, 1.08595, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.20006, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.MyriadProBoldItalicFactors = MyriadProBoldItalicFactors; +const MyriadProBoldItalicMetrics = { + lineHeight: 1.2, + lineGap: 0.2 +}; +exports.MyriadProBoldItalicMetrics = MyriadProBoldItalicMetrics; +const MyriadProItalicFactors = [1.36898, 1, 1, 0.65507, 0.84943, 0.85639, 0.88465, 0.88465, 0.86936, 0.88307, 0.86948, 0.85283, 0.85283, 1.06383, 1.02058, 0.75945, 0.9219, 0.75945, 1.17337, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.75945, 0.75945, 1.02058, 1.02058, 1.02058, 0.69046, 0.70926, 0.85158, 0.77812, 0.76852, 0.89591, 0.70466, 0.76125, 0.80094, 0.86822, 0.83864, 0.728, 0.77212, 0.79475, 0.93637, 0.87514, 0.8588, 0.76013, 0.8588, 0.72421, 0.69866, 0.77598, 0.85991, 0.80811, 0.87832, 0.78112, 0.77512, 0.8562, 1.0222, 1.18417, 1.0222, 1.27014, 0.89903, 1.15012, 0.93859, 0.94399, 0.846, 0.94399, 0.81453, 1.0186, 0.94219, 0.96017, 1.03075, 1.02175, 0.912, 1.03075, 0.96998, 0.96017, 0.93859, 0.94399, 0.94399, 0.95493, 0.746, 1.12658, 0.94578, 0.91, 0.979, 0.882, 0.882, 0.83, 0.85034, 0.83537, 0.85034, 1.02058, 0.70869, 0.88465, 0.88465, 0.88465, 0.88465, 0.83537, 0.90083, 1.15012, 0.9161, 0.94565, 0.73541, 1.02058, 0.53609, 0.69353, 0.79519, 1.08595, 1, 1, 1.15012, 1, 0.91974, 0.75945, 1.15012, 1, 0.9446, 0.73361, 0.9005, 0.9005, 0.9005, 0.62864, 0.85158, 0.85158, 0.85158, 0.85158, 0.85158, 0.85158, 0.773, 0.76852, 0.70466, 0.70466, 0.70466, 0.70466, 0.83864, 0.83864, 0.83864, 0.83864, 0.90561, 0.87514, 0.8588, 0.8588, 0.8588, 0.8588, 0.8588, 1.02058, 0.85751, 0.85991, 0.85991, 0.85991, 0.85991, 0.77512, 0.76013, 0.88075, 0.93859, 0.93859, 0.93859, 0.93859, 0.93859, 0.93859, 0.8075, 0.846, 0.81453, 0.81453, 0.81453, 0.81453, 0.82424, 0.82424, 0.82424, 0.82424, 0.9278, 0.96017, 0.93859, 0.93859, 0.93859, 0.93859, 0.93859, 1.08595, 0.8562, 0.94578, 0.94578, 0.94578, 0.94578, 0.882, 0.94578, 0.882, 0.85158, 0.93859, 0.85158, 0.93859, 0.85158, 0.93859, 0.76852, 0.846, 0.76852, 0.846, 0.76852, 0.846, 0.76852, 0.846, 0.89591, 0.8544, 0.90561, 0.94399, 0.70466, 0.81453, 0.70466, 0.81453, 0.70466, 0.81453, 0.70466, 0.81453, 0.70466, 0.81453, 0.80094, 0.94219, 0.80094, 0.94219, 0.80094, 0.94219, 1, 1, 0.86822, 0.96017, 0.86822, 0.96017, 0.83864, 0.82424, 0.83864, 0.82424, 0.83864, 0.82424, 0.83864, 1.03075, 0.83864, 0.82424, 0.81402, 1.02738, 0.728, 1.02175, 1, 1, 0.912, 0.79475, 1.03075, 1, 1, 0.79475, 0.83911, 0.79475, 0.66266, 0.80553, 1.06676, 0.87514, 0.96017, 1, 1, 0.87514, 0.96017, 0.86865, 0.87396, 0.96017, 0.8588, 0.93859, 0.8588, 0.93859, 0.8588, 0.93859, 0.867, 0.84759, 0.72421, 0.95493, 1, 1, 0.72421, 0.95493, 0.69866, 0.746, 0.69866, 0.746, 1, 1, 0.69866, 0.746, 1, 1, 0.77598, 0.88417, 0.77598, 1.12658, 0.85991, 0.94578, 0.85991, 0.94578, 0.85991, 0.94578, 0.85991, 0.94578, 0.85991, 0.94578, 0.85991, 0.94578, 0.87832, 0.979, 0.77512, 0.882, 0.77512, 0.8562, 0.83, 0.8562, 0.83, 0.8562, 0.83, 1, 0.88465, 0.85158, 0.93859, 0.773, 0.8075, 0.85751, 0.8562, 1, 1, 0.77598, 1.12658, 1.15012, 1.15012, 1.15012, 1.15012, 1.15012, 1.15313, 1.15012, 1.15012, 1.15012, 1.08106, 1.03901, 0.85158, 0.77025, 0.62264, 0.7646, 0.65351, 0.86026, 0.69461, 0.89947, 1.03075, 0.85158, 0.77812, 0.76449, 0.88836, 0.70466, 0.8562, 0.86822, 0.8588, 0.83864, 0.77212, 0.85308, 0.93637, 0.87514, 0.82352, 0.8588, 0.85701, 0.76013, 0.89058, 0.77598, 0.8156, 0.82565, 0.78112, 0.77899, 0.89386, 0.83864, 0.8156, 0.9486, 0.92388, 0.96186, 1.03075, 0.91123, 0.9486, 0.93298, 0.878, 0.93942, 0.92388, 0.84596, 0.96186, 0.95119, 1.03075, 0.922, 0.88787, 0.95829, 0.88, 0.93559, 0.93859, 0.78815, 0.93758, 1, 0.89217, 1.03737, 0.91123, 0.93969, 0.77487, 0.85769, 0.86799, 1.03075, 0.91123, 0.93859, 0.91123, 0.86799, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.87832, 0.979, 0.87832, 0.979, 0.87832, 0.979, 0.77512, 0.882, 0.9219, 1, 0.89903, 1, 1, 1, 0.87321, 0.87321, 0.87321, 1, 1.027, 1.027, 1.027, 0.86847, 0.86847, 0.79121, 1, 1.124, 1, 1, 0.73572, 0.73572, 1, 1, 0.85034, 1, 1, 1, 1, 0.88465, 1, 1, 1, 0.669, 1, 1.36145, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.04828, 1, 0.74948, 0.75187, 1.02058, 0.98391, 1.02119, 1, 1, 1.06233, 1.08595, 1.08595, 1, 1.08595, 1.08595, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.05233, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.MyriadProItalicFactors = MyriadProItalicFactors; +const MyriadProItalicMetrics = { + lineHeight: 1.2, + lineGap: 0.2 +}; +exports.MyriadProItalicMetrics = MyriadProItalicMetrics; +const MyriadProRegularFactors = [1.36898, 1, 1, 0.76305, 0.82784, 0.94935, 0.89364, 0.92241, 0.89073, 0.90706, 0.98472, 0.85283, 0.85283, 1.0664, 1.02058, 0.74505, 0.9219, 0.74505, 1.23456, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.74505, 0.74505, 1.02058, 1.02058, 1.02058, 0.73002, 0.72601, 0.91755, 0.8126, 0.80314, 0.92222, 0.73764, 0.79726, 0.83051, 0.90284, 0.86023, 0.74, 0.8126, 0.84869, 0.96518, 0.91115, 0.8858, 0.79761, 0.8858, 0.74498, 0.73914, 0.81363, 0.89591, 0.83659, 0.89633, 0.85608, 0.8111, 0.90531, 1.0222, 1.22736, 1.0222, 1.27014, 0.89903, 0.90088, 0.86667, 1.0231, 0.896, 1.01411, 0.90083, 1.05099, 1.00512, 0.99793, 1.05326, 1.09377, 0.938, 1.06226, 1.00119, 0.99793, 0.98714, 1.0231, 1.01231, 0.98196, 0.792, 1.19137, 0.99074, 0.962, 1.01915, 0.926, 0.942, 0.856, 0.85034, 0.92006, 0.85034, 1.02058, 0.69067, 0.92241, 0.92241, 0.92241, 0.92241, 0.92006, 0.9332, 0.90088, 0.91882, 0.93484, 0.75339, 1.02058, 0.56866, 0.54324, 0.79519, 1.08595, 1, 1, 0.90088, 1, 0.95325, 0.74505, 0.90088, 1, 0.97198, 0.75339, 0.91009, 0.91009, 0.91009, 0.66466, 0.91755, 0.91755, 0.91755, 0.91755, 0.91755, 0.91755, 0.788, 0.80314, 0.73764, 0.73764, 0.73764, 0.73764, 0.86023, 0.86023, 0.86023, 0.86023, 0.92915, 0.91115, 0.8858, 0.8858, 0.8858, 0.8858, 0.8858, 1.02058, 0.8858, 0.89591, 0.89591, 0.89591, 0.89591, 0.8111, 0.79611, 0.89713, 0.86667, 0.86667, 0.86667, 0.86667, 0.86667, 0.86667, 0.86936, 0.896, 0.90083, 0.90083, 0.90083, 0.90083, 0.84224, 0.84224, 0.84224, 0.84224, 0.97276, 0.99793, 0.98714, 0.98714, 0.98714, 0.98714, 0.98714, 1.08595, 0.89876, 0.99074, 0.99074, 0.99074, 0.99074, 0.942, 1.0231, 0.942, 0.91755, 0.86667, 0.91755, 0.86667, 0.91755, 0.86667, 0.80314, 0.896, 0.80314, 0.896, 0.80314, 0.896, 0.80314, 0.896, 0.92222, 0.93372, 0.92915, 1.01411, 0.73764, 0.90083, 0.73764, 0.90083, 0.73764, 0.90083, 0.73764, 0.90083, 0.73764, 0.90083, 0.83051, 1.00512, 0.83051, 1.00512, 0.83051, 1.00512, 1, 1, 0.90284, 0.99793, 0.90976, 0.99793, 0.86023, 0.84224, 0.86023, 0.84224, 0.86023, 0.84224, 0.86023, 1.05326, 0.86023, 0.84224, 0.82873, 1.07469, 0.74, 1.09377, 1, 1, 0.938, 0.84869, 1.06226, 1, 1, 0.84869, 0.83704, 0.84869, 0.81441, 0.85588, 1.08927, 0.91115, 0.99793, 1, 1, 0.91115, 0.99793, 0.91887, 0.90991, 0.99793, 0.8858, 0.98714, 0.8858, 0.98714, 0.8858, 0.98714, 0.894, 0.91434, 0.74498, 0.98196, 1, 1, 0.74498, 0.98196, 0.73914, 0.792, 0.73914, 0.792, 1, 1, 0.73914, 0.792, 1, 1, 0.81363, 0.904, 0.81363, 1.19137, 0.89591, 0.99074, 0.89591, 0.99074, 0.89591, 0.99074, 0.89591, 0.99074, 0.89591, 0.99074, 0.89591, 0.99074, 0.89633, 1.01915, 0.8111, 0.942, 0.8111, 0.90531, 0.856, 0.90531, 0.856, 0.90531, 0.856, 1, 0.92241, 0.91755, 0.86667, 0.788, 0.86936, 0.8858, 0.89876, 1, 1, 0.81363, 1.19137, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90388, 1.03901, 0.92138, 0.78105, 0.7154, 0.86169, 0.80513, 0.94007, 0.82528, 0.98612, 1.06226, 0.91755, 0.8126, 0.81884, 0.92819, 0.73764, 0.90531, 0.90284, 0.8858, 0.86023, 0.8126, 0.91172, 0.96518, 0.91115, 0.83089, 0.8858, 0.87791, 0.79761, 0.89297, 0.81363, 0.88157, 0.89992, 0.85608, 0.81992, 0.94307, 0.86023, 0.88157, 0.95308, 0.98699, 0.99793, 1.06226, 0.95817, 0.95308, 0.97358, 0.928, 0.98088, 0.98699, 0.92761, 0.99793, 0.96017, 1.06226, 0.986, 0.944, 0.95978, 0.938, 0.96705, 0.98714, 0.80442, 0.98972, 1, 0.89762, 1.04552, 0.95817, 0.99007, 0.87064, 0.91879, 0.88888, 1.06226, 0.95817, 0.98714, 0.95817, 0.88888, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.89633, 1.01915, 0.89633, 1.01915, 0.89633, 1.01915, 0.8111, 0.942, 0.9219, 1, 0.89903, 1, 1, 1, 0.93173, 0.93173, 0.93173, 1, 1.06304, 1.06304, 1.06904, 0.89903, 0.89903, 0.80549, 1, 1.156, 1, 1, 0.76575, 0.76575, 1, 1, 0.72458, 1, 1, 1, 1, 0.92241, 1, 1, 1, 0.619, 1, 1.36145, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.07257, 1, 0.74705, 0.71119, 1.02058, 1.024, 1.02119, 1, 1, 1.1536, 1.08595, 1.08595, 1, 1.08595, 1.08595, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.05638, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.MyriadProRegularFactors = MyriadProRegularFactors; +const MyriadProRegularMetrics = { + lineHeight: 1.2, + lineGap: 0.2 +}; +exports.MyriadProRegularMetrics = MyriadProRegularMetrics; + +/***/ }), +/* 56 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.SegoeuiRegularMetrics = exports.SegoeuiRegularFactors = exports.SegoeuiItalicMetrics = exports.SegoeuiItalicFactors = exports.SegoeuiBoldMetrics = exports.SegoeuiBoldItalicMetrics = exports.SegoeuiBoldItalicFactors = exports.SegoeuiBoldFactors = void 0; +const SegoeuiBoldFactors = [1.76738, 1, 1, 0.99297, 0.9824, 1.04016, 1.06497, 1.03424, 0.97529, 1.17647, 1.23203, 1.1085, 1.1085, 1.16939, 1.2107, 0.9754, 1.21408, 0.9754, 1.59578, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 0.81378, 0.81378, 1.2107, 1.2107, 1.2107, 0.71703, 0.97847, 0.97363, 0.88776, 0.8641, 1.02096, 0.79795, 0.85132, 0.914, 1.06085, 1.1406, 0.8007, 0.89858, 0.83693, 1.14889, 1.09398, 0.97489, 0.92094, 0.97489, 0.90399, 0.84041, 0.95923, 1.00135, 1, 1.06467, 0.98243, 0.90996, 0.99361, 1.1085, 1.56942, 1.1085, 1.2107, 0.74627, 0.94282, 0.96752, 1.01519, 0.86304, 1.01359, 0.97278, 1.15103, 1.01359, 0.98561, 1.02285, 1.02285, 1.00527, 1.02285, 1.0302, 0.99041, 1.0008, 1.01519, 1.01359, 1.02258, 0.79104, 1.16862, 0.99041, 0.97454, 1.02511, 0.99298, 0.96752, 0.95801, 0.94856, 1.16579, 0.94856, 1.2107, 0.9824, 1.03424, 1.03424, 1, 1.03424, 1.16579, 0.8727, 1.3871, 1.18622, 1.10818, 1.04478, 1.2107, 1.18622, 0.75155, 0.94994, 1.28826, 1.21408, 1.21408, 0.91056, 1, 0.91572, 0.9754, 0.64663, 1.18328, 1.24866, 1.04478, 1.14169, 1.15749, 1.17389, 0.71703, 0.97363, 0.97363, 0.97363, 0.97363, 0.97363, 0.97363, 0.93506, 0.8641, 0.79795, 0.79795, 0.79795, 0.79795, 1.1406, 1.1406, 1.1406, 1.1406, 1.02096, 1.09398, 0.97426, 0.97426, 0.97426, 0.97426, 0.97426, 1.2107, 0.97489, 1.00135, 1.00135, 1.00135, 1.00135, 0.90996, 0.92094, 1.02798, 0.96752, 0.96752, 0.96752, 0.96752, 0.96752, 0.96752, 0.93136, 0.86304, 0.97278, 0.97278, 0.97278, 0.97278, 1.02285, 1.02285, 1.02285, 1.02285, 0.97122, 0.99041, 1, 1, 1, 1, 1, 1.28826, 1.0008, 0.99041, 0.99041, 0.99041, 0.99041, 0.96752, 1.01519, 0.96752, 0.97363, 0.96752, 0.97363, 0.96752, 0.97363, 0.96752, 0.8641, 0.86304, 0.8641, 0.86304, 0.8641, 0.86304, 0.8641, 0.86304, 1.02096, 1.03057, 1.02096, 1.03517, 0.79795, 0.97278, 0.79795, 0.97278, 0.79795, 0.97278, 0.79795, 0.97278, 0.79795, 0.97278, 0.914, 1.01359, 0.914, 1.01359, 0.914, 1.01359, 1, 1, 1.06085, 0.98561, 1.06085, 1.00879, 1.1406, 1.02285, 1.1406, 1.02285, 1.1406, 1.02285, 1.1406, 1.02285, 1.1406, 1.02285, 0.97138, 1.08692, 0.8007, 1.02285, 1, 1, 1.00527, 0.83693, 1.02285, 1, 1, 0.83693, 0.9455, 0.83693, 0.90418, 0.83693, 1.13005, 1.09398, 0.99041, 1, 1, 1.09398, 0.99041, 0.96692, 1.09251, 0.99041, 0.97489, 1.0008, 0.97489, 1.0008, 0.97489, 1.0008, 0.93994, 0.97931, 0.90399, 1.02258, 1, 1, 0.90399, 1.02258, 0.84041, 0.79104, 0.84041, 0.79104, 0.84041, 0.79104, 0.84041, 0.79104, 1, 1, 0.95923, 1.07034, 0.95923, 1.16862, 1.00135, 0.99041, 1.00135, 0.99041, 1.00135, 0.99041, 1.00135, 0.99041, 1.00135, 0.99041, 1.00135, 0.99041, 1.06467, 1.02511, 0.90996, 0.96752, 0.90996, 0.99361, 0.95801, 0.99361, 0.95801, 0.99361, 0.95801, 1.07733, 1.03424, 0.97363, 0.96752, 0.93506, 0.93136, 0.97489, 1.0008, 1, 1, 0.95923, 1.16862, 1.15103, 1.15103, 1.01173, 1.03959, 0.75953, 0.81378, 0.79912, 1.15103, 1.21994, 0.95161, 0.87815, 1.01149, 0.81525, 0.7676, 0.98167, 1.01134, 1.02546, 0.84097, 1.03089, 1.18102, 0.97363, 0.88776, 0.85134, 0.97826, 0.79795, 0.99361, 1.06085, 0.97489, 1.1406, 0.89858, 1.0388, 1.14889, 1.09398, 0.86039, 0.97489, 1.0595, 0.92094, 0.94793, 0.95923, 0.90996, 0.99346, 0.98243, 1.02112, 0.95493, 1.1406, 0.90996, 1.03574, 1.02597, 1.0008, 1.18102, 1.06628, 1.03574, 1.0192, 1.01932, 1.00886, 0.97531, 1.0106, 1.0008, 1.13189, 1.18102, 1.02277, 0.98683, 1.0016, 0.99561, 1.07237, 1.0008, 0.90434, 0.99921, 0.93803, 0.8965, 1.23085, 1.06628, 1.04983, 0.96268, 1.0499, 0.98439, 1.18102, 1.06628, 1.0008, 1.06628, 0.98439, 0.79795, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.09466, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.97278, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.02065, 1, 1, 1, 1, 1, 1, 1.06467, 1.02511, 1.06467, 1.02511, 1.06467, 1.02511, 0.90996, 0.96752, 1, 1.21408, 0.89903, 1, 1, 0.75155, 1.04394, 1.04394, 1.04394, 1.04394, 0.98633, 0.98633, 0.98633, 0.73047, 0.73047, 1.20642, 0.91211, 1.25635, 1.222, 1.02956, 1.03372, 1.03372, 0.96039, 1.24633, 1, 1.12454, 0.93503, 1.03424, 1.19687, 1.03424, 1, 1, 1, 0.771, 1, 1, 1.15749, 1.15749, 1.15749, 1.10948, 0.86279, 0.94434, 0.86279, 0.94434, 0.86182, 1, 1, 1.16897, 1, 0.96085, 0.90137, 1.2107, 1.18416, 1.13973, 0.69825, 0.9716, 2.10339, 1.29004, 1.29004, 1.21172, 1.29004, 1.29004, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.42603, 1, 0.99862, 0.99862, 1, 0.87025, 0.87025, 0.87025, 0.87025, 1.18874, 1.42603, 1, 1.42603, 1.42603, 0.99862, 1, 1, 1, 1, 1, 1.2886, 1.04315, 1.15296, 1.34163, 1, 1, 1, 1.09193, 1.09193, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.SegoeuiBoldFactors = SegoeuiBoldFactors; +const SegoeuiBoldMetrics = { + lineHeight: 1.33008, + lineGap: 0 +}; +exports.SegoeuiBoldMetrics = SegoeuiBoldMetrics; +const SegoeuiBoldItalicFactors = [1.76738, 1, 1, 0.98946, 1.03959, 1.04016, 1.02809, 1.036, 0.97639, 1.10953, 1.23203, 1.11144, 1.11144, 1.16939, 1.21237, 0.9754, 1.21261, 0.9754, 1.59754, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 0.81378, 0.81378, 1.21237, 1.21237, 1.21237, 0.73541, 0.97847, 0.97363, 0.89723, 0.87897, 1.0426, 0.79429, 0.85292, 0.91149, 1.05815, 1.1406, 0.79631, 0.90128, 0.83853, 1.04396, 1.10615, 0.97552, 0.94436, 0.97552, 0.88641, 0.80527, 0.96083, 1.00135, 1, 1.06777, 0.9817, 0.91142, 0.99361, 1.11144, 1.57293, 1.11144, 1.21237, 0.74627, 1.31818, 1.06585, 0.97042, 0.83055, 0.97042, 0.93503, 1.1261, 0.97042, 0.97922, 1.14236, 0.94552, 1.01054, 1.14236, 1.02471, 0.97922, 0.94165, 0.97042, 0.97042, 1.0276, 0.78929, 1.1261, 0.97922, 0.95874, 1.02197, 0.98507, 0.96752, 0.97168, 0.95107, 1.16579, 0.95107, 1.21237, 1.03959, 1.036, 1.036, 1, 1.036, 1.16579, 0.87357, 1.31818, 1.18754, 1.26781, 1.05356, 1.21237, 1.18622, 0.79487, 0.94994, 1.29004, 1.24047, 1.24047, 1.31818, 1, 0.91484, 0.9754, 1.31818, 1.1349, 1.24866, 1.05356, 1.13934, 1.15574, 1.17389, 0.73541, 0.97363, 0.97363, 0.97363, 0.97363, 0.97363, 0.97363, 0.94385, 0.87897, 0.79429, 0.79429, 0.79429, 0.79429, 1.1406, 1.1406, 1.1406, 1.1406, 1.0426, 1.10615, 0.97552, 0.97552, 0.97552, 0.97552, 0.97552, 1.21237, 0.97552, 1.00135, 1.00135, 1.00135, 1.00135, 0.91142, 0.94436, 0.98721, 1.06585, 1.06585, 1.06585, 1.06585, 1.06585, 1.06585, 0.96705, 0.83055, 0.93503, 0.93503, 0.93503, 0.93503, 1.14236, 1.14236, 1.14236, 1.14236, 0.93125, 0.97922, 0.94165, 0.94165, 0.94165, 0.94165, 0.94165, 1.29004, 0.94165, 0.97922, 0.97922, 0.97922, 0.97922, 0.96752, 0.97042, 0.96752, 0.97363, 1.06585, 0.97363, 1.06585, 0.97363, 1.06585, 0.87897, 0.83055, 0.87897, 0.83055, 0.87897, 0.83055, 0.87897, 0.83055, 1.0426, 1.0033, 1.0426, 0.97042, 0.79429, 0.93503, 0.79429, 0.93503, 0.79429, 0.93503, 0.79429, 0.93503, 0.79429, 0.93503, 0.91149, 0.97042, 0.91149, 0.97042, 0.91149, 0.97042, 1, 1, 1.05815, 0.97922, 1.05815, 0.97922, 1.1406, 1.14236, 1.1406, 1.14236, 1.1406, 1.14236, 1.1406, 1.14236, 1.1406, 1.14236, 0.97441, 1.04302, 0.79631, 1.01582, 1, 1, 1.01054, 0.83853, 1.14236, 1, 1, 0.83853, 1.09125, 0.83853, 0.90418, 0.83853, 1.19508, 1.10615, 0.97922, 1, 1, 1.10615, 0.97922, 1.01034, 1.10466, 0.97922, 0.97552, 0.94165, 0.97552, 0.94165, 0.97552, 0.94165, 0.91602, 0.91981, 0.88641, 1.0276, 1, 1, 0.88641, 1.0276, 0.80527, 0.78929, 0.80527, 0.78929, 0.80527, 0.78929, 0.80527, 0.78929, 1, 1, 0.96083, 1.05403, 0.95923, 1.16862, 1.00135, 0.97922, 1.00135, 0.97922, 1.00135, 0.97922, 1.00135, 0.97922, 1.00135, 0.97922, 1.00135, 0.97922, 1.06777, 1.02197, 0.91142, 0.96752, 0.91142, 0.99361, 0.97168, 0.99361, 0.97168, 0.99361, 0.97168, 1.23199, 1.036, 0.97363, 1.06585, 0.94385, 0.96705, 0.97552, 0.94165, 1, 1, 0.96083, 1.1261, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 0.95161, 1.27126, 1.00811, 0.83284, 0.77702, 0.99137, 0.95253, 1.0347, 0.86142, 1.07205, 1.14236, 0.97363, 0.89723, 0.86869, 1.09818, 0.79429, 0.99361, 1.05815, 0.97552, 1.1406, 0.90128, 1.06662, 1.04396, 1.10615, 0.84918, 0.97552, 1.04694, 0.94436, 0.98015, 0.96083, 0.91142, 1.00356, 0.9817, 1.01945, 0.98999, 1.1406, 0.91142, 1.04961, 0.9898, 1.00639, 1.14236, 1.07514, 1.04961, 0.99607, 1.02897, 1.008, 0.9898, 0.95134, 1.00639, 1.11121, 1.14236, 1.00518, 0.97981, 1.02186, 1, 1.08578, 0.94165, 0.99314, 0.98387, 0.93028, 0.93377, 1.35125, 1.07514, 1.10687, 0.93491, 1.04232, 1.00351, 1.14236, 1.07514, 0.94165, 1.07514, 1.00351, 0.79429, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.09097, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.93503, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.96609, 1, 1, 1, 1, 1, 1, 1.06777, 1.02197, 1.06777, 1.02197, 1.06777, 1.02197, 0.91142, 0.96752, 1, 1.21261, 0.89903, 1, 1, 0.75155, 1.04745, 1.04745, 1.04745, 1.04394, 0.98633, 0.98633, 0.98633, 0.72959, 0.72959, 1.20502, 0.91406, 1.26514, 1.222, 1.02956, 1.03372, 1.03372, 0.96039, 1.24633, 1, 1.09125, 0.93327, 1.03336, 1.16541, 1.036, 1, 1, 1, 0.771, 1, 1, 1.15574, 1.15574, 1.15574, 1.15574, 0.86364, 0.94434, 0.86279, 0.94434, 0.86224, 1, 1, 1.16798, 1, 0.96085, 0.90068, 1.21237, 1.18416, 1.13904, 0.69825, 0.9716, 2.10339, 1.29004, 1.29004, 1.21339, 1.29004, 1.29004, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.42603, 1, 0.99862, 0.99862, 1, 0.87025, 0.87025, 0.87025, 0.87025, 1.18775, 1.42603, 1, 1.42603, 1.42603, 0.99862, 1, 1, 1, 1, 1, 1.2886, 1.04315, 1.15296, 1.34163, 1, 1, 1, 1.13269, 1.13269, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.SegoeuiBoldItalicFactors = SegoeuiBoldItalicFactors; +const SegoeuiBoldItalicMetrics = { + lineHeight: 1.33008, + lineGap: 0 +}; +exports.SegoeuiBoldItalicMetrics = SegoeuiBoldItalicMetrics; +const SegoeuiItalicFactors = [1.76738, 1, 1, 0.98946, 1.14763, 1.05365, 1.06234, 0.96927, 0.92586, 1.15373, 1.18414, 0.91349, 0.91349, 1.07403, 1.17308, 0.78383, 1.20088, 0.78383, 1.42531, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.78383, 0.78383, 1.17308, 1.17308, 1.17308, 0.77349, 0.94565, 0.94729, 0.85944, 0.88506, 0.9858, 0.74817, 0.80016, 0.88449, 0.98039, 0.95782, 0.69238, 0.89898, 0.83231, 0.98183, 1.03989, 0.96924, 0.86237, 0.96924, 0.80595, 0.74524, 0.86091, 0.95402, 0.94143, 0.98448, 0.8858, 0.83089, 0.93285, 1.0949, 1.39016, 1.0949, 1.45994, 0.74627, 1.04839, 0.97454, 0.97454, 0.87207, 0.97454, 0.87533, 1.06151, 0.97454, 1.00176, 1.16484, 1.08132, 0.98047, 1.16484, 1.02989, 1.01054, 0.96225, 0.97454, 0.97454, 1.06598, 0.79004, 1.16344, 1.00351, 0.94629, 0.9973, 0.91016, 0.96777, 0.9043, 0.91082, 0.92481, 0.91082, 1.17308, 0.95748, 0.96927, 0.96927, 1, 0.96927, 0.92481, 0.80597, 1.04839, 1.23393, 1.1781, 0.9245, 1.17308, 1.20808, 0.63218, 0.94261, 1.24822, 1.09971, 1.09971, 1.04839, 1, 0.85273, 0.78032, 1.04839, 1.09971, 1.22326, 0.9245, 1.09836, 1.13525, 1.15222, 0.70424, 0.94729, 0.94729, 0.94729, 0.94729, 0.94729, 0.94729, 0.85498, 0.88506, 0.74817, 0.74817, 0.74817, 0.74817, 0.95782, 0.95782, 0.95782, 0.95782, 0.9858, 1.03989, 0.96924, 0.96924, 0.96924, 0.96924, 0.96924, 1.17308, 0.96924, 0.95402, 0.95402, 0.95402, 0.95402, 0.83089, 0.86237, 0.88409, 0.97454, 0.97454, 0.97454, 0.97454, 0.97454, 0.97454, 0.92916, 0.87207, 0.87533, 0.87533, 0.87533, 0.87533, 0.93146, 0.93146, 0.93146, 0.93146, 0.93854, 1.01054, 0.96225, 0.96225, 0.96225, 0.96225, 0.96225, 1.24822, 0.8761, 1.00351, 1.00351, 1.00351, 1.00351, 0.96777, 0.97454, 0.96777, 0.94729, 0.97454, 0.94729, 0.97454, 0.94729, 0.97454, 0.88506, 0.87207, 0.88506, 0.87207, 0.88506, 0.87207, 0.88506, 0.87207, 0.9858, 0.95391, 0.9858, 0.97454, 0.74817, 0.87533, 0.74817, 0.87533, 0.74817, 0.87533, 0.74817, 0.87533, 0.74817, 0.87533, 0.88449, 0.97454, 0.88449, 0.97454, 0.88449, 0.97454, 1, 1, 0.98039, 1.00176, 0.98039, 1.00176, 0.95782, 0.93146, 0.95782, 0.93146, 0.95782, 0.93146, 0.95782, 1.16484, 0.95782, 0.93146, 0.84421, 1.12761, 0.69238, 1.08132, 1, 1, 0.98047, 0.83231, 1.16484, 1, 1, 0.84723, 1.04861, 0.84723, 0.78755, 0.83231, 1.23736, 1.03989, 1.01054, 1, 1, 1.03989, 1.01054, 0.9857, 1.03849, 1.01054, 0.96924, 0.96225, 0.96924, 0.96225, 0.96924, 0.96225, 0.92383, 0.90171, 0.80595, 1.06598, 1, 1, 0.80595, 1.06598, 0.74524, 0.79004, 0.74524, 0.79004, 0.74524, 0.79004, 0.74524, 0.79004, 1, 1, 0.86091, 1.02759, 0.85771, 1.16344, 0.95402, 1.00351, 0.95402, 1.00351, 0.95402, 1.00351, 0.95402, 1.00351, 0.95402, 1.00351, 0.95402, 1.00351, 0.98448, 0.9973, 0.83089, 0.96777, 0.83089, 0.93285, 0.9043, 0.93285, 0.9043, 0.93285, 0.9043, 1.31868, 0.96927, 0.94729, 0.97454, 0.85498, 0.92916, 0.96924, 0.8761, 1, 1, 0.86091, 1.16344, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 0.81965, 0.81965, 0.94729, 0.78032, 0.71022, 0.90883, 0.84171, 0.99877, 0.77596, 1.05734, 1.2, 0.94729, 0.85944, 0.82791, 0.9607, 0.74817, 0.93285, 0.98039, 0.96924, 0.95782, 0.89898, 0.98316, 0.98183, 1.03989, 0.78614, 0.96924, 0.97642, 0.86237, 0.86075, 0.86091, 0.83089, 0.90082, 0.8858, 0.97296, 1.01284, 0.95782, 0.83089, 1.0976, 1.04, 1.03342, 1.2, 1.0675, 1.0976, 0.98205, 1.03809, 1.05097, 1.04, 0.95364, 1.03342, 1.05401, 1.2, 1.02148, 1.0119, 1.04724, 1.0127, 1.02732, 0.96225, 0.8965, 0.97783, 0.93574, 0.94818, 1.30679, 1.0675, 1.11826, 0.99821, 1.0557, 1.0326, 1.2, 1.0675, 0.96225, 1.0675, 1.0326, 0.74817, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.03754, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.87533, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.98705, 1, 1, 1, 1, 1, 1, 0.98448, 0.9973, 0.98448, 0.9973, 0.98448, 0.9973, 0.83089, 0.96777, 1, 1.20088, 0.89903, 1, 1, 0.75155, 0.94945, 0.94945, 0.94945, 0.94945, 1.12317, 1.12317, 1.12317, 0.67603, 0.67603, 1.15621, 0.73584, 1.21191, 1.22135, 1.06483, 0.94868, 0.94868, 0.95996, 1.24633, 1, 1.07497, 0.87709, 0.96927, 1.01473, 0.96927, 1, 1, 1, 0.77295, 1, 1, 1.09836, 1.09836, 1.09836, 1.01522, 0.86321, 0.94434, 0.8649, 0.94434, 0.86182, 1, 1, 1.083, 1, 0.91578, 0.86438, 1.17308, 1.18416, 1.14589, 0.69825, 0.97622, 1.96791, 1.24822, 1.24822, 1.17308, 1.24822, 1.24822, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.42603, 1, 0.99862, 0.99862, 1, 0.87025, 0.87025, 0.87025, 0.87025, 1.17984, 1.42603, 1, 1.42603, 1.42603, 0.99862, 1, 1, 1, 1, 1, 1.2886, 1.04315, 1.15296, 1.34163, 1, 1, 1, 1.10742, 1.10742, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.SegoeuiItalicFactors = SegoeuiItalicFactors; +const SegoeuiItalicMetrics = { + lineHeight: 1.33008, + lineGap: 0 +}; +exports.SegoeuiItalicMetrics = SegoeuiItalicMetrics; +const SegoeuiRegularFactors = [1.76738, 1, 1, 0.98594, 1.02285, 1.10454, 1.06234, 0.96927, 0.92037, 1.19985, 1.2046, 0.90616, 0.90616, 1.07152, 1.1714, 0.78032, 1.20088, 0.78032, 1.40246, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.78032, 0.78032, 1.1714, 1.1714, 1.1714, 0.80597, 0.94084, 0.96706, 0.85944, 0.85734, 0.97093, 0.75842, 0.79936, 0.88198, 0.9831, 0.95782, 0.71387, 0.86969, 0.84636, 1.07796, 1.03584, 0.96924, 0.83968, 0.96924, 0.82826, 0.79649, 0.85771, 0.95132, 0.93119, 0.98965, 0.88433, 0.8287, 0.93365, 1.08612, 1.3638, 1.08612, 1.45786, 0.74627, 0.80499, 0.91484, 1.05707, 0.92383, 1.05882, 0.9403, 1.12654, 1.05882, 1.01756, 1.09011, 1.09011, 0.99414, 1.09011, 1.034, 1.01756, 1.05356, 1.05707, 1.05882, 1.04399, 0.84863, 1.21968, 1.01756, 0.95801, 1.00068, 0.91797, 0.96777, 0.9043, 0.90351, 0.92105, 0.90351, 1.1714, 0.85337, 0.96927, 0.96927, 0.99912, 0.96927, 0.92105, 0.80597, 1.2434, 1.20808, 1.05937, 0.90957, 1.1714, 1.20808, 0.75155, 0.94261, 1.24644, 1.09971, 1.09971, 0.84751, 1, 0.85273, 0.78032, 0.61584, 1.05425, 1.17914, 0.90957, 1.08665, 1.11593, 1.14169, 0.73381, 0.96706, 0.96706, 0.96706, 0.96706, 0.96706, 0.96706, 0.86035, 0.85734, 0.75842, 0.75842, 0.75842, 0.75842, 0.95782, 0.95782, 0.95782, 0.95782, 0.97093, 1.03584, 0.96924, 0.96924, 0.96924, 0.96924, 0.96924, 1.1714, 0.96924, 0.95132, 0.95132, 0.95132, 0.95132, 0.8287, 0.83968, 0.89049, 0.91484, 0.91484, 0.91484, 0.91484, 0.91484, 0.91484, 0.93575, 0.92383, 0.9403, 0.9403, 0.9403, 0.9403, 0.8717, 0.8717, 0.8717, 0.8717, 1.00527, 1.01756, 1.05356, 1.05356, 1.05356, 1.05356, 1.05356, 1.24644, 0.95923, 1.01756, 1.01756, 1.01756, 1.01756, 0.96777, 1.05707, 0.96777, 0.96706, 0.91484, 0.96706, 0.91484, 0.96706, 0.91484, 0.85734, 0.92383, 0.85734, 0.92383, 0.85734, 0.92383, 0.85734, 0.92383, 0.97093, 1.0969, 0.97093, 1.05882, 0.75842, 0.9403, 0.75842, 0.9403, 0.75842, 0.9403, 0.75842, 0.9403, 0.75842, 0.9403, 0.88198, 1.05882, 0.88198, 1.05882, 0.88198, 1.05882, 1, 1, 0.9831, 1.01756, 0.9831, 1.01756, 0.95782, 0.8717, 0.95782, 0.8717, 0.95782, 0.8717, 0.95782, 1.09011, 0.95782, 0.8717, 0.84784, 1.11551, 0.71387, 1.09011, 1, 1, 0.99414, 0.84636, 1.09011, 1, 1, 0.84636, 1.0536, 0.84636, 0.94298, 0.84636, 1.23297, 1.03584, 1.01756, 1, 1, 1.03584, 1.01756, 1.00323, 1.03444, 1.01756, 0.96924, 1.05356, 0.96924, 1.05356, 0.96924, 1.05356, 0.93066, 0.98293, 0.82826, 1.04399, 1, 1, 0.82826, 1.04399, 0.79649, 0.84863, 0.79649, 0.84863, 0.79649, 0.84863, 0.79649, 0.84863, 1, 1, 0.85771, 1.17318, 0.85771, 1.21968, 0.95132, 1.01756, 0.95132, 1.01756, 0.95132, 1.01756, 0.95132, 1.01756, 0.95132, 1.01756, 0.95132, 1.01756, 0.98965, 1.00068, 0.8287, 0.96777, 0.8287, 0.93365, 0.9043, 0.93365, 0.9043, 0.93365, 0.9043, 1.08571, 0.96927, 0.96706, 0.91484, 0.86035, 0.93575, 0.96924, 0.95923, 1, 1, 0.85771, 1.21968, 1.11437, 1.11437, 0.93109, 0.91202, 0.60411, 0.84164, 0.55572, 1.01173, 0.97361, 0.81818, 0.81818, 0.96635, 0.78032, 0.72727, 0.92366, 0.98601, 1.03405, 0.77968, 1.09799, 1.2, 0.96706, 0.85944, 0.85638, 0.96491, 0.75842, 0.93365, 0.9831, 0.96924, 0.95782, 0.86969, 0.94152, 1.07796, 1.03584, 0.78437, 0.96924, 0.98715, 0.83968, 0.83491, 0.85771, 0.8287, 0.94492, 0.88433, 0.9287, 1.0098, 0.95782, 0.8287, 1.0625, 0.98248, 1.03424, 1.2, 1.01071, 1.0625, 0.95246, 1.03809, 1.04912, 0.98248, 1.00221, 1.03424, 1.05443, 1.2, 1.04785, 0.99609, 1.00169, 1.05176, 0.99346, 1.05356, 0.9087, 1.03004, 0.95542, 0.93117, 1.23362, 1.01071, 1.07831, 1.02512, 1.05205, 1.03502, 1.2, 1.01071, 1.05356, 1.01071, 1.03502, 0.75842, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.03719, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9403, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.04021, 1, 1, 1, 1, 1, 1, 0.98965, 1.00068, 0.98965, 1.00068, 0.98965, 1.00068, 0.8287, 0.96777, 1, 1.20088, 0.89903, 1, 1, 0.75155, 1.03077, 1.03077, 1.03077, 1.03077, 1.13196, 1.13196, 1.13196, 0.67428, 0.67428, 1.16039, 0.73291, 1.20996, 1.22135, 1.06483, 0.94868, 0.94868, 0.95996, 1.24633, 1, 1.07497, 0.87796, 0.96927, 1.01518, 0.96927, 1, 1, 1, 0.77295, 1, 1, 1.10539, 1.10539, 1.11358, 1.06967, 0.86279, 0.94434, 0.86279, 0.94434, 0.86182, 1, 1, 1.083, 1, 0.91578, 0.86507, 1.1714, 1.18416, 1.14589, 0.69825, 0.97622, 1.9697, 1.24822, 1.24822, 1.17238, 1.24822, 1.24822, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.42603, 1, 0.99862, 0.99862, 1, 0.87025, 0.87025, 0.87025, 0.87025, 1.18083, 1.42603, 1, 1.42603, 1.42603, 0.99862, 1, 1, 1, 1, 1, 1.2886, 1.04315, 1.15296, 1.34163, 1, 1, 1, 1.10938, 1.10938, 1, 1, 1, 1.05425, 1.09971, 1.09971, 1.09971, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +exports.SegoeuiRegularFactors = SegoeuiRegularFactors; +const SegoeuiRegularMetrics = { + lineHeight: 1.33008, + lineGap: 0 +}; +exports.SegoeuiRegularMetrics = SegoeuiRegularMetrics; + +/***/ }), +/* 57 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PostScriptEvaluator = exports.PostScriptCompiler = exports.PDFFunctionFactory = void 0; +exports.isPDFFunction = isPDFFunction; + +var _primitives = __w_pdfjs_require__(5); + +var _util = __w_pdfjs_require__(2); + +var _ps_parser = __w_pdfjs_require__(58); + +var _base_stream = __w_pdfjs_require__(7); + +var _image_utils = __w_pdfjs_require__(59); + +class PDFFunctionFactory { + constructor({ + xref, + isEvalSupported = true + }) { + this.xref = xref; + this.isEvalSupported = isEvalSupported !== false; + } + + create(fn) { + const cachedFunction = this.getCached(fn); + + if (cachedFunction) { + return cachedFunction; + } + + const parsedFunction = PDFFunction.parse({ + xref: this.xref, + isEvalSupported: this.isEvalSupported, + fn: fn instanceof _primitives.Ref ? this.xref.fetch(fn) : fn + }); + + this._cache(fn, parsedFunction); + + return parsedFunction; + } + + createFromArray(fnObj) { + const cachedFunction = this.getCached(fnObj); + + if (cachedFunction) { + return cachedFunction; + } + + const parsedFunction = PDFFunction.parseArray({ + xref: this.xref, + isEvalSupported: this.isEvalSupported, + fnObj: fnObj instanceof _primitives.Ref ? this.xref.fetch(fnObj) : fnObj + }); + + this._cache(fnObj, parsedFunction); + + return parsedFunction; + } + + getCached(cacheKey) { + let fnRef; + + if (cacheKey instanceof _primitives.Ref) { + fnRef = cacheKey; + } else if (cacheKey instanceof _primitives.Dict) { + fnRef = cacheKey.objId; + } else if (cacheKey instanceof _base_stream.BaseStream) { + fnRef = cacheKey.dict && cacheKey.dict.objId; + } + + if (fnRef) { + const localFunction = this._localFunctionCache.getByRef(fnRef); + + if (localFunction) { + return localFunction; + } + } + + return null; + } + + _cache(cacheKey, parsedFunction) { + if (!parsedFunction) { + throw new Error('PDFFunctionFactory._cache - expected "parsedFunction" argument.'); + } + + let fnRef; + + if (cacheKey instanceof _primitives.Ref) { + fnRef = cacheKey; + } else if (cacheKey instanceof _primitives.Dict) { + fnRef = cacheKey.objId; + } else if (cacheKey instanceof _base_stream.BaseStream) { + fnRef = cacheKey.dict && cacheKey.dict.objId; + } + + if (fnRef) { + this._localFunctionCache.set(null, fnRef, parsedFunction); + } + } + + get _localFunctionCache() { + return (0, _util.shadow)(this, "_localFunctionCache", new _image_utils.LocalFunctionCache()); + } + +} + +exports.PDFFunctionFactory = PDFFunctionFactory; + +function toNumberArray(arr) { + if (!Array.isArray(arr)) { + return null; + } + + const length = arr.length; + + for (let i = 0; i < length; i++) { + if (typeof arr[i] !== "number") { + const result = new Array(length); + + for (let j = 0; j < length; j++) { + result[j] = +arr[j]; + } + + return result; + } + } + + return arr; +} + +class PDFFunction { + static getSampleArray(size, outputSize, bps, stream) { + let i, ii; + let length = 1; + + for (i = 0, ii = size.length; i < ii; i++) { + length *= size[i]; + } + + length *= outputSize; + const array = new Array(length); + let codeSize = 0; + let codeBuf = 0; + const sampleMul = 1.0 / (2.0 ** bps - 1); + const strBytes = stream.getBytes((length * bps + 7) / 8); + let strIdx = 0; + + for (i = 0; i < length; i++) { + while (codeSize < bps) { + codeBuf <<= 8; + codeBuf |= strBytes[strIdx++]; + codeSize += 8; + } + + codeSize -= bps; + array[i] = (codeBuf >> codeSize) * sampleMul; + codeBuf &= (1 << codeSize) - 1; + } + + return array; + } + + static parse({ + xref, + isEvalSupported, + fn + }) { + const dict = fn.dict || fn; + const typeNum = dict.get("FunctionType"); + + switch (typeNum) { + case 0: + return this.constructSampled({ + xref, + isEvalSupported, + fn, + dict + }); + + case 1: + break; + + case 2: + return this.constructInterpolated({ + xref, + isEvalSupported, + dict + }); + + case 3: + return this.constructStiched({ + xref, + isEvalSupported, + dict + }); + + case 4: + return this.constructPostScript({ + xref, + isEvalSupported, + fn, + dict + }); + } + + throw new _util.FormatError("Unknown type of function"); + } + + static parseArray({ + xref, + isEvalSupported, + fnObj + }) { + if (!Array.isArray(fnObj)) { + return this.parse({ + xref, + isEvalSupported, + fn: fnObj + }); + } + + const fnArray = []; + + for (let j = 0, jj = fnObj.length; j < jj; j++) { + fnArray.push(this.parse({ + xref, + isEvalSupported, + fn: xref.fetchIfRef(fnObj[j]) + })); + } + + return function (src, srcOffset, dest, destOffset) { + for (let i = 0, ii = fnArray.length; i < ii; i++) { + fnArray[i](src, srcOffset, dest, destOffset + i); + } + }; + } + + static constructSampled({ + xref, + isEvalSupported, + fn, + dict + }) { + function toMultiArray(arr) { + const inputLength = arr.length; + const out = []; + let index = 0; + + for (let i = 0; i < inputLength; i += 2) { + out[index++] = [arr[i], arr[i + 1]]; + } + + return out; + } + + function interpolate(x, xmin, xmax, ymin, ymax) { + return ymin + (x - xmin) * ((ymax - ymin) / (xmax - xmin)); + } + + let domain = toNumberArray(dict.getArray("Domain")); + let range = toNumberArray(dict.getArray("Range")); + + if (!domain || !range) { + throw new _util.FormatError("No domain or range"); + } + + const inputSize = domain.length / 2; + const outputSize = range.length / 2; + domain = toMultiArray(domain); + range = toMultiArray(range); + const size = toNumberArray(dict.getArray("Size")); + const bps = dict.get("BitsPerSample"); + const order = dict.get("Order") || 1; + + if (order !== 1) { + (0, _util.info)("No support for cubic spline interpolation: " + order); + } + + let encode = toNumberArray(dict.getArray("Encode")); + + if (!encode) { + encode = []; + + for (let i = 0; i < inputSize; ++i) { + encode.push([0, size[i] - 1]); + } + } else { + encode = toMultiArray(encode); + } + + let decode = toNumberArray(dict.getArray("Decode")); + + if (!decode) { + decode = range; + } else { + decode = toMultiArray(decode); + } + + const samples = this.getSampleArray(size, outputSize, bps, fn); + return function constructSampledFn(src, srcOffset, dest, destOffset) { + const cubeVertices = 1 << inputSize; + const cubeN = new Float64Array(cubeVertices); + const cubeVertex = new Uint32Array(cubeVertices); + let i, j; + + for (j = 0; j < cubeVertices; j++) { + cubeN[j] = 1; + } + + let k = outputSize, + pos = 1; + + for (i = 0; i < inputSize; ++i) { + const domain_2i = domain[i][0]; + const domain_2i_1 = domain[i][1]; + const xi = Math.min(Math.max(src[srcOffset + i], domain_2i), domain_2i_1); + let e = interpolate(xi, domain_2i, domain_2i_1, encode[i][0], encode[i][1]); + const size_i = size[i]; + e = Math.min(Math.max(e, 0), size_i - 1); + const e0 = e < size_i - 1 ? Math.floor(e) : e - 1; + const n0 = e0 + 1 - e; + const n1 = e - e0; + const offset0 = e0 * k; + const offset1 = offset0 + k; + + for (j = 0; j < cubeVertices; j++) { + if (j & pos) { + cubeN[j] *= n1; + cubeVertex[j] += offset1; + } else { + cubeN[j] *= n0; + cubeVertex[j] += offset0; + } + } + + k *= size_i; + pos <<= 1; + } + + for (j = 0; j < outputSize; ++j) { + let rj = 0; + + for (i = 0; i < cubeVertices; i++) { + rj += samples[cubeVertex[i] + j] * cubeN[i]; + } + + rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]); + dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]), range[j][1]); + } + }; + } + + static constructInterpolated({ + xref, + isEvalSupported, + dict + }) { + const c0 = toNumberArray(dict.getArray("C0")) || [0]; + const c1 = toNumberArray(dict.getArray("C1")) || [1]; + const n = dict.get("N"); + const diff = []; + + for (let i = 0, ii = c0.length; i < ii; ++i) { + diff.push(c1[i] - c0[i]); + } + + const length = diff.length; + return function constructInterpolatedFn(src, srcOffset, dest, destOffset) { + const x = n === 1 ? src[srcOffset] : src[srcOffset] ** n; + + for (let j = 0; j < length; ++j) { + dest[destOffset + j] = c0[j] + x * diff[j]; + } + }; + } + + static constructStiched({ + xref, + isEvalSupported, + dict + }) { + const domain = toNumberArray(dict.getArray("Domain")); + + if (!domain) { + throw new _util.FormatError("No domain"); + } + + const inputSize = domain.length / 2; + + if (inputSize !== 1) { + throw new _util.FormatError("Bad domain for stiched function"); + } + + const fnRefs = dict.get("Functions"); + const fns = []; + + for (let i = 0, ii = fnRefs.length; i < ii; ++i) { + fns.push(this.parse({ + xref, + isEvalSupported, + fn: xref.fetchIfRef(fnRefs[i]) + })); + } + + const bounds = toNumberArray(dict.getArray("Bounds")); + const encode = toNumberArray(dict.getArray("Encode")); + const tmpBuf = new Float32Array(1); + return function constructStichedFn(src, srcOffset, dest, destOffset) { + const clip = function constructStichedFromIRClip(v, min, max) { + if (v > max) { + v = max; + } else if (v < min) { + v = min; + } + + return v; + }; + + const v = clip(src[srcOffset], domain[0], domain[1]); + const length = bounds.length; + let i; + + for (i = 0; i < length; ++i) { + if (v < bounds[i]) { + break; + } + } + + let dmin = domain[0]; + + if (i > 0) { + dmin = bounds[i - 1]; + } + + let dmax = domain[1]; + + if (i < bounds.length) { + dmax = bounds[i]; + } + + const rmin = encode[2 * i]; + const rmax = encode[2 * i + 1]; + tmpBuf[0] = dmin === dmax ? rmin : rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin); + fns[i](tmpBuf, 0, dest, destOffset); + }; + } + + static constructPostScript({ + xref, + isEvalSupported, + fn, + dict + }) { + const domain = toNumberArray(dict.getArray("Domain")); + const range = toNumberArray(dict.getArray("Range")); + + if (!domain) { + throw new _util.FormatError("No domain."); + } + + if (!range) { + throw new _util.FormatError("No range."); + } + + const lexer = new _ps_parser.PostScriptLexer(fn); + const parser = new _ps_parser.PostScriptParser(lexer); + const code = parser.parse(); + + if (isEvalSupported && _util.FeatureTest.isEvalSupported) { + const compiled = new PostScriptCompiler().compile(code, domain, range); + + if (compiled) { + return new Function("src", "srcOffset", "dest", "destOffset", compiled); + } + } + + (0, _util.info)("Unable to compile PS function"); + const numOutputs = range.length >> 1; + const numInputs = domain.length >> 1; + const evaluator = new PostScriptEvaluator(code); + const cache = Object.create(null); + const MAX_CACHE_SIZE = 2048 * 4; + let cache_available = MAX_CACHE_SIZE; + const tmpBuf = new Float32Array(numInputs); + return function constructPostScriptFn(src, srcOffset, dest, destOffset) { + let i, value; + let key = ""; + const input = tmpBuf; + + for (i = 0; i < numInputs; i++) { + value = src[srcOffset + i]; + input[i] = value; + key += value + "_"; + } + + const cachedValue = cache[key]; + + if (cachedValue !== undefined) { + dest.set(cachedValue, destOffset); + return; + } + + const output = new Float32Array(numOutputs); + const stack = evaluator.execute(input); + const stackIndex = stack.length - numOutputs; + + for (i = 0; i < numOutputs; i++) { + value = stack[stackIndex + i]; + let bound = range[i * 2]; + + if (value < bound) { + value = bound; + } else { + bound = range[i * 2 + 1]; + + if (value > bound) { + value = bound; + } + } + + output[i] = value; + } + + if (cache_available > 0) { + cache_available--; + cache[key] = output; + } + + dest.set(output, destOffset); + }; + } + +} + +function isPDFFunction(v) { + let fnDict; + + if (typeof v !== "object") { + return false; + } else if (v instanceof _primitives.Dict) { + fnDict = v; + } else if (v instanceof _base_stream.BaseStream) { + fnDict = v.dict; + } else { + return false; + } + + return fnDict.has("FunctionType"); +} + +class PostScriptStack { + static get MAX_STACK_SIZE() { + return (0, _util.shadow)(this, "MAX_STACK_SIZE", 100); + } + + constructor(initialStack) { + this.stack = !initialStack ? [] : Array.prototype.slice.call(initialStack, 0); + } + + push(value) { + if (this.stack.length >= PostScriptStack.MAX_STACK_SIZE) { + throw new Error("PostScript function stack overflow."); + } + + this.stack.push(value); + } + + pop() { + if (this.stack.length <= 0) { + throw new Error("PostScript function stack underflow."); + } + + return this.stack.pop(); + } + + copy(n) { + if (this.stack.length + n >= PostScriptStack.MAX_STACK_SIZE) { + throw new Error("PostScript function stack overflow."); + } + + const stack = this.stack; + + for (let i = stack.length - n, j = n - 1; j >= 0; j--, i++) { + stack.push(stack[i]); + } + } + + index(n) { + this.push(this.stack[this.stack.length - n - 1]); + } + + roll(n, p) { + const stack = this.stack; + const l = stack.length - n; + const r = stack.length - 1; + const c = l + (p - Math.floor(p / n) * n); + + for (let i = l, j = r; i < j; i++, j--) { + const t = stack[i]; + stack[i] = stack[j]; + stack[j] = t; + } + + for (let i = l, j = c - 1; i < j; i++, j--) { + const t = stack[i]; + stack[i] = stack[j]; + stack[j] = t; + } + + for (let i = c, j = r; i < j; i++, j--) { + const t = stack[i]; + stack[i] = stack[j]; + stack[j] = t; + } + } + +} + +class PostScriptEvaluator { + constructor(operators) { + this.operators = operators; + } + + execute(initialStack) { + const stack = new PostScriptStack(initialStack); + let counter = 0; + const operators = this.operators; + const length = operators.length; + let operator, a, b; + + while (counter < length) { + operator = operators[counter++]; + + if (typeof operator === "number") { + stack.push(operator); + continue; + } + + switch (operator) { + case "jz": + b = stack.pop(); + a = stack.pop(); + + if (!a) { + counter = b; + } + + break; + + case "j": + a = stack.pop(); + counter = a; + break; + + case "abs": + a = stack.pop(); + stack.push(Math.abs(a)); + break; + + case "add": + b = stack.pop(); + a = stack.pop(); + stack.push(a + b); + break; + + case "and": + b = stack.pop(); + a = stack.pop(); + + if (typeof a === "boolean" && typeof b === "boolean") { + stack.push(a && b); + } else { + stack.push(a & b); + } + + break; + + case "atan": + a = stack.pop(); + stack.push(Math.atan(a)); + break; + + case "bitshift": + b = stack.pop(); + a = stack.pop(); + + if (a > 0) { + stack.push(a << b); + } else { + stack.push(a >> b); + } + + break; + + case "ceiling": + a = stack.pop(); + stack.push(Math.ceil(a)); + break; + + case "copy": + a = stack.pop(); + stack.copy(a); + break; + + case "cos": + a = stack.pop(); + stack.push(Math.cos(a)); + break; + + case "cvi": + a = stack.pop() | 0; + stack.push(a); + break; + + case "cvr": + break; + + case "div": + b = stack.pop(); + a = stack.pop(); + stack.push(a / b); + break; + + case "dup": + stack.copy(1); + break; + + case "eq": + b = stack.pop(); + a = stack.pop(); + stack.push(a === b); + break; + + case "exch": + stack.roll(2, 1); + break; + + case "exp": + b = stack.pop(); + a = stack.pop(); + stack.push(a ** b); + break; + + case "false": + stack.push(false); + break; + + case "floor": + a = stack.pop(); + stack.push(Math.floor(a)); + break; + + case "ge": + b = stack.pop(); + a = stack.pop(); + stack.push(a >= b); + break; + + case "gt": + b = stack.pop(); + a = stack.pop(); + stack.push(a > b); + break; + + case "idiv": + b = stack.pop(); + a = stack.pop(); + stack.push(a / b | 0); + break; + + case "index": + a = stack.pop(); + stack.index(a); + break; + + case "le": + b = stack.pop(); + a = stack.pop(); + stack.push(a <= b); + break; + + case "ln": + a = stack.pop(); + stack.push(Math.log(a)); + break; + + case "log": + a = stack.pop(); + stack.push(Math.log(a) / Math.LN10); + break; + + case "lt": + b = stack.pop(); + a = stack.pop(); + stack.push(a < b); + break; + + case "mod": + b = stack.pop(); + a = stack.pop(); + stack.push(a % b); + break; + + case "mul": + b = stack.pop(); + a = stack.pop(); + stack.push(a * b); + break; + + case "ne": + b = stack.pop(); + a = stack.pop(); + stack.push(a !== b); + break; + + case "neg": + a = stack.pop(); + stack.push(-a); + break; + + case "not": + a = stack.pop(); + + if (typeof a === "boolean") { + stack.push(!a); + } else { + stack.push(~a); + } + + break; + + case "or": + b = stack.pop(); + a = stack.pop(); + + if (typeof a === "boolean" && typeof b === "boolean") { + stack.push(a || b); + } else { + stack.push(a | b); + } + + break; + + case "pop": + stack.pop(); + break; + + case "roll": + b = stack.pop(); + a = stack.pop(); + stack.roll(a, b); + break; + + case "round": + a = stack.pop(); + stack.push(Math.round(a)); + break; + + case "sin": + a = stack.pop(); + stack.push(Math.sin(a)); + break; + + case "sqrt": + a = stack.pop(); + stack.push(Math.sqrt(a)); + break; + + case "sub": + b = stack.pop(); + a = stack.pop(); + stack.push(a - b); + break; + + case "true": + stack.push(true); + break; + + case "truncate": + a = stack.pop(); + a = a < 0 ? Math.ceil(a) : Math.floor(a); + stack.push(a); + break; + + case "xor": + b = stack.pop(); + a = stack.pop(); + + if (typeof a === "boolean" && typeof b === "boolean") { + stack.push(a !== b); + } else { + stack.push(a ^ b); + } + + break; + + default: + throw new _util.FormatError(`Unknown operator ${operator}`); + } + } + + return stack.stack; + } + +} + +exports.PostScriptEvaluator = PostScriptEvaluator; + +class AstNode { + constructor(type) { + this.type = type; + } + + visit(visitor) { + (0, _util.unreachable)("abstract method"); + } + +} + +class AstArgument extends AstNode { + constructor(index, min, max) { + super("args"); + this.index = index; + this.min = min; + this.max = max; + } + + visit(visitor) { + visitor.visitArgument(this); + } + +} + +class AstLiteral extends AstNode { + constructor(number) { + super("literal"); + this.number = number; + this.min = number; + this.max = number; + } + + visit(visitor) { + visitor.visitLiteral(this); + } + +} + +class AstBinaryOperation extends AstNode { + constructor(op, arg1, arg2, min, max) { + super("binary"); + this.op = op; + this.arg1 = arg1; + this.arg2 = arg2; + this.min = min; + this.max = max; + } + + visit(visitor) { + visitor.visitBinaryOperation(this); + } + +} + +class AstMin extends AstNode { + constructor(arg, max) { + super("max"); + this.arg = arg; + this.min = arg.min; + this.max = max; + } + + visit(visitor) { + visitor.visitMin(this); + } + +} + +class AstVariable extends AstNode { + constructor(index, min, max) { + super("var"); + this.index = index; + this.min = min; + this.max = max; + } + + visit(visitor) { + visitor.visitVariable(this); + } + +} + +class AstVariableDefinition extends AstNode { + constructor(variable, arg) { + super("definition"); + this.variable = variable; + this.arg = arg; + } + + visit(visitor) { + visitor.visitVariableDefinition(this); + } + +} + +class ExpressionBuilderVisitor { + constructor() { + this.parts = []; + } + + visitArgument(arg) { + this.parts.push("Math.max(", arg.min, ", Math.min(", arg.max, ", src[srcOffset + ", arg.index, "]))"); + } + + visitVariable(variable) { + this.parts.push("v", variable.index); + } + + visitLiteral(literal) { + this.parts.push(literal.number); + } + + visitBinaryOperation(operation) { + this.parts.push("("); + operation.arg1.visit(this); + this.parts.push(" ", operation.op, " "); + operation.arg2.visit(this); + this.parts.push(")"); + } + + visitVariableDefinition(definition) { + this.parts.push("var "); + definition.variable.visit(this); + this.parts.push(" = "); + definition.arg.visit(this); + this.parts.push(";"); + } + + visitMin(max) { + this.parts.push("Math.min("); + max.arg.visit(this); + this.parts.push(", ", max.max, ")"); + } + + toString() { + return this.parts.join(""); + } + +} + +function buildAddOperation(num1, num2) { + if (num2.type === "literal" && num2.number === 0) { + return num1; + } + + if (num1.type === "literal" && num1.number === 0) { + return num2; + } + + if (num2.type === "literal" && num1.type === "literal") { + return new AstLiteral(num1.number + num2.number); + } + + return new AstBinaryOperation("+", num1, num2, num1.min + num2.min, num1.max + num2.max); +} + +function buildMulOperation(num1, num2) { + if (num2.type === "literal") { + if (num2.number === 0) { + return new AstLiteral(0); + } else if (num2.number === 1) { + return num1; + } else if (num1.type === "literal") { + return new AstLiteral(num1.number * num2.number); + } + } + + if (num1.type === "literal") { + if (num1.number === 0) { + return new AstLiteral(0); + } else if (num1.number === 1) { + return num2; + } + } + + const min = Math.min(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max); + const max = Math.max(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max); + return new AstBinaryOperation("*", num1, num2, min, max); +} + +function buildSubOperation(num1, num2) { + if (num2.type === "literal") { + if (num2.number === 0) { + return num1; + } else if (num1.type === "literal") { + return new AstLiteral(num1.number - num2.number); + } + } + + if (num2.type === "binary" && num2.op === "-" && num1.type === "literal" && num1.number === 1 && num2.arg1.type === "literal" && num2.arg1.number === 1) { + return num2.arg2; + } + + return new AstBinaryOperation("-", num1, num2, num1.min - num2.max, num1.max - num2.min); +} + +function buildMinOperation(num1, max) { + if (num1.min >= max) { + return new AstLiteral(max); + } else if (num1.max <= max) { + return num1; + } + + return new AstMin(num1, max); +} + +class PostScriptCompiler { + compile(code, domain, range) { + const stack = []; + const instructions = []; + const inputSize = domain.length >> 1, + outputSize = range.length >> 1; + let lastRegister = 0; + let n, j; + let num1, num2, ast1, ast2, tmpVar, item; + + for (let i = 0; i < inputSize; i++) { + stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1])); + } + + for (let i = 0, ii = code.length; i < ii; i++) { + item = code[i]; + + if (typeof item === "number") { + stack.push(new AstLiteral(item)); + continue; + } + + switch (item) { + case "add": + if (stack.length < 2) { + return null; + } + + num2 = stack.pop(); + num1 = stack.pop(); + stack.push(buildAddOperation(num1, num2)); + break; + + case "cvr": + if (stack.length < 1) { + return null; + } + + break; + + case "mul": + if (stack.length < 2) { + return null; + } + + num2 = stack.pop(); + num1 = stack.pop(); + stack.push(buildMulOperation(num1, num2)); + break; + + case "sub": + if (stack.length < 2) { + return null; + } + + num2 = stack.pop(); + num1 = stack.pop(); + stack.push(buildSubOperation(num1, num2)); + break; + + case "exch": + if (stack.length < 2) { + return null; + } + + ast1 = stack.pop(); + ast2 = stack.pop(); + stack.push(ast1, ast2); + break; + + case "pop": + if (stack.length < 1) { + return null; + } + + stack.pop(); + break; + + case "index": + if (stack.length < 1) { + return null; + } + + num1 = stack.pop(); + + if (num1.type !== "literal") { + return null; + } + + n = num1.number; + + if (n < 0 || !Number.isInteger(n) || stack.length < n) { + return null; + } + + ast1 = stack[stack.length - n - 1]; + + if (ast1.type === "literal" || ast1.type === "var") { + stack.push(ast1); + break; + } + + tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max); + stack[stack.length - n - 1] = tmpVar; + stack.push(tmpVar); + instructions.push(new AstVariableDefinition(tmpVar, ast1)); + break; + + case "dup": + if (stack.length < 1) { + return null; + } + + if (typeof code[i + 1] === "number" && code[i + 2] === "gt" && code[i + 3] === i + 7 && code[i + 4] === "jz" && code[i + 5] === "pop" && code[i + 6] === code[i + 1]) { + num1 = stack.pop(); + stack.push(buildMinOperation(num1, code[i + 1])); + i += 6; + break; + } + + ast1 = stack.at(-1); + + if (ast1.type === "literal" || ast1.type === "var") { + stack.push(ast1); + break; + } + + tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max); + stack[stack.length - 1] = tmpVar; + stack.push(tmpVar); + instructions.push(new AstVariableDefinition(tmpVar, ast1)); + break; + + case "roll": + if (stack.length < 2) { + return null; + } + + num2 = stack.pop(); + num1 = stack.pop(); + + if (num2.type !== "literal" || num1.type !== "literal") { + return null; + } + + j = num2.number; + n = num1.number; + + if (n <= 0 || !Number.isInteger(n) || !Number.isInteger(j) || stack.length < n) { + return null; + } + + j = (j % n + n) % n; + + if (j === 0) { + break; + } + + Array.prototype.push.apply(stack, stack.splice(stack.length - n, n - j)); + break; + + default: + return null; + } + } + + if (stack.length !== outputSize) { + return null; + } + + const result = []; + + for (const instruction of instructions) { + const statementBuilder = new ExpressionBuilderVisitor(); + instruction.visit(statementBuilder); + result.push(statementBuilder.toString()); + } + + for (let i = 0, ii = stack.length; i < ii; i++) { + const expr = stack[i], + statementBuilder = new ExpressionBuilderVisitor(); + expr.visit(statementBuilder); + const min = range[i * 2], + max = range[i * 2 + 1]; + const out = [statementBuilder.toString()]; + + if (min > expr.min) { + out.unshift("Math.max(", min, ", "); + out.push(")"); + } + + if (max < expr.max) { + out.unshift("Math.min(", max, ", "); + out.push(")"); + } + + out.unshift("dest[destOffset + ", i, "] = "); + out.push(";"); + result.push(out.join("")); + } + + return result.join("\n"); + } + +} + +exports.PostScriptCompiler = PostScriptCompiler; + +/***/ }), +/* 58 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PostScriptParser = exports.PostScriptLexer = void 0; + +var _util = __w_pdfjs_require__(2); + +var _primitives = __w_pdfjs_require__(5); + +var _core_utils = __w_pdfjs_require__(6); + +class PostScriptParser { + constructor(lexer) { + this.lexer = lexer; + this.operators = []; + this.token = null; + this.prev = null; + } + + nextToken() { + this.prev = this.token; + this.token = this.lexer.getToken(); + } + + accept(type) { + if (this.token.type === type) { + this.nextToken(); + return true; + } + + return false; + } + + expect(type) { + if (this.accept(type)) { + return true; + } + + throw new _util.FormatError(`Unexpected symbol: found ${this.token.type} expected ${type}.`); + } + + parse() { + this.nextToken(); + this.expect(PostScriptTokenTypes.LBRACE); + this.parseBlock(); + this.expect(PostScriptTokenTypes.RBRACE); + return this.operators; + } + + parseBlock() { + while (true) { + if (this.accept(PostScriptTokenTypes.NUMBER)) { + this.operators.push(this.prev.value); + } else if (this.accept(PostScriptTokenTypes.OPERATOR)) { + this.operators.push(this.prev.value); + } else if (this.accept(PostScriptTokenTypes.LBRACE)) { + this.parseCondition(); + } else { + return; + } + } + } + + parseCondition() { + const conditionLocation = this.operators.length; + this.operators.push(null, null); + this.parseBlock(); + this.expect(PostScriptTokenTypes.RBRACE); + + if (this.accept(PostScriptTokenTypes.IF)) { + this.operators[conditionLocation] = this.operators.length; + this.operators[conditionLocation + 1] = "jz"; + } else if (this.accept(PostScriptTokenTypes.LBRACE)) { + const jumpLocation = this.operators.length; + this.operators.push(null, null); + const endOfTrue = this.operators.length; + this.parseBlock(); + this.expect(PostScriptTokenTypes.RBRACE); + this.expect(PostScriptTokenTypes.IFELSE); + this.operators[jumpLocation] = this.operators.length; + this.operators[jumpLocation + 1] = "j"; + this.operators[conditionLocation] = endOfTrue; + this.operators[conditionLocation + 1] = "jz"; + } else { + throw new _util.FormatError("PS Function: error parsing conditional."); + } + } + +} + +exports.PostScriptParser = PostScriptParser; +const PostScriptTokenTypes = { + LBRACE: 0, + RBRACE: 1, + NUMBER: 2, + OPERATOR: 3, + IF: 4, + IFELSE: 5 +}; + +class PostScriptToken { + static get opCache() { + return (0, _util.shadow)(this, "opCache", Object.create(null)); + } + + constructor(type, value) { + this.type = type; + this.value = value; + } + + static getOperator(op) { + const opValue = PostScriptToken.opCache[op]; + + if (opValue) { + return opValue; + } + + return PostScriptToken.opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op); + } + + static get LBRACE() { + return (0, _util.shadow)(this, "LBRACE", new PostScriptToken(PostScriptTokenTypes.LBRACE, "{")); + } + + static get RBRACE() { + return (0, _util.shadow)(this, "RBRACE", new PostScriptToken(PostScriptTokenTypes.RBRACE, "}")); + } + + static get IF() { + return (0, _util.shadow)(this, "IF", new PostScriptToken(PostScriptTokenTypes.IF, "IF")); + } + + static get IFELSE() { + return (0, _util.shadow)(this, "IFELSE", new PostScriptToken(PostScriptTokenTypes.IFELSE, "IFELSE")); + } + +} + +class PostScriptLexer { + constructor(stream) { + this.stream = stream; + this.nextChar(); + this.strBuf = []; + } + + nextChar() { + return this.currentChar = this.stream.getByte(); + } + + getToken() { + let comment = false; + let ch = this.currentChar; + + while (true) { + if (ch < 0) { + return _primitives.EOF; + } + + if (comment) { + if (ch === 0x0a || ch === 0x0d) { + comment = false; + } + } else if (ch === 0x25) { + comment = true; + } else if (!(0, _core_utils.isWhiteSpace)(ch)) { + break; + } + + ch = this.nextChar(); + } + + switch (ch | 0) { + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x2b: + case 0x2d: + case 0x2e: + return new PostScriptToken(PostScriptTokenTypes.NUMBER, this.getNumber()); + + case 0x7b: + this.nextChar(); + return PostScriptToken.LBRACE; + + case 0x7d: + this.nextChar(); + return PostScriptToken.RBRACE; + } + + const strBuf = this.strBuf; + strBuf.length = 0; + strBuf[0] = String.fromCharCode(ch); + + while ((ch = this.nextChar()) >= 0 && (ch >= 0x41 && ch <= 0x5a || ch >= 0x61 && ch <= 0x7a)) { + strBuf.push(String.fromCharCode(ch)); + } + + const str = strBuf.join(""); + + switch (str.toLowerCase()) { + case "if": + return PostScriptToken.IF; + + case "ifelse": + return PostScriptToken.IFELSE; + + default: + return PostScriptToken.getOperator(str); + } + } + + getNumber() { + let ch = this.currentChar; + const strBuf = this.strBuf; + strBuf.length = 0; + strBuf[0] = String.fromCharCode(ch); + + while ((ch = this.nextChar()) >= 0) { + if (ch >= 0x30 && ch <= 0x39 || ch === 0x2d || ch === 0x2e) { + strBuf.push(String.fromCharCode(ch)); + } else { + break; + } + } + + const value = parseFloat(strBuf.join("")); + + if (isNaN(value)) { + throw new _util.FormatError(`Invalid floating point number: ${value}`); + } + + return value; + } + +} + +exports.PostScriptLexer = PostScriptLexer; + +/***/ }), +/* 59 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.LocalTilingPatternCache = exports.LocalImageCache = exports.LocalGStateCache = exports.LocalFunctionCache = exports.LocalColorSpaceCache = exports.GlobalImageCache = void 0; + +var _util = __w_pdfjs_require__(2); + +var _primitives = __w_pdfjs_require__(5); + +class BaseLocalCache { + constructor(options) { + if (this.constructor === BaseLocalCache) { + (0, _util.unreachable)("Cannot initialize BaseLocalCache."); + } + + this._onlyRefs = (options && options.onlyRefs) === true; + + if (!this._onlyRefs) { + this._nameRefMap = new Map(); + this._imageMap = new Map(); + } + + this._imageCache = new _primitives.RefSetCache(); + } + + getByName(name) { + if (this._onlyRefs) { + (0, _util.unreachable)("Should not call `getByName` method."); + } + + const ref = this._nameRefMap.get(name); + + if (ref) { + return this.getByRef(ref); + } + + return this._imageMap.get(name) || null; + } + + getByRef(ref) { + return this._imageCache.get(ref) || null; + } + + set(name, ref, data) { + (0, _util.unreachable)("Abstract method `set` called."); + } + +} + +class LocalImageCache extends BaseLocalCache { + set(name, ref = null, data) { + if (typeof name !== "string") { + throw new Error('LocalImageCache.set - expected "name" argument.'); + } + + if (ref) { + if (this._imageCache.has(ref)) { + return; + } + + this._nameRefMap.set(name, ref); + + this._imageCache.put(ref, data); + + return; + } + + if (this._imageMap.has(name)) { + return; + } + + this._imageMap.set(name, data); + } + +} + +exports.LocalImageCache = LocalImageCache; + +class LocalColorSpaceCache extends BaseLocalCache { + set(name = null, ref = null, data) { + if (typeof name !== "string" && !ref) { + throw new Error('LocalColorSpaceCache.set - expected "name" and/or "ref" argument.'); + } + + if (ref) { + if (this._imageCache.has(ref)) { + return; + } + + if (name !== null) { + this._nameRefMap.set(name, ref); + } + + this._imageCache.put(ref, data); + + return; + } + + if (this._imageMap.has(name)) { + return; + } + + this._imageMap.set(name, data); + } + +} + +exports.LocalColorSpaceCache = LocalColorSpaceCache; + +class LocalFunctionCache extends BaseLocalCache { + constructor(options) { + super({ + onlyRefs: true + }); + } + + set(name = null, ref, data) { + if (!ref) { + throw new Error('LocalFunctionCache.set - expected "ref" argument.'); + } + + if (this._imageCache.has(ref)) { + return; + } + + this._imageCache.put(ref, data); + } + +} + +exports.LocalFunctionCache = LocalFunctionCache; + +class LocalGStateCache extends BaseLocalCache { + set(name, ref = null, data) { + if (typeof name !== "string") { + throw new Error('LocalGStateCache.set - expected "name" argument.'); + } + + if (ref) { + if (this._imageCache.has(ref)) { + return; + } + + this._nameRefMap.set(name, ref); + + this._imageCache.put(ref, data); + + return; + } + + if (this._imageMap.has(name)) { + return; + } + + this._imageMap.set(name, data); + } + +} + +exports.LocalGStateCache = LocalGStateCache; + +class LocalTilingPatternCache extends BaseLocalCache { + constructor(options) { + super({ + onlyRefs: true + }); + } + + set(name = null, ref, data) { + if (!ref) { + throw new Error('LocalTilingPatternCache.set - expected "ref" argument.'); + } + + if (this._imageCache.has(ref)) { + return; + } + + this._imageCache.put(ref, data); + } + +} + +exports.LocalTilingPatternCache = LocalTilingPatternCache; + +class GlobalImageCache { + static get NUM_PAGES_THRESHOLD() { + return (0, _util.shadow)(this, "NUM_PAGES_THRESHOLD", 2); + } + + static get MIN_IMAGES_TO_CACHE() { + return (0, _util.shadow)(this, "MIN_IMAGES_TO_CACHE", 10); + } + + static get MAX_BYTE_SIZE() { + return (0, _util.shadow)(this, "MAX_BYTE_SIZE", 40e6); + } + + constructor() { + this._refCache = new _primitives.RefSetCache(); + this._imageCache = new _primitives.RefSetCache(); + } + + get _byteSize() { + let byteSize = 0; + + for (const imageData of this._imageCache) { + byteSize += imageData.byteSize; + } + + return byteSize; + } + + get _cacheLimitReached() { + if (this._imageCache.size < GlobalImageCache.MIN_IMAGES_TO_CACHE) { + return false; + } + + if (this._byteSize < GlobalImageCache.MAX_BYTE_SIZE) { + return false; + } + + return true; + } + + shouldCache(ref, pageIndex) { + const pageIndexSet = this._refCache.get(ref); + + const numPages = pageIndexSet ? pageIndexSet.size + (pageIndexSet.has(pageIndex) ? 0 : 1) : 1; + + if (numPages < GlobalImageCache.NUM_PAGES_THRESHOLD) { + return false; + } + + if (!this._imageCache.has(ref) && this._cacheLimitReached) { + return false; + } + + return true; + } + + addPageIndex(ref, pageIndex) { + let pageIndexSet = this._refCache.get(ref); + + if (!pageIndexSet) { + pageIndexSet = new Set(); + + this._refCache.put(ref, pageIndexSet); + } + + pageIndexSet.add(pageIndex); + } + + addByteSize(ref, byteSize) { + const imageData = this._imageCache.get(ref); + + if (!imageData) { + return; + } + + if (imageData.byteSize) { + return; + } + + imageData.byteSize = byteSize; + } + + getData(ref, pageIndex) { + const pageIndexSet = this._refCache.get(ref); + + if (!pageIndexSet) { + return null; + } + + if (pageIndexSet.size < GlobalImageCache.NUM_PAGES_THRESHOLD) { + return null; + } + + const imageData = this._imageCache.get(ref); + + if (!imageData) { + return null; + } + + pageIndexSet.add(pageIndex); + return imageData; + } + + setData(ref, data) { + if (!this._refCache.has(ref)) { + throw new Error('GlobalImageCache.setData - expected "addPageIndex" to have been called.'); + } + + if (this._imageCache.has(ref)) { + return; + } + + if (this._cacheLimitReached) { + (0, _util.warn)("GlobalImageCache.setData - cache limit reached."); + return; + } + + this._imageCache.put(ref, data); + } + + clear(onlyData = false) { + if (!onlyData) { + this._refCache.clear(); + } + + this._imageCache.clear(); + } + +} + +exports.GlobalImageCache = GlobalImageCache; + +/***/ }), +/* 60 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.bidi = bidi; + +var _util = __w_pdfjs_require__(2); + +const baseTypes = ["BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "S", "B", "S", "WS", "B", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "B", "B", "B", "S", "WS", "ON", "ON", "ET", "ET", "ET", "ON", "ON", "ON", "ON", "ON", "ES", "CS", "ES", "CS", "CS", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "CS", "ON", "ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "ON", "ON", "ON", "BN", "BN", "BN", "BN", "BN", "BN", "B", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "CS", "ON", "ET", "ET", "ET", "ET", "ON", "ON", "ON", "ON", "L", "ON", "ON", "BN", "ON", "ON", "ET", "ET", "EN", "EN", "ON", "L", "ON", "ON", "ON", "EN", "L", "ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "L", "L", "L", "L", "L", "L", "L", "L"]; +const arabicTypes = ["AN", "AN", "AN", "AN", "AN", "AN", "ON", "ON", "AL", "ET", "ET", "AL", "CS", "AL", "ON", "ON", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "ET", "AN", "AN", "AL", "AL", "AL", "NSM", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AN", "ON", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "NSM", "NSM", "ON", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "AL", "AL", "AL", "AL", "AL", "AL"]; + +function isOdd(i) { + return (i & 1) !== 0; +} + +function isEven(i) { + return (i & 1) === 0; +} + +function findUnequal(arr, start, value) { + let j, jj; + + for (j = start, jj = arr.length; j < jj; ++j) { + if (arr[j] !== value) { + return j; + } + } + + return j; +} + +function setValues(arr, start, end, value) { + for (let j = start; j < end; ++j) { + arr[j] = value; + } +} + +function reverseValues(arr, start, end) { + for (let i = start, j = end - 1; i < j; ++i, --j) { + const temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } +} + +function createBidiText(str, isLTR, vertical = false) { + let dir = "ltr"; + + if (vertical) { + dir = "ttb"; + } else if (!isLTR) { + dir = "rtl"; + } + + return { + str, + dir + }; +} + +const chars = []; +const types = []; + +function bidi(str, startLevel = -1, vertical = false) { + let isLTR = true; + const strLength = str.length; + + if (strLength === 0 || vertical) { + return createBidiText(str, isLTR, vertical); + } + + chars.length = strLength; + types.length = strLength; + let numBidi = 0; + let i, ii; + + for (i = 0; i < strLength; ++i) { + chars[i] = str.charAt(i); + const charCode = str.charCodeAt(i); + let charType = "L"; + + if (charCode <= 0x00ff) { + charType = baseTypes[charCode]; + } else if (0x0590 <= charCode && charCode <= 0x05f4) { + charType = "R"; + } else if (0x0600 <= charCode && charCode <= 0x06ff) { + charType = arabicTypes[charCode & 0xff]; + + if (!charType) { + (0, _util.warn)("Bidi: invalid Unicode character " + charCode.toString(16)); + } + } else if (0x0700 <= charCode && charCode <= 0x08ac) { + charType = "AL"; + } + + if (charType === "R" || charType === "AL" || charType === "AN") { + numBidi++; + } + + types[i] = charType; + } + + if (numBidi === 0) { + isLTR = true; + return createBidiText(str, isLTR); + } + + if (startLevel === -1) { + if (numBidi / strLength < 0.3 && strLength > 4) { + isLTR = true; + startLevel = 0; + } else { + isLTR = false; + startLevel = 1; + } + } + + const levels = []; + + for (i = 0; i < strLength; ++i) { + levels[i] = startLevel; + } + + const e = isOdd(startLevel) ? "R" : "L"; + const sor = e; + const eor = sor; + let lastType = sor; + + for (i = 0; i < strLength; ++i) { + if (types[i] === "NSM") { + types[i] = lastType; + } else { + lastType = types[i]; + } + } + + lastType = sor; + let t; + + for (i = 0; i < strLength; ++i) { + t = types[i]; + + if (t === "EN") { + types[i] = lastType === "AL" ? "AN" : "EN"; + } else if (t === "R" || t === "L" || t === "AL") { + lastType = t; + } + } + + for (i = 0; i < strLength; ++i) { + t = types[i]; + + if (t === "AL") { + types[i] = "R"; + } + } + + for (i = 1; i < strLength - 1; ++i) { + if (types[i] === "ES" && types[i - 1] === "EN" && types[i + 1] === "EN") { + types[i] = "EN"; + } + + if (types[i] === "CS" && (types[i - 1] === "EN" || types[i - 1] === "AN") && types[i + 1] === types[i - 1]) { + types[i] = types[i - 1]; + } + } + + for (i = 0; i < strLength; ++i) { + if (types[i] === "EN") { + for (let j = i - 1; j >= 0; --j) { + if (types[j] !== "ET") { + break; + } + + types[j] = "EN"; + } + + for (let j = i + 1; j < strLength; ++j) { + if (types[j] !== "ET") { + break; + } + + types[j] = "EN"; + } + } + } + + for (i = 0; i < strLength; ++i) { + t = types[i]; + + if (t === "WS" || t === "ES" || t === "ET" || t === "CS") { + types[i] = "ON"; + } + } + + lastType = sor; + + for (i = 0; i < strLength; ++i) { + t = types[i]; + + if (t === "EN") { + types[i] = lastType === "L" ? "L" : "EN"; + } else if (t === "R" || t === "L") { + lastType = t; + } + } + + for (i = 0; i < strLength; ++i) { + if (types[i] === "ON") { + const end = findUnequal(types, i + 1, "ON"); + let before = sor; + + if (i > 0) { + before = types[i - 1]; + } + + let after = eor; + + if (end + 1 < strLength) { + after = types[end + 1]; + } + + if (before !== "L") { + before = "R"; + } + + if (after !== "L") { + after = "R"; + } + + if (before === after) { + setValues(types, i, end, before); + } + + i = end - 1; + } + } + + for (i = 0; i < strLength; ++i) { + if (types[i] === "ON") { + types[i] = e; + } + } + + for (i = 0; i < strLength; ++i) { + t = types[i]; + + if (isEven(levels[i])) { + if (t === "R") { + levels[i] += 1; + } else if (t === "AN" || t === "EN") { + levels[i] += 2; + } + } else { + if (t === "L" || t === "AN" || t === "EN") { + levels[i] += 1; + } + } + } + + let highestLevel = -1; + let lowestOddLevel = 99; + let level; + + for (i = 0, ii = levels.length; i < ii; ++i) { + level = levels[i]; + + if (highestLevel < level) { + highestLevel = level; + } + + if (lowestOddLevel > level && isOdd(level)) { + lowestOddLevel = level; + } + } + + for (level = highestLevel; level >= lowestOddLevel; --level) { + let start = -1; + + for (i = 0, ii = levels.length; i < ii; ++i) { + if (levels[i] < level) { + if (start >= 0) { + reverseValues(chars, start, i); + start = -1; + } + } else if (start < 0) { + start = i; + } + } + + if (start >= 0) { + reverseValues(chars, start, levels.length); + } + } + + for (i = 0, ii = chars.length; i < ii; ++i) { + const ch = chars[i]; + + if (ch === "<" || ch === ">") { + chars[i] = ""; + } + } + + return createBidiText(chars.join(""), isLTR); +} + +/***/ }), +/* 61 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.MurmurHash3_64 = void 0; var _util = __w_pdfjs_require__(2); @@ -46205,7 +53058,7 @@ class MurmurHash3_64 { update(input) { let data, length; - if ((0, _util.isString)(input)) { + if (typeof input === "string") { data = new Uint8Array(input.length * 2); length = 0; @@ -46220,7 +53073,7 @@ class MurmurHash3_64 { } } } else if ((0, _util.isArrayBuffer)(input)) { - data = input; + data = input.slice(); length = data.byteLength; } else { throw new Error("Wrong data format in MurmurHash3_64_update. " + "Input must be a string or array."); @@ -46305,29 +53158,681 @@ class MurmurHash3_64 { exports.MurmurHash3_64 = MurmurHash3_64; /***/ }), -/* 45 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 62 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true +})); +exports.OperatorList = void 0; + +var _util = __w_pdfjs_require__(2); + +function addState(parentState, pattern, checkFn, iterateFn, processFn) { + let state = parentState; + + for (let i = 0, ii = pattern.length - 1; i < ii; i++) { + const item = pattern[i]; + state = state[item] || (state[item] = []); + } + + state[pattern.at(-1)] = { + checkFn, + iterateFn, + processFn + }; +} + +const InitialState = []; +addState(InitialState, [_util.OPS.save, _util.OPS.transform, _util.OPS.paintInlineImageXObject, _util.OPS.restore], null, function iterateInlineImageGroup(context, i) { + const fnArray = context.fnArray; + const iFirstSave = context.iCurr - 3; + const pos = (i - iFirstSave) % 4; + + switch (pos) { + case 0: + return fnArray[i] === _util.OPS.save; + + case 1: + return fnArray[i] === _util.OPS.transform; + + case 2: + return fnArray[i] === _util.OPS.paintInlineImageXObject; + + case 3: + return fnArray[i] === _util.OPS.restore; + } + + throw new Error(`iterateInlineImageGroup - invalid pos: ${pos}`); +}, function foundInlineImageGroup(context, i) { + const MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10; + const MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200; + const MAX_WIDTH = 1000; + const IMAGE_PADDING = 1; + const fnArray = context.fnArray, + argsArray = context.argsArray; + const curr = context.iCurr; + const iFirstSave = curr - 3; + const iFirstTransform = curr - 2; + const iFirstPIIXO = curr - 1; + const count = Math.min(Math.floor((i - iFirstSave) / 4), MAX_IMAGES_IN_INLINE_IMAGES_BLOCK); + + if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) { + return i - (i - iFirstSave) % 4; + } + + let maxX = 0; + const map = []; + let maxLineHeight = 0; + let currentX = IMAGE_PADDING, + currentY = IMAGE_PADDING; + + for (let q = 0; q < count; q++) { + const transform = argsArray[iFirstTransform + (q << 2)]; + const img = argsArray[iFirstPIIXO + (q << 2)][0]; + + if (currentX + img.width > MAX_WIDTH) { + maxX = Math.max(maxX, currentX); + currentY += maxLineHeight + 2 * IMAGE_PADDING; + currentX = 0; + maxLineHeight = 0; + } + + map.push({ + transform, + x: currentX, + y: currentY, + w: img.width, + h: img.height + }); + currentX += img.width + 2 * IMAGE_PADDING; + maxLineHeight = Math.max(maxLineHeight, img.height); + } + + const imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING; + const imgHeight = currentY + maxLineHeight + IMAGE_PADDING; + const imgData = new Uint8Array(imgWidth * imgHeight * 4); + const imgRowSize = imgWidth << 2; + + for (let q = 0; q < count; q++) { + const data = argsArray[iFirstPIIXO + (q << 2)][0].data; + const rowSize = map[q].w << 2; + let dataOffset = 0; + let offset = map[q].x + map[q].y * imgWidth << 2; + imgData.set(data.subarray(0, rowSize), offset - imgRowSize); + + for (let k = 0, kk = map[q].h; k < kk; k++) { + imgData.set(data.subarray(dataOffset, dataOffset + rowSize), offset); + dataOffset += rowSize; + offset += imgRowSize; + } + + imgData.set(data.subarray(dataOffset - rowSize, dataOffset), offset); + + while (offset >= 0) { + data[offset - 4] = data[offset]; + data[offset - 3] = data[offset + 1]; + data[offset - 2] = data[offset + 2]; + data[offset - 1] = data[offset + 3]; + data[offset + rowSize] = data[offset + rowSize - 4]; + data[offset + rowSize + 1] = data[offset + rowSize - 3]; + data[offset + rowSize + 2] = data[offset + rowSize - 2]; + data[offset + rowSize + 3] = data[offset + rowSize - 1]; + offset -= imgRowSize; + } + } + + fnArray.splice(iFirstSave, count * 4, _util.OPS.paintInlineImageXObjectGroup); + argsArray.splice(iFirstSave, count * 4, [{ + width: imgWidth, + height: imgHeight, + kind: _util.ImageKind.RGBA_32BPP, + data: imgData + }, map]); + return iFirstSave + 1; }); +addState(InitialState, [_util.OPS.save, _util.OPS.transform, _util.OPS.paintImageMaskXObject, _util.OPS.restore], null, function iterateImageMaskGroup(context, i) { + const fnArray = context.fnArray; + const iFirstSave = context.iCurr - 3; + const pos = (i - iFirstSave) % 4; + + switch (pos) { + case 0: + return fnArray[i] === _util.OPS.save; + + case 1: + return fnArray[i] === _util.OPS.transform; + + case 2: + return fnArray[i] === _util.OPS.paintImageMaskXObject; + + case 3: + return fnArray[i] === _util.OPS.restore; + } + + throw new Error(`iterateImageMaskGroup - invalid pos: ${pos}`); +}, function foundImageMaskGroup(context, i) { + const MIN_IMAGES_IN_MASKS_BLOCK = 10; + const MAX_IMAGES_IN_MASKS_BLOCK = 100; + const MAX_SAME_IMAGES_IN_MASKS_BLOCK = 1000; + const fnArray = context.fnArray, + argsArray = context.argsArray; + const curr = context.iCurr; + const iFirstSave = curr - 3; + const iFirstTransform = curr - 2; + const iFirstPIMXO = curr - 1; + let count = Math.floor((i - iFirstSave) / 4); + + if (count < MIN_IMAGES_IN_MASKS_BLOCK) { + return i - (i - iFirstSave) % 4; + } + + let isSameImage = false; + let iTransform, transformArgs; + const firstPIMXOArg0 = argsArray[iFirstPIMXO][0]; + const firstTransformArg0 = argsArray[iFirstTransform][0], + firstTransformArg1 = argsArray[iFirstTransform][1], + firstTransformArg2 = argsArray[iFirstTransform][2], + firstTransformArg3 = argsArray[iFirstTransform][3]; + + if (firstTransformArg1 === firstTransformArg2) { + isSameImage = true; + iTransform = iFirstTransform + 4; + let iPIMXO = iFirstPIMXO + 4; + + for (let q = 1; q < count; q++, iTransform += 4, iPIMXO += 4) { + transformArgs = argsArray[iTransform]; + + if (argsArray[iPIMXO][0] !== firstPIMXOArg0 || transformArgs[0] !== firstTransformArg0 || transformArgs[1] !== firstTransformArg1 || transformArgs[2] !== firstTransformArg2 || transformArgs[3] !== firstTransformArg3) { + if (q < MIN_IMAGES_IN_MASKS_BLOCK) { + isSameImage = false; + } else { + count = q; + } + + break; + } + } + } + + if (isSameImage) { + count = Math.min(count, MAX_SAME_IMAGES_IN_MASKS_BLOCK); + const positions = new Float32Array(count * 2); + iTransform = iFirstTransform; + + for (let q = 0; q < count; q++, iTransform += 4) { + transformArgs = argsArray[iTransform]; + positions[q << 1] = transformArgs[4]; + positions[(q << 1) + 1] = transformArgs[5]; + } + + fnArray.splice(iFirstSave, count * 4, _util.OPS.paintImageMaskXObjectRepeat); + argsArray.splice(iFirstSave, count * 4, [firstPIMXOArg0, firstTransformArg0, firstTransformArg1, firstTransformArg2, firstTransformArg3, positions]); + } else { + count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK); + const images = []; + + for (let q = 0; q < count; q++) { + transformArgs = argsArray[iFirstTransform + (q << 2)]; + const maskParams = argsArray[iFirstPIMXO + (q << 2)][0]; + images.push({ + data: maskParams.data, + width: maskParams.width, + height: maskParams.height, + interpolate: maskParams.interpolate, + count: maskParams.count, + transform: transformArgs + }); + } + + fnArray.splice(iFirstSave, count * 4, _util.OPS.paintImageMaskXObjectGroup); + argsArray.splice(iFirstSave, count * 4, [images]); + } + + return iFirstSave + 1; +}); +addState(InitialState, [_util.OPS.save, _util.OPS.transform, _util.OPS.paintImageXObject, _util.OPS.restore], function (context) { + const argsArray = context.argsArray; + const iFirstTransform = context.iCurr - 2; + return argsArray[iFirstTransform][1] === 0 && argsArray[iFirstTransform][2] === 0; +}, function iterateImageGroup(context, i) { + const fnArray = context.fnArray, + argsArray = context.argsArray; + const iFirstSave = context.iCurr - 3; + const pos = (i - iFirstSave) % 4; + + switch (pos) { + case 0: + return fnArray[i] === _util.OPS.save; + + case 1: + if (fnArray[i] !== _util.OPS.transform) { + return false; + } + + const iFirstTransform = context.iCurr - 2; + const firstTransformArg0 = argsArray[iFirstTransform][0]; + const firstTransformArg3 = argsArray[iFirstTransform][3]; + + if (argsArray[i][0] !== firstTransformArg0 || argsArray[i][1] !== 0 || argsArray[i][2] !== 0 || argsArray[i][3] !== firstTransformArg3) { + return false; + } + + return true; + + case 2: + if (fnArray[i] !== _util.OPS.paintImageXObject) { + return false; + } + + const iFirstPIXO = context.iCurr - 1; + const firstPIXOArg0 = argsArray[iFirstPIXO][0]; + + if (argsArray[i][0] !== firstPIXOArg0) { + return false; + } + + return true; + + case 3: + return fnArray[i] === _util.OPS.restore; + } + + throw new Error(`iterateImageGroup - invalid pos: ${pos}`); +}, function (context, i) { + const MIN_IMAGES_IN_BLOCK = 3; + const MAX_IMAGES_IN_BLOCK = 1000; + const fnArray = context.fnArray, + argsArray = context.argsArray; + const curr = context.iCurr; + const iFirstSave = curr - 3; + const iFirstTransform = curr - 2; + const iFirstPIXO = curr - 1; + const firstPIXOArg0 = argsArray[iFirstPIXO][0]; + const firstTransformArg0 = argsArray[iFirstTransform][0]; + const firstTransformArg3 = argsArray[iFirstTransform][3]; + const count = Math.min(Math.floor((i - iFirstSave) / 4), MAX_IMAGES_IN_BLOCK); + + if (count < MIN_IMAGES_IN_BLOCK) { + return i - (i - iFirstSave) % 4; + } + + const positions = new Float32Array(count * 2); + let iTransform = iFirstTransform; + + for (let q = 0; q < count; q++, iTransform += 4) { + const transformArgs = argsArray[iTransform]; + positions[q << 1] = transformArgs[4]; + positions[(q << 1) + 1] = transformArgs[5]; + } + + const args = [firstPIXOArg0, firstTransformArg0, firstTransformArg3, positions]; + fnArray.splice(iFirstSave, count * 4, _util.OPS.paintImageXObjectRepeat); + argsArray.splice(iFirstSave, count * 4, args); + return iFirstSave + 1; +}); +addState(InitialState, [_util.OPS.beginText, _util.OPS.setFont, _util.OPS.setTextMatrix, _util.OPS.showText, _util.OPS.endText], null, function iterateShowTextGroup(context, i) { + const fnArray = context.fnArray, + argsArray = context.argsArray; + const iFirstSave = context.iCurr - 4; + const pos = (i - iFirstSave) % 5; + + switch (pos) { + case 0: + return fnArray[i] === _util.OPS.beginText; + + case 1: + return fnArray[i] === _util.OPS.setFont; + + case 2: + return fnArray[i] === _util.OPS.setTextMatrix; + + case 3: + if (fnArray[i] !== _util.OPS.showText) { + return false; + } + + const iFirstSetFont = context.iCurr - 3; + const firstSetFontArg0 = argsArray[iFirstSetFont][0]; + const firstSetFontArg1 = argsArray[iFirstSetFont][1]; + + if (argsArray[i][0] !== firstSetFontArg0 || argsArray[i][1] !== firstSetFontArg1) { + return false; + } + + return true; + + case 4: + return fnArray[i] === _util.OPS.endText; + } + + throw new Error(`iterateShowTextGroup - invalid pos: ${pos}`); +}, function (context, i) { + const MIN_CHARS_IN_BLOCK = 3; + const MAX_CHARS_IN_BLOCK = 1000; + const fnArray = context.fnArray, + argsArray = context.argsArray; + const curr = context.iCurr; + const iFirstBeginText = curr - 4; + const iFirstSetFont = curr - 3; + const iFirstSetTextMatrix = curr - 2; + const iFirstShowText = curr - 1; + const iFirstEndText = curr; + const firstSetFontArg0 = argsArray[iFirstSetFont][0]; + const firstSetFontArg1 = argsArray[iFirstSetFont][1]; + let count = Math.min(Math.floor((i - iFirstBeginText) / 5), MAX_CHARS_IN_BLOCK); + + if (count < MIN_CHARS_IN_BLOCK) { + return i - (i - iFirstBeginText) % 5; + } + + let iFirst = iFirstBeginText; + + if (iFirstBeginText >= 4 && fnArray[iFirstBeginText - 4] === fnArray[iFirstSetFont] && fnArray[iFirstBeginText - 3] === fnArray[iFirstSetTextMatrix] && fnArray[iFirstBeginText - 2] === fnArray[iFirstShowText] && fnArray[iFirstBeginText - 1] === fnArray[iFirstEndText] && argsArray[iFirstBeginText - 4][0] === firstSetFontArg0 && argsArray[iFirstBeginText - 4][1] === firstSetFontArg1) { + count++; + iFirst -= 5; + } + + let iEndText = iFirst + 4; + + for (let q = 1; q < count; q++) { + fnArray.splice(iEndText, 3); + argsArray.splice(iEndText, 3); + iEndText += 2; + } + + return iEndText + 1; +}); + +class NullOptimizer { + constructor(queue) { + this.queue = queue; + } + + _optimize() {} + + push(fn, args) { + this.queue.fnArray.push(fn); + this.queue.argsArray.push(args); + + this._optimize(); + } + + flush() {} + + reset() {} + +} + +class QueueOptimizer extends NullOptimizer { + constructor(queue) { + super(queue); + this.state = null; + this.context = { + iCurr: 0, + fnArray: queue.fnArray, + argsArray: queue.argsArray + }; + this.match = null; + this.lastProcessed = 0; + } + + _optimize() { + const fnArray = this.queue.fnArray; + let i = this.lastProcessed, + ii = fnArray.length; + let state = this.state; + let match = this.match; + + if (!state && !match && i + 1 === ii && !InitialState[fnArray[i]]) { + this.lastProcessed = ii; + return; + } + + const context = this.context; + + while (i < ii) { + if (match) { + const iterate = (0, match.iterateFn)(context, i); + + if (iterate) { + i++; + continue; + } + + i = (0, match.processFn)(context, i + 1); + ii = fnArray.length; + match = null; + state = null; + + if (i >= ii) { + break; + } + } + + state = (state || InitialState)[fnArray[i]]; + + if (!state || Array.isArray(state)) { + i++; + continue; + } + + context.iCurr = i; + i++; + + if (state.checkFn && !(0, state.checkFn)(context)) { + state = null; + continue; + } + + match = state; + state = null; + } + + this.state = state; + this.match = match; + this.lastProcessed = i; + } + + flush() { + while (this.match) { + const length = this.queue.fnArray.length; + this.lastProcessed = (0, this.match.processFn)(this.context, length); + this.match = null; + this.state = null; + + this._optimize(); + } + } + + reset() { + this.state = null; + this.match = null; + this.lastProcessed = 0; + } + +} + +class OperatorList { + static get CHUNK_SIZE() { + return (0, _util.shadow)(this, "CHUNK_SIZE", 1000); + } + + static get CHUNK_SIZE_ABOUT() { + return (0, _util.shadow)(this, "CHUNK_SIZE_ABOUT", this.CHUNK_SIZE - 5); + } + + constructor(intent = 0, streamSink) { + this._streamSink = streamSink; + this.fnArray = []; + this.argsArray = []; + + if (streamSink && !(intent & _util.RenderingIntentFlag.OPLIST)) { + this.optimizer = new QueueOptimizer(this); + } else { + this.optimizer = new NullOptimizer(this); + } + + this.dependencies = new Set(); + this._totalLength = 0; + this.weight = 0; + this._resolved = streamSink ? null : Promise.resolve(); + } + + get length() { + return this.argsArray.length; + } + + get ready() { + return this._resolved || this._streamSink.ready; + } + + get totalLength() { + return this._totalLength + this.length; + } + + addOp(fn, args) { + this.optimizer.push(fn, args); + this.weight++; + + if (this._streamSink) { + if (this.weight >= OperatorList.CHUNK_SIZE) { + this.flush(); + } else if (this.weight >= OperatorList.CHUNK_SIZE_ABOUT && (fn === _util.OPS.restore || fn === _util.OPS.endText)) { + this.flush(); + } + } + } + + addImageOps(fn, args, optionalContent) { + if (optionalContent !== undefined) { + this.addOp(_util.OPS.beginMarkedContentProps, ["OC", optionalContent]); + } + + this.addOp(fn, args); + + if (optionalContent !== undefined) { + this.addOp(_util.OPS.endMarkedContent, []); + } + } + + addDependency(dependency) { + if (this.dependencies.has(dependency)) { + return; + } + + this.dependencies.add(dependency); + this.addOp(_util.OPS.dependency, [dependency]); + } + + addDependencies(dependencies) { + for (const dependency of dependencies) { + this.addDependency(dependency); + } + } + + addOpList(opList) { + if (!(opList instanceof OperatorList)) { + (0, _util.warn)('addOpList - ignoring invalid "opList" parameter.'); + return; + } + + for (const dependency of opList.dependencies) { + this.dependencies.add(dependency); + } + + for (let i = 0, ii = opList.length; i < ii; i++) { + this.addOp(opList.fnArray[i], opList.argsArray[i]); + } + } + + getIR() { + return { + fnArray: this.fnArray, + argsArray: this.argsArray, + length: this.length + }; + } + + get _transfers() { + const transfers = []; + const { + fnArray, + argsArray, + length + } = this; + + for (let i = 0; i < length; i++) { + switch (fnArray[i]) { + case _util.OPS.paintInlineImageXObject: + case _util.OPS.paintInlineImageXObjectGroup: + case _util.OPS.paintImageMaskXObject: + const arg = argsArray[i][0]; + + if (!arg.cached && arg.data && arg.data.buffer instanceof ArrayBuffer) { + transfers.push(arg.data.buffer); + } + + break; + } + } + + return transfers; + } + + flush(lastChunk = false, separateAnnots = null) { + this.optimizer.flush(); + const length = this.length; + this._totalLength += length; + + this._streamSink.enqueue({ + fnArray: this.fnArray, + argsArray: this.argsArray, + lastChunk, + separateAnnots, + length + }, 1, this._transfers); + + this.dependencies.clear(); + this.fnArray.length = 0; + this.argsArray.length = 0; + this.weight = 0; + this.optimizer.reset(); + } + +} + +exports.OperatorList = OperatorList; + +/***/ }), +/* 63 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.PDFImage = void 0; var _util = __w_pdfjs_require__(2); +var _image_utils = __w_pdfjs_require__(64); + +var _base_stream = __w_pdfjs_require__(7); + +var _colorspace = __w_pdfjs_require__(14); + +var _decode_stream = __w_pdfjs_require__(19); + +var _jpeg_stream = __w_pdfjs_require__(27); + +var _jpx = __w_pdfjs_require__(30); + var _primitives = __w_pdfjs_require__(5); -var _colorspace = __w_pdfjs_require__(23); - -var _stream = __w_pdfjs_require__(12); - -var _jpeg_stream = __w_pdfjs_require__(18); - -var _jpx = __w_pdfjs_require__(21); - function decodeAndClamp(value, addend, coefficient, max) { value = addend + value * coefficient; @@ -46341,7 +53846,7 @@ function decodeAndClamp(value, addend, coefficient, max) { } function resizeImageMask(src, bpc, w1, h1, w2, h2) { - var length = w2 * h2; + const length = w2 * h2; let dest; if (bpc <= 8) { @@ -46352,15 +53857,15 @@ function resizeImageMask(src, bpc, w1, h1, w2, h2) { dest = new Uint32Array(length); } - var xRatio = w1 / w2; - var yRatio = h1 / h2; - var i, + const xRatio = w1 / w2; + const yRatio = h1 / h2; + let i, j, py, newIndex = 0, oldIndex; - var xScaled = new Uint16Array(w2); - var w1Scanline = w1; + const xScaled = new Uint16Array(w2); + const w1Scanline = w1; for (i = 0; i < w2; i++) { xScaled[i] = Math.floor(i * xRatio); @@ -46391,30 +53896,39 @@ class PDFImage { localColorSpaceCache }) { this.image = image; - var dict = image.dict; - const filter = dict.get("Filter"); + const dict = image.dict; + const filter = dict.get("F", "Filter"); + let filterName; - if ((0, _primitives.isName)(filter)) { - switch (filter.name) { - case "JPXDecode": - var jpxImage = new _jpx.JpxImage(); - jpxImage.parseImageProperties(image.stream); - image.stream.reset(); - image.width = jpxImage.width; - image.height = jpxImage.height; - image.bitsPerComponent = jpxImage.bitsPerComponent; - image.numComps = jpxImage.componentsCount; - break; + if (filter instanceof _primitives.Name) { + filterName = filter.name; + } else if (Array.isArray(filter)) { + const filterZero = xref.fetchIfRef(filter[0]); - case "JBIG2Decode": - image.bitsPerComponent = 1; - image.numComps = 1; - break; + if (filterZero instanceof _primitives.Name) { + filterName = filterZero.name; } } - let width = dict.get("Width", "W"); - let height = dict.get("Height", "H"); + switch (filterName) { + case "JPXDecode": + const jpxImage = new _jpx.JpxImage(); + jpxImage.parseImageProperties(image.stream); + image.stream.reset(); + image.width = jpxImage.width; + image.height = jpxImage.height; + image.bitsPerComponent = jpxImage.bitsPerComponent; + image.numComps = jpxImage.componentsCount; + break; + + case "JBIG2Decode": + image.bitsPerComponent = 1; + image.numComps = 1; + break; + } + + let width = dict.get("W", "Width"); + let height = dict.get("H", "Height"); if (Number.isInteger(image.width) && image.width > 0 && Number.isInteger(image.height) && image.height > 0 && (image.width !== width || image.height !== height)) { (0, _util.warn)("PDFImage - using the Width/Height of the image data, " + "rather than the image dictionary."); @@ -46428,13 +53942,13 @@ class PDFImage { this.width = width; this.height = height; - this.interpolate = dict.get("Interpolate", "I") || false; - this.imageMask = dict.get("ImageMask", "IM") || false; + this.interpolate = dict.get("I", "Interpolate"); + this.imageMask = dict.get("IM", "ImageMask") || false; this.matte = dict.get("Matte") || false; - var bitsPerComponent = image.bitsPerComponent; + let bitsPerComponent = image.bitsPerComponent; if (!bitsPerComponent) { - bitsPerComponent = dict.get("BitsPerComponent", "BPC"); + bitsPerComponent = dict.get("BPC", "BitsPerComponent"); if (!bitsPerComponent) { if (this.imageMask) { @@ -46448,7 +53962,7 @@ class PDFImage { this.bpc = bitsPerComponent; if (!this.imageMask) { - let colorSpace = dict.getRaw("ColorSpace") || dict.getRaw("CS"); + let colorSpace = dict.getRaw("CS") || dict.getRaw("ColorSpace"); if (!colorSpace) { (0, _util.info)("JPX images (which do not require color spaces)"); @@ -46467,7 +53981,7 @@ class PDFImage { break; default: - throw new Error(`JPX images with ${image.numComps} ` + "color components not supported."); + throw new Error(`JPX images with ${image.numComps} color components not supported.`); } } @@ -46481,19 +53995,19 @@ class PDFImage { this.numComps = this.colorSpace.numComps; } - this.decode = dict.getArray("Decode", "D"); + this.decode = dict.getArray("D", "Decode"); this.needsDecode = false; if (this.decode && (this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode, bitsPerComponent) || isMask && !_colorspace.ColorSpace.isDefaultDecode(this.decode, 1))) { this.needsDecode = true; - var max = (1 << bitsPerComponent) - 1; + const max = (1 << bitsPerComponent) - 1; this.decodeCoefficients = []; this.decodeAddends = []; const isIndexed = this.colorSpace && this.colorSpace.name === "Indexed"; - for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) { - var dmin = this.decode[i]; - var dmax = this.decode[i + 1]; + for (let i = 0, j = 0; i < this.decode.length; i += 2, ++j) { + const dmin = this.decode[i]; + const dmax = this.decode[i + 1]; this.decodeCoefficients[j] = isIndexed ? (dmax - dmin) / max : dmax - dmin; this.decodeAddends[j] = isIndexed ? dmin : max * dmin; } @@ -46509,9 +54023,9 @@ class PDFImage { localColorSpaceCache }); } else if (mask) { - if ((0, _primitives.isStream)(mask)) { - var maskDict = mask.dict, - imageMask = maskDict.get("ImageMask", "IM"); + if (mask instanceof _base_stream.BaseStream) { + const maskDict = mask.dict, + imageMask = maskDict.get("IM", "ImageMask"); if (!imageMask) { (0, _util.warn)("Ignoring /Mask in image without /ImageMask."); @@ -46547,12 +54061,16 @@ class PDFImage { const mask = image.dict.get("Mask"); if (smask) { - smaskData = smask; + if (smask instanceof _base_stream.BaseStream) { + smaskData = smask; + } else { + (0, _util.warn)("Unsupported /SMask format."); + } } else if (mask) { - if ((0, _primitives.isStream)(mask) || Array.isArray(mask)) { + if (mask instanceof _base_stream.BaseStream || Array.isArray(mask)) { maskData = mask; } else { - (0, _util.warn)("Unsupported mask format."); + (0, _util.warn)("Unsupported /Mask format."); } } @@ -46568,30 +54086,27 @@ class PDFImage { }); } - static createMask({ + static createRawMask({ imgArray, width, height, imageIsFromDecodeStream, - inverseDecode + inverseDecode, + interpolate }) { - var computedLength = (width + 7 >> 3) * height; - var actualLength = imgArray.byteLength; - var haveFullData = computedLength === actualLength; - var data, i; + const computedLength = (width + 7 >> 3) * height; + const actualLength = imgArray.byteLength; + const haveFullData = computedLength === actualLength; + let data, i; if (imageIsFromDecodeStream && (!inverseDecode || haveFullData)) { data = imgArray; } else if (!inverseDecode) { - data = new Uint8ClampedArray(actualLength); - data.set(imgArray); + data = new Uint8Array(imgArray); } else { - data = new Uint8ClampedArray(computedLength); + data = new Uint8Array(computedLength); data.set(imgArray); - - for (i = actualLength; i < computedLength; i++) { - data[i] = 0xff; - } + data.fill(0xff, actualLength); } if (inverseDecode) { @@ -46603,10 +54118,59 @@ class PDFImage { return { data, width, - height + height, + interpolate }; } + static createMask({ + imgArray, + width, + height, + imageIsFromDecodeStream, + inverseDecode, + interpolate + }) { + const isSingleOpaquePixel = width === 1 && height === 1 && inverseDecode === (imgArray.length === 0 || !!(imgArray[0] & 128)); + + if (isSingleOpaquePixel) { + return { + isSingleOpaquePixel + }; + } + + if (_util.FeatureTest.isOffscreenCanvasSupported) { + const canvas = new OffscreenCanvas(width, height); + const ctx = canvas.getContext("2d"); + const imgData = ctx.createImageData(width, height); + (0, _image_utils.applyMaskImageData)({ + src: imgArray, + dest: imgData.data, + width, + height, + inverseDecode + }); + ctx.putImageData(imgData, 0, 0); + const bitmap = canvas.transferToImageBitmap(); + return { + data: null, + width, + height, + interpolate, + bitmap + }; + } + + return this.createRawMask({ + imgArray, + width, + height, + inverseDecode, + imageIsFromDecodeStream, + interpolate + }); + } + get drawWidth() { return Math.max(this.width, this.smask && this.smask.width || 0, this.mask && this.mask.width || 0); } @@ -46616,12 +54180,12 @@ class PDFImage { } decodeBuffer(buffer) { - var bpc = this.bpc; - var numComps = this.numComps; - var decodeAddends = this.decodeAddends; - var decodeCoefficients = this.decodeCoefficients; - var max = (1 << bpc) - 1; - var i, ii; + const bpc = this.bpc; + const numComps = this.numComps; + const decodeAddends = this.decodeAddends; + const decodeCoefficients = this.decodeCoefficients; + const max = (1 << bpc) - 1; + let i, ii; if (bpc === 1) { for (i = 0, ii = buffer.length; i < ii; i++) { @@ -46631,10 +54195,10 @@ class PDFImage { return; } - var index = 0; + let index = 0; for (i = 0, ii = this.width * this.height; i < ii; i++) { - for (var j = 0; j < numComps; j++) { + for (let j = 0; j < numComps; j++) { buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j], decodeCoefficients[j], max); index++; } @@ -46642,17 +54206,17 @@ class PDFImage { } getComponents(buffer) { - var bpc = this.bpc; + const bpc = this.bpc; if (bpc === 8) { return buffer; } - var width = this.width; - var height = this.height; - var numComps = this.numComps; - var length = width * height * numComps; - var bufferPos = 0; + const width = this.width; + const height = this.height; + const numComps = this.numComps; + const length = width * height * numComps; + let bufferPos = 0; let output; if (bpc <= 8) { @@ -46663,16 +54227,16 @@ class PDFImage { output = new Uint32Array(length); } - var rowComps = width * numComps; - var max = (1 << bpc) - 1; - var i = 0, + const rowComps = width * numComps; + const max = (1 << bpc) - 1; + let i = 0, ii, buf; if (bpc === 1) { - var mask, loop1End, loop2End; + let mask, loop1End, loop2End; - for (var j = 0; j < height; j++) { + for (let j = 0; j < height; j++) { loop1End = i + (rowComps & ~7); loop2End = i + rowComps; @@ -46700,7 +54264,7 @@ class PDFImage { } } } else { - var bits = 0; + let bits = 0; buf = 0; for (i = 0, ii = length; i < ii; ++i) { @@ -46714,7 +54278,7 @@ class PDFImage { bits += 8; } - var remainingBits = bits - bpc; + const remainingBits = bits - bpc; let value = buf >> remainingBits; if (value < 0) { @@ -46724,7 +54288,7 @@ class PDFImage { } output[i] = value; - buf = buf & (1 << remainingBits) - 1; + buf &= (1 << remainingBits) - 1; bits = remainingBits; } } @@ -46733,9 +54297,9 @@ class PDFImage { } fillOpacity(rgbaBuf, width, height, actualHeight, image) { - var smask = this.smask; - var mask = this.mask; - var alphaBuf, sw, sh, i, ii, j; + const smask = this.smask; + const mask = this.mask; + let alphaBuf, sw, sh, i, ii, j; if (smask) { sw = smask.width; @@ -46763,15 +54327,15 @@ class PDFImage { } } else if (Array.isArray(mask)) { alphaBuf = new Uint8ClampedArray(width * height); - var numComps = this.numComps; + const numComps = this.numComps; for (i = 0, ii = width * height; i < ii; ++i) { - var opacity = 0; - var imageOffset = i * numComps; + let opacity = 0; + const imageOffset = i * numComps; for (j = 0; j < numComps; ++j) { - var color = image[imageOffset + j]; - var maskOffset = j * 2; + const color = image[imageOffset + j]; + const maskOffset = j * 2; if (color < mask[maskOffset] || color > mask[maskOffset + 1]) { opacity = 255; @@ -46798,20 +54362,20 @@ class PDFImage { } undoPreblend(buffer, width, height) { - var matte = this.smask && this.smask.matte; + const matte = this.smask && this.smask.matte; if (!matte) { return; } - var matteRgb = this.colorSpace.getRgb(matte, 0); - var matteR = matteRgb[0]; - var matteG = matteRgb[1]; - var matteB = matteRgb[2]; - var length = width * height * 4; + const matteRgb = this.colorSpace.getRgb(matte, 0); + const matteR = matteRgb[0]; + const matteG = matteRgb[1]; + const matteB = matteRgb[2]; + const length = width * height * 4; - for (var i = 0; i < length; i += 4) { - var alpha = buffer[i + 3]; + for (let i = 0; i < length; i += 4) { + const alpha = buffer[i + 3]; if (alpha === 0) { buffer[i] = 255; @@ -46820,7 +54384,7 @@ class PDFImage { continue; } - var k = 255 / alpha; + const k = 255 / alpha; buffer[i] = (buffer[i] - matteR) * k + matteR; buffer[i + 1] = (buffer[i + 1] - matteG) * k + matteG; buffer[i + 2] = (buffer[i + 2] - matteB) * k + matteB; @@ -46828,23 +54392,23 @@ class PDFImage { } createImageData(forceRGBA = false) { - var drawWidth = this.drawWidth; - var drawHeight = this.drawHeight; - var imgData = { + const drawWidth = this.drawWidth; + const drawHeight = this.drawHeight; + const imgData = { width: drawWidth, height: drawHeight, + interpolate: this.interpolate, kind: 0, data: null }; - var numComps = this.numComps; - var originalWidth = this.width; - var originalHeight = this.height; - var bpc = this.bpc; - var rowBytes = originalWidth * numComps * bpc + 7 >> 3; - var imgArray; + const numComps = this.numComps; + const originalWidth = this.width; + const originalHeight = this.height; + const bpc = this.bpc; + const rowBytes = originalWidth * numComps * bpc + 7 >> 3; if (!forceRGBA) { - var kind; + let kind; if (this.colorSpace.name === "DeviceGray" && bpc === 1) { kind = _util.ImageKind.GRAYSCALE_1BPP; @@ -46854,21 +54418,13 @@ class PDFImage { if (kind && !this.smask && !this.mask && drawWidth === originalWidth && drawHeight === originalHeight) { imgData.kind = kind; - imgArray = this.getImageBytes(originalHeight * rowBytes); - - if (this.image instanceof _stream.DecodeStream) { - imgData.data = imgArray; - } else { - var newArray = new Uint8ClampedArray(imgArray.length); - newArray.set(imgArray); - imgData.data = newArray; - } + imgData.data = this.getImageBytes(originalHeight * rowBytes, {}); if (this.needsDecode) { (0, _util.assert)(kind === _util.ImageKind.GRAYSCALE_1BPP, "PDFImage.createImageData: The image must be grayscale."); - var buffer = imgData.data; + const buffer = imgData.data; - for (var i = 0, ii = buffer.length; i < ii; i++) { + for (let i = 0, ii = buffer.length; i < ii; i++) { buffer[i] ^= 0xff; } } @@ -46886,16 +54442,22 @@ class PDFImage { case "DeviceRGB": case "DeviceCMYK": imgData.kind = _util.ImageKind.RGB_24BPP; - imgData.data = this.getImageBytes(imageLength, drawWidth, drawHeight, true); + imgData.data = this.getImageBytes(imageLength, { + drawWidth, + drawHeight, + forceRGB: true + }); return imgData; } } } - imgArray = this.getImageBytes(originalHeight * rowBytes); - var actualHeight = 0 | imgArray.length / rowBytes * drawHeight / originalHeight; - var comps = this.getComponents(imgArray); - var alpha01, maybeUndoPreblend; + const imgArray = this.getImageBytes(originalHeight * rowBytes, { + internal: true + }); + const actualHeight = 0 | imgArray.length / rowBytes * drawHeight / originalHeight; + const comps = this.getComponents(imgArray); + let alpha01, maybeUndoPreblend; if (!forceRGBA && !this.smask && !this.mask) { imgData.kind = _util.ImageKind.RGB_24BPP; @@ -46924,19 +54486,21 @@ class PDFImage { } fillGrayBuffer(buffer) { - var numComps = this.numComps; + const numComps = this.numComps; if (numComps !== 1) { throw new _util.FormatError(`Reading gray scale from a color image: ${numComps}`); } - var width = this.width; - var height = this.height; - var bpc = this.bpc; - var rowBytes = width * numComps * bpc + 7 >> 3; - var imgArray = this.getImageBytes(height * rowBytes); - var comps = this.getComponents(imgArray); - var i, length; + const width = this.width; + const height = this.height; + const bpc = this.bpc; + const rowBytes = width * numComps * bpc + 7 >> 3; + const imgArray = this.getImageBytes(height * rowBytes, { + internal: true + }); + const comps = this.getComponents(imgArray); + let i, length; if (bpc === 1) { length = width * height; @@ -46959,19 +54523,31 @@ class PDFImage { } length = width * height; - var scale = 255 / ((1 << bpc) - 1); + const scale = 255 / ((1 << bpc) - 1); for (i = 0; i < length; ++i) { buffer[i] = scale * comps[i]; } } - getImageBytes(length, drawWidth, drawHeight, forceRGB = false) { + getImageBytes(length, { + drawWidth, + drawHeight, + forceRGB = false, + internal = false + }) { this.image.reset(); this.image.drawWidth = drawWidth || this.width; this.image.drawHeight = drawHeight || this.height; this.image.forceRGB = !!forceRGB; - return this.image.getBytes(length, true); + const imageBytes = this.image.getBytes(length); + + if (internal || this.image instanceof _decode_stream.DecodeStream) { + return imageBytes; + } + + (0, _util.assert)(imageBytes instanceof Uint8Array, 'PDFImage.getImageBytes: Unsupported "imageBytes" type.'); + return new Uint8Array(imageBytes); } } @@ -46979,15 +54555,20128 @@ class PDFImage { exports.PDFImage = PDFImage; /***/ }), -/* 46 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 64 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.applyMaskImageData = applyMaskImageData; + +var _util = __w_pdfjs_require__(2); + +function applyMaskImageData({ + src, + srcPos = 0, + dest, + destPos = 0, + width, + height, + inverseDecode = false +}) { + const opaque = _util.FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff; + const [zeroMapping, oneMapping] = !inverseDecode ? [opaque, 0] : [0, opaque]; + const widthInSource = width >> 3; + const widthRemainder = width & 7; + const srcLength = src.length; + dest = new Uint32Array(dest.buffer); + + for (let i = 0; i < height; i++) { + for (const max = srcPos + widthInSource; srcPos < max; srcPos++) { + const elem = srcPos < srcLength ? src[srcPos] : 255; + dest[destPos++] = elem & 0b10000000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b1000000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b100000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b10000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b1000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b100 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b10 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b1 ? oneMapping : zeroMapping; + } + + if (widthRemainder === 0) { + continue; + } + + const elem = srcPos < srcLength ? src[srcPos++] : 255; + + for (let j = 0; j < widthRemainder; j++) { + dest[destPos++] = elem & 1 << 7 - j ? oneMapping : zeroMapping; + } + } + + return { + srcPos, + destPos + }; +} + +/***/ }), +/* 65 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.incrementalUpdate = incrementalUpdate; +exports.writeDict = writeDict; +exports.writeObject = writeObject; + +var _util = __w_pdfjs_require__(2); + +var _primitives = __w_pdfjs_require__(5); + +var _core_utils = __w_pdfjs_require__(6); + +var _xml_parser = __w_pdfjs_require__(66); + +var _base_stream = __w_pdfjs_require__(7); + +var _crypto = __w_pdfjs_require__(67); + +function writeObject(ref, obj, buffer, transform) { + buffer.push(`${ref.num} ${ref.gen} obj\n`); + + if (obj instanceof _primitives.Dict) { + writeDict(obj, buffer, transform); + } else if (obj instanceof _base_stream.BaseStream) { + writeStream(obj, buffer, transform); + } + + buffer.push("\nendobj\n"); +} + +function writeDict(dict, buffer, transform) { + buffer.push("<<"); + + for (const key of dict.getKeys()) { + buffer.push(` /${(0, _core_utils.escapePDFName)(key)} `); + writeValue(dict.getRaw(key), buffer, transform); + } + + buffer.push(">>"); +} + +function writeStream(stream, buffer, transform) { + writeDict(stream.dict, buffer, transform); + buffer.push(" stream\n"); + let string = stream.getString(); + + if (transform !== null) { + string = transform.encryptString(string); + } + + buffer.push(string, "\nendstream\n"); +} + +function writeArray(array, buffer, transform) { + buffer.push("["); + let first = true; + + for (const val of array) { + if (!first) { + buffer.push(" "); + } else { + first = false; + } + + writeValue(val, buffer, transform); + } + + buffer.push("]"); +} + +function writeValue(value, buffer, transform) { + if (value instanceof _primitives.Name) { + buffer.push(`/${(0, _core_utils.escapePDFName)(value.name)}`); + } else if (value instanceof _primitives.Ref) { + buffer.push(`${value.num} ${value.gen} R`); + } else if (Array.isArray(value)) { + writeArray(value, buffer, transform); + } else if (typeof value === "string") { + if (transform !== null) { + value = transform.encryptString(value); + } + + buffer.push(`(${(0, _util.escapeString)(value)})`); + } else if (typeof value === "number") { + buffer.push((0, _core_utils.numberToString)(value)); + } else if (typeof value === "boolean") { + buffer.push(value.toString()); + } else if (value instanceof _primitives.Dict) { + writeDict(value, buffer, transform); + } else if (value instanceof _base_stream.BaseStream) { + writeStream(value, buffer, transform); + } else if (value === null) { + buffer.push("null"); + } else { + (0, _util.warn)(`Unhandled value in writer: ${typeof value}, please file a bug.`); + } +} + +function writeInt(number, size, offset, buffer) { + for (let i = size + offset - 1; i > offset - 1; i--) { + buffer[i] = number & 0xff; + number >>= 8; + } + + return offset + size; +} + +function writeString(string, offset, buffer) { + for (let i = 0, len = string.length; i < len; i++) { + buffer[offset + i] = string.charCodeAt(i) & 0xff; + } +} + +function computeMD5(filesize, xrefInfo) { + const time = Math.floor(Date.now() / 1000); + const filename = xrefInfo.filename || ""; + const md5Buffer = [time.toString(), filename, filesize.toString()]; + let md5BufferLen = md5Buffer.reduce((a, str) => a + str.length, 0); + + for (const value of Object.values(xrefInfo.info)) { + md5Buffer.push(value); + md5BufferLen += value.length; + } + + const array = new Uint8Array(md5BufferLen); + let offset = 0; + + for (const str of md5Buffer) { + writeString(str, offset, array); + offset += str.length; + } + + return (0, _util.bytesToString)((0, _crypto.calculateMD5)(array)); +} + +function writeXFADataForAcroform(str, newRefs) { + const xml = new _xml_parser.SimpleXMLParser({ + hasAttributes: true + }).parseFromString(str); + + for (const { + xfa + } of newRefs) { + if (!xfa) { + continue; + } + + const { + path, + value + } = xfa; + + if (!path) { + continue; + } + + const node = xml.documentElement.searchNode((0, _core_utils.parseXFAPath)(path), 0); + + if (node) { + if (Array.isArray(value)) { + node.childNodes = value.map(val => new _xml_parser.SimpleDOMNode("value", val)); + } else { + node.childNodes = [new _xml_parser.SimpleDOMNode("#text", value)]; + } + } else { + (0, _util.warn)(`Node not found for path: ${path}`); + } + } + + const buffer = []; + xml.documentElement.dump(buffer); + return buffer.join(""); +} + +function updateXFA({ + xfaData, + xfaDatasetsRef, + hasXfaDatasetsEntry, + acroFormRef, + acroForm, + newRefs, + xref, + xrefInfo +}) { + if (xref === null) { + return; + } + + if (!hasXfaDatasetsEntry) { + if (!acroFormRef) { + (0, _util.warn)("XFA - Cannot save it"); + return; + } + + const oldXfa = acroForm.get("XFA"); + const newXfa = oldXfa.slice(); + newXfa.splice(2, 0, "datasets"); + newXfa.splice(3, 0, xfaDatasetsRef); + acroForm.set("XFA", newXfa); + const encrypt = xref.encrypt; + let transform = null; + + if (encrypt) { + transform = encrypt.createCipherTransform(acroFormRef.num, acroFormRef.gen); + } + + const buffer = [`${acroFormRef.num} ${acroFormRef.gen} obj\n`]; + writeDict(acroForm, buffer, transform); + buffer.push("\n"); + acroForm.set("XFA", oldXfa); + newRefs.push({ + ref: acroFormRef, + data: buffer.join("") + }); + } + + if (xfaData === null) { + const datasets = xref.fetchIfRef(xfaDatasetsRef); + xfaData = writeXFADataForAcroform(datasets.getString(), newRefs); + } + + const encrypt = xref.encrypt; + + if (encrypt) { + const transform = encrypt.createCipherTransform(xfaDatasetsRef.num, xfaDatasetsRef.gen); + xfaData = transform.encryptString(xfaData); + } + + const data = `${xfaDatasetsRef.num} ${xfaDatasetsRef.gen} obj\n` + `<< /Type /EmbeddedFile /Length ${xfaData.length}>>\nstream\n` + xfaData + "\nendstream\nendobj\n"; + newRefs.push({ + ref: xfaDatasetsRef, + data + }); +} + +function incrementalUpdate({ + originalData, + xrefInfo, + newRefs, + xref = null, + hasXfa = false, + xfaDatasetsRef = null, + hasXfaDatasetsEntry = false, + acroFormRef = null, + acroForm = null, + xfaData = null +}) { + if (hasXfa) { + updateXFA({ + xfaData, + xfaDatasetsRef, + hasXfaDatasetsEntry, + acroFormRef, + acroForm, + newRefs, + xref, + xrefInfo + }); + } + + const newXref = new _primitives.Dict(null); + const refForXrefTable = xrefInfo.newRef; + let buffer, baseOffset; + const lastByte = originalData.at(-1); + + if (lastByte === 0x0a || lastByte === 0x0d) { + buffer = []; + baseOffset = originalData.length; + } else { + buffer = ["\n"]; + baseOffset = originalData.length + 1; + } + + newXref.set("Size", refForXrefTable.num + 1); + newXref.set("Prev", xrefInfo.startXRef); + newXref.set("Type", _primitives.Name.get("XRef")); + + if (xrefInfo.rootRef !== null) { + newXref.set("Root", xrefInfo.rootRef); + } + + if (xrefInfo.infoRef !== null) { + newXref.set("Info", xrefInfo.infoRef); + } + + if (xrefInfo.encryptRef !== null) { + newXref.set("Encrypt", xrefInfo.encryptRef); + } + + newRefs.push({ + ref: refForXrefTable, + data: "" + }); + newRefs = newRefs.sort((a, b) => { + return a.ref.num - b.ref.num; + }); + const xrefTableData = [[0, 1, 0xffff]]; + const indexes = [0, 1]; + let maxOffset = 0; + + for (const { + ref, + data + } of newRefs) { + maxOffset = Math.max(maxOffset, baseOffset); + xrefTableData.push([1, baseOffset, Math.min(ref.gen, 0xffff)]); + baseOffset += data.length; + indexes.push(ref.num, 1); + buffer.push(data); + } + + newXref.set("Index", indexes); + + if (Array.isArray(xrefInfo.fileIds) && xrefInfo.fileIds.length > 0) { + const md5 = computeMD5(baseOffset, xrefInfo); + newXref.set("ID", [xrefInfo.fileIds[0], md5]); + } + + const offsetSize = Math.ceil(Math.log2(maxOffset) / 8); + const sizes = [1, offsetSize, 2]; + const structSize = sizes[0] + sizes[1] + sizes[2]; + const tableLength = structSize * xrefTableData.length; + newXref.set("W", sizes); + newXref.set("Length", tableLength); + buffer.push(`${refForXrefTable.num} ${refForXrefTable.gen} obj\n`); + writeDict(newXref, buffer, null); + buffer.push(" stream\n"); + const bufferLen = buffer.reduce((a, str) => a + str.length, 0); + const footer = `\nendstream\nendobj\nstartxref\n${baseOffset}\n%%EOF\n`; + const array = new Uint8Array(originalData.length + bufferLen + tableLength + footer.length); + array.set(originalData); + let offset = originalData.length; + + for (const str of buffer) { + writeString(str, offset, array); + offset += str.length; + } + + for (const [type, objOffset, gen] of xrefTableData) { + offset = writeInt(type, sizes[0], offset, array); + offset = writeInt(objOffset, sizes[1], offset, array); + offset = writeInt(gen, sizes[2], offset, array); + } + + writeString(footer, offset, array); + return array; +} + +/***/ }), +/* 66 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XMLParserErrorCode = exports.XMLParserBase = exports.SimpleXMLParser = exports.SimpleDOMNode = void 0; + +var _core_utils = __w_pdfjs_require__(6); + +const XMLParserErrorCode = { + NoError: 0, + EndOfDocument: -1, + UnterminatedCdat: -2, + UnterminatedXmlDeclaration: -3, + UnterminatedDoctypeDeclaration: -4, + UnterminatedComment: -5, + MalformedElement: -6, + OutOfMemory: -7, + UnterminatedAttributeValue: -8, + UnterminatedElement: -9, + ElementNeverBegun: -10 +}; +exports.XMLParserErrorCode = XMLParserErrorCode; + +function isWhitespace(s, index) { + const ch = s[index]; + return ch === " " || ch === "\n" || ch === "\r" || ch === "\t"; +} + +function isWhitespaceString(s) { + for (let i = 0, ii = s.length; i < ii; i++) { + if (!isWhitespace(s, i)) { + return false; + } + } + + return true; +} + +class XMLParserBase { + _resolveEntities(s) { + return s.replace(/&([^;]+);/g, (all, entity) => { + if (entity.substring(0, 2) === "#x") { + return String.fromCodePoint(parseInt(entity.substring(2), 16)); + } else if (entity.substring(0, 1) === "#") { + return String.fromCodePoint(parseInt(entity.substring(1), 10)); + } + + switch (entity) { + case "lt": + return "<"; + + case "gt": + return ">"; + + case "amp": + return "&"; + + case "quot": + return '"'; + + case "apos": + return "'"; + } + + return this.onResolveEntity(entity); + }); + } + + _parseContent(s, start) { + const attributes = []; + let pos = start; + + function skipWs() { + while (pos < s.length && isWhitespace(s, pos)) { + ++pos; + } + } + + while (pos < s.length && !isWhitespace(s, pos) && s[pos] !== ">" && s[pos] !== "/") { + ++pos; + } + + const name = s.substring(start, pos); + skipWs(); + + while (pos < s.length && s[pos] !== ">" && s[pos] !== "/" && s[pos] !== "?") { + skipWs(); + let attrName = "", + attrValue = ""; + + while (pos < s.length && !isWhitespace(s, pos) && s[pos] !== "=") { + attrName += s[pos]; + ++pos; + } + + skipWs(); + + if (s[pos] !== "=") { + return null; + } + + ++pos; + skipWs(); + const attrEndChar = s[pos]; + + if (attrEndChar !== '"' && attrEndChar !== "'") { + return null; + } + + const attrEndIndex = s.indexOf(attrEndChar, ++pos); + + if (attrEndIndex < 0) { + return null; + } + + attrValue = s.substring(pos, attrEndIndex); + attributes.push({ + name: attrName, + value: this._resolveEntities(attrValue) + }); + pos = attrEndIndex + 1; + skipWs(); + } + + return { + name, + attributes, + parsed: pos - start + }; + } + + _parseProcessingInstruction(s, start) { + let pos = start; + + function skipWs() { + while (pos < s.length && isWhitespace(s, pos)) { + ++pos; + } + } + + while (pos < s.length && !isWhitespace(s, pos) && s[pos] !== ">" && s[pos] !== "?" && s[pos] !== "/") { + ++pos; + } + + const name = s.substring(start, pos); + skipWs(); + const attrStart = pos; + + while (pos < s.length && (s[pos] !== "?" || s[pos + 1] !== ">")) { + ++pos; + } + + const value = s.substring(attrStart, pos); + return { + name, + value, + parsed: pos - start + }; + } + + parseXml(s) { + let i = 0; + + while (i < s.length) { + const ch = s[i]; + let j = i; + + if (ch === "<") { + ++j; + const ch2 = s[j]; + let q; + + switch (ch2) { + case "/": + ++j; + q = s.indexOf(">", j); + + if (q < 0) { + this.onError(XMLParserErrorCode.UnterminatedElement); + return; + } + + this.onEndElement(s.substring(j, q)); + j = q + 1; + break; + + case "?": + ++j; + + const pi = this._parseProcessingInstruction(s, j); + + if (s.substring(j + pi.parsed, j + pi.parsed + 2) !== "?>") { + this.onError(XMLParserErrorCode.UnterminatedXmlDeclaration); + return; + } + + this.onPi(pi.name, pi.value); + j += pi.parsed + 2; + break; + + case "!": + if (s.substring(j + 1, j + 3) === "--") { + q = s.indexOf("-->", j + 3); + + if (q < 0) { + this.onError(XMLParserErrorCode.UnterminatedComment); + return; + } + + this.onComment(s.substring(j + 3, q)); + j = q + 3; + } else if (s.substring(j + 1, j + 8) === "[CDATA[") { + q = s.indexOf("]]>", j + 8); + + if (q < 0) { + this.onError(XMLParserErrorCode.UnterminatedCdat); + return; + } + + this.onCdata(s.substring(j + 8, q)); + j = q + 3; + } else if (s.substring(j + 1, j + 8) === "DOCTYPE") { + const q2 = s.indexOf("[", j + 8); + let complexDoctype = false; + q = s.indexOf(">", j + 8); + + if (q < 0) { + this.onError(XMLParserErrorCode.UnterminatedDoctypeDeclaration); + return; + } + + if (q2 > 0 && q > q2) { + q = s.indexOf("]>", j + 8); + + if (q < 0) { + this.onError(XMLParserErrorCode.UnterminatedDoctypeDeclaration); + return; + } + + complexDoctype = true; + } + + const doctypeContent = s.substring(j + 8, q + (complexDoctype ? 1 : 0)); + this.onDoctype(doctypeContent); + j = q + (complexDoctype ? 2 : 1); + } else { + this.onError(XMLParserErrorCode.MalformedElement); + return; + } + + break; + + default: + const content = this._parseContent(s, j); + + if (content === null) { + this.onError(XMLParserErrorCode.MalformedElement); + return; + } + + let isClosed = false; + + if (s.substring(j + content.parsed, j + content.parsed + 2) === "/>") { + isClosed = true; + } else if (s.substring(j + content.parsed, j + content.parsed + 1) !== ">") { + this.onError(XMLParserErrorCode.UnterminatedElement); + return; + } + + this.onBeginElement(content.name, content.attributes, isClosed); + j += content.parsed + (isClosed ? 2 : 1); + break; + } + } else { + while (j < s.length && s[j] !== "<") { + j++; + } + + const text = s.substring(i, j); + this.onText(this._resolveEntities(text)); + } + + i = j; + } + } + + onResolveEntity(name) { + return `&${name};`; + } + + onPi(name, value) {} + + onComment(text) {} + + onCdata(text) {} + + onDoctype(doctypeContent) {} + + onText(text) {} + + onBeginElement(name, attributes, isEmpty) {} + + onEndElement(name) {} + + onError(code) {} + +} + +exports.XMLParserBase = XMLParserBase; + +class SimpleDOMNode { + constructor(nodeName, nodeValue) { + this.nodeName = nodeName; + this.nodeValue = nodeValue; + Object.defineProperty(this, "parentNode", { + value: null, + writable: true + }); + } + + get firstChild() { + return this.childNodes && this.childNodes[0]; + } + + get nextSibling() { + const childNodes = this.parentNode.childNodes; + + if (!childNodes) { + return undefined; + } + + const index = childNodes.indexOf(this); + + if (index === -1) { + return undefined; + } + + return childNodes[index + 1]; + } + + get textContent() { + if (!this.childNodes) { + return this.nodeValue || ""; + } + + return this.childNodes.map(function (child) { + return child.textContent; + }).join(""); + } + + get children() { + return this.childNodes || []; + } + + hasChildNodes() { + return this.childNodes && this.childNodes.length > 0; + } + + searchNode(paths, pos) { + if (pos >= paths.length) { + return this; + } + + const component = paths[pos]; + const stack = []; + let node = this; + + while (true) { + if (component.name === node.nodeName) { + if (component.pos === 0) { + const res = node.searchNode(paths, pos + 1); + + if (res !== null) { + return res; + } + } else if (stack.length === 0) { + return null; + } else { + const [parent] = stack.pop(); + let siblingPos = 0; + + for (const child of parent.childNodes) { + if (component.name === child.nodeName) { + if (siblingPos === component.pos) { + return child.searchNode(paths, pos + 1); + } + + siblingPos++; + } + } + + return node.searchNode(paths, pos + 1); + } + } + + if (node.childNodes && node.childNodes.length !== 0) { + stack.push([node, 0]); + node = node.childNodes[0]; + } else if (stack.length === 0) { + return null; + } else { + while (stack.length !== 0) { + const [parent, currentPos] = stack.pop(); + const newPos = currentPos + 1; + + if (newPos < parent.childNodes.length) { + stack.push([parent, newPos]); + node = parent.childNodes[newPos]; + break; + } + } + + if (stack.length === 0) { + return null; + } + } + } + } + + dump(buffer) { + if (this.nodeName === "#text") { + buffer.push((0, _core_utils.encodeToXmlString)(this.nodeValue)); + return; + } + + buffer.push(`<${this.nodeName}`); + + if (this.attributes) { + for (const attribute of this.attributes) { + buffer.push(` ${attribute.name}="${(0, _core_utils.encodeToXmlString)(attribute.value)}"`); + } + } + + if (this.hasChildNodes()) { + buffer.push(">"); + + for (const child of this.childNodes) { + child.dump(buffer); + } + + buffer.push(``); + } else if (this.nodeValue) { + buffer.push(`>${(0, _core_utils.encodeToXmlString)(this.nodeValue)}`); + } else { + buffer.push("/>"); + } + } + +} + +exports.SimpleDOMNode = SimpleDOMNode; + +class SimpleXMLParser extends XMLParserBase { + constructor({ + hasAttributes = false, + lowerCaseName = false + }) { + super(); + this._currentFragment = null; + this._stack = null; + this._errorCode = XMLParserErrorCode.NoError; + this._hasAttributes = hasAttributes; + this._lowerCaseName = lowerCaseName; + } + + parseFromString(data) { + this._currentFragment = []; + this._stack = []; + this._errorCode = XMLParserErrorCode.NoError; + this.parseXml(data); + + if (this._errorCode !== XMLParserErrorCode.NoError) { + return undefined; + } + + const [documentElement] = this._currentFragment; + + if (!documentElement) { + return undefined; + } + + return { + documentElement + }; + } + + onText(text) { + if (isWhitespaceString(text)) { + return; + } + + const node = new SimpleDOMNode("#text", text); + + this._currentFragment.push(node); + } + + onCdata(text) { + const node = new SimpleDOMNode("#text", text); + + this._currentFragment.push(node); + } + + onBeginElement(name, attributes, isEmpty) { + if (this._lowerCaseName) { + name = name.toLowerCase(); + } + + const node = new SimpleDOMNode(name); + node.childNodes = []; + + if (this._hasAttributes) { + node.attributes = attributes; + } + + this._currentFragment.push(node); + + if (isEmpty) { + return; + } + + this._stack.push(this._currentFragment); + + this._currentFragment = node.childNodes; + } + + onEndElement(name) { + this._currentFragment = this._stack.pop() || []; + + const lastElement = this._currentFragment.at(-1); + + if (!lastElement) { + return null; + } + + for (let i = 0, ii = lastElement.childNodes.length; i < ii; i++) { + lastElement.childNodes[i].parentNode = lastElement; + } + + return lastElement; + } + + onError(code) { + this._errorCode = code; + } + +} + +exports.SimpleXMLParser = SimpleXMLParser; + +/***/ }), +/* 67 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.calculateSHA256 = exports.calculateMD5 = exports.PDF20 = exports.PDF17 = exports.CipherTransformFactory = exports.ARCFourCipher = exports.AES256Cipher = exports.AES128Cipher = void 0; +exports.calculateSHA384 = calculateSHA384; +exports.calculateSHA512 = void 0; + +var _util = __w_pdfjs_require__(2); + +var _primitives = __w_pdfjs_require__(5); + +var _decrypt_stream = __w_pdfjs_require__(68); + +class ARCFourCipher { + constructor(key) { + this.a = 0; + this.b = 0; + const s = new Uint8Array(256); + const keyLength = key.length; + + for (let i = 0; i < 256; ++i) { + s[i] = i; + } + + for (let i = 0, j = 0; i < 256; ++i) { + const tmp = s[i]; + j = j + tmp + key[i % keyLength] & 0xff; + s[i] = s[j]; + s[j] = tmp; + } + + this.s = s; + } + + encryptBlock(data) { + let a = this.a, + b = this.b; + const s = this.s; + const n = data.length; + const output = new Uint8Array(n); + + for (let i = 0; i < n; ++i) { + a = a + 1 & 0xff; + const tmp = s[a]; + b = b + tmp & 0xff; + const tmp2 = s[b]; + s[a] = tmp2; + s[b] = tmp; + output[i] = data[i] ^ s[tmp + tmp2 & 0xff]; + } + + this.a = a; + this.b = b; + return output; + } + + decryptBlock(data) { + return this.encryptBlock(data); + } + + encrypt(data) { + return this.encryptBlock(data); + } + +} + +exports.ARCFourCipher = ARCFourCipher; + +const calculateMD5 = function calculateMD5Closure() { + const r = new Uint8Array([7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]); + const k = new Int32Array([-680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162, 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632, 643717713, -373897302, -701558691, 38016083, -660478335, -405537848, 568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784, 1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556, -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222, -722521979, 76029189, -640364487, -421815835, 530742520, -995338651, -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606, -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649, -145523070, -1120210379, 718787259, -343485551]); + + function hash(data, offset, length) { + let h0 = 1732584193, + h1 = -271733879, + h2 = -1732584194, + h3 = 271733878; + const paddedLength = length + 72 & ~63; + const padded = new Uint8Array(paddedLength); + let i, j; + + for (i = 0; i < length; ++i) { + padded[i] = data[offset++]; + } + + padded[i++] = 0x80; + const n = paddedLength - 8; + + while (i < n) { + padded[i++] = 0; + } + + padded[i++] = length << 3 & 0xff; + padded[i++] = length >> 5 & 0xff; + padded[i++] = length >> 13 & 0xff; + padded[i++] = length >> 21 & 0xff; + padded[i++] = length >>> 29 & 0xff; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + const w = new Int32Array(16); + + for (i = 0; i < paddedLength;) { + for (j = 0; j < 16; ++j, i += 4) { + w[j] = padded[i] | padded[i + 1] << 8 | padded[i + 2] << 16 | padded[i + 3] << 24; + } + + let a = h0, + b = h1, + c = h2, + d = h3, + f, + g; + + for (j = 0; j < 64; ++j) { + if (j < 16) { + f = b & c | ~b & d; + g = j; + } else if (j < 32) { + f = d & b | ~d & c; + g = 5 * j + 1 & 15; + } else if (j < 48) { + f = b ^ c ^ d; + g = 3 * j + 5 & 15; + } else { + f = c ^ (b | ~d); + g = 7 * j & 15; + } + + const tmp = d, + rotateArg = a + f + k[j] + w[g] | 0, + rotate = r[j]; + d = c; + c = b; + b = b + (rotateArg << rotate | rotateArg >>> 32 - rotate) | 0; + a = tmp; + } + + h0 = h0 + a | 0; + h1 = h1 + b | 0; + h2 = h2 + c | 0; + h3 = h3 + d | 0; + } + + return new Uint8Array([h0 & 0xFF, h0 >> 8 & 0xFF, h0 >> 16 & 0xFF, h0 >>> 24 & 0xFF, h1 & 0xFF, h1 >> 8 & 0xFF, h1 >> 16 & 0xFF, h1 >>> 24 & 0xFF, h2 & 0xFF, h2 >> 8 & 0xFF, h2 >> 16 & 0xFF, h2 >>> 24 & 0xFF, h3 & 0xFF, h3 >> 8 & 0xFF, h3 >> 16 & 0xFF, h3 >>> 24 & 0xFF]); + } + + return hash; +}(); + +exports.calculateMD5 = calculateMD5; + +class Word64 { + constructor(highInteger, lowInteger) { + this.high = highInteger | 0; + this.low = lowInteger | 0; + } + + and(word) { + this.high &= word.high; + this.low &= word.low; + } + + xor(word) { + this.high ^= word.high; + this.low ^= word.low; + } + + or(word) { + this.high |= word.high; + this.low |= word.low; + } + + shiftRight(places) { + if (places >= 32) { + this.low = this.high >>> places - 32 | 0; + this.high = 0; + } else { + this.low = this.low >>> places | this.high << 32 - places; + this.high = this.high >>> places | 0; + } + } + + shiftLeft(places) { + if (places >= 32) { + this.high = this.low << places - 32; + this.low = 0; + } else { + this.high = this.high << places | this.low >>> 32 - places; + this.low <<= places; + } + } + + rotateRight(places) { + let low, high; + + if (places & 32) { + high = this.low; + low = this.high; + } else { + low = this.low; + high = this.high; + } + + places &= 31; + this.low = low >>> places | high << 32 - places; + this.high = high >>> places | low << 32 - places; + } + + not() { + this.high = ~this.high; + this.low = ~this.low; + } + + add(word) { + const lowAdd = (this.low >>> 0) + (word.low >>> 0); + let highAdd = (this.high >>> 0) + (word.high >>> 0); + + if (lowAdd > 0xffffffff) { + highAdd += 1; + } + + this.low = lowAdd | 0; + this.high = highAdd | 0; + } + + copyTo(bytes, offset) { + bytes[offset] = this.high >>> 24 & 0xff; + bytes[offset + 1] = this.high >> 16 & 0xff; + bytes[offset + 2] = this.high >> 8 & 0xff; + bytes[offset + 3] = this.high & 0xff; + bytes[offset + 4] = this.low >>> 24 & 0xff; + bytes[offset + 5] = this.low >> 16 & 0xff; + bytes[offset + 6] = this.low >> 8 & 0xff; + bytes[offset + 7] = this.low & 0xff; + } + + assign(word) { + this.high = word.high; + this.low = word.low; + } + +} + +const calculateSHA256 = function calculateSHA256Closure() { + function rotr(x, n) { + return x >>> n | x << 32 - n; + } + + function ch(x, y, z) { + return x & y ^ ~x & z; + } + + function maj(x, y, z) { + return x & y ^ x & z ^ y & z; + } + + function sigma(x) { + return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); + } + + function sigmaPrime(x) { + return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); + } + + function littleSigma(x) { + return rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3; + } + + function littleSigmaPrime(x) { + return rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10; + } + + const k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]; + + function hash(data, offset, length) { + let h0 = 0x6a09e667, + h1 = 0xbb67ae85, + h2 = 0x3c6ef372, + h3 = 0xa54ff53a, + h4 = 0x510e527f, + h5 = 0x9b05688c, + h6 = 0x1f83d9ab, + h7 = 0x5be0cd19; + const paddedLength = Math.ceil((length + 9) / 64) * 64; + const padded = new Uint8Array(paddedLength); + let i, j; + + for (i = 0; i < length; ++i) { + padded[i] = data[offset++]; + } + + padded[i++] = 0x80; + const n = paddedLength - 8; + + while (i < n) { + padded[i++] = 0; + } + + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = length >>> 29 & 0xff; + padded[i++] = length >> 21 & 0xff; + padded[i++] = length >> 13 & 0xff; + padded[i++] = length >> 5 & 0xff; + padded[i++] = length << 3 & 0xff; + const w = new Uint32Array(64); + + for (i = 0; i < paddedLength;) { + for (j = 0; j < 16; ++j) { + w[j] = padded[i] << 24 | padded[i + 1] << 16 | padded[i + 2] << 8 | padded[i + 3]; + i += 4; + } + + for (j = 16; j < 64; ++j) { + w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] + littleSigma(w[j - 15]) + w[j - 16] | 0; + } + + let a = h0, + b = h1, + c = h2, + d = h3, + e = h4, + f = h5, + g = h6, + h = h7, + t1, + t2; + + for (j = 0; j < 64; ++j) { + t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j]; + t2 = sigma(a) + maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1 | 0; + d = c; + c = b; + b = a; + a = t1 + t2 | 0; + } + + h0 = h0 + a | 0; + h1 = h1 + b | 0; + h2 = h2 + c | 0; + h3 = h3 + d | 0; + h4 = h4 + e | 0; + h5 = h5 + f | 0; + h6 = h6 + g | 0; + h7 = h7 + h | 0; + } + + return new Uint8Array([h0 >> 24 & 0xFF, h0 >> 16 & 0xFF, h0 >> 8 & 0xFF, h0 & 0xFF, h1 >> 24 & 0xFF, h1 >> 16 & 0xFF, h1 >> 8 & 0xFF, h1 & 0xFF, h2 >> 24 & 0xFF, h2 >> 16 & 0xFF, h2 >> 8 & 0xFF, h2 & 0xFF, h3 >> 24 & 0xFF, h3 >> 16 & 0xFF, h3 >> 8 & 0xFF, h3 & 0xFF, h4 >> 24 & 0xFF, h4 >> 16 & 0xFF, h4 >> 8 & 0xFF, h4 & 0xFF, h5 >> 24 & 0xFF, h5 >> 16 & 0xFF, h5 >> 8 & 0xFF, h5 & 0xFF, h6 >> 24 & 0xFF, h6 >> 16 & 0xFF, h6 >> 8 & 0xFF, h6 & 0xFF, h7 >> 24 & 0xFF, h7 >> 16 & 0xFF, h7 >> 8 & 0xFF, h7 & 0xFF]); + } + + return hash; +}(); + +exports.calculateSHA256 = calculateSHA256; + +const calculateSHA512 = function calculateSHA512Closure() { + function ch(result, x, y, z, tmp) { + result.assign(x); + result.and(y); + tmp.assign(x); + tmp.not(); + tmp.and(z); + result.xor(tmp); + } + + function maj(result, x, y, z, tmp) { + result.assign(x); + result.and(y); + tmp.assign(x); + tmp.and(z); + result.xor(tmp); + tmp.assign(y); + tmp.and(z); + result.xor(tmp); + } + + function sigma(result, x, tmp) { + result.assign(x); + result.rotateRight(28); + tmp.assign(x); + tmp.rotateRight(34); + result.xor(tmp); + tmp.assign(x); + tmp.rotateRight(39); + result.xor(tmp); + } + + function sigmaPrime(result, x, tmp) { + result.assign(x); + result.rotateRight(14); + tmp.assign(x); + tmp.rotateRight(18); + result.xor(tmp); + tmp.assign(x); + tmp.rotateRight(41); + result.xor(tmp); + } + + function littleSigma(result, x, tmp) { + result.assign(x); + result.rotateRight(1); + tmp.assign(x); + tmp.rotateRight(8); + result.xor(tmp); + tmp.assign(x); + tmp.shiftRight(7); + result.xor(tmp); + } + + function littleSigmaPrime(result, x, tmp) { + result.assign(x); + result.rotateRight(19); + tmp.assign(x); + tmp.rotateRight(61); + result.xor(tmp); + tmp.assign(x); + tmp.shiftRight(6); + result.xor(tmp); + } + + const k = [new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd), new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc), new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019), new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118), new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe), new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2), new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1), new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694), new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3), new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65), new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483), new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5), new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210), new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4), new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725), new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70), new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926), new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df), new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8), new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b), new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001), new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30), new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910), new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8), new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53), new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8), new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb), new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3), new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60), new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec), new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9), new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b), new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207), new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178), new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6), new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b), new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493), new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c), new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a), new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)]; + + function hash(data, offset, length, mode384 = false) { + let h0, h1, h2, h3, h4, h5, h6, h7; + + if (!mode384) { + h0 = new Word64(0x6a09e667, 0xf3bcc908); + h1 = new Word64(0xbb67ae85, 0x84caa73b); + h2 = new Word64(0x3c6ef372, 0xfe94f82b); + h3 = new Word64(0xa54ff53a, 0x5f1d36f1); + h4 = new Word64(0x510e527f, 0xade682d1); + h5 = new Word64(0x9b05688c, 0x2b3e6c1f); + h6 = new Word64(0x1f83d9ab, 0xfb41bd6b); + h7 = new Word64(0x5be0cd19, 0x137e2179); + } else { + h0 = new Word64(0xcbbb9d5d, 0xc1059ed8); + h1 = new Word64(0x629a292a, 0x367cd507); + h2 = new Word64(0x9159015a, 0x3070dd17); + h3 = new Word64(0x152fecd8, 0xf70e5939); + h4 = new Word64(0x67332667, 0xffc00b31); + h5 = new Word64(0x8eb44a87, 0x68581511); + h6 = new Word64(0xdb0c2e0d, 0x64f98fa7); + h7 = new Word64(0x47b5481d, 0xbefa4fa4); + } + + const paddedLength = Math.ceil((length + 17) / 128) * 128; + const padded = new Uint8Array(paddedLength); + let i, j; + + for (i = 0; i < length; ++i) { + padded[i] = data[offset++]; + } + + padded[i++] = 0x80; + const n = paddedLength - 16; + + while (i < n) { + padded[i++] = 0; + } + + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = length >>> 29 & 0xff; + padded[i++] = length >> 21 & 0xff; + padded[i++] = length >> 13 & 0xff; + padded[i++] = length >> 5 & 0xff; + padded[i++] = length << 3 & 0xff; + const w = new Array(80); + + for (i = 0; i < 80; i++) { + w[i] = new Word64(0, 0); + } + + let a = new Word64(0, 0), + b = new Word64(0, 0), + c = new Word64(0, 0); + let d = new Word64(0, 0), + e = new Word64(0, 0), + f = new Word64(0, 0); + let g = new Word64(0, 0), + h = new Word64(0, 0); + const t1 = new Word64(0, 0), + t2 = new Word64(0, 0); + const tmp1 = new Word64(0, 0), + tmp2 = new Word64(0, 0); + let tmp3; + + for (i = 0; i < paddedLength;) { + for (j = 0; j < 16; ++j) { + w[j].high = padded[i] << 24 | padded[i + 1] << 16 | padded[i + 2] << 8 | padded[i + 3]; + w[j].low = padded[i + 4] << 24 | padded[i + 5] << 16 | padded[i + 6] << 8 | padded[i + 7]; + i += 8; + } + + for (j = 16; j < 80; ++j) { + tmp3 = w[j]; + littleSigmaPrime(tmp3, w[j - 2], tmp2); + tmp3.add(w[j - 7]); + littleSigma(tmp1, w[j - 15], tmp2); + tmp3.add(tmp1); + tmp3.add(w[j - 16]); + } + + a.assign(h0); + b.assign(h1); + c.assign(h2); + d.assign(h3); + e.assign(h4); + f.assign(h5); + g.assign(h6); + h.assign(h7); + + for (j = 0; j < 80; ++j) { + t1.assign(h); + sigmaPrime(tmp1, e, tmp2); + t1.add(tmp1); + ch(tmp1, e, f, g, tmp2); + t1.add(tmp1); + t1.add(k[j]); + t1.add(w[j]); + sigma(t2, a, tmp2); + maj(tmp1, a, b, c, tmp2); + t2.add(tmp1); + tmp3 = h; + h = g; + g = f; + f = e; + d.add(t1); + e = d; + d = c; + c = b; + b = a; + tmp3.assign(t1); + tmp3.add(t2); + a = tmp3; + } + + h0.add(a); + h1.add(b); + h2.add(c); + h3.add(d); + h4.add(e); + h5.add(f); + h6.add(g); + h7.add(h); + } + + let result; + + if (!mode384) { + result = new Uint8Array(64); + h0.copyTo(result, 0); + h1.copyTo(result, 8); + h2.copyTo(result, 16); + h3.copyTo(result, 24); + h4.copyTo(result, 32); + h5.copyTo(result, 40); + h6.copyTo(result, 48); + h7.copyTo(result, 56); + } else { + result = new Uint8Array(48); + h0.copyTo(result, 0); + h1.copyTo(result, 8); + h2.copyTo(result, 16); + h3.copyTo(result, 24); + h4.copyTo(result, 32); + h5.copyTo(result, 40); + } + + return result; + } + + return hash; +}(); + +exports.calculateSHA512 = calculateSHA512; + +function calculateSHA384(data, offset, length) { + return calculateSHA512(data, offset, length, true); +} + +class NullCipher { + decryptBlock(data) { + return data; + } + + encrypt(data) { + return data; + } + +} + +class AESBaseCipher { + constructor() { + if (this.constructor === AESBaseCipher) { + (0, _util.unreachable)("Cannot initialize AESBaseCipher."); + } + + this._s = new Uint8Array([0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]); + this._inv_s = new Uint8Array([0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]); + this._mix = new Uint32Array([0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]); + this._mixCol = new Uint8Array(256); + + for (let i = 0; i < 256; i++) { + if (i < 128) { + this._mixCol[i] = i << 1; + } else { + this._mixCol[i] = i << 1 ^ 0x1b; + } + } + + this.buffer = new Uint8Array(16); + this.bufferPosition = 0; + } + + _expandKey(cipherKey) { + (0, _util.unreachable)("Cannot call `_expandKey` on the base class"); + } + + _decrypt(input, key) { + let t, u, v; + const state = new Uint8Array(16); + state.set(input); + + for (let j = 0, k = this._keySize; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + + for (let i = this._cyclesOfRepetition - 1; i >= 1; --i) { + t = state[13]; + state[13] = state[9]; + state[9] = state[5]; + state[5] = state[1]; + state[1] = t; + t = state[14]; + u = state[10]; + state[14] = state[6]; + state[10] = state[2]; + state[6] = t; + state[2] = u; + t = state[15]; + u = state[11]; + v = state[7]; + state[15] = state[3]; + state[11] = t; + state[7] = u; + state[3] = v; + + for (let j = 0; j < 16; ++j) { + state[j] = this._inv_s[state[j]]; + } + + for (let j = 0, k = i * 16; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + + for (let j = 0; j < 16; j += 4) { + const s0 = this._mix[state[j]]; + const s1 = this._mix[state[j + 1]]; + const s2 = this._mix[state[j + 2]]; + const s3 = this._mix[state[j + 3]]; + t = s0 ^ s1 >>> 8 ^ s1 << 24 ^ s2 >>> 16 ^ s2 << 16 ^ s3 >>> 24 ^ s3 << 8; + state[j] = t >>> 24 & 0xff; + state[j + 1] = t >> 16 & 0xff; + state[j + 2] = t >> 8 & 0xff; + state[j + 3] = t & 0xff; + } + } + + t = state[13]; + state[13] = state[9]; + state[9] = state[5]; + state[5] = state[1]; + state[1] = t; + t = state[14]; + u = state[10]; + state[14] = state[6]; + state[10] = state[2]; + state[6] = t; + state[2] = u; + t = state[15]; + u = state[11]; + v = state[7]; + state[15] = state[3]; + state[11] = t; + state[7] = u; + state[3] = v; + + for (let j = 0; j < 16; ++j) { + state[j] = this._inv_s[state[j]]; + state[j] ^= key[j]; + } + + return state; + } + + _encrypt(input, key) { + const s = this._s; + let t, u, v; + const state = new Uint8Array(16); + state.set(input); + + for (let j = 0; j < 16; ++j) { + state[j] ^= key[j]; + } + + for (let i = 1; i < this._cyclesOfRepetition; i++) { + for (let j = 0; j < 16; ++j) { + state[j] = s[state[j]]; + } + + v = state[1]; + state[1] = state[5]; + state[5] = state[9]; + state[9] = state[13]; + state[13] = v; + v = state[2]; + u = state[6]; + state[2] = state[10]; + state[6] = state[14]; + state[10] = v; + state[14] = u; + v = state[3]; + u = state[7]; + t = state[11]; + state[3] = state[15]; + state[7] = v; + state[11] = u; + state[15] = t; + + for (let j = 0; j < 16; j += 4) { + const s0 = state[j + 0]; + const s1 = state[j + 1]; + const s2 = state[j + 2]; + const s3 = state[j + 3]; + t = s0 ^ s1 ^ s2 ^ s3; + state[j + 0] ^= t ^ this._mixCol[s0 ^ s1]; + state[j + 1] ^= t ^ this._mixCol[s1 ^ s2]; + state[j + 2] ^= t ^ this._mixCol[s2 ^ s3]; + state[j + 3] ^= t ^ this._mixCol[s3 ^ s0]; + } + + for (let j = 0, k = i * 16; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + } + + for (let j = 0; j < 16; ++j) { + state[j] = s[state[j]]; + } + + v = state[1]; + state[1] = state[5]; + state[5] = state[9]; + state[9] = state[13]; + state[13] = v; + v = state[2]; + u = state[6]; + state[2] = state[10]; + state[6] = state[14]; + state[10] = v; + state[14] = u; + v = state[3]; + u = state[7]; + t = state[11]; + state[3] = state[15]; + state[7] = v; + state[11] = u; + state[15] = t; + + for (let j = 0, k = this._keySize; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + + return state; + } + + _decryptBlock2(data, finalize) { + const sourceLength = data.length; + let buffer = this.buffer, + bufferLength = this.bufferPosition; + const result = []; + let iv = this.iv; + + for (let i = 0; i < sourceLength; ++i) { + buffer[bufferLength] = data[i]; + ++bufferLength; + + if (bufferLength < 16) { + continue; + } + + const plain = this._decrypt(buffer, this._key); + + for (let j = 0; j < 16; ++j) { + plain[j] ^= iv[j]; + } + + iv = buffer; + result.push(plain); + buffer = new Uint8Array(16); + bufferLength = 0; + } + + this.buffer = buffer; + this.bufferLength = bufferLength; + this.iv = iv; + + if (result.length === 0) { + return new Uint8Array(0); + } + + let outputLength = 16 * result.length; + + if (finalize) { + const lastBlock = result.at(-1); + let psLen = lastBlock[15]; + + if (psLen <= 16) { + for (let i = 15, ii = 16 - psLen; i >= ii; --i) { + if (lastBlock[i] !== psLen) { + psLen = 0; + break; + } + } + + outputLength -= psLen; + result[result.length - 1] = lastBlock.subarray(0, 16 - psLen); + } + } + + const output = new Uint8Array(outputLength); + + for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { + output.set(result[i], j); + } + + return output; + } + + decryptBlock(data, finalize, iv = null) { + const sourceLength = data.length; + const buffer = this.buffer; + let bufferLength = this.bufferPosition; + + if (iv) { + this.iv = iv; + } else { + for (let i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) { + buffer[bufferLength] = data[i]; + } + + if (bufferLength < 16) { + this.bufferLength = bufferLength; + return new Uint8Array(0); + } + + this.iv = buffer; + data = data.subarray(16); + } + + this.buffer = new Uint8Array(16); + this.bufferLength = 0; + this.decryptBlock = this._decryptBlock2; + return this.decryptBlock(data, finalize); + } + + encrypt(data, iv) { + const sourceLength = data.length; + let buffer = this.buffer, + bufferLength = this.bufferPosition; + const result = []; + + if (!iv) { + iv = new Uint8Array(16); + } + + for (let i = 0; i < sourceLength; ++i) { + buffer[bufferLength] = data[i]; + ++bufferLength; + + if (bufferLength < 16) { + continue; + } + + for (let j = 0; j < 16; ++j) { + buffer[j] ^= iv[j]; + } + + const cipher = this._encrypt(buffer, this._key); + + iv = cipher; + result.push(cipher); + buffer = new Uint8Array(16); + bufferLength = 0; + } + + this.buffer = buffer; + this.bufferLength = bufferLength; + this.iv = iv; + + if (result.length === 0) { + return new Uint8Array(0); + } + + const outputLength = 16 * result.length; + const output = new Uint8Array(outputLength); + + for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { + output.set(result[i], j); + } + + return output; + } + +} + +class AES128Cipher extends AESBaseCipher { + constructor(key) { + super(); + this._cyclesOfRepetition = 10; + this._keySize = 160; + this._rcon = new Uint8Array([0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d]); + this._key = this._expandKey(key); + } + + _expandKey(cipherKey) { + const b = 176; + const s = this._s; + const rcon = this._rcon; + const result = new Uint8Array(b); + result.set(cipherKey); + + for (let j = 16, i = 1; j < b; ++i) { + let t1 = result[j - 3]; + let t2 = result[j - 2]; + let t3 = result[j - 1]; + let t4 = result[j - 4]; + t1 = s[t1]; + t2 = s[t2]; + t3 = s[t3]; + t4 = s[t4]; + t1 ^= rcon[i]; + + for (let n = 0; n < 4; ++n) { + result[j] = t1 ^= result[j - 16]; + j++; + result[j] = t2 ^= result[j - 16]; + j++; + result[j] = t3 ^= result[j - 16]; + j++; + result[j] = t4 ^= result[j - 16]; + j++; + } + } + + return result; + } + +} + +exports.AES128Cipher = AES128Cipher; + +class AES256Cipher extends AESBaseCipher { + constructor(key) { + super(); + this._cyclesOfRepetition = 14; + this._keySize = 224; + this._key = this._expandKey(key); + } + + _expandKey(cipherKey) { + const b = 240; + const s = this._s; + const result = new Uint8Array(b); + result.set(cipherKey); + let r = 1; + let t1, t2, t3, t4; + + for (let j = 32, i = 1; j < b; ++i) { + if (j % 32 === 16) { + t1 = s[t1]; + t2 = s[t2]; + t3 = s[t3]; + t4 = s[t4]; + } else if (j % 32 === 0) { + t1 = result[j - 3]; + t2 = result[j - 2]; + t3 = result[j - 1]; + t4 = result[j - 4]; + t1 = s[t1]; + t2 = s[t2]; + t3 = s[t3]; + t4 = s[t4]; + t1 ^= r; + + if ((r <<= 1) >= 256) { + r = (r ^ 0x1b) & 0xff; + } + } + + for (let n = 0; n < 4; ++n) { + result[j] = t1 ^= result[j - 32]; + j++; + result[j] = t2 ^= result[j - 32]; + j++; + result[j] = t3 ^= result[j - 32]; + j++; + result[j] = t4 ^= result[j - 32]; + j++; + } + } + + return result; + } + +} + +exports.AES256Cipher = AES256Cipher; + +class PDF17 { + checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerValidationSalt, password.length); + hashData.set(userBytes, password.length + ownerValidationSalt.length); + const result = calculateSHA256(hashData, 0, hashData.length); + return (0, _util.isArrayEqual)(result, ownerPassword); + } + + checkUserPassword(password, userValidationSalt, userPassword) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userValidationSalt, password.length); + const result = calculateSHA256(hashData, 0, hashData.length); + return (0, _util.isArrayEqual)(result, userPassword); + } + + getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerKeySalt, password.length); + hashData.set(userBytes, password.length + ownerKeySalt.length); + const key = calculateSHA256(hashData, 0, hashData.length); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); + } + + getUserKey(password, userKeySalt, userEncryption) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userKeySalt, password.length); + const key = calculateSHA256(hashData, 0, hashData.length); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); + } + +} + +exports.PDF17 = PDF17; + +const PDF20 = function PDF20Closure() { + function calculatePDF20Hash(password, input, userBytes) { + let k = calculateSHA256(input, 0, input.length).subarray(0, 32); + let e = [0]; + let i = 0; + + while (i < 64 || e.at(-1) > i - 32) { + const combinedLength = password.length + k.length + userBytes.length, + combinedArray = new Uint8Array(combinedLength); + let writeOffset = 0; + combinedArray.set(password, writeOffset); + writeOffset += password.length; + combinedArray.set(k, writeOffset); + writeOffset += k.length; + combinedArray.set(userBytes, writeOffset); + const k1 = new Uint8Array(combinedLength * 64); + + for (let j = 0, pos = 0; j < 64; j++, pos += combinedLength) { + k1.set(combinedArray, pos); + } + + const cipher = new AES128Cipher(k.subarray(0, 16)); + e = cipher.encrypt(k1, k.subarray(16, 32)); + let remainder = 0; + + for (let z = 0; z < 16; z++) { + remainder *= 256 % 3; + remainder %= 3; + remainder += (e[z] >>> 0) % 3; + remainder %= 3; + } + + if (remainder === 0) { + k = calculateSHA256(e, 0, e.length); + } else if (remainder === 1) { + k = calculateSHA384(e, 0, e.length); + } else if (remainder === 2) { + k = calculateSHA512(e, 0, e.length); + } + + i++; + } + + return k.subarray(0, 32); + } + + class PDF20 { + hash(password, concatBytes, userBytes) { + return calculatePDF20Hash(password, concatBytes, userBytes); + } + + checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerValidationSalt, password.length); + hashData.set(userBytes, password.length + ownerValidationSalt.length); + const result = calculatePDF20Hash(password, hashData, userBytes); + return (0, _util.isArrayEqual)(result, ownerPassword); + } + + checkUserPassword(password, userValidationSalt, userPassword) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userValidationSalt, password.length); + const result = calculatePDF20Hash(password, hashData, []); + return (0, _util.isArrayEqual)(result, userPassword); + } + + getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerKeySalt, password.length); + hashData.set(userBytes, password.length + ownerKeySalt.length); + const key = calculatePDF20Hash(password, hashData, userBytes); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); + } + + getUserKey(password, userKeySalt, userEncryption) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userKeySalt, password.length); + const key = calculatePDF20Hash(password, hashData, []); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); + } + + } + + return PDF20; +}(); + +exports.PDF20 = PDF20; + +class CipherTransform { + constructor(stringCipherConstructor, streamCipherConstructor) { + this.StringCipherConstructor = stringCipherConstructor; + this.StreamCipherConstructor = streamCipherConstructor; + } + + createStream(stream, length) { + const cipher = new this.StreamCipherConstructor(); + return new _decrypt_stream.DecryptStream(stream, length, function cipherTransformDecryptStream(data, finalize) { + return cipher.decryptBlock(data, finalize); + }); + } + + decryptString(s) { + const cipher = new this.StringCipherConstructor(); + let data = (0, _util.stringToBytes)(s); + data = cipher.decryptBlock(data, true); + return (0, _util.bytesToString)(data); + } + + encryptString(s) { + const cipher = new this.StringCipherConstructor(); + + if (cipher instanceof AESBaseCipher) { + const strLen = s.length; + const pad = 16 - strLen % 16; + s += String.fromCharCode(pad).repeat(pad); + const iv = new Uint8Array(16); + + if (typeof crypto !== "undefined") { + crypto.getRandomValues(iv); + } else { + for (let i = 0; i < 16; i++) { + iv[i] = Math.floor(256 * Math.random()); + } + } + + let data = (0, _util.stringToBytes)(s); + data = cipher.encrypt(data, iv); + const buf = new Uint8Array(16 + data.length); + buf.set(iv); + buf.set(data, 16); + return (0, _util.bytesToString)(buf); + } + + let data = (0, _util.stringToBytes)(s); + data = cipher.encrypt(data); + return (0, _util.bytesToString)(data); + } + +} + +const CipherTransformFactory = function CipherTransformFactoryClosure() { + const defaultPasswordBytes = new Uint8Array([0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a]); + + function createEncryptionKey20(revision, password, ownerPassword, ownerValidationSalt, ownerKeySalt, uBytes, userPassword, userValidationSalt, userKeySalt, ownerEncryption, userEncryption, perms) { + if (password) { + const passwordLength = Math.min(127, password.length); + password = password.subarray(0, passwordLength); + } else { + password = []; + } + + let pdfAlgorithm; + + if (revision === 6) { + pdfAlgorithm = new PDF20(); + } else { + pdfAlgorithm = new PDF17(); + } + + if (pdfAlgorithm.checkUserPassword(password, userValidationSalt, userPassword)) { + return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption); + } else if (password.length && pdfAlgorithm.checkOwnerPassword(password, ownerValidationSalt, uBytes, ownerPassword)) { + return pdfAlgorithm.getOwnerKey(password, ownerKeySalt, uBytes, ownerEncryption); + } + + return null; + } + + function prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata) { + const hashDataSize = 40 + ownerPassword.length + fileId.length; + const hashData = new Uint8Array(hashDataSize); + let i = 0, + j, + n; + + if (password) { + n = Math.min(32, password.length); + + for (; i < n; ++i) { + hashData[i] = password[i]; + } + } + + j = 0; + + while (i < 32) { + hashData[i++] = defaultPasswordBytes[j++]; + } + + for (j = 0, n = ownerPassword.length; j < n; ++j) { + hashData[i++] = ownerPassword[j]; + } + + hashData[i++] = flags & 0xff; + hashData[i++] = flags >> 8 & 0xff; + hashData[i++] = flags >> 16 & 0xff; + hashData[i++] = flags >>> 24 & 0xff; + + for (j = 0, n = fileId.length; j < n; ++j) { + hashData[i++] = fileId[j]; + } + + if (revision >= 4 && !encryptMetadata) { + hashData[i++] = 0xff; + hashData[i++] = 0xff; + hashData[i++] = 0xff; + hashData[i++] = 0xff; + } + + let hash = calculateMD5(hashData, 0, i); + const keyLengthInBytes = keyLength >> 3; + + if (revision >= 3) { + for (j = 0; j < 50; ++j) { + hash = calculateMD5(hash, 0, keyLengthInBytes); + } + } + + const encryptionKey = hash.subarray(0, keyLengthInBytes); + let cipher, checkData; + + if (revision >= 3) { + for (i = 0; i < 32; ++i) { + hashData[i] = defaultPasswordBytes[i]; + } + + for (j = 0, n = fileId.length; j < n; ++j) { + hashData[i++] = fileId[j]; + } + + cipher = new ARCFourCipher(encryptionKey); + checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i)); + n = encryptionKey.length; + const derivedKey = new Uint8Array(n); + + for (j = 1; j <= 19; ++j) { + for (let k = 0; k < n; ++k) { + derivedKey[k] = encryptionKey[k] ^ j; + } + + cipher = new ARCFourCipher(derivedKey); + checkData = cipher.encryptBlock(checkData); + } + + for (j = 0, n = checkData.length; j < n; ++j) { + if (userPassword[j] !== checkData[j]) { + return null; + } + } + } else { + cipher = new ARCFourCipher(encryptionKey); + checkData = cipher.encryptBlock(defaultPasswordBytes); + + for (j = 0, n = checkData.length; j < n; ++j) { + if (userPassword[j] !== checkData[j]) { + return null; + } + } + } + + return encryptionKey; + } + + function decodeUserPassword(password, ownerPassword, revision, keyLength) { + const hashData = new Uint8Array(32); + let i = 0; + const n = Math.min(32, password.length); + + for (; i < n; ++i) { + hashData[i] = password[i]; + } + + let j = 0; + + while (i < 32) { + hashData[i++] = defaultPasswordBytes[j++]; + } + + let hash = calculateMD5(hashData, 0, i); + const keyLengthInBytes = keyLength >> 3; + + if (revision >= 3) { + for (j = 0; j < 50; ++j) { + hash = calculateMD5(hash, 0, hash.length); + } + } + + let cipher, userPassword; + + if (revision >= 3) { + userPassword = ownerPassword; + const derivedKey = new Uint8Array(keyLengthInBytes); + + for (j = 19; j >= 0; j--) { + for (let k = 0; k < keyLengthInBytes; ++k) { + derivedKey[k] = hash[k] ^ j; + } + + cipher = new ARCFourCipher(derivedKey); + userPassword = cipher.encryptBlock(userPassword); + } + } else { + cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes)); + userPassword = cipher.encryptBlock(ownerPassword); + } + + return userPassword; + } + + const identityName = _primitives.Name.get("Identity"); + + function buildObjectKey(num, gen, encryptionKey, isAes = false) { + const key = new Uint8Array(encryptionKey.length + 9); + const n = encryptionKey.length; + let i; + + for (i = 0; i < n; ++i) { + key[i] = encryptionKey[i]; + } + + key[i++] = num & 0xff; + key[i++] = num >> 8 & 0xff; + key[i++] = num >> 16 & 0xff; + key[i++] = gen & 0xff; + key[i++] = gen >> 8 & 0xff; + + if (isAes) { + key[i++] = 0x73; + key[i++] = 0x41; + key[i++] = 0x6c; + key[i++] = 0x54; + } + + const hash = calculateMD5(key, 0, i); + return hash.subarray(0, Math.min(encryptionKey.length + 5, 16)); + } + + function buildCipherConstructor(cf, name, num, gen, key) { + if (!(name instanceof _primitives.Name)) { + throw new _util.FormatError("Invalid crypt filter name."); + } + + const cryptFilter = cf.get(name.name); + let cfm; + + if (cryptFilter !== null && cryptFilter !== undefined) { + cfm = cryptFilter.get("CFM"); + } + + if (!cfm || cfm.name === "None") { + return function cipherTransformFactoryBuildCipherConstructorNone() { + return new NullCipher(); + }; + } + + if (cfm.name === "V2") { + return function cipherTransformFactoryBuildCipherConstructorV2() { + return new ARCFourCipher(buildObjectKey(num, gen, key, false)); + }; + } + + if (cfm.name === "AESV2") { + return function cipherTransformFactoryBuildCipherConstructorAESV2() { + return new AES128Cipher(buildObjectKey(num, gen, key, true)); + }; + } + + if (cfm.name === "AESV3") { + return function cipherTransformFactoryBuildCipherConstructorAESV3() { + return new AES256Cipher(key); + }; + } + + throw new _util.FormatError("Unknown crypto method"); + } + + class CipherTransformFactory { + constructor(dict, fileId, password) { + const filter = dict.get("Filter"); + + if (!(0, _primitives.isName)(filter, "Standard")) { + throw new _util.FormatError("unknown encryption method"); + } + + this.filterName = filter.name; + this.dict = dict; + const algorithm = dict.get("V"); + + if (!Number.isInteger(algorithm) || algorithm !== 1 && algorithm !== 2 && algorithm !== 4 && algorithm !== 5) { + throw new _util.FormatError("unsupported encryption algorithm"); + } + + this.algorithm = algorithm; + let keyLength = dict.get("Length"); + + if (!keyLength) { + if (algorithm <= 3) { + keyLength = 40; + } else { + const cfDict = dict.get("CF"); + const streamCryptoName = dict.get("StmF"); + + if (cfDict instanceof _primitives.Dict && streamCryptoName instanceof _primitives.Name) { + cfDict.suppressEncryption = true; + const handlerDict = cfDict.get(streamCryptoName.name); + keyLength = handlerDict && handlerDict.get("Length") || 128; + + if (keyLength < 40) { + keyLength <<= 3; + } + } + } + } + + if (!Number.isInteger(keyLength) || keyLength < 40 || keyLength % 8 !== 0) { + throw new _util.FormatError("invalid key length"); + } + + const ownerPassword = (0, _util.stringToBytes)(dict.get("O")).subarray(0, 32); + const userPassword = (0, _util.stringToBytes)(dict.get("U")).subarray(0, 32); + const flags = dict.get("P"); + const revision = dict.get("R"); + const encryptMetadata = (algorithm === 4 || algorithm === 5) && dict.get("EncryptMetadata") !== false; + this.encryptMetadata = encryptMetadata; + const fileIdBytes = (0, _util.stringToBytes)(fileId); + let passwordBytes; + + if (password) { + if (revision === 6) { + try { + password = (0, _util.utf8StringToString)(password); + } catch (ex) { + (0, _util.warn)("CipherTransformFactory: " + "Unable to convert UTF8 encoded password."); + } + } + + passwordBytes = (0, _util.stringToBytes)(password); + } + + let encryptionKey; + + if (algorithm !== 5) { + encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata); + } else { + const ownerValidationSalt = (0, _util.stringToBytes)(dict.get("O")).subarray(32, 40); + const ownerKeySalt = (0, _util.stringToBytes)(dict.get("O")).subarray(40, 48); + const uBytes = (0, _util.stringToBytes)(dict.get("U")).subarray(0, 48); + const userValidationSalt = (0, _util.stringToBytes)(dict.get("U")).subarray(32, 40); + const userKeySalt = (0, _util.stringToBytes)(dict.get("U")).subarray(40, 48); + const ownerEncryption = (0, _util.stringToBytes)(dict.get("OE")); + const userEncryption = (0, _util.stringToBytes)(dict.get("UE")); + const perms = (0, _util.stringToBytes)(dict.get("Perms")); + encryptionKey = createEncryptionKey20(revision, passwordBytes, ownerPassword, ownerValidationSalt, ownerKeySalt, uBytes, userPassword, userValidationSalt, userKeySalt, ownerEncryption, userEncryption, perms); + } + + if (!encryptionKey && !password) { + throw new _util.PasswordException("No password given", _util.PasswordResponses.NEED_PASSWORD); + } else if (!encryptionKey && password) { + const decodedPassword = decodeUserPassword(passwordBytes, ownerPassword, revision, keyLength); + encryptionKey = prepareKeyData(fileIdBytes, decodedPassword, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata); + } + + if (!encryptionKey) { + throw new _util.PasswordException("Incorrect Password", _util.PasswordResponses.INCORRECT_PASSWORD); + } + + this.encryptionKey = encryptionKey; + + if (algorithm >= 4) { + const cf = dict.get("CF"); + + if (cf instanceof _primitives.Dict) { + cf.suppressEncryption = true; + } + + this.cf = cf; + this.stmf = dict.get("StmF") || identityName; + this.strf = dict.get("StrF") || identityName; + this.eff = dict.get("EFF") || this.stmf; + } + } + + createCipherTransform(num, gen) { + if (this.algorithm === 4 || this.algorithm === 5) { + return new CipherTransform(buildCipherConstructor(this.cf, this.strf, num, gen, this.encryptionKey), buildCipherConstructor(this.cf, this.stmf, num, gen, this.encryptionKey)); + } + + const key = buildObjectKey(num, gen, this.encryptionKey, false); + + const cipherConstructor = function buildCipherCipherConstructor() { + return new ARCFourCipher(key); + }; + + return new CipherTransform(cipherConstructor, cipherConstructor); + } + + } + + return CipherTransformFactory; +}(); + +exports.CipherTransformFactory = CipherTransformFactory; + +/***/ }), +/* 68 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.DecryptStream = void 0; + +var _decode_stream = __w_pdfjs_require__(19); + +const chunkSize = 512; + +class DecryptStream extends _decode_stream.DecodeStream { + constructor(str, maybeLength, decrypt) { + super(maybeLength); + this.str = str; + this.dict = str.dict; + this.decrypt = decrypt; + this.nextChunk = null; + this.initialized = false; + } + + readBlock() { + let chunk; + + if (this.initialized) { + chunk = this.nextChunk; + } else { + chunk = this.str.getBytes(chunkSize); + this.initialized = true; + } + + if (!chunk || chunk.length === 0) { + this.eof = true; + return; + } + + this.nextChunk = this.str.getBytes(chunkSize); + const hasMoreData = this.nextChunk && this.nextChunk.length > 0; + const decrypt = this.decrypt; + chunk = decrypt(chunk, !hasMoreData); + let bufferLength = this.bufferLength; + const n = chunk.length, + buffer = this.ensureBuffer(bufferLength + n); + + for (let i = 0; i < n; i++) { + buffer[bufferLength++] = chunk[i]; + } + + this.bufferLength = bufferLength; + } + +} + +exports.DecryptStream = DecryptStream; + +/***/ }), +/* 69 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Catalog = void 0; + +var _core_utils = __w_pdfjs_require__(6); + +var _util = __w_pdfjs_require__(2); + +var _primitives = __w_pdfjs_require__(5); + +var _name_number_tree = __w_pdfjs_require__(70); + +var _base_stream = __w_pdfjs_require__(7); + +var _cleanup_helper = __w_pdfjs_require__(71); + +var _colorspace = __w_pdfjs_require__(14); + +var _file_spec = __w_pdfjs_require__(72); + +var _image_utils = __w_pdfjs_require__(59); + +var _metadata_parser = __w_pdfjs_require__(73); + +var _struct_tree = __w_pdfjs_require__(74); + +function fetchDestination(dest) { + if (dest instanceof _primitives.Dict) { + dest = dest.get("D"); + } + + return Array.isArray(dest) ? dest : null; +} + +class Catalog { + constructor(pdfManager, xref) { + this.pdfManager = pdfManager; + this.xref = xref; + this._catDict = xref.getCatalogObj(); + + if (!(this._catDict instanceof _primitives.Dict)) { + throw new _util.FormatError("Catalog object is not a dictionary."); + } + + this.toplevelPagesDict; + this._actualNumPages = null; + this.fontCache = new _primitives.RefSetCache(); + this.builtInCMapCache = new Map(); + this.standardFontDataCache = new Map(); + this.globalImageCache = new _image_utils.GlobalImageCache(); + this.pageKidsCountCache = new _primitives.RefSetCache(); + this.pageIndexCache = new _primitives.RefSetCache(); + this.nonBlendModesSet = new _primitives.RefSet(); + } + + get version() { + const version = this._catDict.get("Version"); + + return (0, _util.shadow)(this, "version", version instanceof _primitives.Name ? version.name : null); + } + + get lang() { + const lang = this._catDict.get("Lang"); + + return (0, _util.shadow)(this, "lang", typeof lang === "string" ? (0, _util.stringToPDFString)(lang) : null); + } + + get needsRendering() { + const needsRendering = this._catDict.get("NeedsRendering"); + + return (0, _util.shadow)(this, "needsRendering", typeof needsRendering === "boolean" ? needsRendering : false); + } + + get collection() { + let collection = null; + + try { + const obj = this._catDict.get("Collection"); + + if (obj instanceof _primitives.Dict && obj.size > 0) { + collection = obj; + } + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.info)("Cannot fetch Collection entry; assuming no collection is present."); + } + + return (0, _util.shadow)(this, "collection", collection); + } + + get acroForm() { + let acroForm = null; + + try { + const obj = this._catDict.get("AcroForm"); + + if (obj instanceof _primitives.Dict && obj.size > 0) { + acroForm = obj; + } + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.info)("Cannot fetch AcroForm entry; assuming no forms are present."); + } + + return (0, _util.shadow)(this, "acroForm", acroForm); + } + + get acroFormRef() { + const value = this._catDict.getRaw("AcroForm"); + + return (0, _util.shadow)(this, "acroFormRef", value instanceof _primitives.Ref ? value : null); + } + + get metadata() { + const streamRef = this._catDict.getRaw("Metadata"); + + if (!(streamRef instanceof _primitives.Ref)) { + return (0, _util.shadow)(this, "metadata", null); + } + + let metadata = null; + + try { + const suppressEncryption = !(this.xref.encrypt && this.xref.encrypt.encryptMetadata); + const stream = this.xref.fetch(streamRef, suppressEncryption); + + if (stream instanceof _base_stream.BaseStream && stream.dict instanceof _primitives.Dict) { + const type = stream.dict.get("Type"); + const subtype = stream.dict.get("Subtype"); + + if ((0, _primitives.isName)(type, "Metadata") && (0, _primitives.isName)(subtype, "XML")) { + const data = (0, _util.stringToUTF8String)(stream.getString()); + + if (data) { + metadata = new _metadata_parser.MetadataParser(data).serializable; + } + } + } + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.info)(`Skipping invalid Metadata: "${ex}".`); + } + + return (0, _util.shadow)(this, "metadata", metadata); + } + + get markInfo() { + let markInfo = null; + + try { + markInfo = this._readMarkInfo(); + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)("Unable to read mark info."); + } + + return (0, _util.shadow)(this, "markInfo", markInfo); + } + + _readMarkInfo() { + const obj = this._catDict.get("MarkInfo"); + + if (!(obj instanceof _primitives.Dict)) { + return null; + } + + const markInfo = { + Marked: false, + UserProperties: false, + Suspects: false + }; + + for (const key in markInfo) { + const value = obj.get(key); + + if (typeof value === "boolean") { + markInfo[key] = value; + } + } + + return markInfo; + } + + get structTreeRoot() { + let structTree = null; + + try { + structTree = this._readStructTreeRoot(); + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)("Unable read to structTreeRoot info."); + } + + return (0, _util.shadow)(this, "structTreeRoot", structTree); + } + + _readStructTreeRoot() { + const obj = this._catDict.get("StructTreeRoot"); + + if (!(obj instanceof _primitives.Dict)) { + return null; + } + + const root = new _struct_tree.StructTreeRoot(obj); + root.init(); + return root; + } + + get toplevelPagesDict() { + const pagesObj = this._catDict.get("Pages"); + + if (!(pagesObj instanceof _primitives.Dict)) { + throw new _util.FormatError("Invalid top-level pages dictionary."); + } + + return (0, _util.shadow)(this, "toplevelPagesDict", pagesObj); + } + + get documentOutline() { + let obj = null; + + try { + obj = this._readDocumentOutline(); + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)("Unable to read document outline."); + } + + return (0, _util.shadow)(this, "documentOutline", obj); + } + + _readDocumentOutline() { + let obj = this._catDict.get("Outlines"); + + if (!(obj instanceof _primitives.Dict)) { + return null; + } + + obj = obj.getRaw("First"); + + if (!(obj instanceof _primitives.Ref)) { + return null; + } + + const root = { + items: [] + }; + const queue = [{ + obj, + parent: root + }]; + const processed = new _primitives.RefSet(); + processed.put(obj); + const xref = this.xref, + blackColor = new Uint8ClampedArray(3); + + while (queue.length > 0) { + const i = queue.shift(); + const outlineDict = xref.fetchIfRef(i.obj); + + if (outlineDict === null) { + continue; + } + + if (!outlineDict.has("Title")) { + throw new _util.FormatError("Invalid outline item encountered."); + } + + const data = { + url: null, + dest: null + }; + Catalog.parseDestDictionary({ + destDict: outlineDict, + resultObj: data, + docBaseUrl: this.pdfManager.docBaseUrl + }); + const title = outlineDict.get("Title"); + const flags = outlineDict.get("F") || 0; + const color = outlineDict.getArray("C"); + const count = outlineDict.get("Count"); + let rgbColor = blackColor; + + if (Array.isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) { + rgbColor = _colorspace.ColorSpace.singletons.rgb.getRgb(color, 0); + } + + const outlineItem = { + dest: data.dest, + url: data.url, + unsafeUrl: data.unsafeUrl, + newWindow: data.newWindow, + title: (0, _util.stringToPDFString)(title), + color: rgbColor, + count: Number.isInteger(count) ? count : undefined, + bold: !!(flags & 2), + italic: !!(flags & 1), + items: [] + }; + i.parent.items.push(outlineItem); + obj = outlineDict.getRaw("First"); + + if (obj instanceof _primitives.Ref && !processed.has(obj)) { + queue.push({ + obj, + parent: outlineItem + }); + processed.put(obj); + } + + obj = outlineDict.getRaw("Next"); + + if (obj instanceof _primitives.Ref && !processed.has(obj)) { + queue.push({ + obj, + parent: i.parent + }); + processed.put(obj); + } + } + + return root.items.length > 0 ? root.items : null; + } + + get permissions() { + let permissions = null; + + try { + permissions = this._readPermissions(); + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)("Unable to read permissions."); + } + + return (0, _util.shadow)(this, "permissions", permissions); + } + + _readPermissions() { + const encrypt = this.xref.trailer.get("Encrypt"); + + if (!(encrypt instanceof _primitives.Dict)) { + return null; + } + + let flags = encrypt.get("P"); + + if (typeof flags !== "number") { + return null; + } + + flags += 2 ** 32; + const permissions = []; + + for (const key in _util.PermissionFlag) { + const value = _util.PermissionFlag[key]; + + if (flags & value) { + permissions.push(value); + } + } + + return permissions; + } + + get optionalContentConfig() { + let config = null; + + try { + const properties = this._catDict.get("OCProperties"); + + if (!properties) { + return (0, _util.shadow)(this, "optionalContentConfig", null); + } + + const defaultConfig = properties.get("D"); + + if (!defaultConfig) { + return (0, _util.shadow)(this, "optionalContentConfig", null); + } + + const groupsData = properties.get("OCGs"); + + if (!Array.isArray(groupsData)) { + return (0, _util.shadow)(this, "optionalContentConfig", null); + } + + const groups = []; + const groupRefs = []; + + for (const groupRef of groupsData) { + if (!(groupRef instanceof _primitives.Ref)) { + continue; + } + + groupRefs.push(groupRef); + const group = this.xref.fetchIfRef(groupRef); + groups.push({ + id: groupRef.toString(), + name: typeof group.get("Name") === "string" ? (0, _util.stringToPDFString)(group.get("Name")) : null, + intent: typeof group.get("Intent") === "string" ? (0, _util.stringToPDFString)(group.get("Intent")) : null + }); + } + + config = this._readOptionalContentConfig(defaultConfig, groupRefs); + config.groups = groups; + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)(`Unable to read optional content config: ${ex}`); + } + + return (0, _util.shadow)(this, "optionalContentConfig", config); + } + + _readOptionalContentConfig(config, contentGroupRefs) { + function parseOnOff(refs) { + const onParsed = []; + + if (Array.isArray(refs)) { + for (const value of refs) { + if (!(value instanceof _primitives.Ref)) { + continue; + } + + if (contentGroupRefs.includes(value)) { + onParsed.push(value.toString()); + } + } + } + + return onParsed; + } + + function parseOrder(refs, nestedLevels = 0) { + if (!Array.isArray(refs)) { + return null; + } + + const order = []; + + for (const value of refs) { + if (value instanceof _primitives.Ref && contentGroupRefs.includes(value)) { + parsedOrderRefs.put(value); + order.push(value.toString()); + continue; + } + + const nestedOrder = parseNestedOrder(value, nestedLevels); + + if (nestedOrder) { + order.push(nestedOrder); + } + } + + if (nestedLevels > 0) { + return order; + } + + const hiddenGroups = []; + + for (const groupRef of contentGroupRefs) { + if (parsedOrderRefs.has(groupRef)) { + continue; + } + + hiddenGroups.push(groupRef.toString()); + } + + if (hiddenGroups.length) { + order.push({ + name: null, + order: hiddenGroups + }); + } + + return order; + } + + function parseNestedOrder(ref, nestedLevels) { + if (++nestedLevels > MAX_NESTED_LEVELS) { + (0, _util.warn)("parseNestedOrder - reached MAX_NESTED_LEVELS."); + return null; + } + + const value = xref.fetchIfRef(ref); + + if (!Array.isArray(value)) { + return null; + } + + const nestedName = xref.fetchIfRef(value[0]); + + if (typeof nestedName !== "string") { + return null; + } + + const nestedOrder = parseOrder(value.slice(1), nestedLevels); + + if (!nestedOrder || !nestedOrder.length) { + return null; + } + + return { + name: (0, _util.stringToPDFString)(nestedName), + order: nestedOrder + }; + } + + const xref = this.xref, + parsedOrderRefs = new _primitives.RefSet(), + MAX_NESTED_LEVELS = 10; + return { + name: typeof config.get("Name") === "string" ? (0, _util.stringToPDFString)(config.get("Name")) : null, + creator: typeof config.get("Creator") === "string" ? (0, _util.stringToPDFString)(config.get("Creator")) : null, + baseState: config.get("BaseState") instanceof _primitives.Name ? config.get("BaseState").name : null, + on: parseOnOff(config.get("ON")), + off: parseOnOff(config.get("OFF")), + order: parseOrder(config.get("Order")), + groups: null + }; + } + + setActualNumPages(num = null) { + this._actualNumPages = num; + } + + get hasActualNumPages() { + return this._actualNumPages !== null; + } + + get _pagesCount() { + const obj = this.toplevelPagesDict.get("Count"); + + if (!Number.isInteger(obj)) { + throw new _util.FormatError("Page count in top-level pages dictionary is not an integer."); + } + + return (0, _util.shadow)(this, "_pagesCount", obj); + } + + get numPages() { + return this.hasActualNumPages ? this._actualNumPages : this._pagesCount; + } + + get destinations() { + const obj = this._readDests(), + dests = Object.create(null); + + if (obj instanceof _name_number_tree.NameTree) { + for (const [key, value] of obj.getAll()) { + const dest = fetchDestination(value); + + if (dest) { + dests[(0, _util.stringToPDFString)(key)] = dest; + } + } + } else if (obj instanceof _primitives.Dict) { + obj.forEach(function (key, value) { + const dest = fetchDestination(value); + + if (dest) { + dests[key] = dest; + } + }); + } + + return (0, _util.shadow)(this, "destinations", dests); + } + + getDestination(id) { + const obj = this._readDests(); + + if (obj instanceof _name_number_tree.NameTree) { + const dest = fetchDestination(obj.get(id)); + + if (dest) { + return dest; + } + + const allDest = this.destinations[id]; + + if (allDest) { + (0, _util.warn)(`Found "${id}" at an incorrect position in the NameTree.`); + return allDest; + } + } else if (obj instanceof _primitives.Dict) { + const dest = fetchDestination(obj.get(id)); + + if (dest) { + return dest; + } + } + + return null; + } + + _readDests() { + const obj = this._catDict.get("Names"); + + if (obj && obj.has("Dests")) { + return new _name_number_tree.NameTree(obj.getRaw("Dests"), this.xref); + } else if (this._catDict.has("Dests")) { + return this._catDict.get("Dests"); + } + + return undefined; + } + + get pageLabels() { + let obj = null; + + try { + obj = this._readPageLabels(); + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)("Unable to read page labels."); + } + + return (0, _util.shadow)(this, "pageLabels", obj); + } + + _readPageLabels() { + const obj = this._catDict.getRaw("PageLabels"); + + if (!obj) { + return null; + } + + const pageLabels = new Array(this.numPages); + let style = null, + prefix = ""; + const numberTree = new _name_number_tree.NumberTree(obj, this.xref); + const nums = numberTree.getAll(); + let currentLabel = "", + currentIndex = 1; + + for (let i = 0, ii = this.numPages; i < ii; i++) { + const labelDict = nums.get(i); + + if (labelDict !== undefined) { + if (!(labelDict instanceof _primitives.Dict)) { + throw new _util.FormatError("PageLabel is not a dictionary."); + } + + if (labelDict.has("Type") && !(0, _primitives.isName)(labelDict.get("Type"), "PageLabel")) { + throw new _util.FormatError("Invalid type in PageLabel dictionary."); + } + + if (labelDict.has("S")) { + const s = labelDict.get("S"); + + if (!(s instanceof _primitives.Name)) { + throw new _util.FormatError("Invalid style in PageLabel dictionary."); + } + + style = s.name; + } else { + style = null; + } + + if (labelDict.has("P")) { + const p = labelDict.get("P"); + + if (typeof p !== "string") { + throw new _util.FormatError("Invalid prefix in PageLabel dictionary."); + } + + prefix = (0, _util.stringToPDFString)(p); + } else { + prefix = ""; + } + + if (labelDict.has("St")) { + const st = labelDict.get("St"); + + if (!(Number.isInteger(st) && st >= 1)) { + throw new _util.FormatError("Invalid start in PageLabel dictionary."); + } + + currentIndex = st; + } else { + currentIndex = 1; + } + } + + switch (style) { + case "D": + currentLabel = currentIndex; + break; + + case "R": + case "r": + currentLabel = (0, _core_utils.toRomanNumerals)(currentIndex, style === "r"); + break; + + case "A": + case "a": + const LIMIT = 26; + const A_UPPER_CASE = 0x41, + A_LOWER_CASE = 0x61; + const baseCharCode = style === "a" ? A_LOWER_CASE : A_UPPER_CASE; + const letterIndex = currentIndex - 1; + const character = String.fromCharCode(baseCharCode + letterIndex % LIMIT); + currentLabel = character.repeat(Math.floor(letterIndex / LIMIT) + 1); + break; + + default: + if (style) { + throw new _util.FormatError(`Invalid style "${style}" in PageLabel dictionary.`); + } + + currentLabel = ""; + } + + pageLabels[i] = prefix + currentLabel; + currentIndex++; + } + + return pageLabels; + } + + get pageLayout() { + const obj = this._catDict.get("PageLayout"); + + let pageLayout = ""; + + if (obj instanceof _primitives.Name) { + switch (obj.name) { + case "SinglePage": + case "OneColumn": + case "TwoColumnLeft": + case "TwoColumnRight": + case "TwoPageLeft": + case "TwoPageRight": + pageLayout = obj.name; + } + } + + return (0, _util.shadow)(this, "pageLayout", pageLayout); + } + + get pageMode() { + const obj = this._catDict.get("PageMode"); + + let pageMode = "UseNone"; + + if (obj instanceof _primitives.Name) { + switch (obj.name) { + case "UseNone": + case "UseOutlines": + case "UseThumbs": + case "FullScreen": + case "UseOC": + case "UseAttachments": + pageMode = obj.name; + } + } + + return (0, _util.shadow)(this, "pageMode", pageMode); + } + + get viewerPreferences() { + const obj = this._catDict.get("ViewerPreferences"); + + if (!(obj instanceof _primitives.Dict)) { + return (0, _util.shadow)(this, "viewerPreferences", null); + } + + let prefs = null; + + for (const key of obj.getKeys()) { + const value = obj.get(key); + let prefValue; + + switch (key) { + case "HideToolbar": + case "HideMenubar": + case "HideWindowUI": + case "FitWindow": + case "CenterWindow": + case "DisplayDocTitle": + case "PickTrayByPDFSize": + if (typeof value === "boolean") { + prefValue = value; + } + + break; + + case "NonFullScreenPageMode": + if (value instanceof _primitives.Name) { + switch (value.name) { + case "UseNone": + case "UseOutlines": + case "UseThumbs": + case "UseOC": + prefValue = value.name; + break; + + default: + prefValue = "UseNone"; + } + } + + break; + + case "Direction": + if (value instanceof _primitives.Name) { + switch (value.name) { + case "L2R": + case "R2L": + prefValue = value.name; + break; + + default: + prefValue = "L2R"; + } + } + + break; + + case "ViewArea": + case "ViewClip": + case "PrintArea": + case "PrintClip": + if (value instanceof _primitives.Name) { + switch (value.name) { + case "MediaBox": + case "CropBox": + case "BleedBox": + case "TrimBox": + case "ArtBox": + prefValue = value.name; + break; + + default: + prefValue = "CropBox"; + } + } + + break; + + case "PrintScaling": + if (value instanceof _primitives.Name) { + switch (value.name) { + case "None": + case "AppDefault": + prefValue = value.name; + break; + + default: + prefValue = "AppDefault"; + } + } + + break; + + case "Duplex": + if (value instanceof _primitives.Name) { + switch (value.name) { + case "Simplex": + case "DuplexFlipShortEdge": + case "DuplexFlipLongEdge": + prefValue = value.name; + break; + + default: + prefValue = "None"; + } + } + + break; + + case "PrintPageRange": + if (Array.isArray(value) && value.length % 2 === 0) { + const isValid = value.every((page, i, arr) => { + return Number.isInteger(page) && page > 0 && (i === 0 || page >= arr[i - 1]) && page <= this.numPages; + }); + + if (isValid) { + prefValue = value; + } + } + + break; + + case "NumCopies": + if (Number.isInteger(value) && value > 0) { + prefValue = value; + } + + break; + + default: + (0, _util.warn)(`Ignoring non-standard key in ViewerPreferences: ${key}.`); + continue; + } + + if (prefValue === undefined) { + (0, _util.warn)(`Bad value, for key "${key}", in ViewerPreferences: ${value}.`); + continue; + } + + if (!prefs) { + prefs = Object.create(null); + } + + prefs[key] = prefValue; + } + + return (0, _util.shadow)(this, "viewerPreferences", prefs); + } + + get openAction() { + const obj = this._catDict.get("OpenAction"); + + const openAction = Object.create(null); + + if (obj instanceof _primitives.Dict) { + const destDict = new _primitives.Dict(this.xref); + destDict.set("A", obj); + const resultObj = { + url: null, + dest: null, + action: null + }; + Catalog.parseDestDictionary({ + destDict, + resultObj + }); + + if (Array.isArray(resultObj.dest)) { + openAction.dest = resultObj.dest; + } else if (resultObj.action) { + openAction.action = resultObj.action; + } + } else if (Array.isArray(obj)) { + openAction.dest = obj; + } + + return (0, _util.shadow)(this, "openAction", (0, _util.objectSize)(openAction) > 0 ? openAction : null); + } + + get attachments() { + const obj = this._catDict.get("Names"); + + let attachments = null; + + if (obj instanceof _primitives.Dict && obj.has("EmbeddedFiles")) { + const nameTree = new _name_number_tree.NameTree(obj.getRaw("EmbeddedFiles"), this.xref); + + for (const [key, value] of nameTree.getAll()) { + const fs = new _file_spec.FileSpec(value, this.xref); + + if (!attachments) { + attachments = Object.create(null); + } + + attachments[(0, _util.stringToPDFString)(key)] = fs.serializable; + } + } + + return (0, _util.shadow)(this, "attachments", attachments); + } + + get xfaImages() { + const obj = this._catDict.get("Names"); + + let xfaImages = null; + + if (obj instanceof _primitives.Dict && obj.has("XFAImages")) { + const nameTree = new _name_number_tree.NameTree(obj.getRaw("XFAImages"), this.xref); + + for (const [key, value] of nameTree.getAll()) { + if (!xfaImages) { + xfaImages = new _primitives.Dict(this.xref); + } + + xfaImages.set((0, _util.stringToPDFString)(key), value); + } + } + + return (0, _util.shadow)(this, "xfaImages", xfaImages); + } + + _collectJavaScript() { + const obj = this._catDict.get("Names"); + + let javaScript = null; + + function appendIfJavaScriptDict(name, jsDict) { + if (!(jsDict instanceof _primitives.Dict)) { + return; + } + + if (!(0, _primitives.isName)(jsDict.get("S"), "JavaScript")) { + return; + } + + let js = jsDict.get("JS"); + + if (js instanceof _base_stream.BaseStream) { + js = js.getString(); + } else if (typeof js !== "string") { + return; + } + + if (javaScript === null) { + javaScript = new Map(); + } + + js = (0, _util.stringToPDFString)(js).replace(/\u0000/g, ""); + javaScript.set(name, js); + } + + if (obj instanceof _primitives.Dict && obj.has("JavaScript")) { + const nameTree = new _name_number_tree.NameTree(obj.getRaw("JavaScript"), this.xref); + + for (const [key, value] of nameTree.getAll()) { + appendIfJavaScriptDict((0, _util.stringToPDFString)(key), value); + } + } + + const openAction = this._catDict.get("OpenAction"); + + if (openAction) { + appendIfJavaScriptDict("OpenAction", openAction); + } + + return javaScript; + } + + get javaScript() { + const javaScript = this._collectJavaScript(); + + return (0, _util.shadow)(this, "javaScript", javaScript ? [...javaScript.values()] : null); + } + + get jsActions() { + const javaScript = this._collectJavaScript(); + + let actions = (0, _core_utils.collectActions)(this.xref, this._catDict, _util.DocumentActionEventType); + + if (javaScript) { + if (!actions) { + actions = Object.create(null); + } + + for (const [key, val] of javaScript) { + if (key in actions) { + actions[key].push(val); + } else { + actions[key] = [val]; + } + } + } + + return (0, _util.shadow)(this, "jsActions", actions); + } + + async fontFallback(id, handler) { + const translatedFonts = await Promise.all(this.fontCache); + + for (const translatedFont of translatedFonts) { + if (translatedFont.loadedName === id) { + translatedFont.fallback(handler); + return; + } + } + } + + async cleanup(manuallyTriggered = false) { + (0, _cleanup_helper.clearGlobalCaches)(); + this.globalImageCache.clear(manuallyTriggered); + this.pageKidsCountCache.clear(); + this.pageIndexCache.clear(); + this.nonBlendModesSet.clear(); + const translatedFonts = await Promise.all(this.fontCache); + + for (const { + dict + } of translatedFonts) { + delete dict.cacheKey; + } + + this.fontCache.clear(); + this.builtInCMapCache.clear(); + this.standardFontDataCache.clear(); + } + + async getPageDict(pageIndex) { + const nodesToVisit = [this.toplevelPagesDict]; + const visitedNodes = new _primitives.RefSet(); + + const pagesRef = this._catDict.getRaw("Pages"); + + if (pagesRef instanceof _primitives.Ref) { + visitedNodes.put(pagesRef); + } + + const xref = this.xref, + pageKidsCountCache = this.pageKidsCountCache, + pageIndexCache = this.pageIndexCache; + let currentPageIndex = 0; + + while (nodesToVisit.length) { + const currentNode = nodesToVisit.pop(); + + if (currentNode instanceof _primitives.Ref) { + const count = pageKidsCountCache.get(currentNode); + + if (count >= 0 && currentPageIndex + count <= pageIndex) { + currentPageIndex += count; + continue; + } + + if (visitedNodes.has(currentNode)) { + throw new _util.FormatError("Pages tree contains circular reference."); + } + + visitedNodes.put(currentNode); + const obj = await xref.fetchAsync(currentNode); + + if (obj instanceof _primitives.Dict) { + let type = obj.getRaw("Type"); + + if (type instanceof _primitives.Ref) { + type = await xref.fetchAsync(type); + } + + if ((0, _primitives.isName)(type, "Page") || !obj.has("Kids")) { + if (!pageKidsCountCache.has(currentNode)) { + pageKidsCountCache.put(currentNode, 1); + } + + if (!pageIndexCache.has(currentNode)) { + pageIndexCache.put(currentNode, currentPageIndex); + } + + if (currentPageIndex === pageIndex) { + return [obj, currentNode]; + } + + currentPageIndex++; + continue; + } + } + + nodesToVisit.push(obj); + continue; + } + + if (!(currentNode instanceof _primitives.Dict)) { + throw new _util.FormatError("Page dictionary kid reference points to wrong type of object."); + } + + const { + objId + } = currentNode; + let count = currentNode.getRaw("Count"); + + if (count instanceof _primitives.Ref) { + count = await xref.fetchAsync(count); + } + + if (Number.isInteger(count) && count >= 0) { + if (objId && !pageKidsCountCache.has(objId)) { + pageKidsCountCache.put(objId, count); + } + + if (currentPageIndex + count <= pageIndex) { + currentPageIndex += count; + continue; + } + } + + let kids = currentNode.getRaw("Kids"); + + if (kids instanceof _primitives.Ref) { + kids = await xref.fetchAsync(kids); + } + + if (!Array.isArray(kids)) { + let type = currentNode.getRaw("Type"); + + if (type instanceof _primitives.Ref) { + type = await xref.fetchAsync(type); + } + + if ((0, _primitives.isName)(type, "Page") || !currentNode.has("Kids")) { + if (currentPageIndex === pageIndex) { + return [currentNode, null]; + } + + currentPageIndex++; + continue; + } + + throw new _util.FormatError("Page dictionary kids object is not an array."); + } + + for (let last = kids.length - 1; last >= 0; last--) { + nodesToVisit.push(kids[last]); + } + } + + throw new Error(`Page index ${pageIndex} not found.`); + } + + async getAllPageDicts(recoveryMode = false) { + const queue = [{ + currentNode: this.toplevelPagesDict, + posInKids: 0 + }]; + const visitedNodes = new _primitives.RefSet(); + + const pagesRef = this._catDict.getRaw("Pages"); + + if (pagesRef instanceof _primitives.Ref) { + visitedNodes.put(pagesRef); + } + + const map = new Map(), + xref = this.xref, + pageIndexCache = this.pageIndexCache; + let pageIndex = 0; + + function addPageDict(pageDict, pageRef) { + if (pageRef && !pageIndexCache.has(pageRef)) { + pageIndexCache.put(pageRef, pageIndex); + } + + map.set(pageIndex++, [pageDict, pageRef]); + } + + function addPageError(error) { + if (error instanceof _core_utils.XRefEntryException && !recoveryMode) { + throw error; + } + + map.set(pageIndex++, [error, null]); + } + + while (queue.length > 0) { + const queueItem = queue.at(-1); + const { + currentNode, + posInKids + } = queueItem; + let kids = currentNode.getRaw("Kids"); + + if (kids instanceof _primitives.Ref) { + try { + kids = await xref.fetchAsync(kids); + } catch (ex) { + addPageError(ex); + break; + } + } + + if (!Array.isArray(kids)) { + addPageError(new _util.FormatError("Page dictionary kids object is not an array.")); + break; + } + + if (posInKids >= kids.length) { + queue.pop(); + continue; + } + + const kidObj = kids[posInKids]; + let obj; + + if (kidObj instanceof _primitives.Ref) { + if (visitedNodes.has(kidObj)) { + addPageError(new _util.FormatError("Pages tree contains circular reference.")); + break; + } + + visitedNodes.put(kidObj); + + try { + obj = await xref.fetchAsync(kidObj); + } catch (ex) { + addPageError(ex); + break; + } + } else { + obj = kidObj; + } + + if (!(obj instanceof _primitives.Dict)) { + addPageError(new _util.FormatError("Page dictionary kid reference points to wrong type of object.")); + break; + } + + let type = obj.getRaw("Type"); + + if (type instanceof _primitives.Ref) { + try { + type = await xref.fetchAsync(type); + } catch (ex) { + addPageError(ex); + break; + } + } + + if ((0, _primitives.isName)(type, "Page") || !obj.has("Kids")) { + addPageDict(obj, kidObj instanceof _primitives.Ref ? kidObj : null); + } else { + queue.push({ + currentNode: obj, + posInKids: 0 + }); + } + + queueItem.posInKids++; + } + + return map; + } + + getPageIndex(pageRef) { + const cachedPageIndex = this.pageIndexCache.get(pageRef); + + if (cachedPageIndex !== undefined) { + return Promise.resolve(cachedPageIndex); + } + + const xref = this.xref; + + function pagesBeforeRef(kidRef) { + let total = 0, + parentRef; + return xref.fetchAsync(kidRef).then(function (node) { + if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, "Page") && !(node instanceof _primitives.Dict && !node.has("Type") && node.has("Contents"))) { + throw new _util.FormatError("The reference does not point to a /Page dictionary."); + } + + if (!node) { + return null; + } + + if (!(node instanceof _primitives.Dict)) { + throw new _util.FormatError("Node must be a dictionary."); + } + + parentRef = node.getRaw("Parent"); + return node.getAsync("Parent"); + }).then(function (parent) { + if (!parent) { + return null; + } + + if (!(parent instanceof _primitives.Dict)) { + throw new _util.FormatError("Parent must be a dictionary."); + } + + return parent.getAsync("Kids"); + }).then(function (kids) { + if (!kids) { + return null; + } + + const kidPromises = []; + let found = false; + + for (let i = 0, ii = kids.length; i < ii; i++) { + const kid = kids[i]; + + if (!(kid instanceof _primitives.Ref)) { + throw new _util.FormatError("Kid must be a reference."); + } + + if ((0, _primitives.isRefsEqual)(kid, kidRef)) { + found = true; + break; + } + + kidPromises.push(xref.fetchAsync(kid).then(function (obj) { + if (!(obj instanceof _primitives.Dict)) { + throw new _util.FormatError("Kid node must be a dictionary."); + } + + if (obj.has("Count")) { + total += obj.get("Count"); + } else { + total++; + } + })); + } + + if (!found) { + throw new _util.FormatError("Kid reference not found in parent's kids."); + } + + return Promise.all(kidPromises).then(function () { + return [total, parentRef]; + }); + }); + } + + let total = 0; + + const next = ref => pagesBeforeRef(ref).then(args => { + if (!args) { + this.pageIndexCache.put(pageRef, total); + return total; + } + + const [count, parentRef] = args; + total += count; + return next(parentRef); + }); + + return next(pageRef); + } + + get baseUrl() { + const uri = this._catDict.get("URI"); + + if (uri instanceof _primitives.Dict) { + const base = uri.get("Base"); + + if (typeof base === "string") { + const absoluteUrl = (0, _util.createValidAbsoluteUrl)(base, null, { + tryConvertEncoding: true + }); + + if (absoluteUrl) { + return (0, _util.shadow)(this, "baseUrl", absoluteUrl.href); + } + } + } + + return (0, _util.shadow)(this, "baseUrl", null); + } + + static parseDestDictionary(params) { + const destDict = params.destDict; + + if (!(destDict instanceof _primitives.Dict)) { + (0, _util.warn)("parseDestDictionary: `destDict` must be a dictionary."); + return; + } + + const resultObj = params.resultObj; + + if (typeof resultObj !== "object") { + (0, _util.warn)("parseDestDictionary: `resultObj` must be an object."); + return; + } + + const docBaseUrl = params.docBaseUrl || null; + let action = destDict.get("A"), + url, + dest; + + if (!(action instanceof _primitives.Dict)) { + if (destDict.has("Dest")) { + action = destDict.get("Dest"); + } else { + action = destDict.get("AA"); + + if (action instanceof _primitives.Dict) { + if (action.has("D")) { + action = action.get("D"); + } else if (action.has("U")) { + action = action.get("U"); + } + } + } + } + + if (action instanceof _primitives.Dict) { + const actionType = action.get("S"); + + if (!(actionType instanceof _primitives.Name)) { + (0, _util.warn)("parseDestDictionary: Invalid type in Action dictionary."); + return; + } + + const actionName = actionType.name; + + switch (actionName) { + case "ResetForm": + const flags = action.get("Flags"); + const include = ((typeof flags === "number" ? flags : 0) & 1) === 0; + const fields = []; + const refs = []; + + for (const obj of action.get("Fields") || []) { + if (obj instanceof _primitives.Ref) { + refs.push(obj.toString()); + } else if (typeof obj === "string") { + fields.push((0, _util.stringToPDFString)(obj)); + } + } + + resultObj.resetForm = { + fields, + refs, + include + }; + break; + + case "URI": + url = action.get("URI"); + + if (url instanceof _primitives.Name) { + url = "/" + url.name; + } + + break; + + case "GoTo": + dest = action.get("D"); + break; + + case "Launch": + case "GoToR": + const urlDict = action.get("F"); + + if (urlDict instanceof _primitives.Dict) { + url = urlDict.get("F") || null; + } else if (typeof urlDict === "string") { + url = urlDict; + } + + let remoteDest = action.get("D"); + + if (remoteDest) { + if (remoteDest instanceof _primitives.Name) { + remoteDest = remoteDest.name; + } + + if (typeof url === "string") { + const baseUrl = url.split("#")[0]; + + if (typeof remoteDest === "string") { + url = baseUrl + "#" + remoteDest; + } else if (Array.isArray(remoteDest)) { + url = baseUrl + "#" + JSON.stringify(remoteDest); + } + } + } + + const newWindow = action.get("NewWindow"); + + if (typeof newWindow === "boolean") { + resultObj.newWindow = newWindow; + } + + break; + + case "Named": + const namedAction = action.get("N"); + + if (namedAction instanceof _primitives.Name) { + resultObj.action = namedAction.name; + } + + break; + + case "JavaScript": + const jsAction = action.get("JS"); + let js; + + if (jsAction instanceof _base_stream.BaseStream) { + js = jsAction.getString(); + } else if (typeof jsAction === "string") { + js = jsAction; + } + + const jsURL = js && (0, _core_utils.recoverJsURL)((0, _util.stringToPDFString)(js)); + + if (jsURL) { + url = jsURL.url; + resultObj.newWindow = jsURL.newWindow; + break; + } + + default: + if (actionName === "JavaScript" || actionName === "SubmitForm") { + break; + } + + (0, _util.warn)(`parseDestDictionary - unsupported action: "${actionName}".`); + break; + } + } else if (destDict.has("Dest")) { + dest = destDict.get("Dest"); + } + + if (typeof url === "string") { + const absoluteUrl = (0, _util.createValidAbsoluteUrl)(url, docBaseUrl, { + addDefaultProtocol: true, + tryConvertEncoding: true + }); + + if (absoluteUrl) { + resultObj.url = absoluteUrl.href; + } + + resultObj.unsafeUrl = url; + } + + if (dest) { + if (dest instanceof _primitives.Name) { + dest = dest.name; + } + + if (typeof dest === "string") { + resultObj.dest = (0, _util.stringToPDFString)(dest); + } else if (Array.isArray(dest)) { + resultObj.dest = dest; + } + } + } + +} + +exports.Catalog = Catalog; + +/***/ }), +/* 70 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.NumberTree = exports.NameTree = void 0; + +var _primitives = __w_pdfjs_require__(5); + +var _util = __w_pdfjs_require__(2); + +class NameOrNumberTree { + constructor(root, xref, type) { + if (this.constructor === NameOrNumberTree) { + (0, _util.unreachable)("Cannot initialize NameOrNumberTree."); + } + + this.root = root; + this.xref = xref; + this._type = type; + } + + getAll() { + const map = new Map(); + + if (!this.root) { + return map; + } + + const xref = this.xref; + const processed = new _primitives.RefSet(); + processed.put(this.root); + const queue = [this.root]; + + while (queue.length > 0) { + const obj = xref.fetchIfRef(queue.shift()); + + if (!(obj instanceof _primitives.Dict)) { + continue; + } + + if (obj.has("Kids")) { + const kids = obj.get("Kids"); + + if (!Array.isArray(kids)) { + continue; + } + + for (const kid of kids) { + if (processed.has(kid)) { + throw new _util.FormatError(`Duplicate entry in "${this._type}" tree.`); + } + + queue.push(kid); + processed.put(kid); + } + + continue; + } + + const entries = obj.get(this._type); + + if (!Array.isArray(entries)) { + continue; + } + + for (let i = 0, ii = entries.length; i < ii; i += 2) { + map.set(xref.fetchIfRef(entries[i]), xref.fetchIfRef(entries[i + 1])); + } + } + + return map; + } + + get(key) { + if (!this.root) { + return null; + } + + const xref = this.xref; + let kidsOrEntries = xref.fetchIfRef(this.root); + let loopCount = 0; + const MAX_LEVELS = 10; + + while (kidsOrEntries.has("Kids")) { + if (++loopCount > MAX_LEVELS) { + (0, _util.warn)(`Search depth limit reached for "${this._type}" tree.`); + return null; + } + + const kids = kidsOrEntries.get("Kids"); + + if (!Array.isArray(kids)) { + return null; + } + + let l = 0, + r = kids.length - 1; + + while (l <= r) { + const m = l + r >> 1; + const kid = xref.fetchIfRef(kids[m]); + const limits = kid.get("Limits"); + + if (key < xref.fetchIfRef(limits[0])) { + r = m - 1; + } else if (key > xref.fetchIfRef(limits[1])) { + l = m + 1; + } else { + kidsOrEntries = kid; + break; + } + } + + if (l > r) { + return null; + } + } + + const entries = kidsOrEntries.get(this._type); + + if (Array.isArray(entries)) { + let l = 0, + r = entries.length - 2; + + while (l <= r) { + const tmp = l + r >> 1, + m = tmp + (tmp & 1); + const currentKey = xref.fetchIfRef(entries[m]); + + if (key < currentKey) { + r = m - 2; + } else if (key > currentKey) { + l = m + 2; + } else { + return xref.fetchIfRef(entries[m + 1]); + } + } + } + + return null; + } + +} + +class NameTree extends NameOrNumberTree { + constructor(root, xref) { + super(root, xref, "Names"); + } + +} + +exports.NameTree = NameTree; + +class NumberTree extends NameOrNumberTree { + constructor(root, xref) { + super(root, xref, "Nums"); + } + +} + +exports.NumberTree = NumberTree; + +/***/ }), +/* 71 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.clearGlobalCaches = clearGlobalCaches; + +var _primitives = __w_pdfjs_require__(5); + +var _unicode = __w_pdfjs_require__(40); + +function clearGlobalCaches() { + (0, _primitives.clearPrimitiveCaches)(); + (0, _unicode.clearUnicodeCaches)(); +} + +/***/ }), +/* 72 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.FileSpec = void 0; + +var _util = __w_pdfjs_require__(2); + +var _base_stream = __w_pdfjs_require__(7); + +var _primitives = __w_pdfjs_require__(5); + +function pickPlatformItem(dict) { + if (dict.has("UF")) { + return dict.get("UF"); + } else if (dict.has("F")) { + return dict.get("F"); + } else if (dict.has("Unix")) { + return dict.get("Unix"); + } else if (dict.has("Mac")) { + return dict.get("Mac"); + } else if (dict.has("DOS")) { + return dict.get("DOS"); + } + + return null; +} + +class FileSpec { + constructor(root, xref) { + if (!(root instanceof _primitives.Dict)) { + return; + } + + this.xref = xref; + this.root = root; + + if (root.has("FS")) { + this.fs = root.get("FS"); + } + + this.description = root.has("Desc") ? (0, _util.stringToPDFString)(root.get("Desc")) : ""; + + if (root.has("RF")) { + (0, _util.warn)("Related file specifications are not supported"); + } + + this.contentAvailable = true; + + if (!root.has("EF")) { + this.contentAvailable = false; + (0, _util.warn)("Non-embedded file specifications are not supported"); + } + } + + get filename() { + if (!this._filename && this.root) { + const filename = pickPlatformItem(this.root) || "unnamed"; + this._filename = (0, _util.stringToPDFString)(filename).replace(/\\\\/g, "\\").replace(/\\\//g, "/").replace(/\\/g, "/"); + } + + return this._filename; + } + + get content() { + if (!this.contentAvailable) { + return null; + } + + if (!this.contentRef && this.root) { + this.contentRef = pickPlatformItem(this.root.get("EF")); + } + + let content = null; + + if (this.contentRef) { + const fileObj = this.xref.fetchIfRef(this.contentRef); + + if (fileObj instanceof _base_stream.BaseStream) { + content = fileObj.getBytes(); + } else { + (0, _util.warn)("Embedded file specification points to non-existing/invalid content"); + } + } else { + (0, _util.warn)("Embedded file specification does not have a content"); + } + + return content; + } + + get serializable() { + return { + filename: this.filename, + content: this.content + }; + } + +} + +exports.FileSpec = FileSpec; + +/***/ }), +/* 73 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.MetadataParser = void 0; + +var _xml_parser = __w_pdfjs_require__(66); + +class MetadataParser { + constructor(data) { + data = this._repair(data); + const parser = new _xml_parser.SimpleXMLParser({ + lowerCaseName: true + }); + const xmlDocument = parser.parseFromString(data); + this._metadataMap = new Map(); + this._data = data; + + if (xmlDocument) { + this._parse(xmlDocument); + } + } + + _repair(data) { + return data.replace(/^[^<]+/, "").replace(/>\\376\\377([^<]+)/g, function (all, codes) { + const bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g, function (code, d1, d2, d3) { + return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1); + }).replace(/&(amp|apos|gt|lt|quot);/g, function (str, name) { + switch (name) { + case "amp": + return "&"; + + case "apos": + return "'"; + + case "gt": + return ">"; + + case "lt": + return "<"; + + case "quot": + return '"'; + } + + throw new Error(`_repair: ${name} isn't defined.`); + }); + const charBuf = []; + + for (let i = 0, ii = bytes.length; i < ii; i += 2) { + const code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1); + + if (code >= 32 && code < 127 && code !== 60 && code !== 62 && code !== 38) { + charBuf.push(String.fromCharCode(code)); + } else { + charBuf.push("&#x" + (0x10000 + code).toString(16).substring(1) + ";"); + } + } + + return ">" + charBuf.join(""); + }); + } + + _getSequence(entry) { + const name = entry.nodeName; + + if (name !== "rdf:bag" && name !== "rdf:seq" && name !== "rdf:alt") { + return null; + } + + return entry.childNodes.filter(node => node.nodeName === "rdf:li"); + } + + _parseArray(entry) { + if (!entry.hasChildNodes()) { + return; + } + + const [seqNode] = entry.childNodes; + const sequence = this._getSequence(seqNode) || []; + + this._metadataMap.set(entry.nodeName, sequence.map(node => node.textContent.trim())); + } + + _parse(xmlDocument) { + let rdf = xmlDocument.documentElement; + + if (rdf.nodeName !== "rdf:rdf") { + rdf = rdf.firstChild; + + while (rdf && rdf.nodeName !== "rdf:rdf") { + rdf = rdf.nextSibling; + } + } + + if (!rdf || rdf.nodeName !== "rdf:rdf" || !rdf.hasChildNodes()) { + return; + } + + for (const desc of rdf.childNodes) { + if (desc.nodeName !== "rdf:description") { + continue; + } + + for (const entry of desc.childNodes) { + const name = entry.nodeName; + + switch (name) { + case "#text": + continue; + + case "dc:creator": + case "dc:subject": + this._parseArray(entry); + + continue; + } + + this._metadataMap.set(name, entry.textContent.trim()); + } + } + } + + get serializable() { + return { + parsedData: this._metadataMap, + rawData: this._data + }; + } + +} + +exports.MetadataParser = MetadataParser; + +/***/ }), +/* 74 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.StructTreeRoot = exports.StructTreePage = void 0; + +var _primitives = __w_pdfjs_require__(5); + +var _util = __w_pdfjs_require__(2); + +var _name_number_tree = __w_pdfjs_require__(70); + +const MAX_DEPTH = 40; +const StructElementType = { + PAGE_CONTENT: "PAGE_CONTENT", + STREAM_CONTENT: "STREAM_CONTENT", + OBJECT: "OBJECT", + ELEMENT: "ELEMENT" +}; + +class StructTreeRoot { + constructor(rootDict) { + this.dict = rootDict; + this.roleMap = new Map(); + } + + init() { + this.readRoleMap(); + } + + readRoleMap() { + const roleMapDict = this.dict.get("RoleMap"); + + if (!(roleMapDict instanceof _primitives.Dict)) { + return; + } + + roleMapDict.forEach((key, value) => { + if (!(value instanceof _primitives.Name)) { + return; + } + + this.roleMap.set(key, value.name); + }); + } + +} + +exports.StructTreeRoot = StructTreeRoot; + +class StructElementNode { + constructor(tree, dict) { + this.tree = tree; + this.dict = dict; + this.kids = []; + this.parseKids(); + } + + get role() { + const nameObj = this.dict.get("S"); + const name = nameObj instanceof _primitives.Name ? nameObj.name : ""; + const { + root + } = this.tree; + + if (root.roleMap.has(name)) { + return root.roleMap.get(name); + } + + return name; + } + + parseKids() { + let pageObjId = null; + const objRef = this.dict.getRaw("Pg"); + + if (objRef instanceof _primitives.Ref) { + pageObjId = objRef.toString(); + } + + const kids = this.dict.get("K"); + + if (Array.isArray(kids)) { + for (const kid of kids) { + const element = this.parseKid(pageObjId, kid); + + if (element) { + this.kids.push(element); + } + } + } else { + const element = this.parseKid(pageObjId, kids); + + if (element) { + this.kids.push(element); + } + } + } + + parseKid(pageObjId, kid) { + if (Number.isInteger(kid)) { + if (this.tree.pageDict.objId !== pageObjId) { + return null; + } + + return new StructElement({ + type: StructElementType.PAGE_CONTENT, + mcid: kid, + pageObjId + }); + } + + let kidDict = null; + + if (kid instanceof _primitives.Ref) { + kidDict = this.dict.xref.fetch(kid); + } else if (kid instanceof _primitives.Dict) { + kidDict = kid; + } + + if (!kidDict) { + return null; + } + + const pageRef = kidDict.getRaw("Pg"); + + if (pageRef instanceof _primitives.Ref) { + pageObjId = pageRef.toString(); + } + + const type = kidDict.get("Type") instanceof _primitives.Name ? kidDict.get("Type").name : null; + + if (type === "MCR") { + if (this.tree.pageDict.objId !== pageObjId) { + return null; + } + + return new StructElement({ + type: StructElementType.STREAM_CONTENT, + refObjId: kidDict.getRaw("Stm") instanceof _primitives.Ref ? kidDict.getRaw("Stm").toString() : null, + pageObjId, + mcid: kidDict.get("MCID") + }); + } + + if (type === "OBJR") { + if (this.tree.pageDict.objId !== pageObjId) { + return null; + } + + return new StructElement({ + type: StructElementType.OBJECT, + refObjId: kidDict.getRaw("Obj") instanceof _primitives.Ref ? kidDict.getRaw("Obj").toString() : null, + pageObjId + }); + } + + return new StructElement({ + type: StructElementType.ELEMENT, + dict: kidDict + }); + } + +} + +class StructElement { + constructor({ + type, + dict = null, + mcid = null, + pageObjId = null, + refObjId = null + }) { + this.type = type; + this.dict = dict; + this.mcid = mcid; + this.pageObjId = pageObjId; + this.refObjId = refObjId; + this.parentNode = null; + } + +} + +class StructTreePage { + constructor(structTreeRoot, pageDict) { + this.root = structTreeRoot; + this.rootDict = structTreeRoot ? structTreeRoot.dict : null; + this.pageDict = pageDict; + this.nodes = []; + } + + parse() { + if (!this.root || !this.rootDict) { + return; + } + + const parentTree = this.rootDict.get("ParentTree"); + + if (!parentTree) { + return; + } + + const id = this.pageDict.get("StructParents"); + + if (!Number.isInteger(id)) { + return; + } + + const numberTree = new _name_number_tree.NumberTree(parentTree, this.rootDict.xref); + const parentArray = numberTree.get(id); + + if (!Array.isArray(parentArray)) { + return; + } + + const map = new Map(); + + for (const ref of parentArray) { + if (ref instanceof _primitives.Ref) { + this.addNode(this.rootDict.xref.fetch(ref), map); + } + } + } + + addNode(dict, map, level = 0) { + if (level > MAX_DEPTH) { + (0, _util.warn)("StructTree MAX_DEPTH reached."); + return null; + } + + if (map.has(dict)) { + return map.get(dict); + } + + const element = new StructElementNode(this, dict); + map.set(dict, element); + const parent = dict.get("P"); + + if (!parent || (0, _primitives.isName)(parent.get("Type"), "StructTreeRoot")) { + if (!this.addTopLevelNode(dict, element)) { + map.delete(dict); + } + + return element; + } + + const parentNode = this.addNode(parent, map, level + 1); + + if (!parentNode) { + return element; + } + + let save = false; + + for (const kid of parentNode.kids) { + if (kid.type === StructElementType.ELEMENT && kid.dict === dict) { + kid.parentNode = element; + save = true; + } + } + + if (!save) { + map.delete(dict); + } + + return element; + } + + addTopLevelNode(dict, element) { + const obj = this.rootDict.get("K"); + + if (!obj) { + return false; + } + + if (obj instanceof _primitives.Dict) { + if (obj.objId !== dict.objId) { + return false; + } + + this.nodes[0] = element; + return true; + } + + if (!Array.isArray(obj)) { + return true; + } + + let save = false; + + for (let i = 0; i < obj.length; i++) { + const kidRef = obj[i]; + + if (kidRef && kidRef.toString() === dict.objId) { + this.nodes[i] = element; + save = true; + } + } + + return save; + } + + get serializable() { + function nodeToSerializable(node, parent, level = 0) { + if (level > MAX_DEPTH) { + (0, _util.warn)("StructTree too deep to be fully serialized."); + return; + } + + const obj = Object.create(null); + obj.role = node.role; + obj.children = []; + parent.children.push(obj); + const alt = node.dict.get("Alt"); + + if (typeof alt === "string") { + obj.alt = (0, _util.stringToPDFString)(alt); + } + + const lang = node.dict.get("Lang"); + + if (typeof lang === "string") { + obj.lang = (0, _util.stringToPDFString)(lang); + } + + for (const kid of node.kids) { + const kidElement = kid.type === StructElementType.ELEMENT ? kid.parentNode : null; + + if (kidElement) { + nodeToSerializable(kidElement, obj, level + 1); + continue; + } else if (kid.type === StructElementType.PAGE_CONTENT || kid.type === StructElementType.STREAM_CONTENT) { + obj.children.push({ + type: "content", + id: `page${kid.pageObjId}_mcid${kid.mcid}` + }); + } else if (kid.type === StructElementType.OBJECT) { + obj.children.push({ + type: "object", + id: kid.refObjId + }); + } + } + } + + const root = Object.create(null); + root.children = []; + root.role = "Root"; + + for (const child of this.nodes) { + if (!child) { + continue; + } + + nodeToSerializable(child, root); + } + + return root; + } + +} + +exports.StructTreePage = StructTreePage; + +/***/ }), +/* 75 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.ObjectLoader = void 0; + +var _primitives = __w_pdfjs_require__(5); + +var _base_stream = __w_pdfjs_require__(7); + +var _core_utils = __w_pdfjs_require__(6); + +var _util = __w_pdfjs_require__(2); + +function mayHaveChildren(value) { + return value instanceof _primitives.Ref || value instanceof _primitives.Dict || value instanceof _base_stream.BaseStream || Array.isArray(value); +} + +function addChildren(node, nodesToVisit) { + if (node instanceof _primitives.Dict) { + node = node.getRawValues(); + } else if (node instanceof _base_stream.BaseStream) { + node = node.dict.getRawValues(); + } else if (!Array.isArray(node)) { + return; + } + + for (const rawValue of node) { + if (mayHaveChildren(rawValue)) { + nodesToVisit.push(rawValue); + } + } +} + +class ObjectLoader { + constructor(dict, keys, xref) { + this.dict = dict; + this.keys = keys; + this.xref = xref; + this.refSet = null; + } + + async load() { + if (this.xref.stream.isDataLoaded) { + return undefined; + } + + const { + keys, + dict + } = this; + this.refSet = new _primitives.RefSet(); + const nodesToVisit = []; + + for (let i = 0, ii = keys.length; i < ii; i++) { + const rawValue = dict.getRaw(keys[i]); + + if (rawValue !== undefined) { + nodesToVisit.push(rawValue); + } + } + + return this._walk(nodesToVisit); + } + + async _walk(nodesToVisit) { + const nodesToRevisit = []; + const pendingRequests = []; + + while (nodesToVisit.length) { + let currentNode = nodesToVisit.pop(); + + if (currentNode instanceof _primitives.Ref) { + if (this.refSet.has(currentNode)) { + continue; + } + + try { + this.refSet.put(currentNode); + currentNode = this.xref.fetch(currentNode); + } catch (ex) { + if (!(ex instanceof _core_utils.MissingDataException)) { + (0, _util.warn)(`ObjectLoader._walk - requesting all data: "${ex}".`); + this.refSet = null; + const { + manager + } = this.xref.stream; + return manager.requestAllChunks(); + } + + nodesToRevisit.push(currentNode); + pendingRequests.push({ + begin: ex.begin, + end: ex.end + }); + } + } + + if (currentNode instanceof _base_stream.BaseStream) { + const baseStreams = currentNode.getBaseStreams(); + + if (baseStreams) { + let foundMissingData = false; + + for (const stream of baseStreams) { + if (stream.isDataLoaded) { + continue; + } + + foundMissingData = true; + pendingRequests.push({ + begin: stream.start, + end: stream.end + }); + } + + if (foundMissingData) { + nodesToRevisit.push(currentNode); + } + } + } + + addChildren(currentNode, nodesToVisit); + } + + if (pendingRequests.length) { + await this.xref.stream.manager.requestRanges(pendingRequests); + + for (const node of nodesToRevisit) { + if (node instanceof _primitives.Ref) { + this.refSet.remove(node); + } + } + + return this._walk(nodesToRevisit); + } + + this.refSet = null; + return undefined; + } + +} + +exports.ObjectLoader = ObjectLoader; + +/***/ }), +/* 76 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XFAFactory = void 0; + +var _xfa_object = __w_pdfjs_require__(77); + +var _bind = __w_pdfjs_require__(81); + +var _data = __w_pdfjs_require__(87); + +var _fonts = __w_pdfjs_require__(85); + +var _utils = __w_pdfjs_require__(78); + +var _util = __w_pdfjs_require__(2); + +var _parser = __w_pdfjs_require__(88); + +var _xhtml = __w_pdfjs_require__(98); + +class XFAFactory { + constructor(data) { + try { + this.root = new _parser.XFAParser().parse(XFAFactory._createDocument(data)); + const binder = new _bind.Binder(this.root); + this.form = binder.bind(); + this.dataHandler = new _data.DataHandler(this.root, binder.getData()); + this.form[_xfa_object.$globalData].template = this.form; + } catch (e) { + (0, _util.warn)(`XFA - an error occurred during parsing and binding: ${e}`); + } + } + + isValid() { + return this.root && this.form; + } + + _createPagesHelper() { + const iterator = this.form[_xfa_object.$toPages](); + + return new Promise((resolve, reject) => { + const nextIteration = () => { + try { + const value = iterator.next(); + + if (value.done) { + resolve(value.value); + } else { + setTimeout(nextIteration, 0); + } + } catch (e) { + reject(e); + } + }; + + setTimeout(nextIteration, 0); + }); + } + + async _createPages() { + try { + this.pages = await this._createPagesHelper(); + this.dims = this.pages.children.map(c => { + const { + width, + height + } = c.attributes.style; + return [0, 0, parseInt(width), parseInt(height)]; + }); + } catch (e) { + (0, _util.warn)(`XFA - an error occurred during layout: ${e}`); + } + } + + getBoundingBox(pageIndex) { + return this.dims[pageIndex]; + } + + async getNumPages() { + if (!this.pages) { + await this._createPages(); + } + + return this.dims.length; + } + + setImages(images) { + this.form[_xfa_object.$globalData].images = images; + } + + setFonts(fonts) { + this.form[_xfa_object.$globalData].fontFinder = new _fonts.FontFinder(fonts); + const missingFonts = []; + + for (let typeface of this.form[_xfa_object.$globalData].usedTypefaces) { + typeface = (0, _utils.stripQuotes)(typeface); + + const font = this.form[_xfa_object.$globalData].fontFinder.find(typeface); + + if (!font) { + missingFonts.push(typeface); + } + } + + if (missingFonts.length > 0) { + return missingFonts; + } + + return null; + } + + appendFonts(fonts, reallyMissingFonts) { + this.form[_xfa_object.$globalData].fontFinder.add(fonts, reallyMissingFonts); + } + + async getPages() { + if (!this.pages) { + await this._createPages(); + } + + const pages = this.pages; + this.pages = null; + return pages; + } + + serializeData(storage) { + return this.dataHandler.serialize(storage); + } + + static _createDocument(data) { + if (!data["/xdp:xdp"]) { + return data["xdp:xdp"]; + } + + return Object.values(data).join(""); + } + + static getRichTextAsHtml(rc) { + if (!rc || typeof rc !== "string") { + return null; + } + + try { + let root = new _parser.XFAParser(_xhtml.XhtmlNamespace, true).parse(rc); + + if (!["body", "xhtml"].includes(root[_xfa_object.$nodeName])) { + const newRoot = _xhtml.XhtmlNamespace.body({}); + + newRoot[_xfa_object.$appendChild](root); + + root = newRoot; + } + + const result = root[_xfa_object.$toHTML](); + + if (!result.success) { + return null; + } + + const { + html + } = result; + const { + attributes + } = html; + + if (attributes) { + if (attributes.class) { + attributes.class = attributes.class.filter(attr => !attr.startsWith("xfa")); + } + + attributes.dir = "auto"; + } + + return { + html, + str: root[_xfa_object.$text]() + }; + } catch (e) { + (0, _util.warn)(`XFA - an error occurred during parsing of rich text: ${e}`); + } + + return null; + } + +} + +exports.XFAFactory = XFAFactory; + +/***/ }), +/* 77 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XmlObject = exports.XFAObjectArray = exports.XFAObject = exports.XFAAttribute = exports.StringObject = exports.OptionObject = exports.Option10 = exports.Option01 = exports.IntegerObject = exports.ContentObject = exports.$uid = exports.$toStyle = exports.$toString = exports.$toPages = exports.$toHTML = exports.$text = exports.$tabIndex = exports.$setValue = exports.$setSetAttributes = exports.$setId = exports.$searchNode = exports.$root = exports.$resolvePrototypes = exports.$removeChild = exports.$pushPara = exports.$pushGlyphs = exports.$popPara = exports.$onText = exports.$onChildCheck = exports.$onChild = exports.$nsAttributes = exports.$nodeName = exports.$namespaceId = exports.$isUsable = exports.$isTransparent = exports.$isThereMoreWidth = exports.$isSplittable = exports.$isNsAgnostic = exports.$isDescendent = exports.$isDataValue = exports.$isCDATAXml = exports.$isBindable = exports.$insertAt = exports.$indexOf = exports.$ids = exports.$hasSettableValue = exports.$globalData = exports.$getTemplateRoot = exports.$getSubformParent = exports.$getRealChildrenByNameIt = exports.$getParent = exports.$getNextPage = exports.$getExtra = exports.$getDataValue = exports.$getContainedChildren = exports.$getChildrenByNameIt = exports.$getChildrenByName = exports.$getChildrenByClass = exports.$getChildren = exports.$getAvailableSpace = exports.$getAttributes = exports.$getAttributeIt = exports.$flushHTML = exports.$finalize = exports.$extra = exports.$dump = exports.$data = exports.$content = exports.$consumed = exports.$clone = exports.$cleanup = exports.$cleanPage = exports.$clean = exports.$childrenToHTML = exports.$appendChild = exports.$addHTML = exports.$acceptWhitespace = void 0; + +var _utils = __w_pdfjs_require__(78); + +var _util = __w_pdfjs_require__(2); + +var _core_utils = __w_pdfjs_require__(6); + +var _namespaces = __w_pdfjs_require__(79); + +var _som = __w_pdfjs_require__(80); + +const $acceptWhitespace = Symbol(); +exports.$acceptWhitespace = $acceptWhitespace; +const $addHTML = Symbol(); +exports.$addHTML = $addHTML; +const $appendChild = Symbol(); +exports.$appendChild = $appendChild; +const $childrenToHTML = Symbol(); +exports.$childrenToHTML = $childrenToHTML; +const $clean = Symbol(); +exports.$clean = $clean; +const $cleanPage = Symbol(); +exports.$cleanPage = $cleanPage; +const $cleanup = Symbol(); +exports.$cleanup = $cleanup; +const $clone = Symbol(); +exports.$clone = $clone; +const $consumed = Symbol(); +exports.$consumed = $consumed; +const $content = Symbol("content"); +exports.$content = $content; +const $data = Symbol("data"); +exports.$data = $data; +const $dump = Symbol(); +exports.$dump = $dump; +const $extra = Symbol("extra"); +exports.$extra = $extra; +const $finalize = Symbol(); +exports.$finalize = $finalize; +const $flushHTML = Symbol(); +exports.$flushHTML = $flushHTML; +const $getAttributeIt = Symbol(); +exports.$getAttributeIt = $getAttributeIt; +const $getAttributes = Symbol(); +exports.$getAttributes = $getAttributes; +const $getAvailableSpace = Symbol(); +exports.$getAvailableSpace = $getAvailableSpace; +const $getChildrenByClass = Symbol(); +exports.$getChildrenByClass = $getChildrenByClass; +const $getChildrenByName = Symbol(); +exports.$getChildrenByName = $getChildrenByName; +const $getChildrenByNameIt = Symbol(); +exports.$getChildrenByNameIt = $getChildrenByNameIt; +const $getDataValue = Symbol(); +exports.$getDataValue = $getDataValue; +const $getExtra = Symbol(); +exports.$getExtra = $getExtra; +const $getRealChildrenByNameIt = Symbol(); +exports.$getRealChildrenByNameIt = $getRealChildrenByNameIt; +const $getChildren = Symbol(); +exports.$getChildren = $getChildren; +const $getContainedChildren = Symbol(); +exports.$getContainedChildren = $getContainedChildren; +const $getNextPage = Symbol(); +exports.$getNextPage = $getNextPage; +const $getSubformParent = Symbol(); +exports.$getSubformParent = $getSubformParent; +const $getParent = Symbol(); +exports.$getParent = $getParent; +const $getTemplateRoot = Symbol(); +exports.$getTemplateRoot = $getTemplateRoot; +const $globalData = Symbol(); +exports.$globalData = $globalData; +const $hasSettableValue = Symbol(); +exports.$hasSettableValue = $hasSettableValue; +const $ids = Symbol(); +exports.$ids = $ids; +const $indexOf = Symbol(); +exports.$indexOf = $indexOf; +const $insertAt = Symbol(); +exports.$insertAt = $insertAt; +const $isCDATAXml = Symbol(); +exports.$isCDATAXml = $isCDATAXml; +const $isBindable = Symbol(); +exports.$isBindable = $isBindable; +const $isDataValue = Symbol(); +exports.$isDataValue = $isDataValue; +const $isDescendent = Symbol(); +exports.$isDescendent = $isDescendent; +const $isNsAgnostic = Symbol(); +exports.$isNsAgnostic = $isNsAgnostic; +const $isSplittable = Symbol(); +exports.$isSplittable = $isSplittable; +const $isThereMoreWidth = Symbol(); +exports.$isThereMoreWidth = $isThereMoreWidth; +const $isTransparent = Symbol(); +exports.$isTransparent = $isTransparent; +const $isUsable = Symbol(); +exports.$isUsable = $isUsable; +const $lastAttribute = Symbol(); +const $namespaceId = Symbol("namespaceId"); +exports.$namespaceId = $namespaceId; +const $nodeName = Symbol("nodeName"); +exports.$nodeName = $nodeName; +const $nsAttributes = Symbol(); +exports.$nsAttributes = $nsAttributes; +const $onChild = Symbol(); +exports.$onChild = $onChild; +const $onChildCheck = Symbol(); +exports.$onChildCheck = $onChildCheck; +const $onText = Symbol(); +exports.$onText = $onText; +const $pushGlyphs = Symbol(); +exports.$pushGlyphs = $pushGlyphs; +const $popPara = Symbol(); +exports.$popPara = $popPara; +const $pushPara = Symbol(); +exports.$pushPara = $pushPara; +const $removeChild = Symbol(); +exports.$removeChild = $removeChild; +const $root = Symbol("root"); +exports.$root = $root; +const $resolvePrototypes = Symbol(); +exports.$resolvePrototypes = $resolvePrototypes; +const $searchNode = Symbol(); +exports.$searchNode = $searchNode; +const $setId = Symbol(); +exports.$setId = $setId; +const $setSetAttributes = Symbol(); +exports.$setSetAttributes = $setSetAttributes; +const $setValue = Symbol(); +exports.$setValue = $setValue; +const $tabIndex = Symbol(); +exports.$tabIndex = $tabIndex; +const $text = Symbol(); +exports.$text = $text; +const $toPages = Symbol(); +exports.$toPages = $toPages; +const $toHTML = Symbol(); +exports.$toHTML = $toHTML; +const $toString = Symbol(); +exports.$toString = $toString; +const $toStyle = Symbol(); +exports.$toStyle = $toStyle; +const $uid = Symbol("uid"); +exports.$uid = $uid; + +const _applyPrototype = Symbol(); + +const _attributes = Symbol(); + +const _attributeNames = Symbol(); + +const _children = Symbol("_children"); + +const _cloneAttribute = Symbol(); + +const _dataValue = Symbol(); + +const _defaultValue = Symbol(); + +const _filteredChildrenGenerator = Symbol(); + +const _getPrototype = Symbol(); + +const _getUnsetAttributes = Symbol(); + +const _hasChildren = Symbol(); + +const _max = Symbol(); + +const _options = Symbol(); + +const _parent = Symbol("parent"); + +const _resolvePrototypesHelper = Symbol(); + +const _setAttributes = Symbol(); + +const _validator = Symbol(); + +let uid = 0; +const NS_DATASETS = _namespaces.NamespaceIds.datasets.id; + +class XFAObject { + constructor(nsId, name, hasChildren = false) { + this[$namespaceId] = nsId; + this[$nodeName] = name; + this[_hasChildren] = hasChildren; + this[_parent] = null; + this[_children] = []; + this[$uid] = `${name}${uid++}`; + this[$globalData] = null; + } + + [$onChild](child) { + if (!this[_hasChildren] || !this[$onChildCheck](child)) { + return false; + } + + const name = child[$nodeName]; + const node = this[name]; + + if (node instanceof XFAObjectArray) { + if (node.push(child)) { + this[$appendChild](child); + return true; + } + } else { + if (node !== null) { + this[$removeChild](node); + } + + this[name] = child; + this[$appendChild](child); + return true; + } + + let id = ""; + + if (this.id) { + id = ` (id: ${this.id})`; + } else if (this.name) { + id = ` (name: ${this.name} ${this.h.value})`; + } + + (0, _util.warn)(`XFA - node "${this[$nodeName]}"${id} has already enough "${name}"!`); + return false; + } + + [$onChildCheck](child) { + return this.hasOwnProperty(child[$nodeName]) && child[$namespaceId] === this[$namespaceId]; + } + + [$isNsAgnostic]() { + return false; + } + + [$acceptWhitespace]() { + return false; + } + + [$isCDATAXml]() { + return false; + } + + [$isBindable]() { + return false; + } + + [$popPara]() { + if (this.para) { + this[$getTemplateRoot]()[$extra].paraStack.pop(); + } + } + + [$pushPara]() { + this[$getTemplateRoot]()[$extra].paraStack.push(this.para); + } + + [$setId](ids) { + if (this.id && this[$namespaceId] === _namespaces.NamespaceIds.template.id) { + ids.set(this.id, this); + } + } + + [$getTemplateRoot]() { + return this[$globalData].template; + } + + [$isSplittable]() { + return false; + } + + [$isThereMoreWidth]() { + return false; + } + + [$appendChild](child) { + child[_parent] = this; + + this[_children].push(child); + + if (!child[$globalData] && this[$globalData]) { + child[$globalData] = this[$globalData]; + } + } + + [$removeChild](child) { + const i = this[_children].indexOf(child); + + this[_children].splice(i, 1); + } + + [$hasSettableValue]() { + return this.hasOwnProperty("value"); + } + + [$setValue](_) {} + + [$onText](_) {} + + [$finalize]() {} + + [$clean](builder) { + delete this[_hasChildren]; + + if (this[$cleanup]) { + builder.clean(this[$cleanup]); + delete this[$cleanup]; + } + } + + [$indexOf](child) { + return this[_children].indexOf(child); + } + + [$insertAt](i, child) { + child[_parent] = this; + + this[_children].splice(i, 0, child); + + if (!child[$globalData] && this[$globalData]) { + child[$globalData] = this[$globalData]; + } + } + + [$isTransparent]() { + return !this.name; + } + + [$lastAttribute]() { + return ""; + } + + [$text]() { + if (this[_children].length === 0) { + return this[$content]; + } + + return this[_children].map(c => c[$text]()).join(""); + } + + get [_attributeNames]() { + const proto = Object.getPrototypeOf(this); + + if (!proto._attributes) { + const attributes = proto._attributes = new Set(); + + for (const name of Object.getOwnPropertyNames(this)) { + if (this[name] === null || this[name] instanceof XFAObject || this[name] instanceof XFAObjectArray) { + break; + } + + attributes.add(name); + } + } + + return (0, _util.shadow)(this, _attributeNames, proto._attributes); + } + + [$isDescendent](parent) { + let node = this; + + while (node) { + if (node === parent) { + return true; + } + + node = node[$getParent](); + } + + return false; + } + + [$getParent]() { + return this[_parent]; + } + + [$getSubformParent]() { + return this[$getParent](); + } + + [$getChildren](name = null) { + if (!name) { + return this[_children]; + } + + return this[name]; + } + + [$dump]() { + const dumped = Object.create(null); + + if (this[$content]) { + dumped.$content = this[$content]; + } + + for (const name of Object.getOwnPropertyNames(this)) { + const value = this[name]; + + if (value === null) { + continue; + } + + if (value instanceof XFAObject) { + dumped[name] = value[$dump](); + } else if (value instanceof XFAObjectArray) { + if (!value.isEmpty()) { + dumped[name] = value.dump(); + } + } else { + dumped[name] = value; + } + } + + return dumped; + } + + [$toStyle]() { + return null; + } + + [$toHTML]() { + return _utils.HTMLResult.EMPTY; + } + + *[$getContainedChildren]() { + for (const node of this[$getChildren]()) { + yield node; + } + } + + *[_filteredChildrenGenerator](filter, include) { + for (const node of this[$getContainedChildren]()) { + if (!filter || include === filter.has(node[$nodeName])) { + const availableSpace = this[$getAvailableSpace](); + const res = node[$toHTML](availableSpace); + + if (!res.success) { + this[$extra].failingNode = node; + } + + yield res; + } + } + } + + [$flushHTML]() { + return null; + } + + [$addHTML](html, bbox) { + this[$extra].children.push(html); + } + + [$getAvailableSpace]() {} + + [$childrenToHTML]({ + filter = null, + include = true + }) { + if (!this[$extra].generator) { + this[$extra].generator = this[_filteredChildrenGenerator](filter, include); + } else { + const availableSpace = this[$getAvailableSpace](); + const res = this[$extra].failingNode[$toHTML](availableSpace); + + if (!res.success) { + return res; + } + + if (res.html) { + this[$addHTML](res.html, res.bbox); + } + + delete this[$extra].failingNode; + } + + while (true) { + const gen = this[$extra].generator.next(); + + if (gen.done) { + break; + } + + const res = gen.value; + + if (!res.success) { + return res; + } + + if (res.html) { + this[$addHTML](res.html, res.bbox); + } + } + + this[$extra].generator = null; + return _utils.HTMLResult.EMPTY; + } + + [$setSetAttributes](attributes) { + this[_setAttributes] = new Set(Object.keys(attributes)); + } + + [_getUnsetAttributes](protoAttributes) { + const allAttr = this[_attributeNames]; + const setAttr = this[_setAttributes]; + return [...protoAttributes].filter(x => allAttr.has(x) && !setAttr.has(x)); + } + + [$resolvePrototypes](ids, ancestors = new Set()) { + for (const child of this[_children]) { + child[_resolvePrototypesHelper](ids, ancestors); + } + } + + [_resolvePrototypesHelper](ids, ancestors) { + const proto = this[_getPrototype](ids, ancestors); + + if (proto) { + this[_applyPrototype](proto, ids, ancestors); + } else { + this[$resolvePrototypes](ids, ancestors); + } + } + + [_getPrototype](ids, ancestors) { + const { + use, + usehref + } = this; + + if (!use && !usehref) { + return null; + } + + let proto = null; + let somExpression = null; + let id = null; + let ref = use; + + if (usehref) { + ref = usehref; + + if (usehref.startsWith("#som(") && usehref.endsWith(")")) { + somExpression = usehref.slice("#som(".length, usehref.length - 1); + } else if (usehref.startsWith(".#som(") && usehref.endsWith(")")) { + somExpression = usehref.slice(".#som(".length, usehref.length - 1); + } else if (usehref.startsWith("#")) { + id = usehref.slice(1); + } else if (usehref.startsWith(".#")) { + id = usehref.slice(2); + } + } else if (use.startsWith("#")) { + id = use.slice(1); + } else { + somExpression = use; + } + + this.use = this.usehref = ""; + + if (id) { + proto = ids.get(id); + } else { + proto = (0, _som.searchNode)(ids.get($root), this, somExpression, true, false); + + if (proto) { + proto = proto[0]; + } + } + + if (!proto) { + (0, _util.warn)(`XFA - Invalid prototype reference: ${ref}.`); + return null; + } + + if (proto[$nodeName] !== this[$nodeName]) { + (0, _util.warn)(`XFA - Incompatible prototype: ${proto[$nodeName]} !== ${this[$nodeName]}.`); + return null; + } + + if (ancestors.has(proto)) { + (0, _util.warn)(`XFA - Cycle detected in prototypes use.`); + return null; + } + + ancestors.add(proto); + + const protoProto = proto[_getPrototype](ids, ancestors); + + if (protoProto) { + proto[_applyPrototype](protoProto, ids, ancestors); + } + + proto[$resolvePrototypes](ids, ancestors); + ancestors.delete(proto); + return proto; + } + + [_applyPrototype](proto, ids, ancestors) { + if (ancestors.has(proto)) { + (0, _util.warn)(`XFA - Cycle detected in prototypes use.`); + return; + } + + if (!this[$content] && proto[$content]) { + this[$content] = proto[$content]; + } + + const newAncestors = new Set(ancestors); + newAncestors.add(proto); + + for (const unsetAttrName of this[_getUnsetAttributes](proto[_setAttributes])) { + this[unsetAttrName] = proto[unsetAttrName]; + + if (this[_setAttributes]) { + this[_setAttributes].add(unsetAttrName); + } + } + + for (const name of Object.getOwnPropertyNames(this)) { + if (this[_attributeNames].has(name)) { + continue; + } + + const value = this[name]; + const protoValue = proto[name]; + + if (value instanceof XFAObjectArray) { + for (const child of value[_children]) { + child[_resolvePrototypesHelper](ids, ancestors); + } + + for (let i = value[_children].length, ii = protoValue[_children].length; i < ii; i++) { + const child = proto[_children][i][$clone](); + + if (value.push(child)) { + child[_parent] = this; + + this[_children].push(child); + + child[_resolvePrototypesHelper](ids, ancestors); + } else { + break; + } + } + + continue; + } + + if (value !== null) { + value[$resolvePrototypes](ids, ancestors); + + if (protoValue) { + value[_applyPrototype](protoValue, ids, ancestors); + } + + continue; + } + + if (protoValue !== null) { + const child = protoValue[$clone](); + child[_parent] = this; + this[name] = child; + + this[_children].push(child); + + child[_resolvePrototypesHelper](ids, ancestors); + } + } + } + + static [_cloneAttribute](obj) { + if (Array.isArray(obj)) { + return obj.map(x => XFAObject[_cloneAttribute](x)); + } + + if (typeof obj === "object" && obj !== null) { + return Object.assign({}, obj); + } + + return obj; + } + + [$clone]() { + const clone = Object.create(Object.getPrototypeOf(this)); + + for (const $symbol of Object.getOwnPropertySymbols(this)) { + try { + clone[$symbol] = this[$symbol]; + } catch (_) { + (0, _util.shadow)(clone, $symbol, this[$symbol]); + } + } + + clone[$uid] = `${clone[$nodeName]}${uid++}`; + clone[_children] = []; + + for (const name of Object.getOwnPropertyNames(this)) { + if (this[_attributeNames].has(name)) { + clone[name] = XFAObject[_cloneAttribute](this[name]); + continue; + } + + const value = this[name]; + + if (value instanceof XFAObjectArray) { + clone[name] = new XFAObjectArray(value[_max]); + } else { + clone[name] = null; + } + } + + for (const child of this[_children]) { + const name = child[$nodeName]; + const clonedChild = child[$clone](); + + clone[_children].push(clonedChild); + + clonedChild[_parent] = clone; + + if (clone[name] === null) { + clone[name] = clonedChild; + } else { + clone[name][_children].push(clonedChild); + } + } + + return clone; + } + + [$getChildren](name = null) { + if (!name) { + return this[_children]; + } + + return this[_children].filter(c => c[$nodeName] === name); + } + + [$getChildrenByClass](name) { + return this[name]; + } + + [$getChildrenByName](name, allTransparent, first = true) { + return Array.from(this[$getChildrenByNameIt](name, allTransparent, first)); + } + + *[$getChildrenByNameIt](name, allTransparent, first = true) { + if (name === "parent") { + yield this[_parent]; + return; + } + + for (const child of this[_children]) { + if (child[$nodeName] === name) { + yield child; + } + + if (child.name === name) { + yield child; + } + + if (allTransparent || child[$isTransparent]()) { + yield* child[$getChildrenByNameIt](name, allTransparent, false); + } + } + + if (first && this[_attributeNames].has(name)) { + yield new XFAAttribute(this, name, this[name]); + } + } + +} + +exports.XFAObject = XFAObject; + +class XFAObjectArray { + constructor(max = Infinity) { + this[_max] = max; + this[_children] = []; + } + + push(child) { + const len = this[_children].length; + + if (len <= this[_max]) { + this[_children].push(child); + + return true; + } + + (0, _util.warn)(`XFA - node "${child[$nodeName]}" accepts no more than ${this[_max]} children`); + return false; + } + + isEmpty() { + return this[_children].length === 0; + } + + dump() { + return this[_children].length === 1 ? this[_children][0][$dump]() : this[_children].map(x => x[$dump]()); + } + + [$clone]() { + const clone = new XFAObjectArray(this[_max]); + clone[_children] = this[_children].map(c => c[$clone]()); + return clone; + } + + get children() { + return this[_children]; + } + + clear() { + this[_children].length = 0; + } + +} + +exports.XFAObjectArray = XFAObjectArray; + +class XFAAttribute { + constructor(node, name, value) { + this[_parent] = node; + this[$nodeName] = name; + this[$content] = value; + this[$consumed] = false; + this[$uid] = `attribute${uid++}`; + } + + [$getParent]() { + return this[_parent]; + } + + [$isDataValue]() { + return true; + } + + [$getDataValue]() { + return this[$content].trim(); + } + + [$setValue](value) { + value = value.value || ""; + this[$content] = value.toString(); + } + + [$text]() { + return this[$content]; + } + + [$isDescendent](parent) { + return this[_parent] === parent || this[_parent][$isDescendent](parent); + } + +} + +exports.XFAAttribute = XFAAttribute; + +class XmlObject extends XFAObject { + constructor(nsId, name, attributes = {}) { + super(nsId, name); + this[$content] = ""; + this[_dataValue] = null; + + if (name !== "#text") { + const map = new Map(); + this[_attributes] = map; + + for (const [attrName, value] of Object.entries(attributes)) { + map.set(attrName, new XFAAttribute(this, attrName, value)); + } + + if (attributes.hasOwnProperty($nsAttributes)) { + const dataNode = attributes[$nsAttributes].xfa.dataNode; + + if (dataNode !== undefined) { + if (dataNode === "dataGroup") { + this[_dataValue] = false; + } else if (dataNode === "dataValue") { + this[_dataValue] = true; + } + } + } + } + + this[$consumed] = false; + } + + [$toString](buf) { + const tagName = this[$nodeName]; + + if (tagName === "#text") { + buf.push((0, _core_utils.encodeToXmlString)(this[$content])); + return; + } + + const utf8TagName = (0, _util.utf8StringToString)(tagName); + const prefix = this[$namespaceId] === NS_DATASETS ? "xfa:" : ""; + buf.push(`<${prefix}${utf8TagName}`); + + for (const [name, value] of this[_attributes].entries()) { + const utf8Name = (0, _util.utf8StringToString)(name); + buf.push(` ${utf8Name}="${(0, _core_utils.encodeToXmlString)(value[$content])}"`); + } + + if (this[_dataValue] !== null) { + if (this[_dataValue]) { + buf.push(` xfa:dataNode="dataValue"`); + } else { + buf.push(` xfa:dataNode="dataGroup"`); + } + } + + if (!this[$content] && this[_children].length === 0) { + buf.push("/>"); + return; + } + + buf.push(">"); + + if (this[$content]) { + if (typeof this[$content] === "string") { + buf.push((0, _core_utils.encodeToXmlString)(this[$content])); + } else { + this[$content][$toString](buf); + } + } else { + for (const child of this[_children]) { + child[$toString](buf); + } + } + + buf.push(``); + } + + [$onChild](child) { + if (this[$content]) { + const node = new XmlObject(this[$namespaceId], "#text"); + this[$appendChild](node); + node[$content] = this[$content]; + this[$content] = ""; + } + + this[$appendChild](child); + return true; + } + + [$onText](str) { + this[$content] += str; + } + + [$finalize]() { + if (this[$content] && this[_children].length > 0) { + const node = new XmlObject(this[$namespaceId], "#text"); + this[$appendChild](node); + node[$content] = this[$content]; + delete this[$content]; + } + } + + [$toHTML]() { + if (this[$nodeName] === "#text") { + return _utils.HTMLResult.success({ + name: "#text", + value: this[$content] + }); + } + + return _utils.HTMLResult.EMPTY; + } + + [$getChildren](name = null) { + if (!name) { + return this[_children]; + } + + return this[_children].filter(c => c[$nodeName] === name); + } + + [$getAttributes]() { + return this[_attributes]; + } + + [$getChildrenByClass](name) { + const value = this[_attributes].get(name); + + if (value !== undefined) { + return value; + } + + return this[$getChildren](name); + } + + *[$getChildrenByNameIt](name, allTransparent) { + const value = this[_attributes].get(name); + + if (value) { + yield value; + } + + for (const child of this[_children]) { + if (child[$nodeName] === name) { + yield child; + } + + if (allTransparent) { + yield* child[$getChildrenByNameIt](name, allTransparent); + } + } + } + + *[$getAttributeIt](name, skipConsumed) { + const value = this[_attributes].get(name); + + if (value && (!skipConsumed || !value[$consumed])) { + yield value; + } + + for (const child of this[_children]) { + yield* child[$getAttributeIt](name, skipConsumed); + } + } + + *[$getRealChildrenByNameIt](name, allTransparent, skipConsumed) { + for (const child of this[_children]) { + if (child[$nodeName] === name && (!skipConsumed || !child[$consumed])) { + yield child; + } + + if (allTransparent) { + yield* child[$getRealChildrenByNameIt](name, allTransparent, skipConsumed); + } + } + } + + [$isDataValue]() { + if (this[_dataValue] === null) { + return this[_children].length === 0 || this[_children][0][$namespaceId] === _namespaces.NamespaceIds.xhtml.id; + } + + return this[_dataValue]; + } + + [$getDataValue]() { + if (this[_dataValue] === null) { + if (this[_children].length === 0) { + return this[$content].trim(); + } + + if (this[_children][0][$namespaceId] === _namespaces.NamespaceIds.xhtml.id) { + return this[_children][0][$text]().trim(); + } + + return null; + } + + return this[$content].trim(); + } + + [$setValue](value) { + value = value.value || ""; + this[$content] = value.toString(); + } + + [$dump](hasNS = false) { + const dumped = Object.create(null); + + if (hasNS) { + dumped.$ns = this[$namespaceId]; + } + + if (this[$content]) { + dumped.$content = this[$content]; + } + + dumped.$name = this[$nodeName]; + dumped.children = []; + + for (const child of this[_children]) { + dumped.children.push(child[$dump](hasNS)); + } + + dumped.attributes = Object.create(null); + + for (const [name, value] of this[_attributes]) { + dumped.attributes[name] = value[$content]; + } + + return dumped; + } + +} + +exports.XmlObject = XmlObject; + +class ContentObject extends XFAObject { + constructor(nsId, name) { + super(nsId, name); + this[$content] = ""; + } + + [$onText](text) { + this[$content] += text; + } + + [$finalize]() {} + +} + +exports.ContentObject = ContentObject; + +class OptionObject extends ContentObject { + constructor(nsId, name, options) { + super(nsId, name); + this[_options] = options; + } + + [$finalize]() { + this[$content] = (0, _utils.getKeyword)({ + data: this[$content], + defaultValue: this[_options][0], + validate: k => this[_options].includes(k) + }); + } + + [$clean](builder) { + super[$clean](builder); + delete this[_options]; + } + +} + +exports.OptionObject = OptionObject; + +class StringObject extends ContentObject { + [$finalize]() { + this[$content] = this[$content].trim(); + } + +} + +exports.StringObject = StringObject; + +class IntegerObject extends ContentObject { + constructor(nsId, name, defaultValue, validator) { + super(nsId, name); + this[_defaultValue] = defaultValue; + this[_validator] = validator; + } + + [$finalize]() { + this[$content] = (0, _utils.getInteger)({ + data: this[$content], + defaultValue: this[_defaultValue], + validate: this[_validator] + }); + } + + [$clean](builder) { + super[$clean](builder); + delete this[_defaultValue]; + delete this[_validator]; + } + +} + +exports.IntegerObject = IntegerObject; + +class Option01 extends IntegerObject { + constructor(nsId, name) { + super(nsId, name, 0, n => n === 1); + } + +} + +exports.Option01 = Option01; + +class Option10 extends IntegerObject { + constructor(nsId, name) { + super(nsId, name, 1, n => n === 0); + } + +} + +exports.Option10 = Option10; + +/***/ }), +/* 78 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.HTMLResult = void 0; +exports.getBBox = getBBox; +exports.getColor = getColor; +exports.getFloat = getFloat; +exports.getInteger = getInteger; +exports.getKeyword = getKeyword; +exports.getMeasurement = getMeasurement; +exports.getRatio = getRatio; +exports.getRelevant = getRelevant; +exports.getStringOption = getStringOption; +exports.stripQuotes = stripQuotes; + +var _util = __w_pdfjs_require__(2); + +const dimConverters = { + pt: x => x, + cm: x => x / 2.54 * 72, + mm: x => x / (10 * 2.54) * 72, + in: x => x * 72, + px: x => x +}; +const measurementPattern = /([+-]?\d+\.?\d*)(.*)/; + +function stripQuotes(str) { + if (str.startsWith("'") || str.startsWith('"')) { + return str.slice(1, str.length - 1); + } + + return str; +} + +function getInteger({ + data, + defaultValue, + validate +}) { + if (!data) { + return defaultValue; + } + + data = data.trim(); + const n = parseInt(data, 10); + + if (!isNaN(n) && validate(n)) { + return n; + } + + return defaultValue; +} + +function getFloat({ + data, + defaultValue, + validate +}) { + if (!data) { + return defaultValue; + } + + data = data.trim(); + const n = parseFloat(data); + + if (!isNaN(n) && validate(n)) { + return n; + } + + return defaultValue; +} + +function getKeyword({ + data, + defaultValue, + validate +}) { + if (!data) { + return defaultValue; + } + + data = data.trim(); + + if (validate(data)) { + return data; + } + + return defaultValue; +} + +function getStringOption(data, options) { + return getKeyword({ + data, + defaultValue: options[0], + validate: k => options.includes(k) + }); +} + +function getMeasurement(str, def = "0") { + def = def || "0"; + + if (!str) { + return getMeasurement(def); + } + + const match = str.trim().match(measurementPattern); + + if (!match) { + return getMeasurement(def); + } + + const [, valueStr, unit] = match; + const value = parseFloat(valueStr); + + if (isNaN(value)) { + return getMeasurement(def); + } + + if (value === 0) { + return 0; + } + + const conv = dimConverters[unit]; + + if (conv) { + return conv(value); + } + + return value; +} + +function getRatio(data) { + if (!data) { + return { + num: 1, + den: 1 + }; + } + + const ratio = data.trim().split(/\s*:\s*/).map(x => parseFloat(x)).filter(x => !isNaN(x)); + + if (ratio.length === 1) { + ratio.push(1); + } + + if (ratio.length === 0) { + return { + num: 1, + den: 1 + }; + } + + const [num, den] = ratio; + return { + num, + den + }; +} + +function getRelevant(data) { + if (!data) { + return []; + } + + return data.trim().split(/\s+/).map(e => { + return { + excluded: e[0] === "-", + viewname: e.substring(1) + }; + }); +} + +function getColor(data, def = [0, 0, 0]) { + let [r, g, b] = def; + + if (!data) { + return { + r, + g, + b + }; + } + + const color = data.trim().split(/\s*,\s*/).map(c => Math.min(Math.max(0, parseInt(c.trim(), 10)), 255)).map(c => isNaN(c) ? 0 : c); + + if (color.length < 3) { + return { + r, + g, + b + }; + } + + [r, g, b] = color; + return { + r, + g, + b + }; +} + +function getBBox(data) { + const def = -1; + + if (!data) { + return { + x: def, + y: def, + width: def, + height: def + }; + } + + const bbox = data.trim().split(/\s*,\s*/).map(m => getMeasurement(m, "-1")); + + if (bbox.length < 4 || bbox[2] < 0 || bbox[3] < 0) { + return { + x: def, + y: def, + width: def, + height: def + }; + } + + const [x, y, width, height] = bbox; + return { + x, + y, + width, + height + }; +} + +class HTMLResult { + static get FAILURE() { + return (0, _util.shadow)(this, "FAILURE", new HTMLResult(false, null, null, null)); + } + + static get EMPTY() { + return (0, _util.shadow)(this, "EMPTY", new HTMLResult(true, null, null, null)); + } + + constructor(success, html, bbox, breakNode) { + this.success = success; + this.html = html; + this.bbox = bbox; + this.breakNode = breakNode; + } + + isBreak() { + return !!this.breakNode; + } + + static breakNode(node) { + return new HTMLResult(false, null, null, node); + } + + static success(html, bbox = null) { + return new HTMLResult(true, html, bbox, null); + } + +} + +exports.HTMLResult = HTMLResult; + +/***/ }), +/* 79 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.NamespaceIds = exports.$buildXFAObject = void 0; +const $buildXFAObject = Symbol(); +exports.$buildXFAObject = $buildXFAObject; +const NamespaceIds = { + config: { + id: 0, + check: ns => ns.startsWith("http://www.xfa.org/schema/xci/") + }, + connectionSet: { + id: 1, + check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-connection-set/") + }, + datasets: { + id: 2, + check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-data/") + }, + form: { + id: 3, + check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-form/") + }, + localeSet: { + id: 4, + check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-locale-set/") + }, + pdf: { + id: 5, + check: ns => ns === "http://ns.adobe.com/xdp/pdf/" + }, + signature: { + id: 6, + check: ns => ns === "http://www.w3.org/2000/09/xmldsig#" + }, + sourceSet: { + id: 7, + check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-source-set/") + }, + stylesheet: { + id: 8, + check: ns => ns === "http://www.w3.org/1999/XSL/Transform" + }, + template: { + id: 9, + check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-template/") + }, + xdc: { + id: 10, + check: ns => ns.startsWith("http://www.xfa.org/schema/xdc/") + }, + xdp: { + id: 11, + check: ns => ns === "http://ns.adobe.com/xdp/" + }, + xfdf: { + id: 12, + check: ns => ns === "http://ns.adobe.com/xfdf/" + }, + xhtml: { + id: 13, + check: ns => ns === "http://www.w3.org/1999/xhtml" + }, + xmpmeta: { + id: 14, + check: ns => ns === "http://ns.adobe.com/xmpmeta/" + } +}; +exports.NamespaceIds = NamespaceIds; + +/***/ }), +/* 80 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.createDataNode = createDataNode; +exports.searchNode = searchNode; + +var _xfa_object = __w_pdfjs_require__(77); + +var _namespaces = __w_pdfjs_require__(79); + +var _util = __w_pdfjs_require__(2); + +const namePattern = /^[^.[]+/; +const indexPattern = /^[^\]]+/; +const operators = { + dot: 0, + dotDot: 1, + dotHash: 2, + dotBracket: 3, + dotParen: 4 +}; +const shortcuts = new Map([["$data", (root, current) => root.datasets ? root.datasets.data : root], ["$record", (root, current) => (root.datasets ? root.datasets.data : root)[_xfa_object.$getChildren]()[0]], ["$template", (root, current) => root.template], ["$connectionSet", (root, current) => root.connectionSet], ["$form", (root, current) => root.form], ["$layout", (root, current) => root.layout], ["$host", (root, current) => root.host], ["$dataWindow", (root, current) => root.dataWindow], ["$event", (root, current) => root.event], ["!", (root, current) => root.datasets], ["$xfa", (root, current) => root], ["xfa", (root, current) => root], ["$", (root, current) => current]]); +const somCache = new WeakMap(); +const NS_DATASETS = _namespaces.NamespaceIds.datasets.id; + +function parseIndex(index) { + index = index.trim(); + + if (index === "*") { + return Infinity; + } + + return parseInt(index, 10) || 0; +} + +function parseExpression(expr, dotDotAllowed, noExpr = true) { + let match = expr.match(namePattern); + + if (!match) { + return null; + } + + let [name] = match; + const parsed = [{ + name, + cacheName: "." + name, + index: 0, + js: null, + formCalc: null, + operator: operators.dot + }]; + let pos = name.length; + + while (pos < expr.length) { + const spos = pos; + const char = expr.charAt(pos++); + + if (char === "[") { + match = expr.slice(pos).match(indexPattern); + + if (!match) { + (0, _util.warn)("XFA - Invalid index in SOM expression"); + return null; + } + + parsed.at(-1).index = parseIndex(match[0]); + pos += match[0].length + 1; + continue; + } + + let operator; + + switch (expr.charAt(pos)) { + case ".": + if (!dotDotAllowed) { + return null; + } + + pos++; + operator = operators.dotDot; + break; + + case "#": + pos++; + operator = operators.dotHash; + break; + + case "[": + if (noExpr) { + (0, _util.warn)("XFA - SOM expression contains a FormCalc subexpression which is not supported for now."); + return null; + } + + operator = operators.dotBracket; + break; + + case "(": + if (noExpr) { + (0, _util.warn)("XFA - SOM expression contains a JavaScript subexpression which is not supported for now."); + return null; + } + + operator = operators.dotParen; + break; + + default: + operator = operators.dot; + break; + } + + match = expr.slice(pos).match(namePattern); + + if (!match) { + break; + } + + [name] = match; + pos += name.length; + parsed.push({ + name, + cacheName: expr.slice(spos, pos), + operator, + index: 0, + js: null, + formCalc: null + }); + } + + return parsed; +} + +function searchNode(root, container, expr, dotDotAllowed = true, useCache = true) { + const parsed = parseExpression(expr, dotDotAllowed); + + if (!parsed) { + return null; + } + + const fn = shortcuts.get(parsed[0].name); + let i = 0; + let isQualified; + + if (fn) { + isQualified = true; + root = [fn(root, container)]; + i = 1; + } else { + isQualified = container === null; + root = [container || root]; + } + + for (let ii = parsed.length; i < ii; i++) { + const { + name, + cacheName, + operator, + index + } = parsed[i]; + const nodes = []; + + for (const node of root) { + if (!(node instanceof _xfa_object.XFAObject)) { + continue; + } + + let children, cached; + + if (useCache) { + cached = somCache.get(node); + + if (!cached) { + cached = new Map(); + somCache.set(node, cached); + } + + children = cached.get(cacheName); + } + + if (!children) { + switch (operator) { + case operators.dot: + children = node[_xfa_object.$getChildrenByName](name, false); + break; + + case operators.dotDot: + children = node[_xfa_object.$getChildrenByName](name, true); + break; + + case operators.dotHash: + children = node[_xfa_object.$getChildrenByClass](name); + + if (children instanceof _xfa_object.XFAObjectArray) { + children = children.children; + } else { + children = [children]; + } + + break; + + default: + break; + } + + if (useCache) { + cached.set(cacheName, children); + } + } + + if (children.length > 0) { + nodes.push(children); + } + } + + if (nodes.length === 0 && !isQualified && i === 0) { + const parent = container[_xfa_object.$getParent](); + + container = parent; + + if (!container) { + return null; + } + + i = -1; + root = [container]; + continue; + } + + if (isFinite(index)) { + root = nodes.filter(node => index < node.length).map(node => node[index]); + } else { + root = nodes.flat(); + } + } + + if (root.length === 0) { + return null; + } + + return root; +} + +function createNodes(root, path) { + let node = null; + + for (const { + name, + index + } of path) { + for (let i = 0, ii = !isFinite(index) ? 0 : index; i <= ii; i++) { + const nsId = root[_xfa_object.$namespaceId] === NS_DATASETS ? -1 : root[_xfa_object.$namespaceId]; + node = new _xfa_object.XmlObject(nsId, name); + + root[_xfa_object.$appendChild](node); + } + + root = node; + } + + return node; +} + +function createDataNode(root, container, expr) { + const parsed = parseExpression(expr); + + if (!parsed) { + return null; + } + + if (parsed.some(x => x.operator === operators.dotDot)) { + return null; + } + + const fn = shortcuts.get(parsed[0].name); + let i = 0; + + if (fn) { + root = fn(root, container); + i = 1; + } else { + root = container || root; + } + + for (let ii = parsed.length; i < ii; i++) { + const { + name, + operator, + index + } = parsed[i]; + + if (!isFinite(index)) { + parsed[i].index = 0; + return createNodes(root, parsed.slice(i)); + } + + let children; + + switch (operator) { + case operators.dot: + children = root[_xfa_object.$getChildrenByName](name, false); + break; + + case operators.dotDot: + children = root[_xfa_object.$getChildrenByName](name, true); + break; + + case operators.dotHash: + children = root[_xfa_object.$getChildrenByClass](name); + + if (children instanceof _xfa_object.XFAObjectArray) { + children = children.children; + } else { + children = [children]; + } + + break; + + default: + break; + } + + if (children.length === 0) { + return createNodes(root, parsed.slice(i)); + } + + if (index < children.length) { + const child = children[index]; + + if (!(child instanceof _xfa_object.XFAObject)) { + (0, _util.warn)(`XFA - Cannot create a node.`); + return null; + } + + root = child; + } else { + parsed[i].index = index - children.length; + return createNodes(root, parsed.slice(i)); + } + } + + return null; +} + +/***/ }), +/* 81 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Binder = void 0; + +var _xfa_object = __w_pdfjs_require__(77); + +var _template = __w_pdfjs_require__(82); + +var _som = __w_pdfjs_require__(80); + +var _namespaces = __w_pdfjs_require__(79); + +var _util = __w_pdfjs_require__(2); + +const NS_DATASETS = _namespaces.NamespaceIds.datasets.id; + +function createText(content) { + const node = new _template.Text({}); + node[_xfa_object.$content] = content; + return node; +} + +class Binder { + constructor(root) { + this.root = root; + this.datasets = root.datasets; + + if (root.datasets && root.datasets.data) { + this.data = root.datasets.data; + } else { + this.data = new _xfa_object.XmlObject(_namespaces.NamespaceIds.datasets.id, "data"); + } + + this.emptyMerge = this.data[_xfa_object.$getChildren]().length === 0; + this.root.form = this.form = root.template[_xfa_object.$clone](); + } + + _isConsumeData() { + return !this.emptyMerge && this._mergeMode; + } + + _isMatchTemplate() { + return !this._isConsumeData(); + } + + bind() { + this._bindElement(this.form, this.data); + + return this.form; + } + + getData() { + return this.data; + } + + _bindValue(formNode, data, picture) { + formNode[_xfa_object.$data] = data; + + if (formNode[_xfa_object.$hasSettableValue]()) { + if (data[_xfa_object.$isDataValue]()) { + const value = data[_xfa_object.$getDataValue](); + + formNode[_xfa_object.$setValue](createText(value)); + } else if (formNode instanceof _template.Field && formNode.ui && formNode.ui.choiceList && formNode.ui.choiceList.open === "multiSelect") { + const value = data[_xfa_object.$getChildren]().map(child => child[_xfa_object.$content].trim()).join("\n"); + + formNode[_xfa_object.$setValue](createText(value)); + } else if (this._isConsumeData()) { + (0, _util.warn)(`XFA - Nodes haven't the same type.`); + } + } else if (!data[_xfa_object.$isDataValue]() || this._isMatchTemplate()) { + this._bindElement(formNode, data); + } else { + (0, _util.warn)(`XFA - Nodes haven't the same type.`); + } + } + + _findDataByNameToConsume(name, isValue, dataNode, global) { + if (!name) { + return null; + } + + let generator, match; + + for (let i = 0; i < 3; i++) { + generator = dataNode[_xfa_object.$getRealChildrenByNameIt](name, false, true); + + while (true) { + match = generator.next().value; + + if (!match) { + break; + } + + if (isValue === match[_xfa_object.$isDataValue]()) { + return match; + } + } + + if (dataNode[_xfa_object.$namespaceId] === _namespaces.NamespaceIds.datasets.id && dataNode[_xfa_object.$nodeName] === "data") { + break; + } + + dataNode = dataNode[_xfa_object.$getParent](); + } + + if (!global) { + return null; + } + + generator = this.data[_xfa_object.$getRealChildrenByNameIt](name, true, false); + match = generator.next().value; + + if (match) { + return match; + } + + generator = this.data[_xfa_object.$getAttributeIt](name, true); + match = generator.next().value; + + if (match && match[_xfa_object.$isDataValue]()) { + return match; + } + + return null; + } + + _setProperties(formNode, dataNode) { + if (!formNode.hasOwnProperty("setProperty")) { + return; + } + + for (const { + ref, + target, + connection + } of formNode.setProperty.children) { + if (connection) { + continue; + } + + if (!ref) { + continue; + } + + const nodes = (0, _som.searchNode)(this.root, dataNode, ref, false, false); + + if (!nodes) { + (0, _util.warn)(`XFA - Invalid reference: ${ref}.`); + continue; + } + + const [node] = nodes; + + if (!node[_xfa_object.$isDescendent](this.data)) { + (0, _util.warn)(`XFA - Invalid node: must be a data node.`); + continue; + } + + const targetNodes = (0, _som.searchNode)(this.root, formNode, target, false, false); + + if (!targetNodes) { + (0, _util.warn)(`XFA - Invalid target: ${target}.`); + continue; + } + + const [targetNode] = targetNodes; + + if (!targetNode[_xfa_object.$isDescendent](formNode)) { + (0, _util.warn)(`XFA - Invalid target: must be a property or subproperty.`); + continue; + } + + const targetParent = targetNode[_xfa_object.$getParent](); + + if (targetNode instanceof _template.SetProperty || targetParent instanceof _template.SetProperty) { + (0, _util.warn)(`XFA - Invalid target: cannot be a setProperty or one of its properties.`); + continue; + } + + if (targetNode instanceof _template.BindItems || targetParent instanceof _template.BindItems) { + (0, _util.warn)(`XFA - Invalid target: cannot be a bindItems or one of its properties.`); + continue; + } + + const content = node[_xfa_object.$text](); + + const name = targetNode[_xfa_object.$nodeName]; + + if (targetNode instanceof _xfa_object.XFAAttribute) { + const attrs = Object.create(null); + attrs[name] = content; + const obj = Reflect.construct(Object.getPrototypeOf(targetParent).constructor, [attrs]); + targetParent[name] = obj[name]; + continue; + } + + if (!targetNode.hasOwnProperty(_xfa_object.$content)) { + (0, _util.warn)(`XFA - Invalid node to use in setProperty`); + continue; + } + + targetNode[_xfa_object.$data] = node; + targetNode[_xfa_object.$content] = content; + + targetNode[_xfa_object.$finalize](); + } + } + + _bindItems(formNode, dataNode) { + if (!formNode.hasOwnProperty("items") || !formNode.hasOwnProperty("bindItems") || formNode.bindItems.isEmpty()) { + return; + } + + for (const item of formNode.items.children) { + formNode[_xfa_object.$removeChild](item); + } + + formNode.items.clear(); + const labels = new _template.Items({}); + const values = new _template.Items({}); + + formNode[_xfa_object.$appendChild](labels); + + formNode.items.push(labels); + + formNode[_xfa_object.$appendChild](values); + + formNode.items.push(values); + + for (const { + ref, + labelRef, + valueRef, + connection + } of formNode.bindItems.children) { + if (connection) { + continue; + } + + if (!ref) { + continue; + } + + const nodes = (0, _som.searchNode)(this.root, dataNode, ref, false, false); + + if (!nodes) { + (0, _util.warn)(`XFA - Invalid reference: ${ref}.`); + continue; + } + + for (const node of nodes) { + if (!node[_xfa_object.$isDescendent](this.datasets)) { + (0, _util.warn)(`XFA - Invalid ref (${ref}): must be a datasets child.`); + continue; + } + + const labelNodes = (0, _som.searchNode)(this.root, node, labelRef, true, false); + + if (!labelNodes) { + (0, _util.warn)(`XFA - Invalid label: ${labelRef}.`); + continue; + } + + const [labelNode] = labelNodes; + + if (!labelNode[_xfa_object.$isDescendent](this.datasets)) { + (0, _util.warn)(`XFA - Invalid label: must be a datasets child.`); + continue; + } + + const valueNodes = (0, _som.searchNode)(this.root, node, valueRef, true, false); + + if (!valueNodes) { + (0, _util.warn)(`XFA - Invalid value: ${valueRef}.`); + continue; + } + + const [valueNode] = valueNodes; + + if (!valueNode[_xfa_object.$isDescendent](this.datasets)) { + (0, _util.warn)(`XFA - Invalid value: must be a datasets child.`); + continue; + } + + const label = createText(labelNode[_xfa_object.$text]()); + const value = createText(valueNode[_xfa_object.$text]()); + + labels[_xfa_object.$appendChild](label); + + labels.text.push(label); + + values[_xfa_object.$appendChild](value); + + values.text.push(value); + } + } + } + + _bindOccurrences(formNode, matches, picture) { + let baseClone; + + if (matches.length > 1) { + baseClone = formNode[_xfa_object.$clone](); + + baseClone[_xfa_object.$removeChild](baseClone.occur); + + baseClone.occur = null; + } + + this._bindValue(formNode, matches[0], picture); + + this._setProperties(formNode, matches[0]); + + this._bindItems(formNode, matches[0]); + + if (matches.length === 1) { + return; + } + + const parent = formNode[_xfa_object.$getParent](); + + const name = formNode[_xfa_object.$nodeName]; + + const pos = parent[_xfa_object.$indexOf](formNode); + + for (let i = 1, ii = matches.length; i < ii; i++) { + const match = matches[i]; + + const clone = baseClone[_xfa_object.$clone](); + + parent[name].push(clone); + + parent[_xfa_object.$insertAt](pos + i, clone); + + this._bindValue(clone, match, picture); + + this._setProperties(clone, match); + + this._bindItems(clone, match); + } + } + + _createOccurrences(formNode) { + if (!this.emptyMerge) { + return; + } + + const { + occur + } = formNode; + + if (!occur || occur.initial <= 1) { + return; + } + + const parent = formNode[_xfa_object.$getParent](); + + const name = formNode[_xfa_object.$nodeName]; + + if (!(parent[name] instanceof _xfa_object.XFAObjectArray)) { + return; + } + + let currentNumber; + + if (formNode.name) { + currentNumber = parent[name].children.filter(e => e.name === formNode.name).length; + } else { + currentNumber = parent[name].children.length; + } + + const pos = parent[_xfa_object.$indexOf](formNode) + 1; + const ii = occur.initial - currentNumber; + + if (ii) { + const nodeClone = formNode[_xfa_object.$clone](); + + nodeClone[_xfa_object.$removeChild](nodeClone.occur); + + nodeClone.occur = null; + parent[name].push(nodeClone); + + parent[_xfa_object.$insertAt](pos, nodeClone); + + for (let i = 1; i < ii; i++) { + const clone = nodeClone[_xfa_object.$clone](); + + parent[name].push(clone); + + parent[_xfa_object.$insertAt](pos + i, clone); + } + } + } + + _getOccurInfo(formNode) { + const { + name, + occur + } = formNode; + + if (!occur || !name) { + return [1, 1]; + } + + const max = occur.max === -1 ? Infinity : occur.max; + return [occur.min, max]; + } + + _setAndBind(formNode, dataNode) { + this._setProperties(formNode, dataNode); + + this._bindItems(formNode, dataNode); + + this._bindElement(formNode, dataNode); + } + + _bindElement(formNode, dataNode) { + const uselessNodes = []; + + this._createOccurrences(formNode); + + for (const child of formNode[_xfa_object.$getChildren]()) { + if (child[_xfa_object.$data]) { + continue; + } + + if (this._mergeMode === undefined && child[_xfa_object.$nodeName] === "subform") { + this._mergeMode = child.mergeMode === "consumeData"; + + const dataChildren = dataNode[_xfa_object.$getChildren](); + + if (dataChildren.length > 0) { + this._bindOccurrences(child, [dataChildren[0]], null); + } else if (this.emptyMerge) { + const nsId = dataNode[_xfa_object.$namespaceId] === NS_DATASETS ? -1 : dataNode[_xfa_object.$namespaceId]; + const dataChild = child[_xfa_object.$data] = new _xfa_object.XmlObject(nsId, child.name || "root"); + + dataNode[_xfa_object.$appendChild](dataChild); + + this._bindElement(child, dataChild); + } + + continue; + } + + if (!child[_xfa_object.$isBindable]()) { + continue; + } + + let global = false; + let picture = null; + let ref = null; + let match = null; + + if (child.bind) { + switch (child.bind.match) { + case "none": + this._setAndBind(child, dataNode); + + continue; + + case "global": + global = true; + break; + + case "dataRef": + if (!child.bind.ref) { + (0, _util.warn)(`XFA - ref is empty in node ${child[_xfa_object.$nodeName]}.`); + + this._setAndBind(child, dataNode); + + continue; + } + + ref = child.bind.ref; + break; + + default: + break; + } + + if (child.bind.picture) { + picture = child.bind.picture[_xfa_object.$content]; + } + } + + const [min, max] = this._getOccurInfo(child); + + if (ref) { + match = (0, _som.searchNode)(this.root, dataNode, ref, true, false); + + if (match === null) { + match = (0, _som.createDataNode)(this.data, dataNode, ref); + + if (!match) { + continue; + } + + if (this._isConsumeData()) { + match[_xfa_object.$consumed] = true; + } + + this._setAndBind(child, match); + + continue; + } else { + if (this._isConsumeData()) { + match = match.filter(node => !node[_xfa_object.$consumed]); + } + + if (match.length > max) { + match = match.slice(0, max); + } else if (match.length === 0) { + match = null; + } + + if (match && this._isConsumeData()) { + match.forEach(node => { + node[_xfa_object.$consumed] = true; + }); + } + } + } else { + if (!child.name) { + this._setAndBind(child, dataNode); + + continue; + } + + if (this._isConsumeData()) { + const matches = []; + + while (matches.length < max) { + const found = this._findDataByNameToConsume(child.name, child[_xfa_object.$hasSettableValue](), dataNode, global); + + if (!found) { + break; + } + + found[_xfa_object.$consumed] = true; + matches.push(found); + } + + match = matches.length > 0 ? matches : null; + } else { + match = dataNode[_xfa_object.$getRealChildrenByNameIt](child.name, false, this.emptyMerge).next().value; + + if (!match) { + if (min === 0) { + uselessNodes.push(child); + continue; + } + + const nsId = dataNode[_xfa_object.$namespaceId] === NS_DATASETS ? -1 : dataNode[_xfa_object.$namespaceId]; + match = child[_xfa_object.$data] = new _xfa_object.XmlObject(nsId, child.name); + + if (this.emptyMerge) { + match[_xfa_object.$consumed] = true; + } + + dataNode[_xfa_object.$appendChild](match); + + this._setAndBind(child, match); + + continue; + } + + if (this.emptyMerge) { + match[_xfa_object.$consumed] = true; + } + + match = [match]; + } + } + + if (match) { + this._bindOccurrences(child, match, picture); + } else if (min > 0) { + this._setAndBind(child, dataNode); + } else { + uselessNodes.push(child); + } + } + + uselessNodes.forEach(node => node[_xfa_object.$getParent]()[_xfa_object.$removeChild](node)); + } + +} + +exports.Binder = Binder; + +/***/ }), +/* 82 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Value = exports.Text = exports.TemplateNamespace = exports.Template = exports.SetProperty = exports.Items = exports.Field = exports.BindItems = void 0; + +var _xfa_object = __w_pdfjs_require__(77); + +var _namespaces = __w_pdfjs_require__(79); + +var _layout = __w_pdfjs_require__(83); + +var _html_utils = __w_pdfjs_require__(84); + +var _utils = __w_pdfjs_require__(78); + +var _util = __w_pdfjs_require__(2); + +var _fonts = __w_pdfjs_require__(85); + +var _core_utils = __w_pdfjs_require__(6); + +var _som = __w_pdfjs_require__(80); + +const TEMPLATE_NS_ID = _namespaces.NamespaceIds.template.id; +const SVG_NS = "http://www.w3.org/2000/svg"; +const MAX_ATTEMPTS_FOR_LRTB_LAYOUT = 2; +const MAX_EMPTY_PAGES = 3; +const DEFAULT_TAB_INDEX = 5000; +const HEADING_PATTERN = /^H(\d+)$/; +const MIMES = new Set(["image/gif", "image/jpeg", "image/jpg", "image/pjpeg", "image/png", "image/apng", "image/x-png", "image/bmp", "image/x-ms-bmp", "image/tiff", "image/tif", "application/octet-stream"]); +const IMAGES_HEADERS = [[[0x42, 0x4d], "image/bmp"], [[0xff, 0xd8, 0xff], "image/jpeg"], [[0x49, 0x49, 0x2a, 0x00], "image/tiff"], [[0x4d, 0x4d, 0x00, 0x2a], "image/tiff"], [[0x47, 0x49, 0x46, 0x38, 0x39, 0x61], "image/gif"], [[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a], "image/png"]]; + +function getBorderDims(node) { + if (!node || !node.border) { + return { + w: 0, + h: 0 + }; + } + + const borderExtra = node.border[_xfa_object.$getExtra](); + + if (!borderExtra) { + return { + w: 0, + h: 0 + }; + } + + return { + w: borderExtra.widths[0] + borderExtra.widths[2] + borderExtra.insets[0] + borderExtra.insets[2], + h: borderExtra.widths[1] + borderExtra.widths[3] + borderExtra.insets[1] + borderExtra.insets[3] + }; +} + +function hasMargin(node) { + return node.margin && (node.margin.topInset || node.margin.rightInset || node.margin.bottomInset || node.margin.leftInset); +} + +function _setValue(templateNode, value) { + if (!templateNode.value) { + const nodeValue = new Value({}); + + templateNode[_xfa_object.$appendChild](nodeValue); + + templateNode.value = nodeValue; + } + + templateNode.value[_xfa_object.$setValue](value); +} + +function* getContainedChildren(node) { + for (const child of node[_xfa_object.$getChildren]()) { + if (child instanceof SubformSet) { + yield* child[_xfa_object.$getContainedChildren](); + continue; + } + + yield child; + } +} + +function isRequired(node) { + return node.validate && node.validate.nullTest === "error"; +} + +function setTabIndex(node) { + while (node) { + if (!node.traversal) { + node[_xfa_object.$tabIndex] = node[_xfa_object.$getParent]()[_xfa_object.$tabIndex]; + return; + } + + if (node[_xfa_object.$tabIndex]) { + return; + } + + let next = null; + + for (const child of node.traversal[_xfa_object.$getChildren]()) { + if (child.operation === "next") { + next = child; + break; + } + } + + if (!next || !next.ref) { + node[_xfa_object.$tabIndex] = node[_xfa_object.$getParent]()[_xfa_object.$tabIndex]; + return; + } + + const root = node[_xfa_object.$getTemplateRoot](); + + node[_xfa_object.$tabIndex] = ++root[_xfa_object.$tabIndex]; + + const ref = root[_xfa_object.$searchNode](next.ref, node); + + if (!ref) { + return; + } + + node = ref[0]; + } +} + +function applyAssist(obj, attributes) { + const assist = obj.assist; + + if (assist) { + const assistTitle = assist[_xfa_object.$toHTML](); + + if (assistTitle) { + attributes.title = assistTitle; + } + + const role = assist.role; + const match = role.match(HEADING_PATTERN); + + if (match) { + const ariaRole = "heading"; + const ariaLevel = match[1]; + attributes.role = ariaRole; + attributes["aria-level"] = ariaLevel; + } + } + + if (obj.layout === "table") { + attributes.role = "table"; + } else if (obj.layout === "row") { + attributes.role = "row"; + } else { + const parent = obj[_xfa_object.$getParent](); + + if (parent.layout === "row") { + if (parent.assist && parent.assist.role === "TH") { + attributes.role = "columnheader"; + } else { + attributes.role = "cell"; + } + } + } +} + +function ariaLabel(obj) { + if (!obj.assist) { + return null; + } + + const assist = obj.assist; + + if (assist.speak && assist.speak[_xfa_object.$content] !== "") { + return assist.speak[_xfa_object.$content]; + } + + if (assist.toolTip) { + return assist.toolTip[_xfa_object.$content]; + } + + return null; +} + +function valueToHtml(value) { + return _utils.HTMLResult.success({ + name: "div", + attributes: { + class: ["xfaRich"], + style: Object.create(null) + }, + children: [{ + name: "span", + attributes: { + style: Object.create(null) + }, + value + }] + }); +} + +function setFirstUnsplittable(node) { + const root = node[_xfa_object.$getTemplateRoot](); + + if (root[_xfa_object.$extra].firstUnsplittable === null) { + root[_xfa_object.$extra].firstUnsplittable = node; + root[_xfa_object.$extra].noLayoutFailure = true; + } +} + +function unsetFirstUnsplittable(node) { + const root = node[_xfa_object.$getTemplateRoot](); + + if (root[_xfa_object.$extra].firstUnsplittable === node) { + root[_xfa_object.$extra].noLayoutFailure = false; + } +} + +function handleBreak(node) { + if (node[_xfa_object.$extra]) { + return false; + } + + node[_xfa_object.$extra] = Object.create(null); + + if (node.targetType === "auto") { + return false; + } + + const root = node[_xfa_object.$getTemplateRoot](); + + let target = null; + + if (node.target) { + target = root[_xfa_object.$searchNode](node.target, node[_xfa_object.$getParent]()); + + if (!target) { + return false; + } + + target = target[0]; + } + + const { + currentPageArea, + currentContentArea + } = root[_xfa_object.$extra]; + + if (node.targetType === "pageArea") { + if (!(target instanceof PageArea)) { + target = null; + } + + if (node.startNew) { + node[_xfa_object.$extra].target = target || currentPageArea; + return true; + } else if (target && target !== currentPageArea) { + node[_xfa_object.$extra].target = target; + return true; + } + + return false; + } + + if (!(target instanceof ContentArea)) { + target = null; + } + + const pageArea = target && target[_xfa_object.$getParent](); + + let index; + let nextPageArea = pageArea; + + if (node.startNew) { + if (target) { + const contentAreas = pageArea.contentArea.children; + const indexForCurrent = contentAreas.indexOf(currentContentArea); + const indexForTarget = contentAreas.indexOf(target); + + if (indexForCurrent !== -1 && indexForCurrent < indexForTarget) { + nextPageArea = null; + } + + index = indexForTarget - 1; + } else { + index = currentPageArea.contentArea.children.indexOf(currentContentArea); + } + } else if (target && target !== currentContentArea) { + const contentAreas = pageArea.contentArea.children; + index = contentAreas.indexOf(target) - 1; + nextPageArea = pageArea === currentPageArea ? null : pageArea; + } else { + return false; + } + + node[_xfa_object.$extra].target = nextPageArea; + node[_xfa_object.$extra].index = index; + return true; +} + +function handleOverflow(node, extraNode, space) { + const root = node[_xfa_object.$getTemplateRoot](); + + const saved = root[_xfa_object.$extra].noLayoutFailure; + const savedMethod = extraNode[_xfa_object.$getSubformParent]; + + extraNode[_xfa_object.$getSubformParent] = () => node; + + root[_xfa_object.$extra].noLayoutFailure = true; + + const res = extraNode[_xfa_object.$toHTML](space); + + node[_xfa_object.$addHTML](res.html, res.bbox); + + root[_xfa_object.$extra].noLayoutFailure = saved; + extraNode[_xfa_object.$getSubformParent] = savedMethod; +} + +class AppearanceFilter extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "appearanceFilter"); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Arc extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "arc", true); + this.circular = (0, _utils.getInteger)({ + data: attributes.circular, + defaultValue: 0, + validate: x => x === 1 + }); + this.hand = (0, _utils.getStringOption)(attributes.hand, ["even", "left", "right"]); + this.id = attributes.id || ""; + this.startAngle = (0, _utils.getFloat)({ + data: attributes.startAngle, + defaultValue: 0, + validate: x => true + }); + this.sweepAngle = (0, _utils.getFloat)({ + data: attributes.sweepAngle, + defaultValue: 360, + validate: x => true + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.edge = null; + this.fill = null; + } + + [_xfa_object.$toHTML]() { + const edge = this.edge || new Edge({}); + + const edgeStyle = edge[_xfa_object.$toStyle](); + + const style = Object.create(null); + + if (this.fill && this.fill.presence === "visible") { + Object.assign(style, this.fill[_xfa_object.$toStyle]()); + } else { + style.fill = "transparent"; + } + + style.strokeWidth = (0, _html_utils.measureToString)(edge.presence === "visible" ? edge.thickness : 0); + style.stroke = edgeStyle.color; + let arc; + const attributes = { + xmlns: SVG_NS, + style: { + width: "100%", + height: "100%", + overflow: "visible" + } + }; + + if (this.sweepAngle === 360) { + arc = { + name: "ellipse", + attributes: { + xmlns: SVG_NS, + cx: "50%", + cy: "50%", + rx: "50%", + ry: "50%", + style + } + }; + } else { + const startAngle = this.startAngle * Math.PI / 180; + const sweepAngle = this.sweepAngle * Math.PI / 180; + const largeArc = this.sweepAngle > 180 ? 1 : 0; + const [x1, y1, x2, y2] = [50 * (1 + Math.cos(startAngle)), 50 * (1 - Math.sin(startAngle)), 50 * (1 + Math.cos(startAngle + sweepAngle)), 50 * (1 - Math.sin(startAngle + sweepAngle))]; + arc = { + name: "path", + attributes: { + xmlns: SVG_NS, + d: `M ${x1} ${y1} A 50 50 0 ${largeArc} 0 ${x2} ${y2}`, + vectorEffect: "non-scaling-stroke", + style + } + }; + Object.assign(attributes, { + viewBox: "0 0 100 100", + preserveAspectRatio: "none" + }); + } + + const svg = { + name: "svg", + children: [arc], + attributes + }; + + const parent = this[_xfa_object.$getParent]()[_xfa_object.$getParent](); + + if (hasMargin(parent)) { + return _utils.HTMLResult.success({ + name: "div", + attributes: { + style: { + display: "inline", + width: "100%", + height: "100%" + } + }, + children: [svg] + }); + } + + svg.attributes.style.position = "absolute"; + return _utils.HTMLResult.success(svg); + } + +} + +class Area extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "area", true); + this.colSpan = (0, _utils.getInteger)({ + data: attributes.colSpan, + defaultValue: 1, + validate: n => n >= 1 || n === -1 + }); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.x = (0, _utils.getMeasurement)(attributes.x, "0pt"); + this.y = (0, _utils.getMeasurement)(attributes.y, "0pt"); + this.desc = null; + this.extras = null; + this.area = new _xfa_object.XFAObjectArray(); + this.draw = new _xfa_object.XFAObjectArray(); + this.exObject = new _xfa_object.XFAObjectArray(); + this.exclGroup = new _xfa_object.XFAObjectArray(); + this.field = new _xfa_object.XFAObjectArray(); + this.subform = new _xfa_object.XFAObjectArray(); + this.subformSet = new _xfa_object.XFAObjectArray(); + } + + *[_xfa_object.$getContainedChildren]() { + yield* getContainedChildren(this); + } + + [_xfa_object.$isTransparent]() { + return true; + } + + [_xfa_object.$isBindable]() { + return true; + } + + [_xfa_object.$addHTML](html, bbox) { + const [x, y, w, h] = bbox; + this[_xfa_object.$extra].width = Math.max(this[_xfa_object.$extra].width, x + w); + this[_xfa_object.$extra].height = Math.max(this[_xfa_object.$extra].height, y + h); + + this[_xfa_object.$extra].children.push(html); + } + + [_xfa_object.$getAvailableSpace]() { + return this[_xfa_object.$extra].availableSpace; + } + + [_xfa_object.$toHTML](availableSpace) { + const style = (0, _html_utils.toStyle)(this, "position"); + const attributes = { + style, + id: this[_xfa_object.$uid], + class: ["xfaArea"] + }; + + if ((0, _html_utils.isPrintOnly)(this)) { + attributes.class.push("xfaPrintOnly"); + } + + if (this.name) { + attributes.xfaName = this.name; + } + + const children = []; + this[_xfa_object.$extra] = { + children, + width: 0, + height: 0, + availableSpace + }; + + const result = this[_xfa_object.$childrenToHTML]({ + filter: new Set(["area", "draw", "field", "exclGroup", "subform", "subformSet"]), + include: true + }); + + if (!result.success) { + if (result.isBreak()) { + return result; + } + + delete this[_xfa_object.$extra]; + return _utils.HTMLResult.FAILURE; + } + + style.width = (0, _html_utils.measureToString)(this[_xfa_object.$extra].width); + style.height = (0, _html_utils.measureToString)(this[_xfa_object.$extra].height); + const html = { + name: "div", + attributes, + children + }; + const bbox = [this.x, this.y, this[_xfa_object.$extra].width, this[_xfa_object.$extra].height]; + delete this[_xfa_object.$extra]; + return _utils.HTMLResult.success(html, bbox); + } + +} + +class Assist extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "assist", true); + this.id = attributes.id || ""; + this.role = attributes.role || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.speak = null; + this.toolTip = null; + } + + [_xfa_object.$toHTML]() { + return this.toolTip && this.toolTip[_xfa_object.$content] ? this.toolTip[_xfa_object.$content] : null; + } + +} + +class Barcode extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "barcode", true); + this.charEncoding = (0, _utils.getKeyword)({ + data: attributes.charEncoding ? attributes.charEncoding.toLowerCase() : "", + defaultValue: "", + validate: k => ["utf-8", "big-five", "fontspecific", "gbk", "gb-18030", "gb-2312", "ksc-5601", "none", "shift-jis", "ucs-2", "utf-16"].includes(k) || k.match(/iso-8859-\d{2}/) + }); + this.checksum = (0, _utils.getStringOption)(attributes.checksum, ["none", "1mod10", "1mod10_1mod11", "2mod10", "auto"]); + this.dataColumnCount = (0, _utils.getInteger)({ + data: attributes.dataColumnCount, + defaultValue: -1, + validate: x => x >= 0 + }); + this.dataLength = (0, _utils.getInteger)({ + data: attributes.dataLength, + defaultValue: -1, + validate: x => x >= 0 + }); + this.dataPrep = (0, _utils.getStringOption)(attributes.dataPrep, ["none", "flateCompress"]); + this.dataRowCount = (0, _utils.getInteger)({ + data: attributes.dataRowCount, + defaultValue: -1, + validate: x => x >= 0 + }); + this.endChar = attributes.endChar || ""; + this.errorCorrectionLevel = (0, _utils.getInteger)({ + data: attributes.errorCorrectionLevel, + defaultValue: -1, + validate: x => x >= 0 && x <= 8 + }); + this.id = attributes.id || ""; + this.moduleHeight = (0, _utils.getMeasurement)(attributes.moduleHeight, "5mm"); + this.moduleWidth = (0, _utils.getMeasurement)(attributes.moduleWidth, "0.25mm"); + this.printCheckDigit = (0, _utils.getInteger)({ + data: attributes.printCheckDigit, + defaultValue: 0, + validate: x => x === 1 + }); + this.rowColumnRatio = (0, _utils.getRatio)(attributes.rowColumnRatio); + this.startChar = attributes.startChar || ""; + this.textLocation = (0, _utils.getStringOption)(attributes.textLocation, ["below", "above", "aboveEmbedded", "belowEmbedded", "none"]); + this.truncate = (0, _utils.getInteger)({ + data: attributes.truncate, + defaultValue: 0, + validate: x => x === 1 + }); + this.type = (0, _utils.getStringOption)(attributes.type ? attributes.type.toLowerCase() : "", ["aztec", "codabar", "code2of5industrial", "code2of5interleaved", "code2of5matrix", "code2of5standard", "code3of9", "code3of9extended", "code11", "code49", "code93", "code128", "code128a", "code128b", "code128c", "code128sscc", "datamatrix", "ean8", "ean8add2", "ean8add5", "ean13", "ean13add2", "ean13add5", "ean13pwcd", "fim", "logmars", "maxicode", "msi", "pdf417", "pdf417macro", "plessey", "postauscust2", "postauscust3", "postausreplypaid", "postausstandard", "postukrm4scc", "postusdpbc", "postusimb", "postusstandard", "postus5zip", "qrcode", "rfid", "rss14", "rss14expanded", "rss14limited", "rss14stacked", "rss14stackedomni", "rss14truncated", "telepen", "ucc128", "ucc128random", "ucc128sscc", "upca", "upcaadd2", "upcaadd5", "upcapwcd", "upce", "upceadd2", "upceadd5", "upcean2", "upcean5", "upsmaxicode"]); + this.upsMode = (0, _utils.getStringOption)(attributes.upsMode, ["usCarrier", "internationalCarrier", "secureSymbol", "standardSymbol"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.wideNarrowRatio = (0, _utils.getRatio)(attributes.wideNarrowRatio); + this.encrypt = null; + this.extras = null; + } + +} + +class Bind extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "bind", true); + this.match = (0, _utils.getStringOption)(attributes.match, ["once", "dataRef", "global", "none"]); + this.ref = attributes.ref || ""; + this.picture = null; + } + +} + +class BindItems extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "bindItems"); + this.connection = attributes.connection || ""; + this.labelRef = attributes.labelRef || ""; + this.ref = attributes.ref || ""; + this.valueRef = attributes.valueRef || ""; + } + +} + +exports.BindItems = BindItems; + +class Bookend extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "bookend"); + this.id = attributes.id || ""; + this.leader = attributes.leader || ""; + this.trailer = attributes.trailer || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class BooleanElement extends _xfa_object.Option01 { + constructor(attributes) { + super(TEMPLATE_NS_ID, "boolean"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$toHTML](availableSpace) { + return valueToHtml(this[_xfa_object.$content] === 1 ? "1" : "0"); + } + +} + +class Border extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "border", true); + this.break = (0, _utils.getStringOption)(attributes.break, ["close", "open"]); + this.hand = (0, _utils.getStringOption)(attributes.hand, ["even", "left", "right"]); + this.id = attributes.id || ""; + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.corner = new _xfa_object.XFAObjectArray(4); + this.edge = new _xfa_object.XFAObjectArray(4); + this.extras = null; + this.fill = null; + this.margin = null; + } + + [_xfa_object.$getExtra]() { + if (!this[_xfa_object.$extra]) { + const edges = this.edge.children.slice(); + + if (edges.length < 4) { + const defaultEdge = edges.at(-1) || new Edge({}); + + for (let i = edges.length; i < 4; i++) { + edges.push(defaultEdge); + } + } + + const widths = edges.map(edge => edge.thickness); + const insets = [0, 0, 0, 0]; + + if (this.margin) { + insets[0] = this.margin.topInset; + insets[1] = this.margin.rightInset; + insets[2] = this.margin.bottomInset; + insets[3] = this.margin.leftInset; + } + + this[_xfa_object.$extra] = { + widths, + insets, + edges + }; + } + + return this[_xfa_object.$extra]; + } + + [_xfa_object.$toStyle]() { + const { + edges + } = this[_xfa_object.$getExtra](); + + const edgeStyles = edges.map(node => { + const style = node[_xfa_object.$toStyle](); + + style.color = style.color || "#000000"; + return style; + }); + const style = Object.create(null); + + if (this.margin) { + Object.assign(style, this.margin[_xfa_object.$toStyle]()); + } + + if (this.fill && this.fill.presence === "visible") { + Object.assign(style, this.fill[_xfa_object.$toStyle]()); + } + + if (this.corner.children.some(node => node.radius !== 0)) { + const cornerStyles = this.corner.children.map(node => node[_xfa_object.$toStyle]()); + + if (cornerStyles.length === 2 || cornerStyles.length === 3) { + const last = cornerStyles.at(-1); + + for (let i = cornerStyles.length; i < 4; i++) { + cornerStyles.push(last); + } + } + + style.borderRadius = cornerStyles.map(s => s.radius).join(" "); + } + + switch (this.presence) { + case "invisible": + case "hidden": + style.borderStyle = ""; + break; + + case "inactive": + style.borderStyle = "none"; + break; + + default: + style.borderStyle = edgeStyles.map(s => s.style).join(" "); + break; + } + + style.borderWidth = edgeStyles.map(s => s.width).join(" "); + style.borderColor = edgeStyles.map(s => s.color).join(" "); + return style; + } + +} + +class Break extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "break", true); + this.after = (0, _utils.getStringOption)(attributes.after, ["auto", "contentArea", "pageArea", "pageEven", "pageOdd"]); + this.afterTarget = attributes.afterTarget || ""; + this.before = (0, _utils.getStringOption)(attributes.before, ["auto", "contentArea", "pageArea", "pageEven", "pageOdd"]); + this.beforeTarget = attributes.beforeTarget || ""; + this.bookendLeader = attributes.bookendLeader || ""; + this.bookendTrailer = attributes.bookendTrailer || ""; + this.id = attributes.id || ""; + this.overflowLeader = attributes.overflowLeader || ""; + this.overflowTarget = attributes.overflowTarget || ""; + this.overflowTrailer = attributes.overflowTrailer || ""; + this.startNew = (0, _utils.getInteger)({ + data: attributes.startNew, + defaultValue: 0, + validate: x => x === 1 + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + } + +} + +class BreakAfter extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "breakAfter", true); + this.id = attributes.id || ""; + this.leader = attributes.leader || ""; + this.startNew = (0, _utils.getInteger)({ + data: attributes.startNew, + defaultValue: 0, + validate: x => x === 1 + }); + this.target = attributes.target || ""; + this.targetType = (0, _utils.getStringOption)(attributes.targetType, ["auto", "contentArea", "pageArea"]); + this.trailer = attributes.trailer || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.script = null; + } + +} + +class BreakBefore extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "breakBefore", true); + this.id = attributes.id || ""; + this.leader = attributes.leader || ""; + this.startNew = (0, _utils.getInteger)({ + data: attributes.startNew, + defaultValue: 0, + validate: x => x === 1 + }); + this.target = attributes.target || ""; + this.targetType = (0, _utils.getStringOption)(attributes.targetType, ["auto", "contentArea", "pageArea"]); + this.trailer = attributes.trailer || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.script = null; + } + + [_xfa_object.$toHTML](availableSpace) { + this[_xfa_object.$extra] = {}; + return _utils.HTMLResult.FAILURE; + } + +} + +class Button extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "button", true); + this.highlight = (0, _utils.getStringOption)(attributes.highlight, ["inverted", "none", "outline", "push"]); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + } + + [_xfa_object.$toHTML](availableSpace) { + const parent = this[_xfa_object.$getParent](); + + const grandpa = parent[_xfa_object.$getParent](); + + const htmlButton = { + name: "button", + attributes: { + id: this[_xfa_object.$uid], + class: ["xfaButton"], + style: {} + }, + children: [] + }; + + for (const event of grandpa.event.children) { + if (event.activity !== "click" || !event.script) { + continue; + } + + const jsURL = (0, _core_utils.recoverJsURL)(event.script[_xfa_object.$content]); + + if (!jsURL) { + continue; + } + + const href = (0, _html_utils.fixURL)(jsURL.url); + + if (!href) { + continue; + } + + htmlButton.children.push({ + name: "a", + attributes: { + id: "link" + this[_xfa_object.$uid], + href, + newWindow: jsURL.newWindow, + class: ["xfaLink"], + style: {} + }, + children: [] + }); + } + + return _utils.HTMLResult.success(htmlButton); + } + +} + +class Calculate extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "calculate", true); + this.id = attributes.id || ""; + this.override = (0, _utils.getStringOption)(attributes.override, ["disabled", "error", "ignore", "warning"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.message = null; + this.script = null; + } + +} + +class Caption extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "caption", true); + this.id = attributes.id || ""; + this.placement = (0, _utils.getStringOption)(attributes.placement, ["left", "bottom", "inline", "right", "top"]); + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.reserve = Math.ceil((0, _utils.getMeasurement)(attributes.reserve)); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.font = null; + this.margin = null; + this.para = null; + this.value = null; + } + + [_xfa_object.$setValue](value) { + _setValue(this, value); + } + + [_xfa_object.$getExtra](availableSpace) { + if (!this[_xfa_object.$extra]) { + let { + width, + height + } = availableSpace; + + switch (this.placement) { + case "left": + case "right": + case "inline": + width = this.reserve <= 0 ? width : this.reserve; + break; + + case "top": + case "bottom": + height = this.reserve <= 0 ? height : this.reserve; + break; + } + + this[_xfa_object.$extra] = (0, _html_utils.layoutNode)(this, { + width, + height + }); + } + + return this[_xfa_object.$extra]; + } + + [_xfa_object.$toHTML](availableSpace) { + if (!this.value) { + return _utils.HTMLResult.EMPTY; + } + + this[_xfa_object.$pushPara](); + + const value = this.value[_xfa_object.$toHTML](availableSpace).html; + + if (!value) { + this[_xfa_object.$popPara](); + + return _utils.HTMLResult.EMPTY; + } + + const savedReserve = this.reserve; + + if (this.reserve <= 0) { + const { + w, + h + } = this[_xfa_object.$getExtra](availableSpace); + + switch (this.placement) { + case "left": + case "right": + case "inline": + this.reserve = w; + break; + + case "top": + case "bottom": + this.reserve = h; + break; + } + } + + const children = []; + + if (typeof value === "string") { + children.push({ + name: "#text", + value + }); + } else { + children.push(value); + } + + const style = (0, _html_utils.toStyle)(this, "font", "margin", "visibility"); + + switch (this.placement) { + case "left": + case "right": + if (this.reserve > 0) { + style.width = (0, _html_utils.measureToString)(this.reserve); + } + + break; + + case "top": + case "bottom": + if (this.reserve > 0) { + style.height = (0, _html_utils.measureToString)(this.reserve); + } + + break; + } + + (0, _html_utils.setPara)(this, null, value); + + this[_xfa_object.$popPara](); + + this.reserve = savedReserve; + return _utils.HTMLResult.success({ + name: "div", + attributes: { + style, + class: ["xfaCaption"] + }, + children + }); + } + +} + +class Certificate extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "certificate"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Certificates extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "certificates", true); + this.credentialServerPolicy = (0, _utils.getStringOption)(attributes.credentialServerPolicy, ["optional", "required"]); + this.id = attributes.id || ""; + this.url = attributes.url || ""; + this.urlPolicy = attributes.urlPolicy || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.encryption = null; + this.issuers = null; + this.keyUsage = null; + this.oids = null; + this.signing = null; + this.subjectDNs = null; + } + +} + +class CheckButton extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "checkButton", true); + this.id = attributes.id || ""; + this.mark = (0, _utils.getStringOption)(attributes.mark, ["default", "check", "circle", "cross", "diamond", "square", "star"]); + this.shape = (0, _utils.getStringOption)(attributes.shape, ["square", "round"]); + this.size = (0, _utils.getMeasurement)(attributes.size, "10pt"); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.border = null; + this.extras = null; + this.margin = null; + } + + [_xfa_object.$toHTML](availableSpace) { + const style = (0, _html_utils.toStyle)("margin"); + const size = (0, _html_utils.measureToString)(this.size); + style.width = style.height = size; + let type; + let className; + let groupId; + + const field = this[_xfa_object.$getParent]()[_xfa_object.$getParent](); + + const items = field.items.children.length && field.items.children[0][_xfa_object.$toHTML]().html || []; + const exportedValue = { + on: (items[0] !== undefined ? items[0] : "on").toString(), + off: (items[1] !== undefined ? items[1] : "off").toString() + }; + const value = field.value && field.value[_xfa_object.$text]() || "off"; + const checked = value === exportedValue.on || undefined; + + const container = field[_xfa_object.$getSubformParent](); + + const fieldId = field[_xfa_object.$uid]; + let dataId; + + if (container instanceof ExclGroup) { + groupId = container[_xfa_object.$uid]; + type = "radio"; + className = "xfaRadio"; + dataId = container[_xfa_object.$data] && container[_xfa_object.$data][_xfa_object.$uid] || container[_xfa_object.$uid]; + } else { + type = "checkbox"; + className = "xfaCheckbox"; + dataId = field[_xfa_object.$data] && field[_xfa_object.$data][_xfa_object.$uid] || field[_xfa_object.$uid]; + } + + const input = { + name: "input", + attributes: { + class: [className], + style, + fieldId, + dataId, + type, + checked, + xfaOn: exportedValue.on, + xfaOff: exportedValue.off, + "aria-label": ariaLabel(field), + "aria-required": false + } + }; + + if (groupId) { + input.attributes.name = groupId; + } + + if (isRequired(field)) { + input.attributes["aria-required"] = true; + input.attributes.required = true; + } + + return _utils.HTMLResult.success({ + name: "label", + attributes: { + class: ["xfaLabel"] + }, + children: [input] + }); + } + +} + +class ChoiceList extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "choiceList", true); + this.commitOn = (0, _utils.getStringOption)(attributes.commitOn, ["select", "exit"]); + this.id = attributes.id || ""; + this.open = (0, _utils.getStringOption)(attributes.open, ["userControl", "always", "multiSelect", "onEntry"]); + this.textEntry = (0, _utils.getInteger)({ + data: attributes.textEntry, + defaultValue: 0, + validate: x => x === 1 + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.border = null; + this.extras = null; + this.margin = null; + } + + [_xfa_object.$toHTML](availableSpace) { + const style = (0, _html_utils.toStyle)(this, "border", "margin"); + + const ui = this[_xfa_object.$getParent](); + + const field = ui[_xfa_object.$getParent](); + + const fontSize = field.font && field.font.size || 10; + const optionStyle = { + fontSize: `calc(${fontSize}px * var(--scale-factor))` + }; + const children = []; + + if (field.items.children.length > 0) { + const items = field.items; + let displayedIndex = 0; + let saveIndex = 0; + + if (items.children.length === 2) { + displayedIndex = items.children[0].save; + saveIndex = 1 - displayedIndex; + } + + const displayed = items.children[displayedIndex][_xfa_object.$toHTML]().html; + + const values = items.children[saveIndex][_xfa_object.$toHTML]().html; + + let selected = false; + const value = field.value && field.value[_xfa_object.$text]() || ""; + + for (let i = 0, ii = displayed.length; i < ii; i++) { + const option = { + name: "option", + attributes: { + value: values[i] || displayed[i], + style: optionStyle + }, + value: displayed[i] + }; + + if (values[i] === value) { + option.attributes.selected = selected = true; + } + + children.push(option); + } + + if (!selected) { + children.splice(0, 0, { + name: "option", + attributes: { + hidden: true, + selected: true + }, + value: " " + }); + } + } + + const selectAttributes = { + class: ["xfaSelect"], + fieldId: field[_xfa_object.$uid], + dataId: field[_xfa_object.$data] && field[_xfa_object.$data][_xfa_object.$uid] || field[_xfa_object.$uid], + style, + "aria-label": ariaLabel(field), + "aria-required": false + }; + + if (isRequired(field)) { + selectAttributes["aria-required"] = true; + selectAttributes.required = true; + } + + if (this.open === "multiSelect") { + selectAttributes.multiple = true; + } + + return _utils.HTMLResult.success({ + name: "label", + attributes: { + class: ["xfaLabel"] + }, + children: [{ + name: "select", + children, + attributes: selectAttributes + }] + }); + } + +} + +class Color extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "color", true); + this.cSpace = (0, _utils.getStringOption)(attributes.cSpace, ["SRGB"]); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.value = attributes.value ? (0, _utils.getColor)(attributes.value) : ""; + this.extras = null; + } + + [_xfa_object.$hasSettableValue]() { + return false; + } + + [_xfa_object.$toStyle]() { + return this.value ? _util.Util.makeHexColor(this.value.r, this.value.g, this.value.b) : null; + } + +} + +class Comb extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "comb"); + this.id = attributes.id || ""; + this.numberOfCells = (0, _utils.getInteger)({ + data: attributes.numberOfCells, + defaultValue: 0, + validate: x => x >= 0 + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Connect extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "connect", true); + this.connection = attributes.connection || ""; + this.id = attributes.id || ""; + this.ref = attributes.ref || ""; + this.usage = (0, _utils.getStringOption)(attributes.usage, ["exportAndImport", "exportOnly", "importOnly"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.picture = null; + } + +} + +class ContentArea extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "contentArea", true); + this.h = (0, _utils.getMeasurement)(attributes.h); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.w = (0, _utils.getMeasurement)(attributes.w); + this.x = (0, _utils.getMeasurement)(attributes.x, "0pt"); + this.y = (0, _utils.getMeasurement)(attributes.y, "0pt"); + this.desc = null; + this.extras = null; + } + + [_xfa_object.$toHTML](availableSpace) { + const left = (0, _html_utils.measureToString)(this.x); + const top = (0, _html_utils.measureToString)(this.y); + const style = { + left, + top, + width: (0, _html_utils.measureToString)(this.w), + height: (0, _html_utils.measureToString)(this.h) + }; + const classNames = ["xfaContentarea"]; + + if ((0, _html_utils.isPrintOnly)(this)) { + classNames.push("xfaPrintOnly"); + } + + return _utils.HTMLResult.success({ + name: "div", + children: [], + attributes: { + style, + class: classNames, + id: this[_xfa_object.$uid] + } + }); + } + +} + +class Corner extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "corner", true); + this.id = attributes.id || ""; + this.inverted = (0, _utils.getInteger)({ + data: attributes.inverted, + defaultValue: 0, + validate: x => x === 1 + }); + this.join = (0, _utils.getStringOption)(attributes.join, ["square", "round"]); + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.radius = (0, _utils.getMeasurement)(attributes.radius); + this.stroke = (0, _utils.getStringOption)(attributes.stroke, ["solid", "dashDot", "dashDotDot", "dashed", "dotted", "embossed", "etched", "lowered", "raised"]); + this.thickness = (0, _utils.getMeasurement)(attributes.thickness, "0.5pt"); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.color = null; + this.extras = null; + } + + [_xfa_object.$toStyle]() { + const style = (0, _html_utils.toStyle)(this, "visibility"); + style.radius = (0, _html_utils.measureToString)(this.join === "square" ? 0 : this.radius); + return style; + } + +} + +class DateElement extends _xfa_object.ContentObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "date"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$finalize]() { + const date = this[_xfa_object.$content].trim(); + + this[_xfa_object.$content] = date ? new Date(date) : null; + } + + [_xfa_object.$toHTML](availableSpace) { + return valueToHtml(this[_xfa_object.$content] ? this[_xfa_object.$content].toString() : ""); + } + +} + +class DateTime extends _xfa_object.ContentObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "dateTime"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$finalize]() { + const date = this[_xfa_object.$content].trim(); + + this[_xfa_object.$content] = date ? new Date(date) : null; + } + + [_xfa_object.$toHTML](availableSpace) { + return valueToHtml(this[_xfa_object.$content] ? this[_xfa_object.$content].toString() : ""); + } + +} + +class DateTimeEdit extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "dateTimeEdit", true); + this.hScrollPolicy = (0, _utils.getStringOption)(attributes.hScrollPolicy, ["auto", "off", "on"]); + this.id = attributes.id || ""; + this.picker = (0, _utils.getStringOption)(attributes.picker, ["host", "none"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.border = null; + this.comb = null; + this.extras = null; + this.margin = null; + } + + [_xfa_object.$toHTML](availableSpace) { + const style = (0, _html_utils.toStyle)(this, "border", "font", "margin"); + + const field = this[_xfa_object.$getParent]()[_xfa_object.$getParent](); + + const html = { + name: "input", + attributes: { + type: "text", + fieldId: field[_xfa_object.$uid], + dataId: field[_xfa_object.$data] && field[_xfa_object.$data][_xfa_object.$uid] || field[_xfa_object.$uid], + class: ["xfaTextfield"], + style, + "aria-label": ariaLabel(field), + "aria-required": false + } + }; + + if (isRequired(field)) { + html.attributes["aria-required"] = true; + html.attributes.required = true; + } + + return _utils.HTMLResult.success({ + name: "label", + attributes: { + class: ["xfaLabel"] + }, + children: [html] + }); + } + +} + +class Decimal extends _xfa_object.ContentObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "decimal"); + this.fracDigits = (0, _utils.getInteger)({ + data: attributes.fracDigits, + defaultValue: 2, + validate: x => true + }); + this.id = attributes.id || ""; + this.leadDigits = (0, _utils.getInteger)({ + data: attributes.leadDigits, + defaultValue: -1, + validate: x => true + }); + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$finalize]() { + const number = parseFloat(this[_xfa_object.$content].trim()); + this[_xfa_object.$content] = isNaN(number) ? null : number; + } + + [_xfa_object.$toHTML](availableSpace) { + return valueToHtml(this[_xfa_object.$content] !== null ? this[_xfa_object.$content].toString() : ""); + } + +} + +class DefaultUi extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "defaultUi", true); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + } + +} + +class Desc extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "desc", true); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.boolean = new _xfa_object.XFAObjectArray(); + this.date = new _xfa_object.XFAObjectArray(); + this.dateTime = new _xfa_object.XFAObjectArray(); + this.decimal = new _xfa_object.XFAObjectArray(); + this.exData = new _xfa_object.XFAObjectArray(); + this.float = new _xfa_object.XFAObjectArray(); + this.image = new _xfa_object.XFAObjectArray(); + this.integer = new _xfa_object.XFAObjectArray(); + this.text = new _xfa_object.XFAObjectArray(); + this.time = new _xfa_object.XFAObjectArray(); + } + +} + +class DigestMethod extends _xfa_object.OptionObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "digestMethod", ["", "SHA1", "SHA256", "SHA512", "RIPEMD160"]); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class DigestMethods extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "digestMethods", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.digestMethod = new _xfa_object.XFAObjectArray(); + } + +} + +class Draw extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "draw", true); + this.anchorType = (0, _utils.getStringOption)(attributes.anchorType, ["topLeft", "bottomCenter", "bottomLeft", "bottomRight", "middleCenter", "middleLeft", "middleRight", "topCenter", "topRight"]); + this.colSpan = (0, _utils.getInteger)({ + data: attributes.colSpan, + defaultValue: 1, + validate: n => n >= 1 || n === -1 + }); + this.h = attributes.h ? (0, _utils.getMeasurement)(attributes.h) : ""; + this.hAlign = (0, _utils.getStringOption)(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]); + this.id = attributes.id || ""; + this.locale = attributes.locale || ""; + this.maxH = (0, _utils.getMeasurement)(attributes.maxH, "0pt"); + this.maxW = (0, _utils.getMeasurement)(attributes.maxW, "0pt"); + this.minH = (0, _utils.getMeasurement)(attributes.minH, "0pt"); + this.minW = (0, _utils.getMeasurement)(attributes.minW, "0pt"); + this.name = attributes.name || ""; + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.rotate = (0, _utils.getInteger)({ + data: attributes.rotate, + defaultValue: 0, + validate: x => x % 90 === 0 + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.w = attributes.w ? (0, _utils.getMeasurement)(attributes.w) : ""; + this.x = (0, _utils.getMeasurement)(attributes.x, "0pt"); + this.y = (0, _utils.getMeasurement)(attributes.y, "0pt"); + this.assist = null; + this.border = null; + this.caption = null; + this.desc = null; + this.extras = null; + this.font = null; + this.keep = null; + this.margin = null; + this.para = null; + this.traversal = null; + this.ui = null; + this.value = null; + this.setProperty = new _xfa_object.XFAObjectArray(); + } + + [_xfa_object.$setValue](value) { + _setValue(this, value); + } + + [_xfa_object.$toHTML](availableSpace) { + setTabIndex(this); + + if (this.presence === "hidden" || this.presence === "inactive") { + return _utils.HTMLResult.EMPTY; + } + + (0, _html_utils.fixDimensions)(this); + + this[_xfa_object.$pushPara](); + + const savedW = this.w; + const savedH = this.h; + const { + w, + h, + isBroken + } = (0, _html_utils.layoutNode)(this, availableSpace); + + if (w && this.w === "") { + if (isBroken && this[_xfa_object.$getSubformParent]()[_xfa_object.$isThereMoreWidth]()) { + this[_xfa_object.$popPara](); + + return _utils.HTMLResult.FAILURE; + } + + this.w = w; + } + + if (h && this.h === "") { + this.h = h; + } + + setFirstUnsplittable(this); + + if (!(0, _layout.checkDimensions)(this, availableSpace)) { + this.w = savedW; + this.h = savedH; + + this[_xfa_object.$popPara](); + + return _utils.HTMLResult.FAILURE; + } + + unsetFirstUnsplittable(this); + const style = (0, _html_utils.toStyle)(this, "font", "hAlign", "dimensions", "position", "presence", "rotate", "anchorType", "border", "margin"); + (0, _html_utils.setMinMaxDimensions)(this, style); + + if (style.margin) { + style.padding = style.margin; + delete style.margin; + } + + const classNames = ["xfaDraw"]; + + if (this.font) { + classNames.push("xfaFont"); + } + + if ((0, _html_utils.isPrintOnly)(this)) { + classNames.push("xfaPrintOnly"); + } + + const attributes = { + style, + id: this[_xfa_object.$uid], + class: classNames + }; + + if (this.name) { + attributes.xfaName = this.name; + } + + const html = { + name: "div", + attributes, + children: [] + }; + applyAssist(this, attributes); + const bbox = (0, _html_utils.computeBbox)(this, html, availableSpace); + const value = this.value ? this.value[_xfa_object.$toHTML](availableSpace).html : null; + + if (value === null) { + this.w = savedW; + this.h = savedH; + + this[_xfa_object.$popPara](); + + return _utils.HTMLResult.success((0, _html_utils.createWrapper)(this, html), bbox); + } + + html.children.push(value); + (0, _html_utils.setPara)(this, style, value); + this.w = savedW; + this.h = savedH; + + this[_xfa_object.$popPara](); + + return _utils.HTMLResult.success((0, _html_utils.createWrapper)(this, html), bbox); + } + +} + +class Edge extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "edge", true); + this.cap = (0, _utils.getStringOption)(attributes.cap, ["square", "butt", "round"]); + this.id = attributes.id || ""; + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.stroke = (0, _utils.getStringOption)(attributes.stroke, ["solid", "dashDot", "dashDotDot", "dashed", "dotted", "embossed", "etched", "lowered", "raised"]); + this.thickness = (0, _utils.getMeasurement)(attributes.thickness, "0.5pt"); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.color = null; + this.extras = null; + } + + [_xfa_object.$toStyle]() { + const style = (0, _html_utils.toStyle)(this, "visibility"); + Object.assign(style, { + linecap: this.cap, + width: (0, _html_utils.measureToString)(this.thickness), + color: this.color ? this.color[_xfa_object.$toStyle]() : "#000000", + style: "" + }); + + if (this.presence !== "visible") { + style.style = "none"; + } else { + switch (this.stroke) { + case "solid": + style.style = "solid"; + break; + + case "dashDot": + style.style = "dashed"; + break; + + case "dashDotDot": + style.style = "dashed"; + break; + + case "dashed": + style.style = "dashed"; + break; + + case "dotted": + style.style = "dotted"; + break; + + case "embossed": + style.style = "ridge"; + break; + + case "etched": + style.style = "groove"; + break; + + case "lowered": + style.style = "inset"; + break; + + case "raised": + style.style = "outset"; + break; + } + } + + return style; + } + +} + +class Encoding extends _xfa_object.OptionObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "encoding", ["adbe.x509.rsa_sha1", "adbe.pkcs7.detached", "adbe.pkcs7.sha1"]); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Encodings extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "encodings", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.encoding = new _xfa_object.XFAObjectArray(); + } + +} + +class Encrypt extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "encrypt", true); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.certificate = null; + } + +} + +class EncryptData extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "encryptData", true); + this.id = attributes.id || ""; + this.operation = (0, _utils.getStringOption)(attributes.operation, ["encrypt", "decrypt"]); + this.target = attributes.target || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.filter = null; + this.manifest = null; + } + +} + +class Encryption extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "encryption", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.certificate = new _xfa_object.XFAObjectArray(); + } + +} + +class EncryptionMethod extends _xfa_object.OptionObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "encryptionMethod", ["", "AES256-CBC", "TRIPLEDES-CBC", "AES128-CBC", "AES192-CBC"]); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class EncryptionMethods extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "encryptionMethods", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.encryptionMethod = new _xfa_object.XFAObjectArray(); + } + +} + +class Event extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "event", true); + this.activity = (0, _utils.getStringOption)(attributes.activity, ["click", "change", "docClose", "docReady", "enter", "exit", "full", "indexChange", "initialize", "mouseDown", "mouseEnter", "mouseExit", "mouseUp", "postExecute", "postOpen", "postPrint", "postSave", "postSign", "postSubmit", "preExecute", "preOpen", "prePrint", "preSave", "preSign", "preSubmit", "ready", "validationState"]); + this.id = attributes.id || ""; + this.listen = (0, _utils.getStringOption)(attributes.listen, ["refOnly", "refAndDescendents"]); + this.name = attributes.name || ""; + this.ref = attributes.ref || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.encryptData = null; + this.execute = null; + this.script = null; + this.signData = null; + this.submit = null; + } + +} + +class ExData extends _xfa_object.ContentObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "exData"); + this.contentType = attributes.contentType || ""; + this.href = attributes.href || ""; + this.id = attributes.id || ""; + this.maxLength = (0, _utils.getInteger)({ + data: attributes.maxLength, + defaultValue: -1, + validate: x => x >= -1 + }); + this.name = attributes.name || ""; + this.rid = attributes.rid || ""; + this.transferEncoding = (0, _utils.getStringOption)(attributes.transferEncoding, ["none", "base64", "package"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$isCDATAXml]() { + return this.contentType === "text/html"; + } + + [_xfa_object.$onChild](child) { + if (this.contentType === "text/html" && child[_xfa_object.$namespaceId] === _namespaces.NamespaceIds.xhtml.id) { + this[_xfa_object.$content] = child; + return true; + } + + if (this.contentType === "text/xml") { + this[_xfa_object.$content] = child; + return true; + } + + return false; + } + + [_xfa_object.$toHTML](availableSpace) { + if (this.contentType !== "text/html" || !this[_xfa_object.$content]) { + return _utils.HTMLResult.EMPTY; + } + + return this[_xfa_object.$content][_xfa_object.$toHTML](availableSpace); + } + +} + +class ExObject extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "exObject", true); + this.archive = attributes.archive || ""; + this.classId = attributes.classId || ""; + this.codeBase = attributes.codeBase || ""; + this.codeType = attributes.codeType || ""; + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.boolean = new _xfa_object.XFAObjectArray(); + this.date = new _xfa_object.XFAObjectArray(); + this.dateTime = new _xfa_object.XFAObjectArray(); + this.decimal = new _xfa_object.XFAObjectArray(); + this.exData = new _xfa_object.XFAObjectArray(); + this.exObject = new _xfa_object.XFAObjectArray(); + this.float = new _xfa_object.XFAObjectArray(); + this.image = new _xfa_object.XFAObjectArray(); + this.integer = new _xfa_object.XFAObjectArray(); + this.text = new _xfa_object.XFAObjectArray(); + this.time = new _xfa_object.XFAObjectArray(); + } + +} + +class ExclGroup extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "exclGroup", true); + this.access = (0, _utils.getStringOption)(attributes.access, ["open", "nonInteractive", "protected", "readOnly"]); + this.accessKey = attributes.accessKey || ""; + this.anchorType = (0, _utils.getStringOption)(attributes.anchorType, ["topLeft", "bottomCenter", "bottomLeft", "bottomRight", "middleCenter", "middleLeft", "middleRight", "topCenter", "topRight"]); + this.colSpan = (0, _utils.getInteger)({ + data: attributes.colSpan, + defaultValue: 1, + validate: n => n >= 1 || n === -1 + }); + this.h = attributes.h ? (0, _utils.getMeasurement)(attributes.h) : ""; + this.hAlign = (0, _utils.getStringOption)(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]); + this.id = attributes.id || ""; + this.layout = (0, _utils.getStringOption)(attributes.layout, ["position", "lr-tb", "rl-row", "rl-tb", "row", "table", "tb"]); + this.maxH = (0, _utils.getMeasurement)(attributes.maxH, "0pt"); + this.maxW = (0, _utils.getMeasurement)(attributes.maxW, "0pt"); + this.minH = (0, _utils.getMeasurement)(attributes.minH, "0pt"); + this.minW = (0, _utils.getMeasurement)(attributes.minW, "0pt"); + this.name = attributes.name || ""; + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.w = attributes.w ? (0, _utils.getMeasurement)(attributes.w) : ""; + this.x = (0, _utils.getMeasurement)(attributes.x, "0pt"); + this.y = (0, _utils.getMeasurement)(attributes.y, "0pt"); + this.assist = null; + this.bind = null; + this.border = null; + this.calculate = null; + this.caption = null; + this.desc = null; + this.extras = null; + this.margin = null; + this.para = null; + this.traversal = null; + this.validate = null; + this.connect = new _xfa_object.XFAObjectArray(); + this.event = new _xfa_object.XFAObjectArray(); + this.field = new _xfa_object.XFAObjectArray(); + this.setProperty = new _xfa_object.XFAObjectArray(); + } + + [_xfa_object.$isBindable]() { + return true; + } + + [_xfa_object.$hasSettableValue]() { + return true; + } + + [_xfa_object.$setValue](value) { + for (const field of this.field.children) { + if (!field.value) { + const nodeValue = new Value({}); + + field[_xfa_object.$appendChild](nodeValue); + + field.value = nodeValue; + } + + field.value[_xfa_object.$setValue](value); + } + } + + [_xfa_object.$isThereMoreWidth]() { + return this.layout.endsWith("-tb") && this[_xfa_object.$extra].attempt === 0 && this[_xfa_object.$extra].numberInLine > 0 || this[_xfa_object.$getParent]()[_xfa_object.$isThereMoreWidth](); + } + + [_xfa_object.$isSplittable]() { + const parent = this[_xfa_object.$getSubformParent](); + + if (!parent[_xfa_object.$isSplittable]()) { + return false; + } + + if (this[_xfa_object.$extra]._isSplittable !== undefined) { + return this[_xfa_object.$extra]._isSplittable; + } + + if (this.layout === "position" || this.layout.includes("row")) { + this[_xfa_object.$extra]._isSplittable = false; + return false; + } + + if (parent.layout && parent.layout.endsWith("-tb") && parent[_xfa_object.$extra].numberInLine !== 0) { + return false; + } + + this[_xfa_object.$extra]._isSplittable = true; + return true; + } + + [_xfa_object.$flushHTML]() { + return (0, _layout.flushHTML)(this); + } + + [_xfa_object.$addHTML](html, bbox) { + (0, _layout.addHTML)(this, html, bbox); + } + + [_xfa_object.$getAvailableSpace]() { + return (0, _layout.getAvailableSpace)(this); + } + + [_xfa_object.$toHTML](availableSpace) { + setTabIndex(this); + + if (this.presence === "hidden" || this.presence === "inactive" || this.h === 0 || this.w === 0) { + return _utils.HTMLResult.EMPTY; + } + + (0, _html_utils.fixDimensions)(this); + const children = []; + const attributes = { + id: this[_xfa_object.$uid], + class: [] + }; + (0, _html_utils.setAccess)(this, attributes.class); + + if (!this[_xfa_object.$extra]) { + this[_xfa_object.$extra] = Object.create(null); + } + + Object.assign(this[_xfa_object.$extra], { + children, + attributes, + attempt: 0, + line: null, + numberInLine: 0, + availableSpace: { + width: Math.min(this.w || Infinity, availableSpace.width), + height: Math.min(this.h || Infinity, availableSpace.height) + }, + width: 0, + height: 0, + prevHeight: 0, + currentWidth: 0 + }); + + const isSplittable = this[_xfa_object.$isSplittable](); + + if (!isSplittable) { + setFirstUnsplittable(this); + } + + if (!(0, _layout.checkDimensions)(this, availableSpace)) { + return _utils.HTMLResult.FAILURE; + } + + const filter = new Set(["field"]); + + if (this.layout.includes("row")) { + const columnWidths = this[_xfa_object.$getSubformParent]().columnWidths; + + if (Array.isArray(columnWidths) && columnWidths.length > 0) { + this[_xfa_object.$extra].columnWidths = columnWidths; + this[_xfa_object.$extra].currentColumn = 0; + } + } + + const style = (0, _html_utils.toStyle)(this, "anchorType", "dimensions", "position", "presence", "border", "margin", "hAlign"); + const classNames = ["xfaExclgroup"]; + const cl = (0, _html_utils.layoutClass)(this); + + if (cl) { + classNames.push(cl); + } + + if ((0, _html_utils.isPrintOnly)(this)) { + classNames.push("xfaPrintOnly"); + } + + attributes.style = style; + attributes.class = classNames; + + if (this.name) { + attributes.xfaName = this.name; + } + + this[_xfa_object.$pushPara](); + + const isLrTb = this.layout === "lr-tb" || this.layout === "rl-tb"; + const maxRun = isLrTb ? MAX_ATTEMPTS_FOR_LRTB_LAYOUT : 1; + + for (; this[_xfa_object.$extra].attempt < maxRun; this[_xfa_object.$extra].attempt++) { + if (isLrTb && this[_xfa_object.$extra].attempt === MAX_ATTEMPTS_FOR_LRTB_LAYOUT - 1) { + this[_xfa_object.$extra].numberInLine = 0; + } + + const result = this[_xfa_object.$childrenToHTML]({ + filter, + include: true + }); + + if (result.success) { + break; + } + + if (result.isBreak()) { + this[_xfa_object.$popPara](); + + return result; + } + + if (isLrTb && this[_xfa_object.$extra].attempt === 0 && this[_xfa_object.$extra].numberInLine === 0 && !this[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].noLayoutFailure) { + this[_xfa_object.$extra].attempt = maxRun; + break; + } + } + + this[_xfa_object.$popPara](); + + if (!isSplittable) { + unsetFirstUnsplittable(this); + } + + if (this[_xfa_object.$extra].attempt === maxRun) { + if (!isSplittable) { + delete this[_xfa_object.$extra]; + } + + return _utils.HTMLResult.FAILURE; + } + + let marginH = 0; + let marginV = 0; + + if (this.margin) { + marginH = this.margin.leftInset + this.margin.rightInset; + marginV = this.margin.topInset + this.margin.bottomInset; + } + + const width = Math.max(this[_xfa_object.$extra].width + marginH, this.w || 0); + const height = Math.max(this[_xfa_object.$extra].height + marginV, this.h || 0); + const bbox = [this.x, this.y, width, height]; + + if (this.w === "") { + style.width = (0, _html_utils.measureToString)(width); + } + + if (this.h === "") { + style.height = (0, _html_utils.measureToString)(height); + } + + const html = { + name: "div", + attributes, + children + }; + applyAssist(this, attributes); + delete this[_xfa_object.$extra]; + return _utils.HTMLResult.success((0, _html_utils.createWrapper)(this, html), bbox); + } + +} + +class Execute extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "execute"); + this.connection = attributes.connection || ""; + this.executeType = (0, _utils.getStringOption)(attributes.executeType, ["import", "remerge"]); + this.id = attributes.id || ""; + this.runAt = (0, _utils.getStringOption)(attributes.runAt, ["client", "both", "server"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Extras extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "extras", true); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.boolean = new _xfa_object.XFAObjectArray(); + this.date = new _xfa_object.XFAObjectArray(); + this.dateTime = new _xfa_object.XFAObjectArray(); + this.decimal = new _xfa_object.XFAObjectArray(); + this.exData = new _xfa_object.XFAObjectArray(); + this.extras = new _xfa_object.XFAObjectArray(); + this.float = new _xfa_object.XFAObjectArray(); + this.image = new _xfa_object.XFAObjectArray(); + this.integer = new _xfa_object.XFAObjectArray(); + this.text = new _xfa_object.XFAObjectArray(); + this.time = new _xfa_object.XFAObjectArray(); + } + +} + +class Field extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "field", true); + this.access = (0, _utils.getStringOption)(attributes.access, ["open", "nonInteractive", "protected", "readOnly"]); + this.accessKey = attributes.accessKey || ""; + this.anchorType = (0, _utils.getStringOption)(attributes.anchorType, ["topLeft", "bottomCenter", "bottomLeft", "bottomRight", "middleCenter", "middleLeft", "middleRight", "topCenter", "topRight"]); + this.colSpan = (0, _utils.getInteger)({ + data: attributes.colSpan, + defaultValue: 1, + validate: n => n >= 1 || n === -1 + }); + this.h = attributes.h ? (0, _utils.getMeasurement)(attributes.h) : ""; + this.hAlign = (0, _utils.getStringOption)(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]); + this.id = attributes.id || ""; + this.locale = attributes.locale || ""; + this.maxH = (0, _utils.getMeasurement)(attributes.maxH, "0pt"); + this.maxW = (0, _utils.getMeasurement)(attributes.maxW, "0pt"); + this.minH = (0, _utils.getMeasurement)(attributes.minH, "0pt"); + this.minW = (0, _utils.getMeasurement)(attributes.minW, "0pt"); + this.name = attributes.name || ""; + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.rotate = (0, _utils.getInteger)({ + data: attributes.rotate, + defaultValue: 0, + validate: x => x % 90 === 0 + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.w = attributes.w ? (0, _utils.getMeasurement)(attributes.w) : ""; + this.x = (0, _utils.getMeasurement)(attributes.x, "0pt"); + this.y = (0, _utils.getMeasurement)(attributes.y, "0pt"); + this.assist = null; + this.bind = null; + this.border = null; + this.calculate = null; + this.caption = null; + this.desc = null; + this.extras = null; + this.font = null; + this.format = null; + this.items = new _xfa_object.XFAObjectArray(2); + this.keep = null; + this.margin = null; + this.para = null; + this.traversal = null; + this.ui = null; + this.validate = null; + this.value = null; + this.bindItems = new _xfa_object.XFAObjectArray(); + this.connect = new _xfa_object.XFAObjectArray(); + this.event = new _xfa_object.XFAObjectArray(); + this.setProperty = new _xfa_object.XFAObjectArray(); + } + + [_xfa_object.$isBindable]() { + return true; + } + + [_xfa_object.$setValue](value) { + _setValue(this, value); + } + + [_xfa_object.$toHTML](availableSpace) { + setTabIndex(this); + + if (!this.ui) { + this.ui = new Ui({}); + this.ui[_xfa_object.$globalData] = this[_xfa_object.$globalData]; + + this[_xfa_object.$appendChild](this.ui); + + let node; + + switch (this.items.children.length) { + case 0: + node = new TextEdit({}); + this.ui.textEdit = node; + break; + + case 1: + node = new CheckButton({}); + this.ui.checkButton = node; + break; + + case 2: + node = new ChoiceList({}); + this.ui.choiceList = node; + break; + } + + this.ui[_xfa_object.$appendChild](node); + } + + if (!this.ui || this.presence === "hidden" || this.presence === "inactive" || this.h === 0 || this.w === 0) { + return _utils.HTMLResult.EMPTY; + } + + if (this.caption) { + delete this.caption[_xfa_object.$extra]; + } + + this[_xfa_object.$pushPara](); + + const caption = this.caption ? this.caption[_xfa_object.$toHTML](availableSpace).html : null; + const savedW = this.w; + const savedH = this.h; + let marginH = 0; + let marginV = 0; + + if (this.margin) { + marginH = this.margin.leftInset + this.margin.rightInset; + marginV = this.margin.topInset + this.margin.bottomInset; + } + + let borderDims = null; + + if (this.w === "" || this.h === "") { + let width = null; + let height = null; + let uiW = 0; + let uiH = 0; + + if (this.ui.checkButton) { + uiW = uiH = this.ui.checkButton.size; + } else { + const { + w, + h + } = (0, _html_utils.layoutNode)(this, availableSpace); + + if (w !== null) { + uiW = w; + uiH = h; + } else { + uiH = (0, _fonts.getMetrics)(this.font, true).lineNoGap; + } + } + + borderDims = getBorderDims(this.ui[_xfa_object.$getExtra]()); + uiW += borderDims.w; + uiH += borderDims.h; + + if (this.caption) { + const { + w, + h, + isBroken + } = this.caption[_xfa_object.$getExtra](availableSpace); + + if (isBroken && this[_xfa_object.$getSubformParent]()[_xfa_object.$isThereMoreWidth]()) { + this[_xfa_object.$popPara](); + + return _utils.HTMLResult.FAILURE; + } + + width = w; + height = h; + + switch (this.caption.placement) { + case "left": + case "right": + case "inline": + width += uiW; + break; + + case "top": + case "bottom": + height += uiH; + break; + } + } else { + width = uiW; + height = uiH; + } + + if (width && this.w === "") { + width += marginH; + this.w = Math.min(this.maxW <= 0 ? Infinity : this.maxW, this.minW + 1 < width ? width : this.minW); + } + + if (height && this.h === "") { + height += marginV; + this.h = Math.min(this.maxH <= 0 ? Infinity : this.maxH, this.minH + 1 < height ? height : this.minH); + } + } + + this[_xfa_object.$popPara](); + + (0, _html_utils.fixDimensions)(this); + setFirstUnsplittable(this); + + if (!(0, _layout.checkDimensions)(this, availableSpace)) { + this.w = savedW; + this.h = savedH; + + this[_xfa_object.$popPara](); + + return _utils.HTMLResult.FAILURE; + } + + unsetFirstUnsplittable(this); + const style = (0, _html_utils.toStyle)(this, "font", "dimensions", "position", "rotate", "anchorType", "presence", "margin", "hAlign"); + (0, _html_utils.setMinMaxDimensions)(this, style); + const classNames = ["xfaField"]; + + if (this.font) { + classNames.push("xfaFont"); + } + + if ((0, _html_utils.isPrintOnly)(this)) { + classNames.push("xfaPrintOnly"); + } + + const attributes = { + style, + id: this[_xfa_object.$uid], + class: classNames + }; + + if (style.margin) { + style.padding = style.margin; + delete style.margin; + } + + (0, _html_utils.setAccess)(this, classNames); + + if (this.name) { + attributes.xfaName = this.name; + } + + const children = []; + const html = { + name: "div", + attributes, + children + }; + applyAssist(this, attributes); + const borderStyle = this.border ? this.border[_xfa_object.$toStyle]() : null; + const bbox = (0, _html_utils.computeBbox)(this, html, availableSpace); + + const ui = this.ui[_xfa_object.$toHTML]().html; + + if (!ui) { + Object.assign(style, borderStyle); + return _utils.HTMLResult.success((0, _html_utils.createWrapper)(this, html), bbox); + } + + if (this[_xfa_object.$tabIndex]) { + if (ui.children && ui.children[0]) { + ui.children[0].attributes.tabindex = this[_xfa_object.$tabIndex]; + } else { + ui.attributes.tabindex = this[_xfa_object.$tabIndex]; + } + } + + if (!ui.attributes.style) { + ui.attributes.style = Object.create(null); + } + + let aElement = null; + + if (this.ui.button) { + if (ui.children.length === 1) { + [aElement] = ui.children.splice(0, 1); + } + + Object.assign(ui.attributes.style, borderStyle); + } else { + Object.assign(style, borderStyle); + } + + children.push(ui); + + if (this.value) { + if (this.ui.imageEdit) { + ui.children.push(this.value[_xfa_object.$toHTML]().html); + } else if (!this.ui.button) { + let value = ""; + + if (this.value.exData) { + value = this.value.exData[_xfa_object.$text](); + } else if (this.value.text) { + value = this.value.text[_xfa_object.$getExtra](); + } else { + const htmlValue = this.value[_xfa_object.$toHTML]().html; + + if (htmlValue !== null) { + value = htmlValue.children[0].value; + } + } + + if (this.ui.textEdit && this.value.text && this.value.text.maxChars) { + ui.children[0].attributes.maxLength = this.value.text.maxChars; + } + + if (value) { + if (this.ui.numericEdit) { + value = parseFloat(value); + value = isNaN(value) ? "" : value.toString(); + } + + if (ui.children[0].name === "textarea") { + ui.children[0].attributes.textContent = value; + } else { + ui.children[0].attributes.value = value; + } + } + } + } + + if (!this.ui.imageEdit && ui.children && ui.children[0] && this.h) { + borderDims = borderDims || getBorderDims(this.ui[_xfa_object.$getExtra]()); + let captionHeight = 0; + + if (this.caption && ["top", "bottom"].includes(this.caption.placement)) { + captionHeight = this.caption.reserve; + + if (captionHeight <= 0) { + captionHeight = this.caption[_xfa_object.$getExtra](availableSpace).h; + } + + const inputHeight = this.h - captionHeight - marginV - borderDims.h; + ui.children[0].attributes.style.height = (0, _html_utils.measureToString)(inputHeight); + } else { + ui.children[0].attributes.style.height = "100%"; + } + } + + if (aElement) { + ui.children.push(aElement); + } + + if (!caption) { + if (ui.attributes.class) { + ui.attributes.class.push("xfaLeft"); + } + + this.w = savedW; + this.h = savedH; + return _utils.HTMLResult.success((0, _html_utils.createWrapper)(this, html), bbox); + } + + if (this.ui.button) { + if (style.padding) { + delete style.padding; + } + + if (caption.name === "div") { + caption.name = "span"; + } + + ui.children.push(caption); + return _utils.HTMLResult.success(html, bbox); + } else if (this.ui.checkButton) { + caption.attributes.class[0] = "xfaCaptionForCheckButton"; + } + + if (!ui.attributes.class) { + ui.attributes.class = []; + } + + ui.children.splice(0, 0, caption); + + switch (this.caption.placement) { + case "left": + ui.attributes.class.push("xfaLeft"); + break; + + case "right": + ui.attributes.class.push("xfaRight"); + break; + + case "top": + ui.attributes.class.push("xfaTop"); + break; + + case "bottom": + ui.attributes.class.push("xfaBottom"); + break; + + case "inline": + ui.attributes.class.push("xfaLeft"); + break; + } + + this.w = savedW; + this.h = savedH; + return _utils.HTMLResult.success((0, _html_utils.createWrapper)(this, html), bbox); + } + +} + +exports.Field = Field; + +class Fill extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "fill", true); + this.id = attributes.id || ""; + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.color = null; + this.extras = null; + this.linear = null; + this.pattern = null; + this.radial = null; + this.solid = null; + this.stipple = null; + } + + [_xfa_object.$toStyle]() { + const parent = this[_xfa_object.$getParent](); + + const grandpa = parent[_xfa_object.$getParent](); + + const ggrandpa = grandpa[_xfa_object.$getParent](); + + const style = Object.create(null); + let propName = "color"; + let altPropName = propName; + + if (parent instanceof Border) { + propName = "background-color"; + altPropName = "background"; + + if (ggrandpa instanceof Ui) { + style.backgroundColor = "white"; + } + } + + if (parent instanceof Rectangle || parent instanceof Arc) { + propName = altPropName = "fill"; + style.fill = "white"; + } + + for (const name of Object.getOwnPropertyNames(this)) { + if (name === "extras" || name === "color") { + continue; + } + + const obj = this[name]; + + if (!(obj instanceof _xfa_object.XFAObject)) { + continue; + } + + const color = obj[_xfa_object.$toStyle](this.color); + + if (color) { + style[color.startsWith("#") ? propName : altPropName] = color; + } + + return style; + } + + if (this.color && this.color.value) { + const color = this.color[_xfa_object.$toStyle](); + + style[color.startsWith("#") ? propName : altPropName] = color; + } + + return style; + } + +} + +class Filter extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "filter", true); + this.addRevocationInfo = (0, _utils.getStringOption)(attributes.addRevocationInfo, ["", "required", "optional", "none"]); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.version = (0, _utils.getInteger)({ + data: this.version, + defaultValue: 5, + validate: x => x >= 1 && x <= 5 + }); + this.appearanceFilter = null; + this.certificates = null; + this.digestMethods = null; + this.encodings = null; + this.encryptionMethods = null; + this.handler = null; + this.lockDocument = null; + this.mdp = null; + this.reasons = null; + this.timeStamp = null; + } + +} + +class Float extends _xfa_object.ContentObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "float"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$finalize]() { + const number = parseFloat(this[_xfa_object.$content].trim()); + this[_xfa_object.$content] = isNaN(number) ? null : number; + } + + [_xfa_object.$toHTML](availableSpace) { + return valueToHtml(this[_xfa_object.$content] !== null ? this[_xfa_object.$content].toString() : ""); + } + +} + +class Font extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "font", true); + this.baselineShift = (0, _utils.getMeasurement)(attributes.baselineShift); + this.fontHorizontalScale = (0, _utils.getFloat)({ + data: attributes.fontHorizontalScale, + defaultValue: 100, + validate: x => x >= 0 + }); + this.fontVerticalScale = (0, _utils.getFloat)({ + data: attributes.fontVerticalScale, + defaultValue: 100, + validate: x => x >= 0 + }); + this.id = attributes.id || ""; + this.kerningMode = (0, _utils.getStringOption)(attributes.kerningMode, ["none", "pair"]); + this.letterSpacing = (0, _utils.getMeasurement)(attributes.letterSpacing, "0"); + this.lineThrough = (0, _utils.getInteger)({ + data: attributes.lineThrough, + defaultValue: 0, + validate: x => x === 1 || x === 2 + }); + this.lineThroughPeriod = (0, _utils.getStringOption)(attributes.lineThroughPeriod, ["all", "word"]); + this.overline = (0, _utils.getInteger)({ + data: attributes.overline, + defaultValue: 0, + validate: x => x === 1 || x === 2 + }); + this.overlinePeriod = (0, _utils.getStringOption)(attributes.overlinePeriod, ["all", "word"]); + this.posture = (0, _utils.getStringOption)(attributes.posture, ["normal", "italic"]); + this.size = (0, _utils.getMeasurement)(attributes.size, "10pt"); + this.typeface = attributes.typeface || "Courier"; + this.underline = (0, _utils.getInteger)({ + data: attributes.underline, + defaultValue: 0, + validate: x => x === 1 || x === 2 + }); + this.underlinePeriod = (0, _utils.getStringOption)(attributes.underlinePeriod, ["all", "word"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.weight = (0, _utils.getStringOption)(attributes.weight, ["normal", "bold"]); + this.extras = null; + this.fill = null; + } + + [_xfa_object.$clean](builder) { + super[_xfa_object.$clean](builder); + + this[_xfa_object.$globalData].usedTypefaces.add(this.typeface); + } + + [_xfa_object.$toStyle]() { + const style = (0, _html_utils.toStyle)(this, "fill"); + const color = style.color; + + if (color) { + if (color === "#000000") { + delete style.color; + } else if (!color.startsWith("#")) { + style.background = color; + style.backgroundClip = "text"; + style.color = "transparent"; + } + } + + if (this.baselineShift) { + style.verticalAlign = (0, _html_utils.measureToString)(this.baselineShift); + } + + style.fontKerning = this.kerningMode === "none" ? "none" : "normal"; + style.letterSpacing = (0, _html_utils.measureToString)(this.letterSpacing); + + if (this.lineThrough !== 0) { + style.textDecoration = "line-through"; + + if (this.lineThrough === 2) { + style.textDecorationStyle = "double"; + } + } + + if (this.overline !== 0) { + style.textDecoration = "overline"; + + if (this.overline === 2) { + style.textDecorationStyle = "double"; + } + } + + style.fontStyle = this.posture; + style.fontSize = (0, _html_utils.measureToString)(0.99 * this.size); + (0, _html_utils.setFontFamily)(this, this, this[_xfa_object.$globalData].fontFinder, style); + + if (this.underline !== 0) { + style.textDecoration = "underline"; + + if (this.underline === 2) { + style.textDecorationStyle = "double"; + } + } + + style.fontWeight = this.weight; + return style; + } + +} + +class Format extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "format", true); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.picture = null; + } + +} + +class Handler extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "handler"); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Hyphenation extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "hyphenation"); + this.excludeAllCaps = (0, _utils.getInteger)({ + data: attributes.excludeAllCaps, + defaultValue: 0, + validate: x => x === 1 + }); + this.excludeInitialCap = (0, _utils.getInteger)({ + data: attributes.excludeInitialCap, + defaultValue: 0, + validate: x => x === 1 + }); + this.hyphenate = (0, _utils.getInteger)({ + data: attributes.hyphenate, + defaultValue: 0, + validate: x => x === 1 + }); + this.id = attributes.id || ""; + this.pushCharacterCount = (0, _utils.getInteger)({ + data: attributes.pushCharacterCount, + defaultValue: 3, + validate: x => x >= 0 + }); + this.remainCharacterCount = (0, _utils.getInteger)({ + data: attributes.remainCharacterCount, + defaultValue: 3, + validate: x => x >= 0 + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.wordCharacterCount = (0, _utils.getInteger)({ + data: attributes.wordCharacterCount, + defaultValue: 7, + validate: x => x >= 0 + }); + } + +} + +class Image extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "image"); + this.aspect = (0, _utils.getStringOption)(attributes.aspect, ["fit", "actual", "height", "none", "width"]); + this.contentType = attributes.contentType || ""; + this.href = attributes.href || ""; + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.transferEncoding = (0, _utils.getStringOption)(attributes.transferEncoding, ["base64", "none", "package"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$toHTML]() { + if (this.contentType && !MIMES.has(this.contentType.toLowerCase())) { + return _utils.HTMLResult.EMPTY; + } + + let buffer = this[_xfa_object.$globalData].images && this[_xfa_object.$globalData].images.get(this.href); + + if (!buffer && (this.href || !this[_xfa_object.$content])) { + return _utils.HTMLResult.EMPTY; + } + + if (!buffer && this.transferEncoding === "base64") { + buffer = (0, _util.stringToBytes)(atob(this[_xfa_object.$content])); + } + + if (!buffer) { + return _utils.HTMLResult.EMPTY; + } + + if (!this.contentType) { + for (const [header, type] of IMAGES_HEADERS) { + if (buffer.length > header.length && header.every((x, i) => x === buffer[i])) { + this.contentType = type; + break; + } + } + + if (!this.contentType) { + return _utils.HTMLResult.EMPTY; + } + } + + const blob = new Blob([buffer], { + type: this.contentType + }); + let style; + + switch (this.aspect) { + case "fit": + case "actual": + break; + + case "height": + style = { + height: "100%", + objectFit: "fill" + }; + break; + + case "none": + style = { + width: "100%", + height: "100%", + objectFit: "fill" + }; + break; + + case "width": + style = { + width: "100%", + objectFit: "fill" + }; + break; + } + + const parent = this[_xfa_object.$getParent](); + + return _utils.HTMLResult.success({ + name: "img", + attributes: { + class: ["xfaImage"], + style, + src: URL.createObjectURL(blob), + alt: parent ? ariaLabel(parent[_xfa_object.$getParent]()) : null + } + }); + } + +} + +class ImageEdit extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "imageEdit", true); + this.data = (0, _utils.getStringOption)(attributes.data, ["link", "embed"]); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.border = null; + this.extras = null; + this.margin = null; + } + + [_xfa_object.$toHTML](availableSpace) { + if (this.data === "embed") { + return _utils.HTMLResult.success({ + name: "div", + children: [], + attributes: {} + }); + } + + return _utils.HTMLResult.EMPTY; + } + +} + +class Integer extends _xfa_object.ContentObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "integer"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$finalize]() { + const number = parseInt(this[_xfa_object.$content].trim(), 10); + this[_xfa_object.$content] = isNaN(number) ? null : number; + } + + [_xfa_object.$toHTML](availableSpace) { + return valueToHtml(this[_xfa_object.$content] !== null ? this[_xfa_object.$content].toString() : ""); + } + +} + +class Issuers extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "issuers", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.certificate = new _xfa_object.XFAObjectArray(); + } + +} + +class Items extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "items", true); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.ref = attributes.ref || ""; + this.save = (0, _utils.getInteger)({ + data: attributes.save, + defaultValue: 0, + validate: x => x === 1 + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.boolean = new _xfa_object.XFAObjectArray(); + this.date = new _xfa_object.XFAObjectArray(); + this.dateTime = new _xfa_object.XFAObjectArray(); + this.decimal = new _xfa_object.XFAObjectArray(); + this.exData = new _xfa_object.XFAObjectArray(); + this.float = new _xfa_object.XFAObjectArray(); + this.image = new _xfa_object.XFAObjectArray(); + this.integer = new _xfa_object.XFAObjectArray(); + this.text = new _xfa_object.XFAObjectArray(); + this.time = new _xfa_object.XFAObjectArray(); + } + + [_xfa_object.$toHTML]() { + const output = []; + + for (const child of this[_xfa_object.$getChildren]()) { + output.push(child[_xfa_object.$text]()); + } + + return _utils.HTMLResult.success(output); + } + +} + +exports.Items = Items; + +class Keep extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "keep", true); + this.id = attributes.id || ""; + const options = ["none", "contentArea", "pageArea"]; + this.intact = (0, _utils.getStringOption)(attributes.intact, options); + this.next = (0, _utils.getStringOption)(attributes.next, options); + this.previous = (0, _utils.getStringOption)(attributes.previous, options); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + } + +} + +class KeyUsage extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "keyUsage"); + const options = ["", "yes", "no"]; + this.crlSign = (0, _utils.getStringOption)(attributes.crlSign, options); + this.dataEncipherment = (0, _utils.getStringOption)(attributes.dataEncipherment, options); + this.decipherOnly = (0, _utils.getStringOption)(attributes.decipherOnly, options); + this.digitalSignature = (0, _utils.getStringOption)(attributes.digitalSignature, options); + this.encipherOnly = (0, _utils.getStringOption)(attributes.encipherOnly, options); + this.id = attributes.id || ""; + this.keyAgreement = (0, _utils.getStringOption)(attributes.keyAgreement, options); + this.keyCertSign = (0, _utils.getStringOption)(attributes.keyCertSign, options); + this.keyEncipherment = (0, _utils.getStringOption)(attributes.keyEncipherment, options); + this.nonRepudiation = (0, _utils.getStringOption)(attributes.nonRepudiation, options); + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Line extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "line", true); + this.hand = (0, _utils.getStringOption)(attributes.hand, ["even", "left", "right"]); + this.id = attributes.id || ""; + this.slope = (0, _utils.getStringOption)(attributes.slope, ["\\", "/"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.edge = null; + } + + [_xfa_object.$toHTML]() { + const parent = this[_xfa_object.$getParent]()[_xfa_object.$getParent](); + + const edge = this.edge || new Edge({}); + + const edgeStyle = edge[_xfa_object.$toStyle](); + + const style = Object.create(null); + const thickness = edge.presence === "visible" ? edge.thickness : 0; + style.strokeWidth = (0, _html_utils.measureToString)(thickness); + style.stroke = edgeStyle.color; + let x1, y1, x2, y2; + let width = "100%"; + let height = "100%"; + + if (parent.w <= thickness) { + [x1, y1, x2, y2] = ["50%", 0, "50%", "100%"]; + width = style.strokeWidth; + } else if (parent.h <= thickness) { + [x1, y1, x2, y2] = [0, "50%", "100%", "50%"]; + height = style.strokeWidth; + } else { + if (this.slope === "\\") { + [x1, y1, x2, y2] = [0, 0, "100%", "100%"]; + } else { + [x1, y1, x2, y2] = [0, "100%", "100%", 0]; + } + } + + const line = { + name: "line", + attributes: { + xmlns: SVG_NS, + x1, + y1, + x2, + y2, + style + } + }; + const svg = { + name: "svg", + children: [line], + attributes: { + xmlns: SVG_NS, + width, + height, + style: { + overflow: "visible" + } + } + }; + + if (hasMargin(parent)) { + return _utils.HTMLResult.success({ + name: "div", + attributes: { + style: { + display: "inline", + width: "100%", + height: "100%" + } + }, + children: [svg] + }); + } + + svg.attributes.style.position = "absolute"; + return _utils.HTMLResult.success(svg); + } + +} + +class Linear extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "linear", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["toRight", "toBottom", "toLeft", "toTop"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.color = null; + this.extras = null; + } + + [_xfa_object.$toStyle](startColor) { + startColor = startColor ? startColor[_xfa_object.$toStyle]() : "#FFFFFF"; + const transf = this.type.replace(/([RBLT])/, " $1").toLowerCase(); + const endColor = this.color ? this.color[_xfa_object.$toStyle]() : "#000000"; + return `linear-gradient(${transf}, ${startColor}, ${endColor})`; + } + +} + +class LockDocument extends _xfa_object.ContentObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "lockDocument"); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$finalize]() { + this[_xfa_object.$content] = (0, _utils.getStringOption)(this[_xfa_object.$content], ["auto", "0", "1"]); + } + +} + +class Manifest extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "manifest", true); + this.action = (0, _utils.getStringOption)(attributes.action, ["include", "all", "exclude"]); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.ref = new _xfa_object.XFAObjectArray(); + } + +} + +class Margin extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "margin", true); + this.bottomInset = (0, _utils.getMeasurement)(attributes.bottomInset, "0"); + this.id = attributes.id || ""; + this.leftInset = (0, _utils.getMeasurement)(attributes.leftInset, "0"); + this.rightInset = (0, _utils.getMeasurement)(attributes.rightInset, "0"); + this.topInset = (0, _utils.getMeasurement)(attributes.topInset, "0"); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + } + + [_xfa_object.$toStyle]() { + return { + margin: (0, _html_utils.measureToString)(this.topInset) + " " + (0, _html_utils.measureToString)(this.rightInset) + " " + (0, _html_utils.measureToString)(this.bottomInset) + " " + (0, _html_utils.measureToString)(this.leftInset) + }; + } + +} + +class Mdp extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "mdp"); + this.id = attributes.id || ""; + this.permissions = (0, _utils.getInteger)({ + data: attributes.permissions, + defaultValue: 2, + validate: x => x === 1 || x === 3 + }); + this.signatureType = (0, _utils.getStringOption)(attributes.signatureType, ["filler", "author"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Medium extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "medium"); + this.id = attributes.id || ""; + this.imagingBBox = (0, _utils.getBBox)(attributes.imagingBBox); + this.long = (0, _utils.getMeasurement)(attributes.long); + this.orientation = (0, _utils.getStringOption)(attributes.orientation, ["portrait", "landscape"]); + this.short = (0, _utils.getMeasurement)(attributes.short); + this.stock = attributes.stock || ""; + this.trayIn = (0, _utils.getStringOption)(attributes.trayIn, ["auto", "delegate", "pageFront"]); + this.trayOut = (0, _utils.getStringOption)(attributes.trayOut, ["auto", "delegate"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Message extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "message", true); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.text = new _xfa_object.XFAObjectArray(); + } + +} + +class NumericEdit extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "numericEdit", true); + this.hScrollPolicy = (0, _utils.getStringOption)(attributes.hScrollPolicy, ["auto", "off", "on"]); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.border = null; + this.comb = null; + this.extras = null; + this.margin = null; + } + + [_xfa_object.$toHTML](availableSpace) { + const style = (0, _html_utils.toStyle)(this, "border", "font", "margin"); + + const field = this[_xfa_object.$getParent]()[_xfa_object.$getParent](); + + const html = { + name: "input", + attributes: { + type: "text", + fieldId: field[_xfa_object.$uid], + dataId: field[_xfa_object.$data] && field[_xfa_object.$data][_xfa_object.$uid] || field[_xfa_object.$uid], + class: ["xfaTextfield"], + style, + "aria-label": ariaLabel(field), + "aria-required": false + } + }; + + if (isRequired(field)) { + html.attributes["aria-required"] = true; + html.attributes.required = true; + } + + return _utils.HTMLResult.success({ + name: "label", + attributes: { + class: ["xfaLabel"] + }, + children: [html] + }); + } + +} + +class Occur extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "occur", true); + this.id = attributes.id || ""; + this.initial = attributes.initial !== "" ? (0, _utils.getInteger)({ + data: attributes.initial, + defaultValue: "", + validate: x => true + }) : ""; + this.max = attributes.max !== "" ? (0, _utils.getInteger)({ + data: attributes.max, + defaultValue: 1, + validate: x => true + }) : ""; + this.min = attributes.min !== "" ? (0, _utils.getInteger)({ + data: attributes.min, + defaultValue: 1, + validate: x => true + }) : ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + } + + [_xfa_object.$clean]() { + const parent = this[_xfa_object.$getParent](); + + const originalMin = this.min; + + if (this.min === "") { + this.min = parent instanceof PageArea || parent instanceof PageSet ? 0 : 1; + } + + if (this.max === "") { + if (originalMin === "") { + this.max = parent instanceof PageArea || parent instanceof PageSet ? -1 : 1; + } else { + this.max = this.min; + } + } + + if (this.max !== -1 && this.max < this.min) { + this.max = this.min; + } + + if (this.initial === "") { + this.initial = parent instanceof Template ? 1 : this.min; + } + } + +} + +class Oid extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "oid"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Oids extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "oids", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.oid = new _xfa_object.XFAObjectArray(); + } + +} + +class Overflow extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "overflow"); + this.id = attributes.id || ""; + this.leader = attributes.leader || ""; + this.target = attributes.target || ""; + this.trailer = attributes.trailer || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$getExtra]() { + if (!this[_xfa_object.$extra]) { + const parent = this[_xfa_object.$getParent](); + + const root = this[_xfa_object.$getTemplateRoot](); + + const target = root[_xfa_object.$searchNode](this.target, parent); + + const leader = root[_xfa_object.$searchNode](this.leader, parent); + + const trailer = root[_xfa_object.$searchNode](this.trailer, parent); + + this[_xfa_object.$extra] = { + target: target && target[0] || null, + leader: leader && leader[0] || null, + trailer: trailer && trailer[0] || null, + addLeader: false, + addTrailer: false + }; + } + + return this[_xfa_object.$extra]; + } + +} + +class PageArea extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "pageArea", true); + this.blankOrNotBlank = (0, _utils.getStringOption)(attributes.blankOrNotBlank, ["any", "blank", "notBlank"]); + this.id = attributes.id || ""; + this.initialNumber = (0, _utils.getInteger)({ + data: attributes.initialNumber, + defaultValue: 1, + validate: x => true + }); + this.name = attributes.name || ""; + this.numbered = (0, _utils.getInteger)({ + data: attributes.numbered, + defaultValue: 1, + validate: x => true + }); + this.oddOrEven = (0, _utils.getStringOption)(attributes.oddOrEven, ["any", "even", "odd"]); + this.pagePosition = (0, _utils.getStringOption)(attributes.pagePosition, ["any", "first", "last", "only", "rest"]); + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.desc = null; + this.extras = null; + this.medium = null; + this.occur = null; + this.area = new _xfa_object.XFAObjectArray(); + this.contentArea = new _xfa_object.XFAObjectArray(); + this.draw = new _xfa_object.XFAObjectArray(); + this.exclGroup = new _xfa_object.XFAObjectArray(); + this.field = new _xfa_object.XFAObjectArray(); + this.subform = new _xfa_object.XFAObjectArray(); + } + + [_xfa_object.$isUsable]() { + if (!this[_xfa_object.$extra]) { + this[_xfa_object.$extra] = { + numberOfUse: 0 + }; + return true; + } + + return !this.occur || this.occur.max === -1 || this[_xfa_object.$extra].numberOfUse < this.occur.max; + } + + [_xfa_object.$cleanPage]() { + delete this[_xfa_object.$extra]; + } + + [_xfa_object.$getNextPage]() { + if (!this[_xfa_object.$extra]) { + this[_xfa_object.$extra] = { + numberOfUse: 0 + }; + } + + const parent = this[_xfa_object.$getParent](); + + if (parent.relation === "orderedOccurrence") { + if (this[_xfa_object.$isUsable]()) { + this[_xfa_object.$extra].numberOfUse += 1; + return this; + } + } + + return parent[_xfa_object.$getNextPage](); + } + + [_xfa_object.$getAvailableSpace]() { + return this[_xfa_object.$extra].space || { + width: 0, + height: 0 + }; + } + + [_xfa_object.$toHTML]() { + if (!this[_xfa_object.$extra]) { + this[_xfa_object.$extra] = { + numberOfUse: 1 + }; + } + + const children = []; + this[_xfa_object.$extra].children = children; + const style = Object.create(null); + + if (this.medium && this.medium.short && this.medium.long) { + style.width = (0, _html_utils.measureToString)(this.medium.short); + style.height = (0, _html_utils.measureToString)(this.medium.long); + this[_xfa_object.$extra].space = { + width: this.medium.short, + height: this.medium.long + }; + + if (this.medium.orientation === "landscape") { + const x = style.width; + style.width = style.height; + style.height = x; + this[_xfa_object.$extra].space = { + width: this.medium.long, + height: this.medium.short + }; + } + } else { + (0, _util.warn)("XFA - No medium specified in pageArea: please file a bug."); + } + + this[_xfa_object.$childrenToHTML]({ + filter: new Set(["area", "draw", "field", "subform"]), + include: true + }); + + this[_xfa_object.$childrenToHTML]({ + filter: new Set(["contentArea"]), + include: true + }); + + return _utils.HTMLResult.success({ + name: "div", + children, + attributes: { + class: ["xfaPage"], + id: this[_xfa_object.$uid], + style, + xfaName: this.name + } + }); + } + +} + +class PageSet extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "pageSet", true); + this.duplexImposition = (0, _utils.getStringOption)(attributes.duplexImposition, ["longEdge", "shortEdge"]); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.relation = (0, _utils.getStringOption)(attributes.relation, ["orderedOccurrence", "duplexPaginated", "simplexPaginated"]); + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.occur = null; + this.pageArea = new _xfa_object.XFAObjectArray(); + this.pageSet = new _xfa_object.XFAObjectArray(); + } + + [_xfa_object.$cleanPage]() { + for (const page of this.pageArea.children) { + page[_xfa_object.$cleanPage](); + } + + for (const page of this.pageSet.children) { + page[_xfa_object.$cleanPage](); + } + } + + [_xfa_object.$isUsable]() { + return !this.occur || this.occur.max === -1 || this[_xfa_object.$extra].numberOfUse < this.occur.max; + } + + [_xfa_object.$getNextPage]() { + if (!this[_xfa_object.$extra]) { + this[_xfa_object.$extra] = { + numberOfUse: 1, + pageIndex: -1, + pageSetIndex: -1 + }; + } + + if (this.relation === "orderedOccurrence") { + if (this[_xfa_object.$extra].pageIndex + 1 < this.pageArea.children.length) { + this[_xfa_object.$extra].pageIndex += 1; + const pageArea = this.pageArea.children[this[_xfa_object.$extra].pageIndex]; + return pageArea[_xfa_object.$getNextPage](); + } + + if (this[_xfa_object.$extra].pageSetIndex + 1 < this.pageSet.children.length) { + this[_xfa_object.$extra].pageSetIndex += 1; + return this.pageSet.children[this[_xfa_object.$extra].pageSetIndex][_xfa_object.$getNextPage](); + } + + if (this[_xfa_object.$isUsable]()) { + this[_xfa_object.$extra].numberOfUse += 1; + this[_xfa_object.$extra].pageIndex = -1; + this[_xfa_object.$extra].pageSetIndex = -1; + return this[_xfa_object.$getNextPage](); + } + + const parent = this[_xfa_object.$getParent](); + + if (parent instanceof PageSet) { + return parent[_xfa_object.$getNextPage](); + } + + this[_xfa_object.$cleanPage](); + + return this[_xfa_object.$getNextPage](); + } + + const pageNumber = this[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].pageNumber; + + const parity = pageNumber % 2 === 0 ? "even" : "odd"; + const position = pageNumber === 0 ? "first" : "rest"; + let page = this.pageArea.children.find(p => p.oddOrEven === parity && p.pagePosition === position); + + if (page) { + return page; + } + + page = this.pageArea.children.find(p => p.oddOrEven === "any" && p.pagePosition === position); + + if (page) { + return page; + } + + page = this.pageArea.children.find(p => p.oddOrEven === "any" && p.pagePosition === "any"); + + if (page) { + return page; + } + + return this.pageArea.children[0]; + } + +} + +class Para extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "para", true); + this.hAlign = (0, _utils.getStringOption)(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]); + this.id = attributes.id || ""; + this.lineHeight = attributes.lineHeight ? (0, _utils.getMeasurement)(attributes.lineHeight, "0pt") : ""; + this.marginLeft = attributes.marginLeft ? (0, _utils.getMeasurement)(attributes.marginLeft, "0pt") : ""; + this.marginRight = attributes.marginRight ? (0, _utils.getMeasurement)(attributes.marginRight, "0pt") : ""; + this.orphans = (0, _utils.getInteger)({ + data: attributes.orphans, + defaultValue: 0, + validate: x => x >= 0 + }); + this.preserve = attributes.preserve || ""; + this.radixOffset = attributes.radixOffset ? (0, _utils.getMeasurement)(attributes.radixOffset, "0pt") : ""; + this.spaceAbove = attributes.spaceAbove ? (0, _utils.getMeasurement)(attributes.spaceAbove, "0pt") : ""; + this.spaceBelow = attributes.spaceBelow ? (0, _utils.getMeasurement)(attributes.spaceBelow, "0pt") : ""; + this.tabDefault = attributes.tabDefault ? (0, _utils.getMeasurement)(this.tabDefault) : ""; + this.tabStops = (attributes.tabStops || "").trim().split(/\s+/).map((x, i) => i % 2 === 1 ? (0, _utils.getMeasurement)(x) : x); + this.textIndent = attributes.textIndent ? (0, _utils.getMeasurement)(attributes.textIndent, "0pt") : ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.vAlign = (0, _utils.getStringOption)(attributes.vAlign, ["top", "bottom", "middle"]); + this.widows = (0, _utils.getInteger)({ + data: attributes.widows, + defaultValue: 0, + validate: x => x >= 0 + }); + this.hyphenation = null; + } + + [_xfa_object.$toStyle]() { + const style = (0, _html_utils.toStyle)(this, "hAlign"); + + if (this.marginLeft !== "") { + style.paddingLeft = (0, _html_utils.measureToString)(this.marginLeft); + } + + if (this.marginRight !== "") { + style.paddingight = (0, _html_utils.measureToString)(this.marginRight); + } + + if (this.spaceAbove !== "") { + style.paddingTop = (0, _html_utils.measureToString)(this.spaceAbove); + } + + if (this.spaceBelow !== "") { + style.paddingBottom = (0, _html_utils.measureToString)(this.spaceBelow); + } + + if (this.textIndent !== "") { + style.textIndent = (0, _html_utils.measureToString)(this.textIndent); + (0, _html_utils.fixTextIndent)(style); + } + + if (this.lineHeight > 0) { + style.lineHeight = (0, _html_utils.measureToString)(this.lineHeight); + } + + if (this.tabDefault !== "") { + style.tabSize = (0, _html_utils.measureToString)(this.tabDefault); + } + + if (this.tabStops.length > 0) {} + + if (this.hyphenatation) { + Object.assign(style, this.hyphenatation[_xfa_object.$toStyle]()); + } + + return style; + } + +} + +class PasswordEdit extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "passwordEdit", true); + this.hScrollPolicy = (0, _utils.getStringOption)(attributes.hScrollPolicy, ["auto", "off", "on"]); + this.id = attributes.id || ""; + this.passwordChar = attributes.passwordChar || "*"; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.border = null; + this.extras = null; + this.margin = null; + } + +} + +class Pattern extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "pattern", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["crossHatch", "crossDiagonal", "diagonalLeft", "diagonalRight", "horizontal", "vertical"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.color = null; + this.extras = null; + } + + [_xfa_object.$toStyle](startColor) { + startColor = startColor ? startColor[_xfa_object.$toStyle]() : "#FFFFFF"; + const endColor = this.color ? this.color[_xfa_object.$toStyle]() : "#000000"; + const width = 5; + const cmd = "repeating-linear-gradient"; + const colors = `${startColor},${startColor} ${width}px,${endColor} ${width}px,${endColor} ${2 * width}px`; + + switch (this.type) { + case "crossHatch": + return `${cmd}(to top,${colors}) ${cmd}(to right,${colors})`; + + case "crossDiagonal": + return `${cmd}(45deg,${colors}) ${cmd}(-45deg,${colors})`; + + case "diagonalLeft": + return `${cmd}(45deg,${colors})`; + + case "diagonalRight": + return `${cmd}(-45deg,${colors})`; + + case "horizontal": + return `${cmd}(to top,${colors})`; + + case "vertical": + return `${cmd}(to right,${colors})`; + } + + return ""; + } + +} + +class Picture extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "picture"); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Proto extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "proto", true); + this.appearanceFilter = new _xfa_object.XFAObjectArray(); + this.arc = new _xfa_object.XFAObjectArray(); + this.area = new _xfa_object.XFAObjectArray(); + this.assist = new _xfa_object.XFAObjectArray(); + this.barcode = new _xfa_object.XFAObjectArray(); + this.bindItems = new _xfa_object.XFAObjectArray(); + this.bookend = new _xfa_object.XFAObjectArray(); + this.boolean = new _xfa_object.XFAObjectArray(); + this.border = new _xfa_object.XFAObjectArray(); + this.break = new _xfa_object.XFAObjectArray(); + this.breakAfter = new _xfa_object.XFAObjectArray(); + this.breakBefore = new _xfa_object.XFAObjectArray(); + this.button = new _xfa_object.XFAObjectArray(); + this.calculate = new _xfa_object.XFAObjectArray(); + this.caption = new _xfa_object.XFAObjectArray(); + this.certificate = new _xfa_object.XFAObjectArray(); + this.certificates = new _xfa_object.XFAObjectArray(); + this.checkButton = new _xfa_object.XFAObjectArray(); + this.choiceList = new _xfa_object.XFAObjectArray(); + this.color = new _xfa_object.XFAObjectArray(); + this.comb = new _xfa_object.XFAObjectArray(); + this.connect = new _xfa_object.XFAObjectArray(); + this.contentArea = new _xfa_object.XFAObjectArray(); + this.corner = new _xfa_object.XFAObjectArray(); + this.date = new _xfa_object.XFAObjectArray(); + this.dateTime = new _xfa_object.XFAObjectArray(); + this.dateTimeEdit = new _xfa_object.XFAObjectArray(); + this.decimal = new _xfa_object.XFAObjectArray(); + this.defaultUi = new _xfa_object.XFAObjectArray(); + this.desc = new _xfa_object.XFAObjectArray(); + this.digestMethod = new _xfa_object.XFAObjectArray(); + this.digestMethods = new _xfa_object.XFAObjectArray(); + this.draw = new _xfa_object.XFAObjectArray(); + this.edge = new _xfa_object.XFAObjectArray(); + this.encoding = new _xfa_object.XFAObjectArray(); + this.encodings = new _xfa_object.XFAObjectArray(); + this.encrypt = new _xfa_object.XFAObjectArray(); + this.encryptData = new _xfa_object.XFAObjectArray(); + this.encryption = new _xfa_object.XFAObjectArray(); + this.encryptionMethod = new _xfa_object.XFAObjectArray(); + this.encryptionMethods = new _xfa_object.XFAObjectArray(); + this.event = new _xfa_object.XFAObjectArray(); + this.exData = new _xfa_object.XFAObjectArray(); + this.exObject = new _xfa_object.XFAObjectArray(); + this.exclGroup = new _xfa_object.XFAObjectArray(); + this.execute = new _xfa_object.XFAObjectArray(); + this.extras = new _xfa_object.XFAObjectArray(); + this.field = new _xfa_object.XFAObjectArray(); + this.fill = new _xfa_object.XFAObjectArray(); + this.filter = new _xfa_object.XFAObjectArray(); + this.float = new _xfa_object.XFAObjectArray(); + this.font = new _xfa_object.XFAObjectArray(); + this.format = new _xfa_object.XFAObjectArray(); + this.handler = new _xfa_object.XFAObjectArray(); + this.hyphenation = new _xfa_object.XFAObjectArray(); + this.image = new _xfa_object.XFAObjectArray(); + this.imageEdit = new _xfa_object.XFAObjectArray(); + this.integer = new _xfa_object.XFAObjectArray(); + this.issuers = new _xfa_object.XFAObjectArray(); + this.items = new _xfa_object.XFAObjectArray(); + this.keep = new _xfa_object.XFAObjectArray(); + this.keyUsage = new _xfa_object.XFAObjectArray(); + this.line = new _xfa_object.XFAObjectArray(); + this.linear = new _xfa_object.XFAObjectArray(); + this.lockDocument = new _xfa_object.XFAObjectArray(); + this.manifest = new _xfa_object.XFAObjectArray(); + this.margin = new _xfa_object.XFAObjectArray(); + this.mdp = new _xfa_object.XFAObjectArray(); + this.medium = new _xfa_object.XFAObjectArray(); + this.message = new _xfa_object.XFAObjectArray(); + this.numericEdit = new _xfa_object.XFAObjectArray(); + this.occur = new _xfa_object.XFAObjectArray(); + this.oid = new _xfa_object.XFAObjectArray(); + this.oids = new _xfa_object.XFAObjectArray(); + this.overflow = new _xfa_object.XFAObjectArray(); + this.pageArea = new _xfa_object.XFAObjectArray(); + this.pageSet = new _xfa_object.XFAObjectArray(); + this.para = new _xfa_object.XFAObjectArray(); + this.passwordEdit = new _xfa_object.XFAObjectArray(); + this.pattern = new _xfa_object.XFAObjectArray(); + this.picture = new _xfa_object.XFAObjectArray(); + this.radial = new _xfa_object.XFAObjectArray(); + this.reason = new _xfa_object.XFAObjectArray(); + this.reasons = new _xfa_object.XFAObjectArray(); + this.rectangle = new _xfa_object.XFAObjectArray(); + this.ref = new _xfa_object.XFAObjectArray(); + this.script = new _xfa_object.XFAObjectArray(); + this.setProperty = new _xfa_object.XFAObjectArray(); + this.signData = new _xfa_object.XFAObjectArray(); + this.signature = new _xfa_object.XFAObjectArray(); + this.signing = new _xfa_object.XFAObjectArray(); + this.solid = new _xfa_object.XFAObjectArray(); + this.speak = new _xfa_object.XFAObjectArray(); + this.stipple = new _xfa_object.XFAObjectArray(); + this.subform = new _xfa_object.XFAObjectArray(); + this.subformSet = new _xfa_object.XFAObjectArray(); + this.subjectDN = new _xfa_object.XFAObjectArray(); + this.subjectDNs = new _xfa_object.XFAObjectArray(); + this.submit = new _xfa_object.XFAObjectArray(); + this.text = new _xfa_object.XFAObjectArray(); + this.textEdit = new _xfa_object.XFAObjectArray(); + this.time = new _xfa_object.XFAObjectArray(); + this.timeStamp = new _xfa_object.XFAObjectArray(); + this.toolTip = new _xfa_object.XFAObjectArray(); + this.traversal = new _xfa_object.XFAObjectArray(); + this.traverse = new _xfa_object.XFAObjectArray(); + this.ui = new _xfa_object.XFAObjectArray(); + this.validate = new _xfa_object.XFAObjectArray(); + this.value = new _xfa_object.XFAObjectArray(); + this.variables = new _xfa_object.XFAObjectArray(); + } + +} + +class Radial extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "radial", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["toEdge", "toCenter"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.color = null; + this.extras = null; + } + + [_xfa_object.$toStyle](startColor) { + startColor = startColor ? startColor[_xfa_object.$toStyle]() : "#FFFFFF"; + const endColor = this.color ? this.color[_xfa_object.$toStyle]() : "#000000"; + const colors = this.type === "toEdge" ? `${startColor},${endColor}` : `${endColor},${startColor}`; + return `radial-gradient(circle at center, ${colors})`; + } + +} + +class Reason extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "reason"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Reasons extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "reasons", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.reason = new _xfa_object.XFAObjectArray(); + } + +} + +class Rectangle extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "rectangle", true); + this.hand = (0, _utils.getStringOption)(attributes.hand, ["even", "left", "right"]); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.corner = new _xfa_object.XFAObjectArray(4); + this.edge = new _xfa_object.XFAObjectArray(4); + this.fill = null; + } + + [_xfa_object.$toHTML]() { + const edge = this.edge.children.length ? this.edge.children[0] : new Edge({}); + + const edgeStyle = edge[_xfa_object.$toStyle](); + + const style = Object.create(null); + + if (this.fill && this.fill.presence === "visible") { + Object.assign(style, this.fill[_xfa_object.$toStyle]()); + } else { + style.fill = "transparent"; + } + + style.strokeWidth = (0, _html_utils.measureToString)(edge.presence === "visible" ? edge.thickness : 0); + style.stroke = edgeStyle.color; + const corner = this.corner.children.length ? this.corner.children[0] : new Corner({}); + + const cornerStyle = corner[_xfa_object.$toStyle](); + + const rect = { + name: "rect", + attributes: { + xmlns: SVG_NS, + width: "100%", + height: "100%", + x: 0, + y: 0, + rx: cornerStyle.radius, + ry: cornerStyle.radius, + style + } + }; + const svg = { + name: "svg", + children: [rect], + attributes: { + xmlns: SVG_NS, + style: { + overflow: "visible" + }, + width: "100%", + height: "100%" + } + }; + + const parent = this[_xfa_object.$getParent]()[_xfa_object.$getParent](); + + if (hasMargin(parent)) { + return _utils.HTMLResult.success({ + name: "div", + attributes: { + style: { + display: "inline", + width: "100%", + height: "100%" + } + }, + children: [svg] + }); + } + + svg.attributes.style.position = "absolute"; + return _utils.HTMLResult.success(svg); + } + +} + +class RefElement extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "ref"); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Script extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "script"); + this.binding = attributes.binding || ""; + this.contentType = attributes.contentType || ""; + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.runAt = (0, _utils.getStringOption)(attributes.runAt, ["client", "both", "server"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class SetProperty extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "setProperty"); + this.connection = attributes.connection || ""; + this.ref = attributes.ref || ""; + this.target = attributes.target || ""; + } + +} + +exports.SetProperty = SetProperty; + +class SignData extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "signData", true); + this.id = attributes.id || ""; + this.operation = (0, _utils.getStringOption)(attributes.operation, ["sign", "clear", "verify"]); + this.ref = attributes.ref || ""; + this.target = attributes.target || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.filter = null; + this.manifest = null; + } + +} + +class Signature extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "signature", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["PDF1.3", "PDF1.6"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.border = null; + this.extras = null; + this.filter = null; + this.manifest = null; + this.margin = null; + } + +} + +class Signing extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "signing", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.certificate = new _xfa_object.XFAObjectArray(); + } + +} + +class Solid extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "solid", true); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + } + + [_xfa_object.$toStyle](startColor) { + return startColor ? startColor[_xfa_object.$toStyle]() : "#FFFFFF"; + } + +} + +class Speak extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "speak"); + this.disable = (0, _utils.getInteger)({ + data: attributes.disable, + defaultValue: 0, + validate: x => x === 1 + }); + this.id = attributes.id || ""; + this.priority = (0, _utils.getStringOption)(attributes.priority, ["custom", "caption", "name", "toolTip"]); + this.rid = attributes.rid || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Stipple extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "stipple", true); + this.id = attributes.id || ""; + this.rate = (0, _utils.getInteger)({ + data: attributes.rate, + defaultValue: 50, + validate: x => x >= 0 && x <= 100 + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.color = null; + this.extras = null; + } + + [_xfa_object.$toStyle](bgColor) { + const alpha = this.rate / 100; + return _util.Util.makeHexColor(Math.round(bgColor.value.r * (1 - alpha) + this.value.r * alpha), Math.round(bgColor.value.g * (1 - alpha) + this.value.g * alpha), Math.round(bgColor.value.b * (1 - alpha) + this.value.b * alpha)); + } + +} + +class Subform extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "subform", true); + this.access = (0, _utils.getStringOption)(attributes.access, ["open", "nonInteractive", "protected", "readOnly"]); + this.allowMacro = (0, _utils.getInteger)({ + data: attributes.allowMacro, + defaultValue: 0, + validate: x => x === 1 + }); + this.anchorType = (0, _utils.getStringOption)(attributes.anchorType, ["topLeft", "bottomCenter", "bottomLeft", "bottomRight", "middleCenter", "middleLeft", "middleRight", "topCenter", "topRight"]); + this.colSpan = (0, _utils.getInteger)({ + data: attributes.colSpan, + defaultValue: 1, + validate: n => n >= 1 || n === -1 + }); + this.columnWidths = (attributes.columnWidths || "").trim().split(/\s+/).map(x => x === "-1" ? -1 : (0, _utils.getMeasurement)(x)); + this.h = attributes.h ? (0, _utils.getMeasurement)(attributes.h) : ""; + this.hAlign = (0, _utils.getStringOption)(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]); + this.id = attributes.id || ""; + this.layout = (0, _utils.getStringOption)(attributes.layout, ["position", "lr-tb", "rl-row", "rl-tb", "row", "table", "tb"]); + this.locale = attributes.locale || ""; + this.maxH = (0, _utils.getMeasurement)(attributes.maxH, "0pt"); + this.maxW = (0, _utils.getMeasurement)(attributes.maxW, "0pt"); + this.mergeMode = (0, _utils.getStringOption)(attributes.mergeMode, ["consumeData", "matchTemplate"]); + this.minH = (0, _utils.getMeasurement)(attributes.minH, "0pt"); + this.minW = (0, _utils.getMeasurement)(attributes.minW, "0pt"); + this.name = attributes.name || ""; + this.presence = (0, _utils.getStringOption)(attributes.presence, ["visible", "hidden", "inactive", "invisible"]); + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.restoreState = (0, _utils.getStringOption)(attributes.restoreState, ["manual", "auto"]); + this.scope = (0, _utils.getStringOption)(attributes.scope, ["name", "none"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.w = attributes.w ? (0, _utils.getMeasurement)(attributes.w) : ""; + this.x = (0, _utils.getMeasurement)(attributes.x, "0pt"); + this.y = (0, _utils.getMeasurement)(attributes.y, "0pt"); + this.assist = null; + this.bind = null; + this.bookend = null; + this.border = null; + this.break = null; + this.calculate = null; + this.desc = null; + this.extras = null; + this.keep = null; + this.margin = null; + this.occur = null; + this.overflow = null; + this.pageSet = null; + this.para = null; + this.traversal = null; + this.validate = null; + this.variables = null; + this.area = new _xfa_object.XFAObjectArray(); + this.breakAfter = new _xfa_object.XFAObjectArray(); + this.breakBefore = new _xfa_object.XFAObjectArray(); + this.connect = new _xfa_object.XFAObjectArray(); + this.draw = new _xfa_object.XFAObjectArray(); + this.event = new _xfa_object.XFAObjectArray(); + this.exObject = new _xfa_object.XFAObjectArray(); + this.exclGroup = new _xfa_object.XFAObjectArray(); + this.field = new _xfa_object.XFAObjectArray(); + this.proto = new _xfa_object.XFAObjectArray(); + this.setProperty = new _xfa_object.XFAObjectArray(); + this.subform = new _xfa_object.XFAObjectArray(); + this.subformSet = new _xfa_object.XFAObjectArray(); + } + + [_xfa_object.$getSubformParent]() { + const parent = this[_xfa_object.$getParent](); + + if (parent instanceof SubformSet) { + return parent[_xfa_object.$getSubformParent](); + } + + return parent; + } + + [_xfa_object.$isBindable]() { + return true; + } + + [_xfa_object.$isThereMoreWidth]() { + return this.layout.endsWith("-tb") && this[_xfa_object.$extra].attempt === 0 && this[_xfa_object.$extra].numberInLine > 0 || this[_xfa_object.$getParent]()[_xfa_object.$isThereMoreWidth](); + } + + *[_xfa_object.$getContainedChildren]() { + yield* getContainedChildren(this); + } + + [_xfa_object.$flushHTML]() { + return (0, _layout.flushHTML)(this); + } + + [_xfa_object.$addHTML](html, bbox) { + (0, _layout.addHTML)(this, html, bbox); + } + + [_xfa_object.$getAvailableSpace]() { + return (0, _layout.getAvailableSpace)(this); + } + + [_xfa_object.$isSplittable]() { + const parent = this[_xfa_object.$getSubformParent](); + + if (!parent[_xfa_object.$isSplittable]()) { + return false; + } + + if (this[_xfa_object.$extra]._isSplittable !== undefined) { + return this[_xfa_object.$extra]._isSplittable; + } + + if (this.layout === "position" || this.layout.includes("row")) { + this[_xfa_object.$extra]._isSplittable = false; + return false; + } + + if (this.keep && this.keep.intact !== "none") { + this[_xfa_object.$extra]._isSplittable = false; + return false; + } + + if (parent.layout && parent.layout.endsWith("-tb") && parent[_xfa_object.$extra].numberInLine !== 0) { + return false; + } + + this[_xfa_object.$extra]._isSplittable = true; + return true; + } + + [_xfa_object.$toHTML](availableSpace) { + setTabIndex(this); + + if (this.break) { + if (this.break.after !== "auto" || this.break.afterTarget !== "") { + const node = new BreakAfter({ + targetType: this.break.after, + target: this.break.afterTarget, + startNew: this.break.startNew.toString() + }); + node[_xfa_object.$globalData] = this[_xfa_object.$globalData]; + + this[_xfa_object.$appendChild](node); + + this.breakAfter.push(node); + } + + if (this.break.before !== "auto" || this.break.beforeTarget !== "") { + const node = new BreakBefore({ + targetType: this.break.before, + target: this.break.beforeTarget, + startNew: this.break.startNew.toString() + }); + node[_xfa_object.$globalData] = this[_xfa_object.$globalData]; + + this[_xfa_object.$appendChild](node); + + this.breakBefore.push(node); + } + + if (this.break.overflowTarget !== "") { + const node = new Overflow({ + target: this.break.overflowTarget, + leader: this.break.overflowLeader, + trailer: this.break.overflowTrailer + }); + node[_xfa_object.$globalData] = this[_xfa_object.$globalData]; + + this[_xfa_object.$appendChild](node); + + this.overflow.push(node); + } + + this[_xfa_object.$removeChild](this.break); + + this.break = null; + } + + if (this.presence === "hidden" || this.presence === "inactive") { + return _utils.HTMLResult.EMPTY; + } + + if (this.breakBefore.children.length > 1 || this.breakAfter.children.length > 1) { + (0, _util.warn)("XFA - Several breakBefore or breakAfter in subforms: please file a bug."); + } + + if (this.breakBefore.children.length >= 1) { + const breakBefore = this.breakBefore.children[0]; + + if (handleBreak(breakBefore)) { + return _utils.HTMLResult.breakNode(breakBefore); + } + } + + if (this[_xfa_object.$extra] && this[_xfa_object.$extra].afterBreakAfter) { + return _utils.HTMLResult.EMPTY; + } + + (0, _html_utils.fixDimensions)(this); + const children = []; + const attributes = { + id: this[_xfa_object.$uid], + class: [] + }; + (0, _html_utils.setAccess)(this, attributes.class); + + if (!this[_xfa_object.$extra]) { + this[_xfa_object.$extra] = Object.create(null); + } + + Object.assign(this[_xfa_object.$extra], { + children, + line: null, + attributes, + attempt: 0, + numberInLine: 0, + availableSpace: { + width: Math.min(this.w || Infinity, availableSpace.width), + height: Math.min(this.h || Infinity, availableSpace.height) + }, + width: 0, + height: 0, + prevHeight: 0, + currentWidth: 0 + }); + + const root = this[_xfa_object.$getTemplateRoot](); + + const savedNoLayoutFailure = root[_xfa_object.$extra].noLayoutFailure; + + const isSplittable = this[_xfa_object.$isSplittable](); + + if (!isSplittable) { + setFirstUnsplittable(this); + } + + if (!(0, _layout.checkDimensions)(this, availableSpace)) { + return _utils.HTMLResult.FAILURE; + } + + const filter = new Set(["area", "draw", "exclGroup", "field", "subform", "subformSet"]); + + if (this.layout.includes("row")) { + const columnWidths = this[_xfa_object.$getSubformParent]().columnWidths; + + if (Array.isArray(columnWidths) && columnWidths.length > 0) { + this[_xfa_object.$extra].columnWidths = columnWidths; + this[_xfa_object.$extra].currentColumn = 0; + } + } + + const style = (0, _html_utils.toStyle)(this, "anchorType", "dimensions", "position", "presence", "border", "margin", "hAlign"); + const classNames = ["xfaSubform"]; + const cl = (0, _html_utils.layoutClass)(this); + + if (cl) { + classNames.push(cl); + } + + attributes.style = style; + attributes.class = classNames; + + if (this.name) { + attributes.xfaName = this.name; + } + + if (this.overflow) { + const overflowExtra = this.overflow[_xfa_object.$getExtra](); + + if (overflowExtra.addLeader) { + overflowExtra.addLeader = false; + handleOverflow(this, overflowExtra.leader, availableSpace); + } + } + + this[_xfa_object.$pushPara](); + + const isLrTb = this.layout === "lr-tb" || this.layout === "rl-tb"; + const maxRun = isLrTb ? MAX_ATTEMPTS_FOR_LRTB_LAYOUT : 1; + + for (; this[_xfa_object.$extra].attempt < maxRun; this[_xfa_object.$extra].attempt++) { + if (isLrTb && this[_xfa_object.$extra].attempt === MAX_ATTEMPTS_FOR_LRTB_LAYOUT - 1) { + this[_xfa_object.$extra].numberInLine = 0; + } + + const result = this[_xfa_object.$childrenToHTML]({ + filter, + include: true + }); + + if (result.success) { + break; + } + + if (result.isBreak()) { + this[_xfa_object.$popPara](); + + return result; + } + + if (isLrTb && this[_xfa_object.$extra].attempt === 0 && this[_xfa_object.$extra].numberInLine === 0 && !root[_xfa_object.$extra].noLayoutFailure) { + this[_xfa_object.$extra].attempt = maxRun; + break; + } + } + + this[_xfa_object.$popPara](); + + if (!isSplittable) { + unsetFirstUnsplittable(this); + } + + root[_xfa_object.$extra].noLayoutFailure = savedNoLayoutFailure; + + if (this[_xfa_object.$extra].attempt === maxRun) { + if (this.overflow) { + this[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].overflowNode = this.overflow; + } + + if (!isSplittable) { + delete this[_xfa_object.$extra]; + } + + return _utils.HTMLResult.FAILURE; + } + + if (this.overflow) { + const overflowExtra = this.overflow[_xfa_object.$getExtra](); + + if (overflowExtra.addTrailer) { + overflowExtra.addTrailer = false; + handleOverflow(this, overflowExtra.trailer, availableSpace); + } + } + + let marginH = 0; + let marginV = 0; + + if (this.margin) { + marginH = this.margin.leftInset + this.margin.rightInset; + marginV = this.margin.topInset + this.margin.bottomInset; + } + + const width = Math.max(this[_xfa_object.$extra].width + marginH, this.w || 0); + const height = Math.max(this[_xfa_object.$extra].height + marginV, this.h || 0); + const bbox = [this.x, this.y, width, height]; + + if (this.w === "") { + style.width = (0, _html_utils.measureToString)(width); + } + + if (this.h === "") { + style.height = (0, _html_utils.measureToString)(height); + } + + if ((style.width === "0px" || style.height === "0px") && children.length === 0) { + return _utils.HTMLResult.EMPTY; + } + + const html = { + name: "div", + attributes, + children + }; + applyAssist(this, attributes); + + const result = _utils.HTMLResult.success((0, _html_utils.createWrapper)(this, html), bbox); + + if (this.breakAfter.children.length >= 1) { + const breakAfter = this.breakAfter.children[0]; + + if (handleBreak(breakAfter)) { + this[_xfa_object.$extra].afterBreakAfter = result; + return _utils.HTMLResult.breakNode(breakAfter); + } + } + + delete this[_xfa_object.$extra]; + return result; + } + +} + +class SubformSet extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "subformSet", true); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.relation = (0, _utils.getStringOption)(attributes.relation, ["ordered", "choice", "unordered"]); + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.bookend = null; + this.break = null; + this.desc = null; + this.extras = null; + this.occur = null; + this.overflow = null; + this.breakAfter = new _xfa_object.XFAObjectArray(); + this.breakBefore = new _xfa_object.XFAObjectArray(); + this.subform = new _xfa_object.XFAObjectArray(); + this.subformSet = new _xfa_object.XFAObjectArray(); + } + + *[_xfa_object.$getContainedChildren]() { + yield* getContainedChildren(this); + } + + [_xfa_object.$getSubformParent]() { + let parent = this[_xfa_object.$getParent](); + + while (!(parent instanceof Subform)) { + parent = parent[_xfa_object.$getParent](); + } + + return parent; + } + + [_xfa_object.$isBindable]() { + return true; + } + +} + +class SubjectDN extends _xfa_object.ContentObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "subjectDN"); + this.delimiter = attributes.delimiter || ","; + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$finalize]() { + this[_xfa_object.$content] = new Map(this[_xfa_object.$content].split(this.delimiter).map(kv => { + kv = kv.split("=", 2); + kv[0] = kv[0].trim(); + return kv; + })); + } + +} + +class SubjectDNs extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "subjectDNs", true); + this.id = attributes.id || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.subjectDN = new _xfa_object.XFAObjectArray(); + } + +} + +class Submit extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "submit", true); + this.embedPDF = (0, _utils.getInteger)({ + data: attributes.embedPDF, + defaultValue: 0, + validate: x => x === 1 + }); + this.format = (0, _utils.getStringOption)(attributes.format, ["xdp", "formdata", "pdf", "urlencoded", "xfd", "xml"]); + this.id = attributes.id || ""; + this.target = attributes.target || ""; + this.textEncoding = (0, _utils.getKeyword)({ + data: attributes.textEncoding ? attributes.textEncoding.toLowerCase() : "", + defaultValue: "", + validate: k => ["utf-8", "big-five", "fontspecific", "gbk", "gb-18030", "gb-2312", "ksc-5601", "none", "shift-jis", "ucs-2", "utf-16"].includes(k) || k.match(/iso-8859-\d{2}/) + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.xdpContent = attributes.xdpContent || ""; + this.encrypt = null; + this.encryptData = new _xfa_object.XFAObjectArray(); + this.signData = new _xfa_object.XFAObjectArray(); + } + +} + +class Template extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "template", true); + this.baseProfile = (0, _utils.getStringOption)(attributes.baseProfile, ["full", "interactiveForms"]); + this.extras = null; + this.subform = new _xfa_object.XFAObjectArray(); + } + + [_xfa_object.$finalize]() { + if (this.subform.children.length === 0) { + (0, _util.warn)("XFA - No subforms in template node."); + } + + if (this.subform.children.length >= 2) { + (0, _util.warn)("XFA - Several subforms in template node: please file a bug."); + } + + this[_xfa_object.$tabIndex] = DEFAULT_TAB_INDEX; + } + + [_xfa_object.$isSplittable]() { + return true; + } + + [_xfa_object.$searchNode](expr, container) { + if (expr.startsWith("#")) { + return [this[_xfa_object.$ids].get(expr.slice(1))]; + } + + return (0, _som.searchNode)(this, container, expr, true, true); + } + + *[_xfa_object.$toPages]() { + if (!this.subform.children.length) { + return _utils.HTMLResult.success({ + name: "div", + children: [] + }); + } + + this[_xfa_object.$extra] = { + overflowNode: null, + firstUnsplittable: null, + currentContentArea: null, + currentPageArea: null, + noLayoutFailure: false, + pageNumber: 1, + pagePosition: "first", + oddOrEven: "odd", + blankOrNotBlank: "nonBlank", + paraStack: [] + }; + const root = this.subform.children[0]; + + root.pageSet[_xfa_object.$cleanPage](); + + const pageAreas = root.pageSet.pageArea.children; + const mainHtml = { + name: "div", + children: [] + }; + let pageArea = null; + let breakBefore = null; + let breakBeforeTarget = null; + + if (root.breakBefore.children.length >= 1) { + breakBefore = root.breakBefore.children[0]; + breakBeforeTarget = breakBefore.target; + } else if (root.subform.children.length >= 1 && root.subform.children[0].breakBefore.children.length >= 1) { + breakBefore = root.subform.children[0].breakBefore.children[0]; + breakBeforeTarget = breakBefore.target; + } else if (root.break && root.break.beforeTarget) { + breakBefore = root.break; + breakBeforeTarget = breakBefore.beforeTarget; + } else if (root.subform.children.length >= 1 && root.subform.children[0].break && root.subform.children[0].break.beforeTarget) { + breakBefore = root.subform.children[0].break; + breakBeforeTarget = breakBefore.beforeTarget; + } + + if (breakBefore) { + const target = this[_xfa_object.$searchNode](breakBeforeTarget, breakBefore[_xfa_object.$getParent]()); + + if (target instanceof PageArea) { + pageArea = target; + breakBefore[_xfa_object.$extra] = {}; + } + } + + if (!pageArea) { + pageArea = pageAreas[0]; + } + + pageArea[_xfa_object.$extra] = { + numberOfUse: 1 + }; + + const pageAreaParent = pageArea[_xfa_object.$getParent](); + + pageAreaParent[_xfa_object.$extra] = { + numberOfUse: 1, + pageIndex: pageAreaParent.pageArea.children.indexOf(pageArea), + pageSetIndex: 0 + }; + let targetPageArea; + let leader = null; + let trailer = null; + let hasSomething = true; + let hasSomethingCounter = 0; + let startIndex = 0; + + while (true) { + if (!hasSomething) { + mainHtml.children.pop(); + + if (++hasSomethingCounter === MAX_EMPTY_PAGES) { + (0, _util.warn)("XFA - Something goes wrong: please file a bug."); + return mainHtml; + } + } else { + hasSomethingCounter = 0; + } + + targetPageArea = null; + this[_xfa_object.$extra].currentPageArea = pageArea; + + const page = pageArea[_xfa_object.$toHTML]().html; + + mainHtml.children.push(page); + + if (leader) { + this[_xfa_object.$extra].noLayoutFailure = true; + page.children.push(leader[_xfa_object.$toHTML](pageArea[_xfa_object.$extra].space).html); + leader = null; + } + + if (trailer) { + this[_xfa_object.$extra].noLayoutFailure = true; + page.children.push(trailer[_xfa_object.$toHTML](pageArea[_xfa_object.$extra].space).html); + trailer = null; + } + + const contentAreas = pageArea.contentArea.children; + const htmlContentAreas = page.children.filter(node => node.attributes.class.includes("xfaContentarea")); + hasSomething = false; + this[_xfa_object.$extra].firstUnsplittable = null; + this[_xfa_object.$extra].noLayoutFailure = false; + + const flush = index => { + const html = root[_xfa_object.$flushHTML](); + + if (html) { + hasSomething = hasSomething || html.children && html.children.length !== 0; + htmlContentAreas[index].children.push(html); + } + }; + + for (let i = startIndex, ii = contentAreas.length; i < ii; i++) { + const contentArea = this[_xfa_object.$extra].currentContentArea = contentAreas[i]; + const space = { + width: contentArea.w, + height: contentArea.h + }; + startIndex = 0; + + if (leader) { + htmlContentAreas[i].children.push(leader[_xfa_object.$toHTML](space).html); + leader = null; + } + + if (trailer) { + htmlContentAreas[i].children.push(trailer[_xfa_object.$toHTML](space).html); + trailer = null; + } + + const html = root[_xfa_object.$toHTML](space); + + if (html.success) { + if (html.html) { + hasSomething = hasSomething || html.html.children && html.html.children.length !== 0; + htmlContentAreas[i].children.push(html.html); + } else if (!hasSomething && mainHtml.children.length > 1) { + mainHtml.children.pop(); + } + + return mainHtml; + } + + if (html.isBreak()) { + const node = html.breakNode; + flush(i); + + if (node.targetType === "auto") { + continue; + } + + if (node.leader) { + leader = this[_xfa_object.$searchNode](node.leader, node[_xfa_object.$getParent]()); + leader = leader ? leader[0] : null; + } + + if (node.trailer) { + trailer = this[_xfa_object.$searchNode](node.trailer, node[_xfa_object.$getParent]()); + trailer = trailer ? trailer[0] : null; + } + + if (node.targetType === "pageArea") { + targetPageArea = node[_xfa_object.$extra].target; + i = Infinity; + } else if (!node[_xfa_object.$extra].target) { + i = node[_xfa_object.$extra].index; + } else { + targetPageArea = node[_xfa_object.$extra].target; + startIndex = node[_xfa_object.$extra].index + 1; + i = Infinity; + } + + continue; + } + + if (this[_xfa_object.$extra].overflowNode) { + const node = this[_xfa_object.$extra].overflowNode; + this[_xfa_object.$extra].overflowNode = null; + + const overflowExtra = node[_xfa_object.$getExtra](); + + const target = overflowExtra.target; + overflowExtra.addLeader = overflowExtra.leader !== null; + overflowExtra.addTrailer = overflowExtra.trailer !== null; + flush(i); + const currentIndex = i; + i = Infinity; + + if (target instanceof PageArea) { + targetPageArea = target; + } else if (target instanceof ContentArea) { + const index = contentAreas.indexOf(target); + + if (index !== -1) { + if (index > currentIndex) { + i = index - 1; + } else { + startIndex = index; + } + } else { + targetPageArea = target[_xfa_object.$getParent](); + startIndex = targetPageArea.contentArea.children.indexOf(target); + } + } + + continue; + } + + flush(i); + } + + this[_xfa_object.$extra].pageNumber += 1; + + if (targetPageArea) { + if (targetPageArea[_xfa_object.$isUsable]()) { + targetPageArea[_xfa_object.$extra].numberOfUse += 1; + } else { + targetPageArea = null; + } + } + + pageArea = targetPageArea || pageArea[_xfa_object.$getNextPage](); + yield null; + } + } + +} + +exports.Template = Template; + +class Text extends _xfa_object.ContentObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "text"); + this.id = attributes.id || ""; + this.maxChars = (0, _utils.getInteger)({ + data: attributes.maxChars, + defaultValue: 0, + validate: x => x >= 0 + }); + this.name = attributes.name || ""; + this.rid = attributes.rid || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$acceptWhitespace]() { + return true; + } + + [_xfa_object.$onChild](child) { + if (child[_xfa_object.$namespaceId] === _namespaces.NamespaceIds.xhtml.id) { + this[_xfa_object.$content] = child; + return true; + } + + (0, _util.warn)(`XFA - Invalid content in Text: ${child[_xfa_object.$nodeName]}.`); + return false; + } + + [_xfa_object.$onText](str) { + if (this[_xfa_object.$content] instanceof _xfa_object.XFAObject) { + return; + } + + super[_xfa_object.$onText](str); + } + + [_xfa_object.$finalize]() { + if (typeof this[_xfa_object.$content] === "string") { + this[_xfa_object.$content] = this[_xfa_object.$content].replace(/\r\n/g, "\n"); + } + } + + [_xfa_object.$getExtra]() { + if (typeof this[_xfa_object.$content] === "string") { + return this[_xfa_object.$content].split(/[\u2029\u2028\n]/).reduce((acc, line) => { + if (line) { + acc.push(line); + } + + return acc; + }, []).join("\n"); + } + + return this[_xfa_object.$content][_xfa_object.$text](); + } + + [_xfa_object.$toHTML](availableSpace) { + if (typeof this[_xfa_object.$content] === "string") { + const html = valueToHtml(this[_xfa_object.$content]).html; + + if (this[_xfa_object.$content].includes("\u2029")) { + html.name = "div"; + html.children = []; + + this[_xfa_object.$content].split("\u2029").map(para => para.split(/[\u2028\n]/).reduce((acc, line) => { + acc.push({ + name: "span", + value: line + }, { + name: "br" + }); + return acc; + }, [])).forEach(lines => { + html.children.push({ + name: "p", + children: lines + }); + }); + } else if (/[\u2028\n]/.test(this[_xfa_object.$content])) { + html.name = "div"; + html.children = []; + + this[_xfa_object.$content].split(/[\u2028\n]/).forEach(line => { + html.children.push({ + name: "span", + value: line + }, { + name: "br" + }); + }); + } + + return _utils.HTMLResult.success(html); + } + + return this[_xfa_object.$content][_xfa_object.$toHTML](availableSpace); + } + +} + +exports.Text = Text; + +class TextEdit extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "textEdit", true); + this.allowRichText = (0, _utils.getInteger)({ + data: attributes.allowRichText, + defaultValue: 0, + validate: x => x === 1 + }); + this.hScrollPolicy = (0, _utils.getStringOption)(attributes.hScrollPolicy, ["auto", "off", "on"]); + this.id = attributes.id || ""; + this.multiLine = (0, _utils.getInteger)({ + data: attributes.multiLine, + defaultValue: "", + validate: x => x === 0 || x === 1 + }); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.vScrollPolicy = (0, _utils.getStringOption)(attributes.vScrollPolicy, ["auto", "off", "on"]); + this.border = null; + this.comb = null; + this.extras = null; + this.margin = null; + } + + [_xfa_object.$toHTML](availableSpace) { + const style = (0, _html_utils.toStyle)(this, "border", "font", "margin"); + let html; + + const field = this[_xfa_object.$getParent]()[_xfa_object.$getParent](); + + if (this.multiLine === "") { + this.multiLine = field instanceof Draw ? 1 : 0; + } + + if (this.multiLine === 1) { + html = { + name: "textarea", + attributes: { + dataId: field[_xfa_object.$data] && field[_xfa_object.$data][_xfa_object.$uid] || field[_xfa_object.$uid], + fieldId: field[_xfa_object.$uid], + class: ["xfaTextfield"], + style, + "aria-label": ariaLabel(field), + "aria-required": false + } + }; + } else { + html = { + name: "input", + attributes: { + type: "text", + dataId: field[_xfa_object.$data] && field[_xfa_object.$data][_xfa_object.$uid] || field[_xfa_object.$uid], + fieldId: field[_xfa_object.$uid], + class: ["xfaTextfield"], + style, + "aria-label": ariaLabel(field), + "aria-required": false + } + }; + } + + if (isRequired(field)) { + html.attributes["aria-required"] = true; + html.attributes.required = true; + } + + return _utils.HTMLResult.success({ + name: "label", + attributes: { + class: ["xfaLabel"] + }, + children: [html] + }); + } + +} + +class Time extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "time"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + + [_xfa_object.$finalize]() { + const date = this[_xfa_object.$content].trim(); + + this[_xfa_object.$content] = date ? new Date(date) : null; + } + + [_xfa_object.$toHTML](availableSpace) { + return valueToHtml(this[_xfa_object.$content] ? this[_xfa_object.$content].toString() : ""); + } + +} + +class TimeStamp extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "timeStamp"); + this.id = attributes.id || ""; + this.server = attributes.server || ""; + this.type = (0, _utils.getStringOption)(attributes.type, ["optional", "required"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class ToolTip extends _xfa_object.StringObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "toolTip"); + this.id = attributes.id || ""; + this.rid = attributes.rid || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Traversal extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "traversal", true); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.traverse = new _xfa_object.XFAObjectArray(); + } + +} + +class Traverse extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "traverse", true); + this.id = attributes.id || ""; + this.operation = (0, _utils.getStringOption)(attributes.operation, ["next", "back", "down", "first", "left", "right", "up"]); + this.ref = attributes.ref || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.script = null; + } + + get name() { + return this.operation; + } + + [_xfa_object.$isTransparent]() { + return false; + } + +} + +class Ui extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "ui", true); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.picture = null; + this.barcode = null; + this.button = null; + this.checkButton = null; + this.choiceList = null; + this.dateTimeEdit = null; + this.defaultUi = null; + this.imageEdit = null; + this.numericEdit = null; + this.passwordEdit = null; + this.signature = null; + this.textEdit = null; + } + + [_xfa_object.$getExtra]() { + if (this[_xfa_object.$extra] === undefined) { + for (const name of Object.getOwnPropertyNames(this)) { + if (name === "extras" || name === "picture") { + continue; + } + + const obj = this[name]; + + if (!(obj instanceof _xfa_object.XFAObject)) { + continue; + } + + this[_xfa_object.$extra] = obj; + return obj; + } + + this[_xfa_object.$extra] = null; + } + + return this[_xfa_object.$extra]; + } + + [_xfa_object.$toHTML](availableSpace) { + const obj = this[_xfa_object.$getExtra](); + + if (obj) { + return obj[_xfa_object.$toHTML](availableSpace); + } + + return _utils.HTMLResult.EMPTY; + } + +} + +class Validate extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "validate", true); + this.formatTest = (0, _utils.getStringOption)(attributes.formatTest, ["warning", "disabled", "error"]); + this.id = attributes.id || ""; + this.nullTest = (0, _utils.getStringOption)(attributes.nullTest, ["disabled", "error", "warning"]); + this.scriptTest = (0, _utils.getStringOption)(attributes.scriptTest, ["error", "disabled", "warning"]); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.extras = null; + this.message = null; + this.picture = null; + this.script = null; + } + +} + +class Value extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "value", true); + this.id = attributes.id || ""; + this.override = (0, _utils.getInteger)({ + data: attributes.override, + defaultValue: 0, + validate: x => x === 1 + }); + this.relevant = (0, _utils.getRelevant)(attributes.relevant); + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.arc = null; + this.boolean = null; + this.date = null; + this.dateTime = null; + this.decimal = null; + this.exData = null; + this.float = null; + this.image = null; + this.integer = null; + this.line = null; + this.rectangle = null; + this.text = null; + this.time = null; + } + + [_xfa_object.$setValue](value) { + const parent = this[_xfa_object.$getParent](); + + if (parent instanceof Field) { + if (parent.ui && parent.ui.imageEdit) { + if (!this.image) { + this.image = new Image({}); + + this[_xfa_object.$appendChild](this.image); + } + + this.image[_xfa_object.$content] = value[_xfa_object.$content]; + return; + } + } + + const valueName = value[_xfa_object.$nodeName]; + + if (this[valueName] !== null) { + this[valueName][_xfa_object.$content] = value[_xfa_object.$content]; + return; + } + + for (const name of Object.getOwnPropertyNames(this)) { + const obj = this[name]; + + if (obj instanceof _xfa_object.XFAObject) { + this[name] = null; + + this[_xfa_object.$removeChild](obj); + } + } + + this[value[_xfa_object.$nodeName]] = value; + + this[_xfa_object.$appendChild](value); + } + + [_xfa_object.$text]() { + if (this.exData) { + if (typeof this.exData[_xfa_object.$content] === "string") { + return this.exData[_xfa_object.$content].trim(); + } + + return this.exData[_xfa_object.$content][_xfa_object.$text]().trim(); + } + + for (const name of Object.getOwnPropertyNames(this)) { + if (name === "image") { + continue; + } + + const obj = this[name]; + + if (obj instanceof _xfa_object.XFAObject) { + return (obj[_xfa_object.$content] || "").toString().trim(); + } + } + + return null; + } + + [_xfa_object.$toHTML](availableSpace) { + for (const name of Object.getOwnPropertyNames(this)) { + const obj = this[name]; + + if (!(obj instanceof _xfa_object.XFAObject)) { + continue; + } + + return obj[_xfa_object.$toHTML](availableSpace); + } + + return _utils.HTMLResult.EMPTY; + } + +} + +exports.Value = Value; + +class Variables extends _xfa_object.XFAObject { + constructor(attributes) { + super(TEMPLATE_NS_ID, "variables", true); + this.id = attributes.id || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + this.boolean = new _xfa_object.XFAObjectArray(); + this.date = new _xfa_object.XFAObjectArray(); + this.dateTime = new _xfa_object.XFAObjectArray(); + this.decimal = new _xfa_object.XFAObjectArray(); + this.exData = new _xfa_object.XFAObjectArray(); + this.float = new _xfa_object.XFAObjectArray(); + this.image = new _xfa_object.XFAObjectArray(); + this.integer = new _xfa_object.XFAObjectArray(); + this.manifest = new _xfa_object.XFAObjectArray(); + this.script = new _xfa_object.XFAObjectArray(); + this.text = new _xfa_object.XFAObjectArray(); + this.time = new _xfa_object.XFAObjectArray(); + } + + [_xfa_object.$isTransparent]() { + return true; + } + +} + +class TemplateNamespace { + static [_namespaces.$buildXFAObject](name, attributes) { + if (TemplateNamespace.hasOwnProperty(name)) { + const node = TemplateNamespace[name](attributes); + + node[_xfa_object.$setSetAttributes](attributes); + + return node; + } + + return undefined; + } + + static appearanceFilter(attrs) { + return new AppearanceFilter(attrs); + } + + static arc(attrs) { + return new Arc(attrs); + } + + static area(attrs) { + return new Area(attrs); + } + + static assist(attrs) { + return new Assist(attrs); + } + + static barcode(attrs) { + return new Barcode(attrs); + } + + static bind(attrs) { + return new Bind(attrs); + } + + static bindItems(attrs) { + return new BindItems(attrs); + } + + static bookend(attrs) { + return new Bookend(attrs); + } + + static boolean(attrs) { + return new BooleanElement(attrs); + } + + static border(attrs) { + return new Border(attrs); + } + + static break(attrs) { + return new Break(attrs); + } + + static breakAfter(attrs) { + return new BreakAfter(attrs); + } + + static breakBefore(attrs) { + return new BreakBefore(attrs); + } + + static button(attrs) { + return new Button(attrs); + } + + static calculate(attrs) { + return new Calculate(attrs); + } + + static caption(attrs) { + return new Caption(attrs); + } + + static certificate(attrs) { + return new Certificate(attrs); + } + + static certificates(attrs) { + return new Certificates(attrs); + } + + static checkButton(attrs) { + return new CheckButton(attrs); + } + + static choiceList(attrs) { + return new ChoiceList(attrs); + } + + static color(attrs) { + return new Color(attrs); + } + + static comb(attrs) { + return new Comb(attrs); + } + + static connect(attrs) { + return new Connect(attrs); + } + + static contentArea(attrs) { + return new ContentArea(attrs); + } + + static corner(attrs) { + return new Corner(attrs); + } + + static date(attrs) { + return new DateElement(attrs); + } + + static dateTime(attrs) { + return new DateTime(attrs); + } + + static dateTimeEdit(attrs) { + return new DateTimeEdit(attrs); + } + + static decimal(attrs) { + return new Decimal(attrs); + } + + static defaultUi(attrs) { + return new DefaultUi(attrs); + } + + static desc(attrs) { + return new Desc(attrs); + } + + static digestMethod(attrs) { + return new DigestMethod(attrs); + } + + static digestMethods(attrs) { + return new DigestMethods(attrs); + } + + static draw(attrs) { + return new Draw(attrs); + } + + static edge(attrs) { + return new Edge(attrs); + } + + static encoding(attrs) { + return new Encoding(attrs); + } + + static encodings(attrs) { + return new Encodings(attrs); + } + + static encrypt(attrs) { + return new Encrypt(attrs); + } + + static encryptData(attrs) { + return new EncryptData(attrs); + } + + static encryption(attrs) { + return new Encryption(attrs); + } + + static encryptionMethod(attrs) { + return new EncryptionMethod(attrs); + } + + static encryptionMethods(attrs) { + return new EncryptionMethods(attrs); + } + + static event(attrs) { + return new Event(attrs); + } + + static exData(attrs) { + return new ExData(attrs); + } + + static exObject(attrs) { + return new ExObject(attrs); + } + + static exclGroup(attrs) { + return new ExclGroup(attrs); + } + + static execute(attrs) { + return new Execute(attrs); + } + + static extras(attrs) { + return new Extras(attrs); + } + + static field(attrs) { + return new Field(attrs); + } + + static fill(attrs) { + return new Fill(attrs); + } + + static filter(attrs) { + return new Filter(attrs); + } + + static float(attrs) { + return new Float(attrs); + } + + static font(attrs) { + return new Font(attrs); + } + + static format(attrs) { + return new Format(attrs); + } + + static handler(attrs) { + return new Handler(attrs); + } + + static hyphenation(attrs) { + return new Hyphenation(attrs); + } + + static image(attrs) { + return new Image(attrs); + } + + static imageEdit(attrs) { + return new ImageEdit(attrs); + } + + static integer(attrs) { + return new Integer(attrs); + } + + static issuers(attrs) { + return new Issuers(attrs); + } + + static items(attrs) { + return new Items(attrs); + } + + static keep(attrs) { + return new Keep(attrs); + } + + static keyUsage(attrs) { + return new KeyUsage(attrs); + } + + static line(attrs) { + return new Line(attrs); + } + + static linear(attrs) { + return new Linear(attrs); + } + + static lockDocument(attrs) { + return new LockDocument(attrs); + } + + static manifest(attrs) { + return new Manifest(attrs); + } + + static margin(attrs) { + return new Margin(attrs); + } + + static mdp(attrs) { + return new Mdp(attrs); + } + + static medium(attrs) { + return new Medium(attrs); + } + + static message(attrs) { + return new Message(attrs); + } + + static numericEdit(attrs) { + return new NumericEdit(attrs); + } + + static occur(attrs) { + return new Occur(attrs); + } + + static oid(attrs) { + return new Oid(attrs); + } + + static oids(attrs) { + return new Oids(attrs); + } + + static overflow(attrs) { + return new Overflow(attrs); + } + + static pageArea(attrs) { + return new PageArea(attrs); + } + + static pageSet(attrs) { + return new PageSet(attrs); + } + + static para(attrs) { + return new Para(attrs); + } + + static passwordEdit(attrs) { + return new PasswordEdit(attrs); + } + + static pattern(attrs) { + return new Pattern(attrs); + } + + static picture(attrs) { + return new Picture(attrs); + } + + static proto(attrs) { + return new Proto(attrs); + } + + static radial(attrs) { + return new Radial(attrs); + } + + static reason(attrs) { + return new Reason(attrs); + } + + static reasons(attrs) { + return new Reasons(attrs); + } + + static rectangle(attrs) { + return new Rectangle(attrs); + } + + static ref(attrs) { + return new RefElement(attrs); + } + + static script(attrs) { + return new Script(attrs); + } + + static setProperty(attrs) { + return new SetProperty(attrs); + } + + static signData(attrs) { + return new SignData(attrs); + } + + static signature(attrs) { + return new Signature(attrs); + } + + static signing(attrs) { + return new Signing(attrs); + } + + static solid(attrs) { + return new Solid(attrs); + } + + static speak(attrs) { + return new Speak(attrs); + } + + static stipple(attrs) { + return new Stipple(attrs); + } + + static subform(attrs) { + return new Subform(attrs); + } + + static subformSet(attrs) { + return new SubformSet(attrs); + } + + static subjectDN(attrs) { + return new SubjectDN(attrs); + } + + static subjectDNs(attrs) { + return new SubjectDNs(attrs); + } + + static submit(attrs) { + return new Submit(attrs); + } + + static template(attrs) { + return new Template(attrs); + } + + static text(attrs) { + return new Text(attrs); + } + + static textEdit(attrs) { + return new TextEdit(attrs); + } + + static time(attrs) { + return new Time(attrs); + } + + static timeStamp(attrs) { + return new TimeStamp(attrs); + } + + static toolTip(attrs) { + return new ToolTip(attrs); + } + + static traversal(attrs) { + return new Traversal(attrs); + } + + static traverse(attrs) { + return new Traverse(attrs); + } + + static ui(attrs) { + return new Ui(attrs); + } + + static validate(attrs) { + return new Validate(attrs); + } + + static value(attrs) { + return new Value(attrs); + } + + static variables(attrs) { + return new Variables(attrs); + } + +} + +exports.TemplateNamespace = TemplateNamespace; + +/***/ }), +/* 83 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.addHTML = addHTML; +exports.checkDimensions = checkDimensions; +exports.flushHTML = flushHTML; +exports.getAvailableSpace = getAvailableSpace; + +var _xfa_object = __w_pdfjs_require__(77); + +var _html_utils = __w_pdfjs_require__(84); + +function createLine(node, children) { + return { + name: "div", + attributes: { + class: [node.layout === "lr-tb" ? "xfaLr" : "xfaRl"] + }, + children + }; +} + +function flushHTML(node) { + if (!node[_xfa_object.$extra]) { + return null; + } + + const attributes = node[_xfa_object.$extra].attributes; + const html = { + name: "div", + attributes, + children: node[_xfa_object.$extra].children + }; + + if (node[_xfa_object.$extra].failingNode) { + const htmlFromFailing = node[_xfa_object.$extra].failingNode[_xfa_object.$flushHTML](); + + if (htmlFromFailing) { + if (node.layout.endsWith("-tb")) { + html.children.push(createLine(node, [htmlFromFailing])); + } else { + html.children.push(htmlFromFailing); + } + } + } + + if (html.children.length === 0) { + return null; + } + + return html; +} + +function addHTML(node, html, bbox) { + const extra = node[_xfa_object.$extra]; + const availableSpace = extra.availableSpace; + const [x, y, w, h] = bbox; + + switch (node.layout) { + case "position": + { + extra.width = Math.max(extra.width, x + w); + extra.height = Math.max(extra.height, y + h); + extra.children.push(html); + break; + } + + case "lr-tb": + case "rl-tb": + if (!extra.line || extra.attempt === 1) { + extra.line = createLine(node, []); + extra.children.push(extra.line); + extra.numberInLine = 0; + } + + extra.numberInLine += 1; + extra.line.children.push(html); + + if (extra.attempt === 0) { + extra.currentWidth += w; + extra.height = Math.max(extra.height, extra.prevHeight + h); + } else { + extra.currentWidth = w; + extra.prevHeight = extra.height; + extra.height += h; + extra.attempt = 0; + } + + extra.width = Math.max(extra.width, extra.currentWidth); + break; + + case "rl-row": + case "row": + { + extra.children.push(html); + extra.width += w; + extra.height = Math.max(extra.height, h); + const height = (0, _html_utils.measureToString)(extra.height); + + for (const child of extra.children) { + child.attributes.style.height = height; + } + + break; + } + + case "table": + { + extra.width = Math.min(availableSpace.width, Math.max(extra.width, w)); + extra.height += h; + extra.children.push(html); + break; + } + + case "tb": + { + extra.width = Math.min(availableSpace.width, Math.max(extra.width, w)); + extra.height += h; + extra.children.push(html); + break; + } + } +} + +function getAvailableSpace(node) { + const availableSpace = node[_xfa_object.$extra].availableSpace; + const marginV = node.margin ? node.margin.topInset + node.margin.bottomInset : 0; + const marginH = node.margin ? node.margin.leftInset + node.margin.rightInset : 0; + + switch (node.layout) { + case "lr-tb": + case "rl-tb": + if (node[_xfa_object.$extra].attempt === 0) { + return { + width: availableSpace.width - marginH - node[_xfa_object.$extra].currentWidth, + height: availableSpace.height - marginV - node[_xfa_object.$extra].prevHeight + }; + } + + return { + width: availableSpace.width - marginH, + height: availableSpace.height - marginV - node[_xfa_object.$extra].height + }; + + case "rl-row": + case "row": + const width = node[_xfa_object.$extra].columnWidths.slice(node[_xfa_object.$extra].currentColumn).reduce((a, x) => a + x); + + return { + width, + height: availableSpace.height - marginH + }; + + case "table": + case "tb": + return { + width: availableSpace.width - marginH, + height: availableSpace.height - marginV - node[_xfa_object.$extra].height + }; + + case "position": + default: + return availableSpace; + } +} + +function getTransformedBBox(node) { + let w = node.w === "" ? NaN : node.w; + let h = node.h === "" ? NaN : node.h; + let [centerX, centerY] = [0, 0]; + + switch (node.anchorType || "") { + case "bottomCenter": + [centerX, centerY] = [w / 2, h]; + break; + + case "bottomLeft": + [centerX, centerY] = [0, h]; + break; + + case "bottomRight": + [centerX, centerY] = [w, h]; + break; + + case "middleCenter": + [centerX, centerY] = [w / 2, h / 2]; + break; + + case "middleLeft": + [centerX, centerY] = [0, h / 2]; + break; + + case "middleRight": + [centerX, centerY] = [w, h / 2]; + break; + + case "topCenter": + [centerX, centerY] = [w / 2, 0]; + break; + + case "topRight": + [centerX, centerY] = [w, 0]; + break; + } + + let x, y; + + switch (node.rotate || 0) { + case 0: + [x, y] = [-centerX, -centerY]; + break; + + case 90: + [x, y] = [-centerY, centerX]; + [w, h] = [h, -w]; + break; + + case 180: + [x, y] = [centerX, centerY]; + [w, h] = [-w, -h]; + break; + + case 270: + [x, y] = [centerY, -centerX]; + [w, h] = [-h, w]; + break; + } + + return [node.x + x + Math.min(0, w), node.y + y + Math.min(0, h), Math.abs(w), Math.abs(h)]; +} + +function checkDimensions(node, space) { + if (node[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].firstUnsplittable === null) { + return true; + } + + if (node.w === 0 || node.h === 0) { + return true; + } + + const ERROR = 2; + + const parent = node[_xfa_object.$getSubformParent](); + + const attempt = parent[_xfa_object.$extra] && parent[_xfa_object.$extra].attempt || 0; + const [, y, w, h] = getTransformedBBox(node); + + switch (parent.layout) { + case "lr-tb": + case "rl-tb": + if (attempt === 0) { + if (!node[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].noLayoutFailure) { + if (node.h !== "" && Math.round(h - space.height) > ERROR) { + return false; + } + + if (node.w !== "") { + if (Math.round(w - space.width) <= ERROR) { + return true; + } + + if (parent[_xfa_object.$extra].numberInLine === 0) { + return space.height > ERROR; + } + + return false; + } + + return space.width > ERROR; + } + + if (node.w !== "") { + return Math.round(w - space.width) <= ERROR; + } + + return space.width > ERROR; + } + + if (node[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].noLayoutFailure) { + return true; + } + + if (node.h !== "" && Math.round(h - space.height) > ERROR) { + return false; + } + + if (node.w === "" || Math.round(w - space.width) <= ERROR) { + return space.height > ERROR; + } + + if (parent[_xfa_object.$isThereMoreWidth]()) { + return false; + } + + return space.height > ERROR; + + case "table": + case "tb": + if (node[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].noLayoutFailure) { + return true; + } + + if (node.h !== "" && !node[_xfa_object.$isSplittable]()) { + return Math.round(h - space.height) <= ERROR; + } + + if (node.w === "" || Math.round(w - space.width) <= ERROR) { + return space.height > ERROR; + } + + if (parent[_xfa_object.$isThereMoreWidth]()) { + return false; + } + + return space.height > ERROR; + + case "position": + if (node[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].noLayoutFailure) { + return true; + } + + if (node.h === "" || Math.round(h + y - space.height) <= ERROR) { + return true; + } + + const area = node[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].currentContentArea; + + return h + y > area.h; + + case "rl-row": + case "row": + if (node[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].noLayoutFailure) { + return true; + } + + if (node.h !== "") { + return Math.round(h - space.height) <= ERROR; + } + + return true; + + default: + return true; + } +} + +/***/ }), +/* 84 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.computeBbox = computeBbox; +exports.createWrapper = createWrapper; +exports.fixDimensions = fixDimensions; +exports.fixTextIndent = fixTextIndent; +exports.fixURL = fixURL; +exports.isPrintOnly = isPrintOnly; +exports.layoutClass = layoutClass; +exports.layoutNode = layoutNode; +exports.measureToString = measureToString; +exports.setAccess = setAccess; +exports.setFontFamily = setFontFamily; +exports.setMinMaxDimensions = setMinMaxDimensions; +exports.setPara = setPara; +exports.toStyle = toStyle; + +var _xfa_object = __w_pdfjs_require__(77); + +var _util = __w_pdfjs_require__(2); + +var _utils = __w_pdfjs_require__(78); + +var _fonts = __w_pdfjs_require__(85); + +var _text = __w_pdfjs_require__(86); + +function measureToString(m) { + if (typeof m === "string") { + return "0px"; + } + + return Number.isInteger(m) ? `${m}px` : `${m.toFixed(2)}px`; +} + +const converters = { + anchorType(node, style) { + const parent = node[_xfa_object.$getSubformParent](); + + if (!parent || parent.layout && parent.layout !== "position") { + return; + } + + if (!("transform" in style)) { + style.transform = ""; + } + + switch (node.anchorType) { + case "bottomCenter": + style.transform += "translate(-50%, -100%)"; + break; + + case "bottomLeft": + style.transform += "translate(0,-100%)"; + break; + + case "bottomRight": + style.transform += "translate(-100%,-100%)"; + break; + + case "middleCenter": + style.transform += "translate(-50%,-50%)"; + break; + + case "middleLeft": + style.transform += "translate(0,-50%)"; + break; + + case "middleRight": + style.transform += "translate(-100%,-50%)"; + break; + + case "topCenter": + style.transform += "translate(-50%,0)"; + break; + + case "topRight": + style.transform += "translate(-100%,0)"; + break; + } + }, + + dimensions(node, style) { + const parent = node[_xfa_object.$getSubformParent](); + + let width = node.w; + const height = node.h; + + if (parent.layout && parent.layout.includes("row")) { + const extra = parent[_xfa_object.$extra]; + const colSpan = node.colSpan; + let w; + + if (colSpan === -1) { + w = extra.columnWidths.slice(extra.currentColumn).reduce((a, x) => a + x, 0); + extra.currentColumn = 0; + } else { + w = extra.columnWidths.slice(extra.currentColumn, extra.currentColumn + colSpan).reduce((a, x) => a + x, 0); + extra.currentColumn = (extra.currentColumn + node.colSpan) % extra.columnWidths.length; + } + + if (!isNaN(w)) { + width = node.w = w; + } + } + + if (width !== "") { + style.width = measureToString(width); + } else { + style.width = "auto"; + } + + if (height !== "") { + style.height = measureToString(height); + } else { + style.height = "auto"; + } + }, + + position(node, style) { + const parent = node[_xfa_object.$getSubformParent](); + + if (parent && parent.layout && parent.layout !== "position") { + return; + } + + style.position = "absolute"; + style.left = measureToString(node.x); + style.top = measureToString(node.y); + }, + + rotate(node, style) { + if (node.rotate) { + if (!("transform" in style)) { + style.transform = ""; + } + + style.transform += `rotate(-${node.rotate}deg)`; + style.transformOrigin = "top left"; + } + }, + + presence(node, style) { + switch (node.presence) { + case "invisible": + style.visibility = "hidden"; + break; + + case "hidden": + case "inactive": + style.display = "none"; + break; + } + }, + + hAlign(node, style) { + if (node[_xfa_object.$nodeName] === "para") { + switch (node.hAlign) { + case "justifyAll": + style.textAlign = "justify-all"; + break; + + case "radix": + style.textAlign = "left"; + break; + + default: + style.textAlign = node.hAlign; + } + } else { + switch (node.hAlign) { + case "left": + style.alignSelf = "start"; + break; + + case "center": + style.alignSelf = "center"; + break; + + case "right": + style.alignSelf = "end"; + break; + } + } + }, + + margin(node, style) { + if (node.margin) { + style.margin = node.margin[_xfa_object.$toStyle]().margin; + } + } + +}; + +function setMinMaxDimensions(node, style) { + const parent = node[_xfa_object.$getSubformParent](); + + if (parent.layout === "position") { + if (node.minW > 0) { + style.minWidth = measureToString(node.minW); + } + + if (node.maxW > 0) { + style.maxWidth = measureToString(node.maxW); + } + + if (node.minH > 0) { + style.minHeight = measureToString(node.minH); + } + + if (node.maxH > 0) { + style.maxHeight = measureToString(node.maxH); + } + } +} + +function layoutText(text, xfaFont, margin, lineHeight, fontFinder, width) { + const measure = new _text.TextMeasure(xfaFont, margin, lineHeight, fontFinder); + + if (typeof text === "string") { + measure.addString(text); + } else { + text[_xfa_object.$pushGlyphs](measure); + } + + return measure.compute(width); +} + +function layoutNode(node, availableSpace) { + let height = null; + let width = null; + let isBroken = false; + + if ((!node.w || !node.h) && node.value) { + let marginH = 0; + let marginV = 0; + + if (node.margin) { + marginH = node.margin.leftInset + node.margin.rightInset; + marginV = node.margin.topInset + node.margin.bottomInset; + } + + let lineHeight = null; + let margin = null; + + if (node.para) { + margin = Object.create(null); + lineHeight = node.para.lineHeight === "" ? null : node.para.lineHeight; + margin.top = node.para.spaceAbove === "" ? 0 : node.para.spaceAbove; + margin.bottom = node.para.spaceBelow === "" ? 0 : node.para.spaceBelow; + margin.left = node.para.marginLeft === "" ? 0 : node.para.marginLeft; + margin.right = node.para.marginRight === "" ? 0 : node.para.marginRight; + } + + let font = node.font; + + if (!font) { + const root = node[_xfa_object.$getTemplateRoot](); + + let parent = node[_xfa_object.$getParent](); + + while (parent && parent !== root) { + if (parent.font) { + font = parent.font; + break; + } + + parent = parent[_xfa_object.$getParent](); + } + } + + const maxWidth = (node.w || availableSpace.width) - marginH; + const fontFinder = node[_xfa_object.$globalData].fontFinder; + + if (node.value.exData && node.value.exData[_xfa_object.$content] && node.value.exData.contentType === "text/html") { + const res = layoutText(node.value.exData[_xfa_object.$content], font, margin, lineHeight, fontFinder, maxWidth); + width = res.width; + height = res.height; + isBroken = res.isBroken; + } else { + const text = node.value[_xfa_object.$text](); + + if (text) { + const res = layoutText(text, font, margin, lineHeight, fontFinder, maxWidth); + width = res.width; + height = res.height; + isBroken = res.isBroken; + } + } + + if (width !== null && !node.w) { + width += marginH; + } + + if (height !== null && !node.h) { + height += marginV; + } + } + + return { + w: width, + h: height, + isBroken + }; +} + +function computeBbox(node, html, availableSpace) { + let bbox; + + if (node.w !== "" && node.h !== "") { + bbox = [node.x, node.y, node.w, node.h]; + } else { + if (!availableSpace) { + return null; + } + + let width = node.w; + + if (width === "") { + if (node.maxW === 0) { + const parent = node[_xfa_object.$getSubformParent](); + + if (parent.layout === "position" && parent.w !== "") { + width = 0; + } else { + width = node.minW; + } + } else { + width = Math.min(node.maxW, availableSpace.width); + } + + html.attributes.style.width = measureToString(width); + } + + let height = node.h; + + if (height === "") { + if (node.maxH === 0) { + const parent = node[_xfa_object.$getSubformParent](); + + if (parent.layout === "position" && parent.h !== "") { + height = 0; + } else { + height = node.minH; + } + } else { + height = Math.min(node.maxH, availableSpace.height); + } + + html.attributes.style.height = measureToString(height); + } + + bbox = [node.x, node.y, width, height]; + } + + return bbox; +} + +function fixDimensions(node) { + const parent = node[_xfa_object.$getSubformParent](); + + if (parent.layout && parent.layout.includes("row")) { + const extra = parent[_xfa_object.$extra]; + const colSpan = node.colSpan; + let width; + + if (colSpan === -1) { + width = extra.columnWidths.slice(extra.currentColumn).reduce((a, w) => a + w, 0); + } else { + width = extra.columnWidths.slice(extra.currentColumn, extra.currentColumn + colSpan).reduce((a, w) => a + w, 0); + } + + if (!isNaN(width)) { + node.w = width; + } + } + + if (parent.layout && parent.layout !== "position") { + node.x = node.y = 0; + } + + if (node.layout === "table") { + if (node.w === "" && Array.isArray(node.columnWidths)) { + node.w = node.columnWidths.reduce((a, x) => a + x, 0); + } + } +} + +function layoutClass(node) { + switch (node.layout) { + case "position": + return "xfaPosition"; + + case "lr-tb": + return "xfaLrTb"; + + case "rl-row": + return "xfaRlRow"; + + case "rl-tb": + return "xfaRlTb"; + + case "row": + return "xfaRow"; + + case "table": + return "xfaTable"; + + case "tb": + return "xfaTb"; + + default: + return "xfaPosition"; + } +} + +function toStyle(node, ...names) { + const style = Object.create(null); + + for (const name of names) { + const value = node[name]; + + if (value === null) { + continue; + } + + if (converters.hasOwnProperty(name)) { + converters[name](node, style); + continue; + } + + if (value instanceof _xfa_object.XFAObject) { + const newStyle = value[_xfa_object.$toStyle](); + + if (newStyle) { + Object.assign(style, newStyle); + } else { + (0, _util.warn)(`(DEBUG) - XFA - style for ${name} not implemented yet`); + } + } + } + + return style; +} + +function createWrapper(node, html) { + const { + attributes + } = html; + const { + style + } = attributes; + const wrapper = { + name: "div", + attributes: { + class: ["xfaWrapper"], + style: Object.create(null) + }, + children: [] + }; + attributes.class.push("xfaWrapped"); + + if (node.border) { + const { + widths, + insets + } = node.border[_xfa_object.$extra]; + let width, height; + let top = insets[0]; + let left = insets[3]; + const insetsH = insets[0] + insets[2]; + const insetsW = insets[1] + insets[3]; + + switch (node.border.hand) { + case "even": + top -= widths[0] / 2; + left -= widths[3] / 2; + width = `calc(100% + ${(widths[1] + widths[3]) / 2 - insetsW}px)`; + height = `calc(100% + ${(widths[0] + widths[2]) / 2 - insetsH}px)`; + break; + + case "left": + top -= widths[0]; + left -= widths[3]; + width = `calc(100% + ${widths[1] + widths[3] - insetsW}px)`; + height = `calc(100% + ${widths[0] + widths[2] - insetsH}px)`; + break; + + case "right": + width = insetsW ? `calc(100% - ${insetsW}px)` : "100%"; + height = insetsH ? `calc(100% - ${insetsH}px)` : "100%"; + break; + } + + const classNames = ["xfaBorder"]; + + if (isPrintOnly(node.border)) { + classNames.push("xfaPrintOnly"); + } + + const border = { + name: "div", + attributes: { + class: classNames, + style: { + top: `${top}px`, + left: `${left}px`, + width, + height + } + }, + children: [] + }; + + for (const key of ["border", "borderWidth", "borderColor", "borderRadius", "borderStyle"]) { + if (style[key] !== undefined) { + border.attributes.style[key] = style[key]; + delete style[key]; + } + } + + wrapper.children.push(border, html); + } else { + wrapper.children.push(html); + } + + for (const key of ["background", "backgroundClip", "top", "left", "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "transform", "transformOrigin", "visibility"]) { + if (style[key] !== undefined) { + wrapper.attributes.style[key] = style[key]; + delete style[key]; + } + } + + if (style.position === "absolute") { + wrapper.attributes.style.position = "absolute"; + } else { + wrapper.attributes.style.position = "relative"; + } + + delete style.position; + + if (style.alignSelf) { + wrapper.attributes.style.alignSelf = style.alignSelf; + delete style.alignSelf; + } + + return wrapper; +} + +function fixTextIndent(styles) { + const indent = (0, _utils.getMeasurement)(styles.textIndent, "0px"); + + if (indent >= 0) { + return; + } + + const align = styles.textAlign === "right" ? "right" : "left"; + const name = "padding" + (align === "left" ? "Left" : "Right"); + const padding = (0, _utils.getMeasurement)(styles[name], "0px"); + styles[name] = `${padding - indent}px`; +} + +function setAccess(node, classNames) { + switch (node.access) { + case "nonInteractive": + classNames.push("xfaNonInteractive"); + break; + + case "readOnly": + classNames.push("xfaReadOnly"); + break; + + case "protected": + classNames.push("xfaDisabled"); + break; + } +} + +function isPrintOnly(node) { + return node.relevant.length > 0 && !node.relevant[0].excluded && node.relevant[0].viewname === "print"; +} + +function getCurrentPara(node) { + const stack = node[_xfa_object.$getTemplateRoot]()[_xfa_object.$extra].paraStack; + + return stack.length ? stack.at(-1) : null; +} + +function setPara(node, nodeStyle, value) { + if (value.attributes.class && value.attributes.class.includes("xfaRich")) { + if (nodeStyle) { + if (node.h === "") { + nodeStyle.height = "auto"; + } + + if (node.w === "") { + nodeStyle.width = "auto"; + } + } + + const para = getCurrentPara(node); + + if (para) { + const valueStyle = value.attributes.style; + valueStyle.display = "flex"; + valueStyle.flexDirection = "column"; + + switch (para.vAlign) { + case "top": + valueStyle.justifyContent = "start"; + break; + + case "bottom": + valueStyle.justifyContent = "end"; + break; + + case "middle": + valueStyle.justifyContent = "center"; + break; + } + + const paraStyle = para[_xfa_object.$toStyle](); + + for (const [key, val] of Object.entries(paraStyle)) { + if (!(key in valueStyle)) { + valueStyle[key] = val; + } + } + } + } +} + +function setFontFamily(xfaFont, node, fontFinder, style) { + if (!fontFinder) { + delete style.fontFamily; + return; + } + + const name = (0, _utils.stripQuotes)(xfaFont.typeface); + style.fontFamily = `"${name}"`; + const typeface = fontFinder.find(name); + + if (typeface) { + const { + fontFamily + } = typeface.regular.cssFontInfo; + + if (fontFamily !== name) { + style.fontFamily = `"${fontFamily}"`; + } + + const para = getCurrentPara(node); + + if (para && para.lineHeight !== "") { + return; + } + + if (style.lineHeight) { + return; + } + + const pdfFont = (0, _fonts.selectFont)(xfaFont, typeface); + + if (pdfFont) { + style.lineHeight = Math.max(1.2, pdfFont.lineHeight); + } + } +} + +function fixURL(str) { + const absoluteUrl = (0, _util.createValidAbsoluteUrl)(str, null, { + addDefaultProtocol: true, + tryConvertEncoding: true + }); + return absoluteUrl ? absoluteUrl.href : null; +} + +/***/ }), +/* 85 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.FontFinder = void 0; +exports.getMetrics = getMetrics; +exports.selectFont = selectFont; + +var _xfa_object = __w_pdfjs_require__(77); + +var _utils = __w_pdfjs_require__(78); + +var _util = __w_pdfjs_require__(2); + +class FontFinder { + constructor(pdfFonts) { + this.fonts = new Map(); + this.cache = new Map(); + this.warned = new Set(); + this.defaultFont = null; + this.add(pdfFonts); + } + + add(pdfFonts, reallyMissingFonts = null) { + for (const pdfFont of pdfFonts) { + this.addPdfFont(pdfFont); + } + + for (const pdfFont of this.fonts.values()) { + if (!pdfFont.regular) { + pdfFont.regular = pdfFont.italic || pdfFont.bold || pdfFont.bolditalic; + } + } + + if (!reallyMissingFonts || reallyMissingFonts.size === 0) { + return; + } + + const myriad = this.fonts.get("PdfJS-Fallback-PdfJS-XFA"); + + for (const missing of reallyMissingFonts) { + this.fonts.set(missing, myriad); + } + } + + addPdfFont(pdfFont) { + const cssFontInfo = pdfFont.cssFontInfo; + const name = cssFontInfo.fontFamily; + let font = this.fonts.get(name); + + if (!font) { + font = Object.create(null); + this.fonts.set(name, font); + + if (!this.defaultFont) { + this.defaultFont = font; + } + } + + let property = ""; + const fontWeight = parseFloat(cssFontInfo.fontWeight); + + if (parseFloat(cssFontInfo.italicAngle) !== 0) { + property = fontWeight >= 700 ? "bolditalic" : "italic"; + } else if (fontWeight >= 700) { + property = "bold"; + } + + if (!property) { + if (pdfFont.name.includes("Bold") || pdfFont.psName && pdfFont.psName.includes("Bold")) { + property = "bold"; + } + + if (pdfFont.name.includes("Italic") || pdfFont.name.endsWith("It") || pdfFont.psName && (pdfFont.psName.includes("Italic") || pdfFont.psName.endsWith("It"))) { + property += "italic"; + } + } + + if (!property) { + property = "regular"; + } + + font[property] = pdfFont; + } + + getDefault() { + return this.defaultFont; + } + + find(fontName, mustWarn = true) { + let font = this.fonts.get(fontName) || this.cache.get(fontName); + + if (font) { + return font; + } + + const pattern = /,|-|_| |bolditalic|bold|italic|regular|it/gi; + let name = fontName.replace(pattern, ""); + font = this.fonts.get(name); + + if (font) { + this.cache.set(fontName, font); + return font; + } + + name = name.toLowerCase(); + const maybe = []; + + for (const [family, pdfFont] of this.fonts.entries()) { + if (family.replace(pattern, "").toLowerCase().startsWith(name)) { + maybe.push(pdfFont); + } + } + + if (maybe.length === 0) { + for (const [, pdfFont] of this.fonts.entries()) { + if (pdfFont.regular.name && pdfFont.regular.name.replace(pattern, "").toLowerCase().startsWith(name)) { + maybe.push(pdfFont); + } + } + } + + if (maybe.length === 0) { + name = name.replace(/psmt|mt/gi, ""); + + for (const [family, pdfFont] of this.fonts.entries()) { + if (family.replace(pattern, "").toLowerCase().startsWith(name)) { + maybe.push(pdfFont); + } + } + } + + if (maybe.length === 0) { + for (const pdfFont of this.fonts.values()) { + if (pdfFont.regular.name && pdfFont.regular.name.replace(pattern, "").toLowerCase().startsWith(name)) { + maybe.push(pdfFont); + } + } + } + + if (maybe.length >= 1) { + if (maybe.length !== 1 && mustWarn) { + (0, _util.warn)(`XFA - Too many choices to guess the correct font: ${fontName}`); + } + + this.cache.set(fontName, maybe[0]); + return maybe[0]; + } + + if (mustWarn && !this.warned.has(fontName)) { + this.warned.add(fontName); + (0, _util.warn)(`XFA - Cannot find the font: ${fontName}`); + } + + return null; + } + +} + +exports.FontFinder = FontFinder; + +function selectFont(xfaFont, typeface) { + if (xfaFont.posture === "italic") { + if (xfaFont.weight === "bold") { + return typeface.bolditalic; + } + + return typeface.italic; + } else if (xfaFont.weight === "bold") { + return typeface.bold; + } + + return typeface.regular; +} + +function getMetrics(xfaFont, real = false) { + let pdfFont = null; + + if (xfaFont) { + const name = (0, _utils.stripQuotes)(xfaFont.typeface); + + const typeface = xfaFont[_xfa_object.$globalData].fontFinder.find(name); + + pdfFont = selectFont(xfaFont, typeface); + } + + if (!pdfFont) { + return { + lineHeight: 12, + lineGap: 2, + lineNoGap: 10 + }; + } + + const size = xfaFont.size || 10; + const lineHeight = pdfFont.lineHeight ? Math.max(real ? 0 : 1.2, pdfFont.lineHeight) : 1.2; + const lineGap = pdfFont.lineGap === undefined ? 0.2 : pdfFont.lineGap; + return { + lineHeight: lineHeight * size, + lineGap: lineGap * size, + lineNoGap: Math.max(1, lineHeight - lineGap) * size + }; +} + +/***/ }), +/* 86 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TextMeasure = void 0; + +var _fonts = __w_pdfjs_require__(85); + +const WIDTH_FACTOR = 1.02; + +class FontInfo { + constructor(xfaFont, margin, lineHeight, fontFinder) { + this.lineHeight = lineHeight; + this.paraMargin = margin || { + top: 0, + bottom: 0, + left: 0, + right: 0 + }; + + if (!xfaFont) { + [this.pdfFont, this.xfaFont] = this.defaultFont(fontFinder); + return; + } + + this.xfaFont = { + typeface: xfaFont.typeface, + posture: xfaFont.posture, + weight: xfaFont.weight, + size: xfaFont.size, + letterSpacing: xfaFont.letterSpacing + }; + const typeface = fontFinder.find(xfaFont.typeface); + + if (!typeface) { + [this.pdfFont, this.xfaFont] = this.defaultFont(fontFinder); + return; + } + + this.pdfFont = (0, _fonts.selectFont)(xfaFont, typeface); + + if (!this.pdfFont) { + [this.pdfFont, this.xfaFont] = this.defaultFont(fontFinder); + } + } + + defaultFont(fontFinder) { + const font = fontFinder.find("Helvetica", false) || fontFinder.find("Myriad Pro", false) || fontFinder.find("Arial", false) || fontFinder.getDefault(); + + if (font && font.regular) { + const pdfFont = font.regular; + const info = pdfFont.cssFontInfo; + const xfaFont = { + typeface: info.fontFamily, + posture: "normal", + weight: "normal", + size: 10, + letterSpacing: 0 + }; + return [pdfFont, xfaFont]; + } + + const xfaFont = { + typeface: "Courier", + posture: "normal", + weight: "normal", + size: 10, + letterSpacing: 0 + }; + return [null, xfaFont]; + } + +} + +class FontSelector { + constructor(defaultXfaFont, defaultParaMargin, defaultLineHeight, fontFinder) { + this.fontFinder = fontFinder; + this.stack = [new FontInfo(defaultXfaFont, defaultParaMargin, defaultLineHeight, fontFinder)]; + } + + pushData(xfaFont, margin, lineHeight) { + const lastFont = this.stack.at(-1); + + for (const name of ["typeface", "posture", "weight", "size", "letterSpacing"]) { + if (!xfaFont[name]) { + xfaFont[name] = lastFont.xfaFont[name]; + } + } + + for (const name of ["top", "bottom", "left", "right"]) { + if (isNaN(margin[name])) { + margin[name] = lastFont.paraMargin[name]; + } + } + + const fontInfo = new FontInfo(xfaFont, margin, lineHeight || lastFont.lineHeight, this.fontFinder); + + if (!fontInfo.pdfFont) { + fontInfo.pdfFont = lastFont.pdfFont; + } + + this.stack.push(fontInfo); + } + + popFont() { + this.stack.pop(); + } + + topFont() { + return this.stack.at(-1); + } + +} + +class TextMeasure { + constructor(defaultXfaFont, defaultParaMargin, defaultLineHeight, fonts) { + this.glyphs = []; + this.fontSelector = new FontSelector(defaultXfaFont, defaultParaMargin, defaultLineHeight, fonts); + this.extraHeight = 0; + } + + pushData(xfaFont, margin, lineHeight) { + this.fontSelector.pushData(xfaFont, margin, lineHeight); + } + + popFont(xfaFont) { + return this.fontSelector.popFont(); + } + + addPara() { + const lastFont = this.fontSelector.topFont(); + this.extraHeight += lastFont.paraMargin.top + lastFont.paraMargin.bottom; + } + + addString(str) { + if (!str) { + return; + } + + const lastFont = this.fontSelector.topFont(); + const fontSize = lastFont.xfaFont.size; + + if (lastFont.pdfFont) { + const letterSpacing = lastFont.xfaFont.letterSpacing; + const pdfFont = lastFont.pdfFont; + const fontLineHeight = pdfFont.lineHeight || 1.2; + const lineHeight = lastFont.lineHeight || Math.max(1.2, fontLineHeight) * fontSize; + const lineGap = pdfFont.lineGap === undefined ? 0.2 : pdfFont.lineGap; + const noGap = fontLineHeight - lineGap; + const firstLineHeight = Math.max(1, noGap) * fontSize; + const scale = fontSize / 1000; + const fallbackWidth = pdfFont.defaultWidth || pdfFont.charsToGlyphs(" ")[0].width; + + for (const line of str.split(/[\u2029\n]/)) { + const encodedLine = pdfFont.encodeString(line).join(""); + const glyphs = pdfFont.charsToGlyphs(encodedLine); + + for (const glyph of glyphs) { + const width = glyph.width || fallbackWidth; + this.glyphs.push([width * scale + letterSpacing, lineHeight, firstLineHeight, glyph.unicode, false]); + } + + this.glyphs.push([0, 0, 0, "\n", true]); + } + + this.glyphs.pop(); + return; + } + + for (const line of str.split(/[\u2029\n]/)) { + for (const char of line.split("")) { + this.glyphs.push([fontSize, 1.2 * fontSize, fontSize, char, false]); + } + + this.glyphs.push([0, 0, 0, "\n", true]); + } + + this.glyphs.pop(); + } + + compute(maxWidth) { + let lastSpacePos = -1, + lastSpaceWidth = 0, + width = 0, + height = 0, + currentLineWidth = 0, + currentLineHeight = 0; + let isBroken = false; + let isFirstLine = true; + + for (let i = 0, ii = this.glyphs.length; i < ii; i++) { + const [glyphWidth, lineHeight, firstLineHeight, char, isEOL] = this.glyphs[i]; + const isSpace = char === " "; + const glyphHeight = isFirstLine ? firstLineHeight : lineHeight; + + if (isEOL) { + width = Math.max(width, currentLineWidth); + currentLineWidth = 0; + height += currentLineHeight; + currentLineHeight = glyphHeight; + lastSpacePos = -1; + lastSpaceWidth = 0; + isFirstLine = false; + continue; + } + + if (isSpace) { + if (currentLineWidth + glyphWidth > maxWidth) { + width = Math.max(width, currentLineWidth); + currentLineWidth = 0; + height += currentLineHeight; + currentLineHeight = glyphHeight; + lastSpacePos = -1; + lastSpaceWidth = 0; + isBroken = true; + isFirstLine = false; + } else { + currentLineHeight = Math.max(glyphHeight, currentLineHeight); + lastSpaceWidth = currentLineWidth; + currentLineWidth += glyphWidth; + lastSpacePos = i; + } + + continue; + } + + if (currentLineWidth + glyphWidth > maxWidth) { + height += currentLineHeight; + currentLineHeight = glyphHeight; + + if (lastSpacePos !== -1) { + i = lastSpacePos; + width = Math.max(width, lastSpaceWidth); + currentLineWidth = 0; + lastSpacePos = -1; + lastSpaceWidth = 0; + } else { + width = Math.max(width, currentLineWidth); + currentLineWidth = glyphWidth; + } + + isBroken = true; + isFirstLine = false; + continue; + } + + currentLineWidth += glyphWidth; + currentLineHeight = Math.max(glyphHeight, currentLineHeight); + } + + width = Math.max(width, currentLineWidth); + height += currentLineHeight + this.extraHeight; + return { + width: WIDTH_FACTOR * width, + height, + isBroken + }; + } + +} + +exports.TextMeasure = TextMeasure; + +/***/ }), +/* 87 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.DataHandler = void 0; + +var _xfa_object = __w_pdfjs_require__(77); + +class DataHandler { + constructor(root, data) { + this.data = data; + this.dataset = root.datasets || null; + } + + serialize(storage) { + const stack = [[-1, this.data[_xfa_object.$getChildren]()]]; + + while (stack.length > 0) { + const last = stack.at(-1); + const [i, children] = last; + + if (i + 1 === children.length) { + stack.pop(); + continue; + } + + const child = children[++last[0]]; + const storageEntry = storage.get(child[_xfa_object.$uid]); + + if (storageEntry) { + child[_xfa_object.$setValue](storageEntry); + } else { + const attributes = child[_xfa_object.$getAttributes](); + + for (const value of attributes.values()) { + const entry = storage.get(value[_xfa_object.$uid]); + + if (entry) { + value[_xfa_object.$setValue](entry); + + break; + } + } + } + + const nodes = child[_xfa_object.$getChildren](); + + if (nodes.length > 0) { + stack.push([-1, nodes]); + } + } + + const buf = [``]; + + if (this.dataset) { + for (const child of this.dataset[_xfa_object.$getChildren]()) { + if (child[_xfa_object.$nodeName] !== "data") { + child[_xfa_object.$toString](buf); + } + } + } + + this.data[_xfa_object.$toString](buf); + + buf.push(""); + return buf.join(""); + } + +} + +exports.DataHandler = DataHandler; + +/***/ }), +/* 88 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XFAParser = void 0; + +var _xfa_object = __w_pdfjs_require__(77); + +var _xml_parser = __w_pdfjs_require__(66); + +var _builder = __w_pdfjs_require__(89); + +var _util = __w_pdfjs_require__(2); + +class XFAParser extends _xml_parser.XMLParserBase { + constructor(rootNameSpace = null, richText = false) { + super(); + this._builder = new _builder.Builder(rootNameSpace); + this._stack = []; + this._globalData = { + usedTypefaces: new Set() + }; + this._ids = new Map(); + this._current = this._builder.buildRoot(this._ids); + this._errorCode = _xml_parser.XMLParserErrorCode.NoError; + this._whiteRegex = /^\s+$/; + this._nbsps = /\xa0+/g; + this._richText = richText; + } + + parse(data) { + this.parseXml(data); + + if (this._errorCode !== _xml_parser.XMLParserErrorCode.NoError) { + return undefined; + } + + this._current[_xfa_object.$finalize](); + + return this._current.element; + } + + onText(text) { + text = text.replace(this._nbsps, match => match.slice(1) + " "); + + if (this._richText || this._current[_xfa_object.$acceptWhitespace]()) { + this._current[_xfa_object.$onText](text, this._richText); + + return; + } + + if (this._whiteRegex.test(text)) { + return; + } + + this._current[_xfa_object.$onText](text.trim()); + } + + onCdata(text) { + this._current[_xfa_object.$onText](text); + } + + _mkAttributes(attributes, tagName) { + let namespace = null; + let prefixes = null; + const attributeObj = Object.create({}); + + for (const { + name, + value + } of attributes) { + if (name === "xmlns") { + if (!namespace) { + namespace = value; + } else { + (0, _util.warn)(`XFA - multiple namespace definition in <${tagName}>`); + } + } else if (name.startsWith("xmlns:")) { + const prefix = name.substring("xmlns:".length); + + if (!prefixes) { + prefixes = []; + } + + prefixes.push({ + prefix, + value + }); + } else { + const i = name.indexOf(":"); + + if (i === -1) { + attributeObj[name] = value; + } else { + let nsAttrs = attributeObj[_xfa_object.$nsAttributes]; + + if (!nsAttrs) { + nsAttrs = attributeObj[_xfa_object.$nsAttributes] = Object.create(null); + } + + const [ns, attrName] = [name.slice(0, i), name.slice(i + 1)]; + let attrs = nsAttrs[ns]; + + if (!attrs) { + attrs = nsAttrs[ns] = Object.create(null); + } + + attrs[attrName] = value; + } + } + } + + return [namespace, prefixes, attributeObj]; + } + + _getNameAndPrefix(name, nsAgnostic) { + const i = name.indexOf(":"); + + if (i === -1) { + return [name, null]; + } + + return [name.substring(i + 1), nsAgnostic ? "" : name.substring(0, i)]; + } + + onBeginElement(tagName, attributes, isEmpty) { + const [namespace, prefixes, attributesObj] = this._mkAttributes(attributes, tagName); + + const [name, nsPrefix] = this._getNameAndPrefix(tagName, this._builder.isNsAgnostic()); + + const node = this._builder.build({ + nsPrefix, + name, + attributes: attributesObj, + namespace, + prefixes + }); + + node[_xfa_object.$globalData] = this._globalData; + + if (isEmpty) { + node[_xfa_object.$finalize](); + + if (this._current[_xfa_object.$onChild](node)) { + node[_xfa_object.$setId](this._ids); + } + + node[_xfa_object.$clean](this._builder); + + return; + } + + this._stack.push(this._current); + + this._current = node; + } + + onEndElement(name) { + const node = this._current; + + if (node[_xfa_object.$isCDATAXml]() && typeof node[_xfa_object.$content] === "string") { + const parser = new XFAParser(); + parser._globalData = this._globalData; + const root = parser.parse(node[_xfa_object.$content]); + node[_xfa_object.$content] = null; + + node[_xfa_object.$onChild](root); + } + + node[_xfa_object.$finalize](); + + this._current = this._stack.pop(); + + if (this._current[_xfa_object.$onChild](node)) { + node[_xfa_object.$setId](this._ids); + } + + node[_xfa_object.$clean](this._builder); + } + + onError(code) { + this._errorCode = code; + } + +} + +exports.XFAParser = XFAParser; + +/***/ }), +/* 89 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Builder = void 0; + +var _namespaces = __w_pdfjs_require__(79); + +var _xfa_object = __w_pdfjs_require__(77); + +var _setup = __w_pdfjs_require__(90); + +var _template = __w_pdfjs_require__(82); + +var _unknown = __w_pdfjs_require__(99); + +var _util = __w_pdfjs_require__(2); + +class Root extends _xfa_object.XFAObject { + constructor(ids) { + super(-1, "root", Object.create(null)); + this.element = null; + this[_xfa_object.$ids] = ids; + } + + [_xfa_object.$onChild](child) { + this.element = child; + return true; + } + + [_xfa_object.$finalize]() { + super[_xfa_object.$finalize](); + + if (this.element.template instanceof _template.Template) { + this[_xfa_object.$ids].set(_xfa_object.$root, this.element); + + this.element.template[_xfa_object.$resolvePrototypes](this[_xfa_object.$ids]); + + this.element.template[_xfa_object.$ids] = this[_xfa_object.$ids]; + } + } + +} + +class Empty extends _xfa_object.XFAObject { + constructor() { + super(-1, "", Object.create(null)); + } + + [_xfa_object.$onChild](_) { + return false; + } + +} + +class Builder { + constructor(rootNameSpace = null) { + this._namespaceStack = []; + this._nsAgnosticLevel = 0; + this._namespacePrefixes = new Map(); + this._namespaces = new Map(); + this._nextNsId = Math.max(...Object.values(_namespaces.NamespaceIds).map(({ + id + }) => id)); + this._currentNamespace = rootNameSpace || new _unknown.UnknownNamespace(++this._nextNsId); + } + + buildRoot(ids) { + return new Root(ids); + } + + build({ + nsPrefix, + name, + attributes, + namespace, + prefixes + }) { + const hasNamespaceDef = namespace !== null; + + if (hasNamespaceDef) { + this._namespaceStack.push(this._currentNamespace); + + this._currentNamespace = this._searchNamespace(namespace); + } + + if (prefixes) { + this._addNamespacePrefix(prefixes); + } + + if (attributes.hasOwnProperty(_xfa_object.$nsAttributes)) { + const dataTemplate = _setup.NamespaceSetUp.datasets; + const nsAttrs = attributes[_xfa_object.$nsAttributes]; + let xfaAttrs = null; + + for (const [ns, attrs] of Object.entries(nsAttrs)) { + const nsToUse = this._getNamespaceToUse(ns); + + if (nsToUse === dataTemplate) { + xfaAttrs = { + xfa: attrs + }; + break; + } + } + + if (xfaAttrs) { + attributes[_xfa_object.$nsAttributes] = xfaAttrs; + } else { + delete attributes[_xfa_object.$nsAttributes]; + } + } + + const namespaceToUse = this._getNamespaceToUse(nsPrefix); + + const node = namespaceToUse && namespaceToUse[_namespaces.$buildXFAObject](name, attributes) || new Empty(); + + if (node[_xfa_object.$isNsAgnostic]()) { + this._nsAgnosticLevel++; + } + + if (hasNamespaceDef || prefixes || node[_xfa_object.$isNsAgnostic]()) { + node[_xfa_object.$cleanup] = { + hasNamespace: hasNamespaceDef, + prefixes, + nsAgnostic: node[_xfa_object.$isNsAgnostic]() + }; + } + + return node; + } + + isNsAgnostic() { + return this._nsAgnosticLevel > 0; + } + + _searchNamespace(nsName) { + let ns = this._namespaces.get(nsName); + + if (ns) { + return ns; + } + + for (const [name, { + check + }] of Object.entries(_namespaces.NamespaceIds)) { + if (check(nsName)) { + ns = _setup.NamespaceSetUp[name]; + + if (ns) { + this._namespaces.set(nsName, ns); + + return ns; + } + + break; + } + } + + ns = new _unknown.UnknownNamespace(++this._nextNsId); + + this._namespaces.set(nsName, ns); + + return ns; + } + + _addNamespacePrefix(prefixes) { + for (const { + prefix, + value + } of prefixes) { + const namespace = this._searchNamespace(value); + + let prefixStack = this._namespacePrefixes.get(prefix); + + if (!prefixStack) { + prefixStack = []; + + this._namespacePrefixes.set(prefix, prefixStack); + } + + prefixStack.push(namespace); + } + } + + _getNamespaceToUse(prefix) { + if (!prefix) { + return this._currentNamespace; + } + + const prefixStack = this._namespacePrefixes.get(prefix); + + if (prefixStack && prefixStack.length > 0) { + return prefixStack.at(-1); + } + + (0, _util.warn)(`Unknown namespace prefix: ${prefix}.`); + return null; + } + + clean(data) { + const { + hasNamespace, + prefixes, + nsAgnostic + } = data; + + if (hasNamespace) { + this._currentNamespace = this._namespaceStack.pop(); + } + + if (prefixes) { + prefixes.forEach(({ + prefix + }) => { + this._namespacePrefixes.get(prefix).pop(); + }); + } + + if (nsAgnostic) { + this._nsAgnosticLevel--; + } + } + +} + +exports.Builder = Builder; + +/***/ }), +/* 90 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.NamespaceSetUp = void 0; + +var _config = __w_pdfjs_require__(91); + +var _connection_set = __w_pdfjs_require__(92); + +var _datasets = __w_pdfjs_require__(93); + +var _locale_set = __w_pdfjs_require__(94); + +var _signature = __w_pdfjs_require__(95); + +var _stylesheet = __w_pdfjs_require__(96); + +var _template = __w_pdfjs_require__(82); + +var _xdp = __w_pdfjs_require__(97); + +var _xhtml = __w_pdfjs_require__(98); + +const NamespaceSetUp = { + config: _config.ConfigNamespace, + connection: _connection_set.ConnectionSetNamespace, + datasets: _datasets.DatasetsNamespace, + localeSet: _locale_set.LocaleSetNamespace, + signature: _signature.SignatureNamespace, + stylesheet: _stylesheet.StylesheetNamespace, + template: _template.TemplateNamespace, + xdp: _xdp.XdpNamespace, + xhtml: _xhtml.XhtmlNamespace +}; +exports.NamespaceSetUp = NamespaceSetUp; + +/***/ }), +/* 91 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.ConfigNamespace = void 0; + +var _namespaces = __w_pdfjs_require__(79); + +var _xfa_object = __w_pdfjs_require__(77); + +var _utils = __w_pdfjs_require__(78); + +var _util = __w_pdfjs_require__(2); + +const CONFIG_NS_ID = _namespaces.NamespaceIds.config.id; + +class Acrobat extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "acrobat", true); + this.acrobat7 = null; + this.autoSave = null; + this.common = null; + this.validate = null; + this.validateApprovalSignatures = null; + this.submitUrl = new _xfa_object.XFAObjectArray(); + } + +} + +class Acrobat7 extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "acrobat7", true); + this.dynamicRender = null; + } + +} + +class ADBE_JSConsole extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "ADBE_JSConsole", ["delegate", "Enable", "Disable"]); + } + +} + +class ADBE_JSDebugger extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "ADBE_JSDebugger", ["delegate", "Enable", "Disable"]); + } + +} + +class AddSilentPrint extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "addSilentPrint"); + } + +} + +class AddViewerPreferences extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "addViewerPreferences"); + } + +} + +class AdjustData extends _xfa_object.Option10 { + constructor(attributes) { + super(CONFIG_NS_ID, "adjustData"); + } + +} + +class AdobeExtensionLevel extends _xfa_object.IntegerObject { + constructor(attributes) { + super(CONFIG_NS_ID, "adobeExtensionLevel", 0, n => n >= 1 && n <= 8); + } + +} + +class Agent extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "agent", true); + this.name = attributes.name ? attributes.name.trim() : ""; + this.common = new _xfa_object.XFAObjectArray(); + } + +} + +class AlwaysEmbed extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "alwaysEmbed"); + } + +} + +class Amd extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "amd"); + } + +} + +class Area extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "area"); + this.level = (0, _utils.getInteger)({ + data: attributes.level, + defaultValue: 0, + validate: n => n >= 1 && n <= 3 + }); + this.name = (0, _utils.getStringOption)(attributes.name, ["", "barcode", "coreinit", "deviceDriver", "font", "general", "layout", "merge", "script", "signature", "sourceSet", "templateCache"]); + } + +} + +class Attributes extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "attributes", ["preserve", "delegate", "ignore"]); + } + +} + +class AutoSave extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "autoSave", ["disabled", "enabled"]); + } + +} + +class Base extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "base"); + } + +} + +class BatchOutput extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "batchOutput"); + this.format = (0, _utils.getStringOption)(attributes.format, ["none", "concat", "zip", "zipCompress"]); + } + +} + +class BehaviorOverride extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "behaviorOverride"); + } + + [_xfa_object.$finalize]() { + this[_xfa_object.$content] = new Map(this[_xfa_object.$content].trim().split(/\s+/).filter(x => x.includes(":")).map(x => x.split(":", 2))); + } + +} + +class Cache extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "cache", true); + this.templateCache = null; + } + +} + +class Change extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "change"); + } + +} + +class Common extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "common", true); + this.data = null; + this.locale = null; + this.localeSet = null; + this.messaging = null; + this.suppressBanner = null; + this.template = null; + this.validationMessaging = null; + this.versionControl = null; + this.log = new _xfa_object.XFAObjectArray(); + } + +} + +class Compress extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "compress"); + this.scope = (0, _utils.getStringOption)(attributes.scope, ["imageOnly", "document"]); + } + +} + +class CompressLogicalStructure extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "compressLogicalStructure"); + } + +} + +class CompressObjectStream extends _xfa_object.Option10 { + constructor(attributes) { + super(CONFIG_NS_ID, "compressObjectStream"); + } + +} + +class Compression extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "compression", true); + this.compressLogicalStructure = null; + this.compressObjectStream = null; + this.level = null; + this.type = null; + } + +} + +class Config extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "config", true); + this.acrobat = null; + this.present = null; + this.trace = null; + this.agent = new _xfa_object.XFAObjectArray(); + } + +} + +class Conformance extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "conformance", ["A", "B"]); + } + +} + +class ContentCopy extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "contentCopy"); + } + +} + +class Copies extends _xfa_object.IntegerObject { + constructor(attributes) { + super(CONFIG_NS_ID, "copies", 1, n => n >= 1); + } + +} + +class Creator extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "creator"); + } + +} + +class CurrentPage extends _xfa_object.IntegerObject { + constructor(attributes) { + super(CONFIG_NS_ID, "currentPage", 0, n => n >= 0); + } + +} + +class Data extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "data", true); + this.adjustData = null; + this.attributes = null; + this.incrementalLoad = null; + this.outputXSL = null; + this.range = null; + this.record = null; + this.startNode = null; + this.uri = null; + this.window = null; + this.xsl = null; + this.excludeNS = new _xfa_object.XFAObjectArray(); + this.transform = new _xfa_object.XFAObjectArray(); + } + +} + +class Debug extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "debug", true); + this.uri = null; + } + +} + +class DefaultTypeface extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "defaultTypeface"); + this.writingScript = (0, _utils.getStringOption)(attributes.writingScript, ["*", "Arabic", "Cyrillic", "EastEuropeanRoman", "Greek", "Hebrew", "Japanese", "Korean", "Roman", "SimplifiedChinese", "Thai", "TraditionalChinese", "Vietnamese"]); + } + +} + +class Destination extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "destination", ["pdf", "pcl", "ps", "webClient", "zpl"]); + } + +} + +class DocumentAssembly extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "documentAssembly"); + } + +} + +class Driver extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "driver", true); + this.name = attributes.name ? attributes.name.trim() : ""; + this.fontInfo = null; + this.xdc = null; + } + +} + +class DuplexOption extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "duplexOption", ["simplex", "duplexFlipLongEdge", "duplexFlipShortEdge"]); + } + +} + +class DynamicRender extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "dynamicRender", ["forbidden", "required"]); + } + +} + +class Embed extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "embed"); + } + +} + +class Encrypt extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "encrypt"); + } + +} + +class Encryption extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "encryption", true); + this.encrypt = null; + this.encryptionLevel = null; + this.permissions = null; + } + +} + +class EncryptionLevel extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "encryptionLevel", ["40bit", "128bit"]); + } + +} + +class Enforce extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "enforce"); + } + +} + +class Equate extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "equate"); + this.force = (0, _utils.getInteger)({ + data: attributes.force, + defaultValue: 1, + validate: n => n === 0 + }); + this.from = attributes.from || ""; + this.to = attributes.to || ""; + } + +} + +class EquateRange extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "equateRange"); + this.from = attributes.from || ""; + this.to = attributes.to || ""; + this._unicodeRange = attributes.unicodeRange || ""; + } + + get unicodeRange() { + const ranges = []; + const unicodeRegex = /U\+([0-9a-fA-F]+)/; + const unicodeRange = this._unicodeRange; + + for (let range of unicodeRange.split(",").map(x => x.trim()).filter(x => !!x)) { + range = range.split("-", 2).map(x => { + const found = x.match(unicodeRegex); + + if (!found) { + return 0; + } + + return parseInt(found[1], 16); + }); + + if (range.length === 1) { + range.push(range[0]); + } + + ranges.push(range); + } + + return (0, _util.shadow)(this, "unicodeRange", ranges); + } + +} + +class Exclude extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "exclude"); + } + + [_xfa_object.$finalize]() { + this[_xfa_object.$content] = this[_xfa_object.$content].trim().split(/\s+/).filter(x => x && ["calculate", "close", "enter", "exit", "initialize", "ready", "validate"].includes(x)); + } + +} + +class ExcludeNS extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "excludeNS"); + } + +} + +class FlipLabel extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "flipLabel", ["usePrinterSetting", "on", "off"]); + } + +} + +class FontInfo extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "fontInfo", true); + this.embed = null; + this.map = null; + this.subsetBelow = null; + this.alwaysEmbed = new _xfa_object.XFAObjectArray(); + this.defaultTypeface = new _xfa_object.XFAObjectArray(); + this.neverEmbed = new _xfa_object.XFAObjectArray(); + } + +} + +class FormFieldFilling extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "formFieldFilling"); + } + +} + +class GroupParent extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "groupParent"); + } + +} + +class IfEmpty extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "ifEmpty", ["dataValue", "dataGroup", "ignore", "remove"]); + } + +} + +class IncludeXDPContent extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "includeXDPContent"); + } + +} + +class IncrementalLoad extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "incrementalLoad", ["none", "forwardOnly"]); + } + +} + +class IncrementalMerge extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "incrementalMerge"); + } + +} + +class Interactive extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "interactive"); + } + +} + +class Jog extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "jog", ["usePrinterSetting", "none", "pageSet"]); + } + +} + +class LabelPrinter extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "labelPrinter", true); + this.name = (0, _utils.getStringOption)(attributes.name, ["zpl", "dpl", "ipl", "tcpl"]); + this.batchOutput = null; + this.flipLabel = null; + this.fontInfo = null; + this.xdc = null; + } + +} + +class Layout extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "layout", ["paginate", "panel"]); + } + +} + +class Level extends _xfa_object.IntegerObject { + constructor(attributes) { + super(CONFIG_NS_ID, "level", 0, n => n > 0); + } + +} + +class Linearized extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "linearized"); + } + +} + +class Locale extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "locale"); + } + +} + +class LocaleSet extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "localeSet"); + } + +} + +class Log extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "log", true); + this.mode = null; + this.threshold = null; + this.to = null; + this.uri = null; + } + +} + +class MapElement extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "map", true); + this.equate = new _xfa_object.XFAObjectArray(); + this.equateRange = new _xfa_object.XFAObjectArray(); + } + +} + +class MediumInfo extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "mediumInfo", true); + this.map = null; + } + +} + +class Message extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "message", true); + this.msgId = null; + this.severity = null; + } + +} + +class Messaging extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "messaging", true); + this.message = new _xfa_object.XFAObjectArray(); + } + +} + +class Mode extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "mode", ["append", "overwrite"]); + } + +} + +class ModifyAnnots extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "modifyAnnots"); + } + +} + +class MsgId extends _xfa_object.IntegerObject { + constructor(attributes) { + super(CONFIG_NS_ID, "msgId", 1, n => n >= 1); + } + +} + +class NameAttr extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "nameAttr"); + } + +} + +class NeverEmbed extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "neverEmbed"); + } + +} + +class NumberOfCopies extends _xfa_object.IntegerObject { + constructor(attributes) { + super(CONFIG_NS_ID, "numberOfCopies", null, n => n >= 2 && n <= 5); + } + +} + +class OpenAction extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "openAction", true); + this.destination = null; + } + +} + +class Output extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "output", true); + this.to = null; + this.type = null; + this.uri = null; + } + +} + +class OutputBin extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "outputBin"); + } + +} + +class OutputXSL extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "outputXSL", true); + this.uri = null; + } + +} + +class Overprint extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "overprint", ["none", "both", "draw", "field"]); + } + +} + +class Packets extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "packets"); + } + + [_xfa_object.$finalize]() { + if (this[_xfa_object.$content] === "*") { + return; + } + + this[_xfa_object.$content] = this[_xfa_object.$content].trim().split(/\s+/).filter(x => ["config", "datasets", "template", "xfdf", "xslt"].includes(x)); + } + +} + +class PageOffset extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "pageOffset"); + this.x = (0, _utils.getInteger)({ + data: attributes.x, + defaultValue: "useXDCSetting", + validate: n => true + }); + this.y = (0, _utils.getInteger)({ + data: attributes.y, + defaultValue: "useXDCSetting", + validate: n => true + }); + } + +} + +class PageRange extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "pageRange"); + } + + [_xfa_object.$finalize]() { + const numbers = this[_xfa_object.$content].trim().split(/\s+/).map(x => parseInt(x, 10)); + + const ranges = []; + + for (let i = 0, ii = numbers.length; i < ii; i += 2) { + ranges.push(numbers.slice(i, i + 2)); + } + + this[_xfa_object.$content] = ranges; + } + +} + +class Pagination extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "pagination", ["simplex", "duplexShortEdge", "duplexLongEdge"]); + } + +} + +class PaginationOverride extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "paginationOverride", ["none", "forceDuplex", "forceDuplexLongEdge", "forceDuplexShortEdge", "forceSimplex"]); + } + +} + +class Part extends _xfa_object.IntegerObject { + constructor(attributes) { + super(CONFIG_NS_ID, "part", 1, n => false); + } + +} + +class Pcl extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "pcl", true); + this.name = attributes.name || ""; + this.batchOutput = null; + this.fontInfo = null; + this.jog = null; + this.mediumInfo = null; + this.outputBin = null; + this.pageOffset = null; + this.staple = null; + this.xdc = null; + } + +} + +class Pdf extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "pdf", true); + this.name = attributes.name || ""; + this.adobeExtensionLevel = null; + this.batchOutput = null; + this.compression = null; + this.creator = null; + this.encryption = null; + this.fontInfo = null; + this.interactive = null; + this.linearized = null; + this.openAction = null; + this.pdfa = null; + this.producer = null; + this.renderPolicy = null; + this.scriptModel = null; + this.silentPrint = null; + this.submitFormat = null; + this.tagged = null; + this.version = null; + this.viewerPreferences = null; + this.xdc = null; + } + +} + +class Pdfa extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "pdfa", true); + this.amd = null; + this.conformance = null; + this.includeXDPContent = null; + this.part = null; + } + +} + +class Permissions extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "permissions", true); + this.accessibleContent = null; + this.change = null; + this.contentCopy = null; + this.documentAssembly = null; + this.formFieldFilling = null; + this.modifyAnnots = null; + this.plaintextMetadata = null; + this.print = null; + this.printHighQuality = null; + } + +} + +class PickTrayByPDFSize extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "pickTrayByPDFSize"); + } + +} + +class Picture extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "picture"); + } + +} + +class PlaintextMetadata extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "plaintextMetadata"); + } + +} + +class Presence extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "presence", ["preserve", "dissolve", "dissolveStructure", "ignore", "remove"]); + } + +} + +class Present extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "present", true); + this.behaviorOverride = null; + this.cache = null; + this.common = null; + this.copies = null; + this.destination = null; + this.incrementalMerge = null; + this.layout = null; + this.output = null; + this.overprint = null; + this.pagination = null; + this.paginationOverride = null; + this.script = null; + this.validate = null; + this.xdp = null; + this.driver = new _xfa_object.XFAObjectArray(); + this.labelPrinter = new _xfa_object.XFAObjectArray(); + this.pcl = new _xfa_object.XFAObjectArray(); + this.pdf = new _xfa_object.XFAObjectArray(); + this.ps = new _xfa_object.XFAObjectArray(); + this.submitUrl = new _xfa_object.XFAObjectArray(); + this.webClient = new _xfa_object.XFAObjectArray(); + this.zpl = new _xfa_object.XFAObjectArray(); + } + +} + +class Print extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "print"); + } + +} + +class PrintHighQuality extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "printHighQuality"); + } + +} + +class PrintScaling extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "printScaling", ["appdefault", "noScaling"]); + } + +} + +class PrinterName extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "printerName"); + } + +} + +class Producer extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "producer"); + } + +} + +class Ps extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "ps", true); + this.name = attributes.name || ""; + this.batchOutput = null; + this.fontInfo = null; + this.jog = null; + this.mediumInfo = null; + this.outputBin = null; + this.staple = null; + this.xdc = null; + } + +} + +class Range extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "range"); + } + + [_xfa_object.$finalize]() { + this[_xfa_object.$content] = this[_xfa_object.$content].trim().split(/\s*,\s*/, 2).map(range => range.split("-").map(x => parseInt(x.trim(), 10))).filter(range => range.every(x => !isNaN(x))).map(range => { + if (range.length === 1) { + range.push(range[0]); + } + + return range; + }); + } + +} + +class Record extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "record"); + } + + [_xfa_object.$finalize]() { + this[_xfa_object.$content] = this[_xfa_object.$content].trim(); + const n = parseInt(this[_xfa_object.$content], 10); + + if (!isNaN(n) && n >= 0) { + this[_xfa_object.$content] = n; + } + } + +} + +class Relevant extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "relevant"); + } + + [_xfa_object.$finalize]() { + this[_xfa_object.$content] = this[_xfa_object.$content].trim().split(/\s+/); + } + +} + +class Rename extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "rename"); + } + + [_xfa_object.$finalize]() { + this[_xfa_object.$content] = this[_xfa_object.$content].trim(); + + if (this[_xfa_object.$content].toLowerCase().startsWith("xml") || this[_xfa_object.$content].match(new RegExp("[\\p{L}_][\\p{L}\\d._\\p{M}-]*", "u"))) { + (0, _util.warn)("XFA - Rename: invalid XFA name"); + } + } + +} + +class RenderPolicy extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "renderPolicy", ["server", "client"]); + } + +} + +class RunScripts extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "runScripts", ["both", "client", "none", "server"]); + } + +} + +class Script extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "script", true); + this.currentPage = null; + this.exclude = null; + this.runScripts = null; + } + +} + +class ScriptModel extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "scriptModel", ["XFA", "none"]); + } + +} + +class Severity extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "severity", ["ignore", "error", "information", "trace", "warning"]); + } + +} + +class SilentPrint extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "silentPrint", true); + this.addSilentPrint = null; + this.printerName = null; + } + +} + +class Staple extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "staple"); + this.mode = (0, _utils.getStringOption)(attributes.mode, ["usePrinterSetting", "on", "off"]); + } + +} + +class StartNode extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "startNode"); + } + +} + +class StartPage extends _xfa_object.IntegerObject { + constructor(attributes) { + super(CONFIG_NS_ID, "startPage", 0, n => true); + } + +} + +class SubmitFormat extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "submitFormat", ["html", "delegate", "fdf", "xml", "pdf"]); + } + +} + +class SubmitUrl extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "submitUrl"); + } + +} + +class SubsetBelow extends _xfa_object.IntegerObject { + constructor(attributes) { + super(CONFIG_NS_ID, "subsetBelow", 100, n => n >= 0 && n <= 100); + } + +} + +class SuppressBanner extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "suppressBanner"); + } + +} + +class Tagged extends _xfa_object.Option01 { + constructor(attributes) { + super(CONFIG_NS_ID, "tagged"); + } + +} + +class Template extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "template", true); + this.base = null; + this.relevant = null; + this.startPage = null; + this.uri = null; + this.xsl = null; + } + +} + +class Threshold extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "threshold", ["trace", "error", "information", "warning"]); + } + +} + +class To extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "to", ["null", "memory", "stderr", "stdout", "system", "uri"]); + } + +} + +class TemplateCache extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "templateCache"); + this.maxEntries = (0, _utils.getInteger)({ + data: attributes.maxEntries, + defaultValue: 5, + validate: n => n >= 0 + }); + } + +} + +class Trace extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "trace", true); + this.area = new _xfa_object.XFAObjectArray(); + } + +} + +class Transform extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "transform", true); + this.groupParent = null; + this.ifEmpty = null; + this.nameAttr = null; + this.picture = null; + this.presence = null; + this.rename = null; + this.whitespace = null; + } + +} + +class Type extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "type", ["none", "ascii85", "asciiHex", "ccittfax", "flate", "lzw", "runLength", "native", "xdp", "mergedXDP"]); + } + +} + +class Uri extends _xfa_object.StringObject { + constructor(attributes) { + super(CONFIG_NS_ID, "uri"); + } + +} + +class Validate extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "validate", ["preSubmit", "prePrint", "preExecute", "preSave"]); + } + +} + +class ValidateApprovalSignatures extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "validateApprovalSignatures"); + } + + [_xfa_object.$finalize]() { + this[_xfa_object.$content] = this[_xfa_object.$content].trim().split(/\s+/).filter(x => ["docReady", "postSign"].includes(x)); + } + +} + +class ValidationMessaging extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "validationMessaging", ["allMessagesIndividually", "allMessagesTogether", "firstMessageOnly", "noMessages"]); + } + +} + +class Version extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "version", ["1.7", "1.6", "1.5", "1.4", "1.3", "1.2"]); + } + +} + +class VersionControl extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "VersionControl"); + this.outputBelow = (0, _utils.getStringOption)(attributes.outputBelow, ["warn", "error", "update"]); + this.sourceAbove = (0, _utils.getStringOption)(attributes.sourceAbove, ["warn", "error"]); + this.sourceBelow = (0, _utils.getStringOption)(attributes.sourceBelow, ["update", "maintain"]); + } + +} + +class ViewerPreferences extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "viewerPreferences", true); + this.ADBE_JSConsole = null; + this.ADBE_JSDebugger = null; + this.addViewerPreferences = null; + this.duplexOption = null; + this.enforce = null; + this.numberOfCopies = null; + this.pageRange = null; + this.pickTrayByPDFSize = null; + this.printScaling = null; + } + +} + +class WebClient extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "webClient", true); + this.name = attributes.name ? attributes.name.trim() : ""; + this.fontInfo = null; + this.xdc = null; + } + +} + +class Whitespace extends _xfa_object.OptionObject { + constructor(attributes) { + super(CONFIG_NS_ID, "whitespace", ["preserve", "ltrim", "normalize", "rtrim", "trim"]); + } + +} + +class Window extends _xfa_object.ContentObject { + constructor(attributes) { + super(CONFIG_NS_ID, "window"); + } + + [_xfa_object.$finalize]() { + const pair = this[_xfa_object.$content].trim().split(/\s*,\s*/, 2).map(x => parseInt(x, 10)); + + if (pair.some(x => isNaN(x))) { + this[_xfa_object.$content] = [0, 0]; + return; + } + + if (pair.length === 1) { + pair.push(pair[0]); + } + + this[_xfa_object.$content] = pair; + } + +} + +class Xdc extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "xdc", true); + this.uri = new _xfa_object.XFAObjectArray(); + this.xsl = new _xfa_object.XFAObjectArray(); + } + +} + +class Xdp extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "xdp", true); + this.packets = null; + } + +} + +class Xsl extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "xsl", true); + this.debug = null; + this.uri = null; + } + +} + +class Zpl extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONFIG_NS_ID, "zpl", true); + this.name = attributes.name ? attributes.name.trim() : ""; + this.batchOutput = null; + this.flipLabel = null; + this.fontInfo = null; + this.xdc = null; + } + +} + +class ConfigNamespace { + static [_namespaces.$buildXFAObject](name, attributes) { + if (ConfigNamespace.hasOwnProperty(name)) { + return ConfigNamespace[name](attributes); + } + + return undefined; + } + + static acrobat(attrs) { + return new Acrobat(attrs); + } + + static acrobat7(attrs) { + return new Acrobat7(attrs); + } + + static ADBE_JSConsole(attrs) { + return new ADBE_JSConsole(attrs); + } + + static ADBE_JSDebugger(attrs) { + return new ADBE_JSDebugger(attrs); + } + + static addSilentPrint(attrs) { + return new AddSilentPrint(attrs); + } + + static addViewerPreferences(attrs) { + return new AddViewerPreferences(attrs); + } + + static adjustData(attrs) { + return new AdjustData(attrs); + } + + static adobeExtensionLevel(attrs) { + return new AdobeExtensionLevel(attrs); + } + + static agent(attrs) { + return new Agent(attrs); + } + + static alwaysEmbed(attrs) { + return new AlwaysEmbed(attrs); + } + + static amd(attrs) { + return new Amd(attrs); + } + + static area(attrs) { + return new Area(attrs); + } + + static attributes(attrs) { + return new Attributes(attrs); + } + + static autoSave(attrs) { + return new AutoSave(attrs); + } + + static base(attrs) { + return new Base(attrs); + } + + static batchOutput(attrs) { + return new BatchOutput(attrs); + } + + static behaviorOverride(attrs) { + return new BehaviorOverride(attrs); + } + + static cache(attrs) { + return new Cache(attrs); + } + + static change(attrs) { + return new Change(attrs); + } + + static common(attrs) { + return new Common(attrs); + } + + static compress(attrs) { + return new Compress(attrs); + } + + static compressLogicalStructure(attrs) { + return new CompressLogicalStructure(attrs); + } + + static compressObjectStream(attrs) { + return new CompressObjectStream(attrs); + } + + static compression(attrs) { + return new Compression(attrs); + } + + static config(attrs) { + return new Config(attrs); + } + + static conformance(attrs) { + return new Conformance(attrs); + } + + static contentCopy(attrs) { + return new ContentCopy(attrs); + } + + static copies(attrs) { + return new Copies(attrs); + } + + static creator(attrs) { + return new Creator(attrs); + } + + static currentPage(attrs) { + return new CurrentPage(attrs); + } + + static data(attrs) { + return new Data(attrs); + } + + static debug(attrs) { + return new Debug(attrs); + } + + static defaultTypeface(attrs) { + return new DefaultTypeface(attrs); + } + + static destination(attrs) { + return new Destination(attrs); + } + + static documentAssembly(attrs) { + return new DocumentAssembly(attrs); + } + + static driver(attrs) { + return new Driver(attrs); + } + + static duplexOption(attrs) { + return new DuplexOption(attrs); + } + + static dynamicRender(attrs) { + return new DynamicRender(attrs); + } + + static embed(attrs) { + return new Embed(attrs); + } + + static encrypt(attrs) { + return new Encrypt(attrs); + } + + static encryption(attrs) { + return new Encryption(attrs); + } + + static encryptionLevel(attrs) { + return new EncryptionLevel(attrs); + } + + static enforce(attrs) { + return new Enforce(attrs); + } + + static equate(attrs) { + return new Equate(attrs); + } + + static equateRange(attrs) { + return new EquateRange(attrs); + } + + static exclude(attrs) { + return new Exclude(attrs); + } + + static excludeNS(attrs) { + return new ExcludeNS(attrs); + } + + static flipLabel(attrs) { + return new FlipLabel(attrs); + } + + static fontInfo(attrs) { + return new FontInfo(attrs); + } + + static formFieldFilling(attrs) { + return new FormFieldFilling(attrs); + } + + static groupParent(attrs) { + return new GroupParent(attrs); + } + + static ifEmpty(attrs) { + return new IfEmpty(attrs); + } + + static includeXDPContent(attrs) { + return new IncludeXDPContent(attrs); + } + + static incrementalLoad(attrs) { + return new IncrementalLoad(attrs); + } + + static incrementalMerge(attrs) { + return new IncrementalMerge(attrs); + } + + static interactive(attrs) { + return new Interactive(attrs); + } + + static jog(attrs) { + return new Jog(attrs); + } + + static labelPrinter(attrs) { + return new LabelPrinter(attrs); + } + + static layout(attrs) { + return new Layout(attrs); + } + + static level(attrs) { + return new Level(attrs); + } + + static linearized(attrs) { + return new Linearized(attrs); + } + + static locale(attrs) { + return new Locale(attrs); + } + + static localeSet(attrs) { + return new LocaleSet(attrs); + } + + static log(attrs) { + return new Log(attrs); + } + + static map(attrs) { + return new MapElement(attrs); + } + + static mediumInfo(attrs) { + return new MediumInfo(attrs); + } + + static message(attrs) { + return new Message(attrs); + } + + static messaging(attrs) { + return new Messaging(attrs); + } + + static mode(attrs) { + return new Mode(attrs); + } + + static modifyAnnots(attrs) { + return new ModifyAnnots(attrs); + } + + static msgId(attrs) { + return new MsgId(attrs); + } + + static nameAttr(attrs) { + return new NameAttr(attrs); + } + + static neverEmbed(attrs) { + return new NeverEmbed(attrs); + } + + static numberOfCopies(attrs) { + return new NumberOfCopies(attrs); + } + + static openAction(attrs) { + return new OpenAction(attrs); + } + + static output(attrs) { + return new Output(attrs); + } + + static outputBin(attrs) { + return new OutputBin(attrs); + } + + static outputXSL(attrs) { + return new OutputXSL(attrs); + } + + static overprint(attrs) { + return new Overprint(attrs); + } + + static packets(attrs) { + return new Packets(attrs); + } + + static pageOffset(attrs) { + return new PageOffset(attrs); + } + + static pageRange(attrs) { + return new PageRange(attrs); + } + + static pagination(attrs) { + return new Pagination(attrs); + } + + static paginationOverride(attrs) { + return new PaginationOverride(attrs); + } + + static part(attrs) { + return new Part(attrs); + } + + static pcl(attrs) { + return new Pcl(attrs); + } + + static pdf(attrs) { + return new Pdf(attrs); + } + + static pdfa(attrs) { + return new Pdfa(attrs); + } + + static permissions(attrs) { + return new Permissions(attrs); + } + + static pickTrayByPDFSize(attrs) { + return new PickTrayByPDFSize(attrs); + } + + static picture(attrs) { + return new Picture(attrs); + } + + static plaintextMetadata(attrs) { + return new PlaintextMetadata(attrs); + } + + static presence(attrs) { + return new Presence(attrs); + } + + static present(attrs) { + return new Present(attrs); + } + + static print(attrs) { + return new Print(attrs); + } + + static printHighQuality(attrs) { + return new PrintHighQuality(attrs); + } + + static printScaling(attrs) { + return new PrintScaling(attrs); + } + + static printerName(attrs) { + return new PrinterName(attrs); + } + + static producer(attrs) { + return new Producer(attrs); + } + + static ps(attrs) { + return new Ps(attrs); + } + + static range(attrs) { + return new Range(attrs); + } + + static record(attrs) { + return new Record(attrs); + } + + static relevant(attrs) { + return new Relevant(attrs); + } + + static rename(attrs) { + return new Rename(attrs); + } + + static renderPolicy(attrs) { + return new RenderPolicy(attrs); + } + + static runScripts(attrs) { + return new RunScripts(attrs); + } + + static script(attrs) { + return new Script(attrs); + } + + static scriptModel(attrs) { + return new ScriptModel(attrs); + } + + static severity(attrs) { + return new Severity(attrs); + } + + static silentPrint(attrs) { + return new SilentPrint(attrs); + } + + static staple(attrs) { + return new Staple(attrs); + } + + static startNode(attrs) { + return new StartNode(attrs); + } + + static startPage(attrs) { + return new StartPage(attrs); + } + + static submitFormat(attrs) { + return new SubmitFormat(attrs); + } + + static submitUrl(attrs) { + return new SubmitUrl(attrs); + } + + static subsetBelow(attrs) { + return new SubsetBelow(attrs); + } + + static suppressBanner(attrs) { + return new SuppressBanner(attrs); + } + + static tagged(attrs) { + return new Tagged(attrs); + } + + static template(attrs) { + return new Template(attrs); + } + + static templateCache(attrs) { + return new TemplateCache(attrs); + } + + static threshold(attrs) { + return new Threshold(attrs); + } + + static to(attrs) { + return new To(attrs); + } + + static trace(attrs) { + return new Trace(attrs); + } + + static transform(attrs) { + return new Transform(attrs); + } + + static type(attrs) { + return new Type(attrs); + } + + static uri(attrs) { + return new Uri(attrs); + } + + static validate(attrs) { + return new Validate(attrs); + } + + static validateApprovalSignatures(attrs) { + return new ValidateApprovalSignatures(attrs); + } + + static validationMessaging(attrs) { + return new ValidationMessaging(attrs); + } + + static version(attrs) { + return new Version(attrs); + } + + static versionControl(attrs) { + return new VersionControl(attrs); + } + + static viewerPreferences(attrs) { + return new ViewerPreferences(attrs); + } + + static webClient(attrs) { + return new WebClient(attrs); + } + + static whitespace(attrs) { + return new Whitespace(attrs); + } + + static window(attrs) { + return new Window(attrs); + } + + static xdc(attrs) { + return new Xdc(attrs); + } + + static xdp(attrs) { + return new Xdp(attrs); + } + + static xsl(attrs) { + return new Xsl(attrs); + } + + static zpl(attrs) { + return new Zpl(attrs); + } + +} + +exports.ConfigNamespace = ConfigNamespace; + +/***/ }), +/* 92 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.ConnectionSetNamespace = void 0; + +var _namespaces = __w_pdfjs_require__(79); + +var _xfa_object = __w_pdfjs_require__(77); + +const CONNECTION_SET_NS_ID = _namespaces.NamespaceIds.connectionSet.id; + +class ConnectionSet extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "connectionSet", true); + this.wsdlConnection = new _xfa_object.XFAObjectArray(); + this.xmlConnection = new _xfa_object.XFAObjectArray(); + this.xsdConnection = new _xfa_object.XFAObjectArray(); + } + +} + +class EffectiveInputPolicy extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "effectiveInputPolicy"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class EffectiveOutputPolicy extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "effectiveOutputPolicy"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Operation extends _xfa_object.StringObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "operation"); + this.id = attributes.id || ""; + this.input = attributes.input || ""; + this.name = attributes.name || ""; + this.output = attributes.output || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class RootElement extends _xfa_object.StringObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "rootElement"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class SoapAction extends _xfa_object.StringObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "soapAction"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class SoapAddress extends _xfa_object.StringObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "soapAddress"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class Uri extends _xfa_object.StringObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "uri"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class WsdlAddress extends _xfa_object.StringObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "wsdlAddress"); + this.id = attributes.id || ""; + this.name = attributes.name || ""; + this.use = attributes.use || ""; + this.usehref = attributes.usehref || ""; + } + +} + +class WsdlConnection extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "wsdlConnection", true); + this.dataDescription = attributes.dataDescription || ""; + this.name = attributes.name || ""; + this.effectiveInputPolicy = null; + this.effectiveOutputPolicy = null; + this.operation = null; + this.soapAction = null; + this.soapAddress = null; + this.wsdlAddress = null; + } + +} + +class XmlConnection extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "xmlConnection", true); + this.dataDescription = attributes.dataDescription || ""; + this.name = attributes.name || ""; + this.uri = null; + } + +} + +class XsdConnection extends _xfa_object.XFAObject { + constructor(attributes) { + super(CONNECTION_SET_NS_ID, "xsdConnection", true); + this.dataDescription = attributes.dataDescription || ""; + this.name = attributes.name || ""; + this.rootElement = null; + this.uri = null; + } + +} + +class ConnectionSetNamespace { + static [_namespaces.$buildXFAObject](name, attributes) { + if (ConnectionSetNamespace.hasOwnProperty(name)) { + return ConnectionSetNamespace[name](attributes); + } + + return undefined; + } + + static connectionSet(attrs) { + return new ConnectionSet(attrs); + } + + static effectiveInputPolicy(attrs) { + return new EffectiveInputPolicy(attrs); + } + + static effectiveOutputPolicy(attrs) { + return new EffectiveOutputPolicy(attrs); + } + + static operation(attrs) { + return new Operation(attrs); + } + + static rootElement(attrs) { + return new RootElement(attrs); + } + + static soapAction(attrs) { + return new SoapAction(attrs); + } + + static soapAddress(attrs) { + return new SoapAddress(attrs); + } + + static uri(attrs) { + return new Uri(attrs); + } + + static wsdlAddress(attrs) { + return new WsdlAddress(attrs); + } + + static wsdlConnection(attrs) { + return new WsdlConnection(attrs); + } + + static xmlConnection(attrs) { + return new XmlConnection(attrs); + } + + static xsdConnection(attrs) { + return new XsdConnection(attrs); + } + +} + +exports.ConnectionSetNamespace = ConnectionSetNamespace; + +/***/ }), +/* 93 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.DatasetsNamespace = void 0; + +var _xfa_object = __w_pdfjs_require__(77); + +var _namespaces = __w_pdfjs_require__(79); + +const DATASETS_NS_ID = _namespaces.NamespaceIds.datasets.id; + +class Data extends _xfa_object.XmlObject { + constructor(attributes) { + super(DATASETS_NS_ID, "data", attributes); + } + + [_xfa_object.$isNsAgnostic]() { + return true; + } + +} + +class Datasets extends _xfa_object.XFAObject { + constructor(attributes) { + super(DATASETS_NS_ID, "datasets", true); + this.data = null; + this.Signature = null; + } + + [_xfa_object.$onChild](child) { + const name = child[_xfa_object.$nodeName]; + + if (name === "data" && child[_xfa_object.$namespaceId] === DATASETS_NS_ID || name === "Signature" && child[_xfa_object.$namespaceId] === _namespaces.NamespaceIds.signature.id) { + this[name] = child; + } + + this[_xfa_object.$appendChild](child); + } + +} + +class DatasetsNamespace { + static [_namespaces.$buildXFAObject](name, attributes) { + if (DatasetsNamespace.hasOwnProperty(name)) { + return DatasetsNamespace[name](attributes); + } + + return undefined; + } + + static datasets(attributes) { + return new Datasets(attributes); + } + + static data(attributes) { + return new Data(attributes); + } + +} + +exports.DatasetsNamespace = DatasetsNamespace; + +/***/ }), +/* 94 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.LocaleSetNamespace = void 0; + +var _namespaces = __w_pdfjs_require__(79); + +var _xfa_object = __w_pdfjs_require__(77); + +var _utils = __w_pdfjs_require__(78); + +const LOCALE_SET_NS_ID = _namespaces.NamespaceIds.localeSet.id; + +class CalendarSymbols extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "calendarSymbols", true); + this.name = "gregorian"; + this.dayNames = new _xfa_object.XFAObjectArray(2); + this.eraNames = null; + this.meridiemNames = null; + this.monthNames = new _xfa_object.XFAObjectArray(2); + } + +} + +class CurrencySymbol extends _xfa_object.StringObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "currencySymbol"); + this.name = (0, _utils.getStringOption)(attributes.name, ["symbol", "isoname", "decimal"]); + } + +} + +class CurrencySymbols extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "currencySymbols", true); + this.currencySymbol = new _xfa_object.XFAObjectArray(3); + } + +} + +class DatePattern extends _xfa_object.StringObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "datePattern"); + this.name = (0, _utils.getStringOption)(attributes.name, ["full", "long", "med", "short"]); + } + +} + +class DatePatterns extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "datePatterns", true); + this.datePattern = new _xfa_object.XFAObjectArray(4); + } + +} + +class DateTimeSymbols extends _xfa_object.ContentObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "dateTimeSymbols"); + } + +} + +class Day extends _xfa_object.StringObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "day"); + } + +} + +class DayNames extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "dayNames", true); + this.abbr = (0, _utils.getInteger)({ + data: attributes.abbr, + defaultValue: 0, + validate: x => x === 1 + }); + this.day = new _xfa_object.XFAObjectArray(7); + } + +} + +class Era extends _xfa_object.StringObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "era"); + } + +} + +class EraNames extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "eraNames", true); + this.era = new _xfa_object.XFAObjectArray(2); + } + +} + +class Locale extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "locale", true); + this.desc = attributes.desc || ""; + this.name = "isoname"; + this.calendarSymbols = null; + this.currencySymbols = null; + this.datePatterns = null; + this.dateTimeSymbols = null; + this.numberPatterns = null; + this.numberSymbols = null; + this.timePatterns = null; + this.typeFaces = null; + } + +} + +class LocaleSet extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "localeSet", true); + this.locale = new _xfa_object.XFAObjectArray(); + } + +} + +class Meridiem extends _xfa_object.StringObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "meridiem"); + } + +} + +class MeridiemNames extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "meridiemNames", true); + this.meridiem = new _xfa_object.XFAObjectArray(2); + } + +} + +class Month extends _xfa_object.StringObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "month"); + } + +} + +class MonthNames extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "monthNames", true); + this.abbr = (0, _utils.getInteger)({ + data: attributes.abbr, + defaultValue: 0, + validate: x => x === 1 + }); + this.month = new _xfa_object.XFAObjectArray(12); + } + +} + +class NumberPattern extends _xfa_object.StringObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "numberPattern"); + this.name = (0, _utils.getStringOption)(attributes.name, ["full", "long", "med", "short"]); + } + +} + +class NumberPatterns extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "numberPatterns", true); + this.numberPattern = new _xfa_object.XFAObjectArray(4); + } + +} + +class NumberSymbol extends _xfa_object.StringObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "numberSymbol"); + this.name = (0, _utils.getStringOption)(attributes.name, ["decimal", "grouping", "percent", "minus", "zero"]); + } + +} + +class NumberSymbols extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "numberSymbols", true); + this.numberSymbol = new _xfa_object.XFAObjectArray(5); + } + +} + +class TimePattern extends _xfa_object.StringObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "timePattern"); + this.name = (0, _utils.getStringOption)(attributes.name, ["full", "long", "med", "short"]); + } + +} + +class TimePatterns extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "timePatterns", true); + this.timePattern = new _xfa_object.XFAObjectArray(4); + } + +} + +class TypeFace extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "typeFace", true); + this.name = attributes.name | ""; + } + +} + +class TypeFaces extends _xfa_object.XFAObject { + constructor(attributes) { + super(LOCALE_SET_NS_ID, "typeFaces", true); + this.typeFace = new _xfa_object.XFAObjectArray(); + } + +} + +class LocaleSetNamespace { + static [_namespaces.$buildXFAObject](name, attributes) { + if (LocaleSetNamespace.hasOwnProperty(name)) { + return LocaleSetNamespace[name](attributes); + } + + return undefined; + } + + static calendarSymbols(attrs) { + return new CalendarSymbols(attrs); + } + + static currencySymbol(attrs) { + return new CurrencySymbol(attrs); + } + + static currencySymbols(attrs) { + return new CurrencySymbols(attrs); + } + + static datePattern(attrs) { + return new DatePattern(attrs); + } + + static datePatterns(attrs) { + return new DatePatterns(attrs); + } + + static dateTimeSymbols(attrs) { + return new DateTimeSymbols(attrs); + } + + static day(attrs) { + return new Day(attrs); + } + + static dayNames(attrs) { + return new DayNames(attrs); + } + + static era(attrs) { + return new Era(attrs); + } + + static eraNames(attrs) { + return new EraNames(attrs); + } + + static locale(attrs) { + return new Locale(attrs); + } + + static localeSet(attrs) { + return new LocaleSet(attrs); + } + + static meridiem(attrs) { + return new Meridiem(attrs); + } + + static meridiemNames(attrs) { + return new MeridiemNames(attrs); + } + + static month(attrs) { + return new Month(attrs); + } + + static monthNames(attrs) { + return new MonthNames(attrs); + } + + static numberPattern(attrs) { + return new NumberPattern(attrs); + } + + static numberPatterns(attrs) { + return new NumberPatterns(attrs); + } + + static numberSymbol(attrs) { + return new NumberSymbol(attrs); + } + + static numberSymbols(attrs) { + return new NumberSymbols(attrs); + } + + static timePattern(attrs) { + return new TimePattern(attrs); + } + + static timePatterns(attrs) { + return new TimePatterns(attrs); + } + + static typeFace(attrs) { + return new TypeFace(attrs); + } + + static typeFaces(attrs) { + return new TypeFaces(attrs); + } + +} + +exports.LocaleSetNamespace = LocaleSetNamespace; + +/***/ }), +/* 95 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.SignatureNamespace = void 0; + +var _namespaces = __w_pdfjs_require__(79); + +var _xfa_object = __w_pdfjs_require__(77); + +const SIGNATURE_NS_ID = _namespaces.NamespaceIds.signature.id; + +class Signature extends _xfa_object.XFAObject { + constructor(attributes) { + super(SIGNATURE_NS_ID, "signature", true); + } + +} + +class SignatureNamespace { + static [_namespaces.$buildXFAObject](name, attributes) { + if (SignatureNamespace.hasOwnProperty(name)) { + return SignatureNamespace[name](attributes); + } + + return undefined; + } + + static signature(attributes) { + return new Signature(attributes); + } + +} + +exports.SignatureNamespace = SignatureNamespace; + +/***/ }), +/* 96 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.StylesheetNamespace = void 0; + +var _namespaces = __w_pdfjs_require__(79); + +var _xfa_object = __w_pdfjs_require__(77); + +const STYLESHEET_NS_ID = _namespaces.NamespaceIds.stylesheet.id; + +class Stylesheet extends _xfa_object.XFAObject { + constructor(attributes) { + super(STYLESHEET_NS_ID, "stylesheet", true); + } + +} + +class StylesheetNamespace { + static [_namespaces.$buildXFAObject](name, attributes) { + if (StylesheetNamespace.hasOwnProperty(name)) { + return StylesheetNamespace[name](attributes); + } + + return undefined; + } + + static stylesheet(attributes) { + return new Stylesheet(attributes); + } + +} + +exports.StylesheetNamespace = StylesheetNamespace; + +/***/ }), +/* 97 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XdpNamespace = void 0; + +var _namespaces = __w_pdfjs_require__(79); + +var _xfa_object = __w_pdfjs_require__(77); + +const XDP_NS_ID = _namespaces.NamespaceIds.xdp.id; + +class Xdp extends _xfa_object.XFAObject { + constructor(attributes) { + super(XDP_NS_ID, "xdp", true); + this.uuid = attributes.uuid || ""; + this.timeStamp = attributes.timeStamp || ""; + this.config = null; + this.connectionSet = null; + this.datasets = null; + this.localeSet = null; + this.stylesheet = new _xfa_object.XFAObjectArray(); + this.template = null; + } + + [_xfa_object.$onChildCheck](child) { + const ns = _namespaces.NamespaceIds[child[_xfa_object.$nodeName]]; + return ns && child[_xfa_object.$namespaceId] === ns.id; + } + +} + +class XdpNamespace { + static [_namespaces.$buildXFAObject](name, attributes) { + if (XdpNamespace.hasOwnProperty(name)) { + return XdpNamespace[name](attributes); + } + + return undefined; + } + + static xdp(attributes) { + return new Xdp(attributes); + } + +} + +exports.XdpNamespace = XdpNamespace; + +/***/ }), +/* 98 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XhtmlNamespace = void 0; + +var _xfa_object = __w_pdfjs_require__(77); + +var _namespaces = __w_pdfjs_require__(79); + +var _html_utils = __w_pdfjs_require__(84); + +var _utils = __w_pdfjs_require__(78); + +const XHTML_NS_ID = _namespaces.NamespaceIds.xhtml.id; +const $richText = Symbol(); +const VALID_STYLES = new Set(["color", "font", "font-family", "font-size", "font-stretch", "font-style", "font-weight", "margin", "margin-bottom", "margin-left", "margin-right", "margin-top", "letter-spacing", "line-height", "orphans", "page-break-after", "page-break-before", "page-break-inside", "tab-interval", "tab-stop", "text-align", "text-decoration", "text-indent", "vertical-align", "widows", "kerning-mode", "xfa-font-horizontal-scale", "xfa-font-vertical-scale", "xfa-spacerun", "xfa-tab-stops"]); +const StyleMapping = new Map([["page-break-after", "breakAfter"], ["page-break-before", "breakBefore"], ["page-break-inside", "breakInside"], ["kerning-mode", value => value === "none" ? "none" : "normal"], ["xfa-font-horizontal-scale", value => `scaleX(${Math.max(0, Math.min(parseInt(value) / 100)).toFixed(2)})`], ["xfa-font-vertical-scale", value => `scaleY(${Math.max(0, Math.min(parseInt(value) / 100)).toFixed(2)})`], ["xfa-spacerun", ""], ["xfa-tab-stops", ""], ["font-size", (value, original) => { + value = original.fontSize = (0, _utils.getMeasurement)(value); + return (0, _html_utils.measureToString)(0.99 * value); +}], ["letter-spacing", value => (0, _html_utils.measureToString)((0, _utils.getMeasurement)(value))], ["line-height", value => (0, _html_utils.measureToString)((0, _utils.getMeasurement)(value))], ["margin", value => (0, _html_utils.measureToString)((0, _utils.getMeasurement)(value))], ["margin-bottom", value => (0, _html_utils.measureToString)((0, _utils.getMeasurement)(value))], ["margin-left", value => (0, _html_utils.measureToString)((0, _utils.getMeasurement)(value))], ["margin-right", value => (0, _html_utils.measureToString)((0, _utils.getMeasurement)(value))], ["margin-top", value => (0, _html_utils.measureToString)((0, _utils.getMeasurement)(value))], ["text-indent", value => (0, _html_utils.measureToString)((0, _utils.getMeasurement)(value))], ["font-family", value => value], ["vertical-align", value => (0, _html_utils.measureToString)((0, _utils.getMeasurement)(value))]]); +const spacesRegExp = /\s+/g; +const crlfRegExp = /[\r\n]+/g; +const crlfForRichTextRegExp = /\r\n?/g; + +function mapStyle(styleStr, node, richText) { + const style = Object.create(null); + + if (!styleStr) { + return style; + } + + const original = Object.create(null); + + for (const [key, value] of styleStr.split(";").map(s => s.split(":", 2))) { + const mapping = StyleMapping.get(key); + + if (mapping === "") { + continue; + } + + let newValue = value; + + if (mapping) { + if (typeof mapping === "string") { + newValue = mapping; + } else { + newValue = mapping(value, original); + } + } + + if (key.endsWith("scale")) { + if (style.transform) { + style.transform = `${style[key]} ${newValue}`; + } else { + style.transform = newValue; + } + } else { + style[key.replaceAll(/-([a-zA-Z])/g, (_, x) => x.toUpperCase())] = newValue; + } + } + + if (style.fontFamily) { + (0, _html_utils.setFontFamily)({ + typeface: style.fontFamily, + weight: style.fontWeight || "normal", + posture: style.fontStyle || "normal", + size: original.fontSize || 0 + }, node, node[_xfa_object.$globalData].fontFinder, style); + } + + if (richText && style.verticalAlign && style.verticalAlign !== "0px" && style.fontSize) { + const SUB_SUPER_SCRIPT_FACTOR = 0.583; + const VERTICAL_FACTOR = 0.333; + const fontSize = (0, _utils.getMeasurement)(style.fontSize); + style.fontSize = (0, _html_utils.measureToString)(fontSize * SUB_SUPER_SCRIPT_FACTOR); + style.verticalAlign = (0, _html_utils.measureToString)(Math.sign((0, _utils.getMeasurement)(style.verticalAlign)) * fontSize * VERTICAL_FACTOR); + } + + if (richText && style.fontSize) { + style.fontSize = `calc(${style.fontSize} * var(--scale-factor))`; + } + + (0, _html_utils.fixTextIndent)(style); + return style; +} + +function checkStyle(node) { + if (!node.style) { + return ""; + } + + return node.style.trim().split(/\s*;\s*/).filter(s => !!s).map(s => s.split(/\s*:\s*/, 2)).filter(([key, value]) => { + if (key === "font-family") { + node[_xfa_object.$globalData].usedTypefaces.add(value); + } + + return VALID_STYLES.has(key); + }).map(kv => kv.join(":")).join(";"); +} + +const NoWhites = new Set(["body", "html"]); + +class XhtmlObject extends _xfa_object.XmlObject { + constructor(attributes, name) { + super(XHTML_NS_ID, name); + this[$richText] = false; + this.style = attributes.style || ""; + } + + [_xfa_object.$clean](builder) { + super[_xfa_object.$clean](builder); + + this.style = checkStyle(this); + } + + [_xfa_object.$acceptWhitespace]() { + return !NoWhites.has(this[_xfa_object.$nodeName]); + } + + [_xfa_object.$onText](str, richText = false) { + if (!richText) { + str = str.replace(crlfRegExp, ""); + + if (!this.style.includes("xfa-spacerun:yes")) { + str = str.replace(spacesRegExp, " "); + } + } else { + this[$richText] = true; + } + + if (str) { + this[_xfa_object.$content] += str; + } + } + + [_xfa_object.$pushGlyphs](measure, mustPop = true) { + const xfaFont = Object.create(null); + const margin = { + top: NaN, + bottom: NaN, + left: NaN, + right: NaN + }; + let lineHeight = null; + + for (const [key, value] of this.style.split(";").map(s => s.split(":", 2))) { + switch (key) { + case "font-family": + xfaFont.typeface = (0, _utils.stripQuotes)(value); + break; + + case "font-size": + xfaFont.size = (0, _utils.getMeasurement)(value); + break; + + case "font-weight": + xfaFont.weight = value; + break; + + case "font-style": + xfaFont.posture = value; + break; + + case "letter-spacing": + xfaFont.letterSpacing = (0, _utils.getMeasurement)(value); + break; + + case "margin": + const values = value.split(/ \t/).map(x => (0, _utils.getMeasurement)(x)); + + switch (values.length) { + case 1: + margin.top = margin.bottom = margin.left = margin.right = values[0]; + break; + + case 2: + margin.top = margin.bottom = values[0]; + margin.left = margin.right = values[1]; + break; + + case 3: + margin.top = values[0]; + margin.bottom = values[2]; + margin.left = margin.right = values[1]; + break; + + case 4: + margin.top = values[0]; + margin.left = values[1]; + margin.bottom = values[2]; + margin.right = values[3]; + break; + } + + break; + + case "margin-top": + margin.top = (0, _utils.getMeasurement)(value); + break; + + case "margin-bottom": + margin.bottom = (0, _utils.getMeasurement)(value); + break; + + case "margin-left": + margin.left = (0, _utils.getMeasurement)(value); + break; + + case "margin-right": + margin.right = (0, _utils.getMeasurement)(value); + break; + + case "line-height": + lineHeight = (0, _utils.getMeasurement)(value); + break; + } + } + + measure.pushData(xfaFont, margin, lineHeight); + + if (this[_xfa_object.$content]) { + measure.addString(this[_xfa_object.$content]); + } else { + for (const child of this[_xfa_object.$getChildren]()) { + if (child[_xfa_object.$nodeName] === "#text") { + measure.addString(child[_xfa_object.$content]); + continue; + } + + child[_xfa_object.$pushGlyphs](measure); + } + } + + if (mustPop) { + measure.popFont(); + } + } + + [_xfa_object.$toHTML](availableSpace) { + const children = []; + this[_xfa_object.$extra] = { + children + }; + + this[_xfa_object.$childrenToHTML]({}); + + if (children.length === 0 && !this[_xfa_object.$content]) { + return _utils.HTMLResult.EMPTY; + } + + let value; + + if (this[$richText]) { + value = this[_xfa_object.$content] ? this[_xfa_object.$content].replace(crlfForRichTextRegExp, "\n") : undefined; + } else { + value = this[_xfa_object.$content] || undefined; + } + + return _utils.HTMLResult.success({ + name: this[_xfa_object.$nodeName], + attributes: { + href: this.href, + style: mapStyle(this.style, this, this[$richText]) + }, + children, + value + }); + } + +} + +class A extends XhtmlObject { + constructor(attributes) { + super(attributes, "a"); + this.href = (0, _html_utils.fixURL)(attributes.href) || ""; + } + +} + +class B extends XhtmlObject { + constructor(attributes) { + super(attributes, "b"); + } + + [_xfa_object.$pushGlyphs](measure) { + measure.pushFont({ + weight: "bold" + }); + + super[_xfa_object.$pushGlyphs](measure); + + measure.popFont(); + } + +} + +class Body extends XhtmlObject { + constructor(attributes) { + super(attributes, "body"); + } + + [_xfa_object.$toHTML](availableSpace) { + const res = super[_xfa_object.$toHTML](availableSpace); + + const { + html + } = res; + + if (!html) { + return _utils.HTMLResult.EMPTY; + } + + html.name = "div"; + html.attributes.class = ["xfaRich"]; + return res; + } + +} + +class Br extends XhtmlObject { + constructor(attributes) { + super(attributes, "br"); + } + + [_xfa_object.$text]() { + return "\n"; + } + + [_xfa_object.$pushGlyphs](measure) { + measure.addString("\n"); + } + + [_xfa_object.$toHTML](availableSpace) { + return _utils.HTMLResult.success({ + name: "br" + }); + } + +} + +class Html extends XhtmlObject { + constructor(attributes) { + super(attributes, "html"); + } + + [_xfa_object.$toHTML](availableSpace) { + const children = []; + this[_xfa_object.$extra] = { + children + }; + + this[_xfa_object.$childrenToHTML]({}); + + if (children.length === 0) { + return _utils.HTMLResult.success({ + name: "div", + attributes: { + class: ["xfaRich"], + style: {} + }, + value: this[_xfa_object.$content] || "" + }); + } + + if (children.length === 1) { + const child = children[0]; + + if (child.attributes && child.attributes.class.includes("xfaRich")) { + return _utils.HTMLResult.success(child); + } + } + + return _utils.HTMLResult.success({ + name: "div", + attributes: { + class: ["xfaRich"], + style: {} + }, + children + }); + } + +} + +class I extends XhtmlObject { + constructor(attributes) { + super(attributes, "i"); + } + + [_xfa_object.$pushGlyphs](measure) { + measure.pushFont({ + posture: "italic" + }); + + super[_xfa_object.$pushGlyphs](measure); + + measure.popFont(); + } + +} + +class Li extends XhtmlObject { + constructor(attributes) { + super(attributes, "li"); + } + +} + +class Ol extends XhtmlObject { + constructor(attributes) { + super(attributes, "ol"); + } + +} + +class P extends XhtmlObject { + constructor(attributes) { + super(attributes, "p"); + } + + [_xfa_object.$pushGlyphs](measure) { + super[_xfa_object.$pushGlyphs](measure, false); + + measure.addString("\n"); + measure.addPara(); + measure.popFont(); + } + + [_xfa_object.$text]() { + const siblings = this[_xfa_object.$getParent]()[_xfa_object.$getChildren](); + + if (siblings.at(-1) === this) { + return super[_xfa_object.$text](); + } + + return super[_xfa_object.$text]() + "\n"; + } + +} + +class Span extends XhtmlObject { + constructor(attributes) { + super(attributes, "span"); + } + +} + +class Sub extends XhtmlObject { + constructor(attributes) { + super(attributes, "sub"); + } + +} + +class Sup extends XhtmlObject { + constructor(attributes) { + super(attributes, "sup"); + } + +} + +class Ul extends XhtmlObject { + constructor(attributes) { + super(attributes, "ul"); + } + +} + +class XhtmlNamespace { + static [_namespaces.$buildXFAObject](name, attributes) { + if (XhtmlNamespace.hasOwnProperty(name)) { + return XhtmlNamespace[name](attributes); + } + + return undefined; + } + + static a(attributes) { + return new A(attributes); + } + + static b(attributes) { + return new B(attributes); + } + + static body(attributes) { + return new Body(attributes); + } + + static br(attributes) { + return new Br(attributes); + } + + static html(attributes) { + return new Html(attributes); + } + + static i(attributes) { + return new I(attributes); + } + + static li(attributes) { + return new Li(attributes); + } + + static ol(attributes) { + return new Ol(attributes); + } + + static p(attributes) { + return new P(attributes); + } + + static span(attributes) { + return new Span(attributes); + } + + static sub(attributes) { + return new Sub(attributes); + } + + static sup(attributes) { + return new Sup(attributes); + } + + static ul(attributes) { + return new Ul(attributes); + } + +} + +exports.XhtmlNamespace = XhtmlNamespace; + +/***/ }), +/* 99 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.UnknownNamespace = void 0; + +var _namespaces = __w_pdfjs_require__(79); + +var _xfa_object = __w_pdfjs_require__(77); + +class UnknownNamespace { + constructor(nsId) { + this.namespaceId = nsId; + } + + [_namespaces.$buildXFAObject](name, attributes) { + return new _xfa_object.XmlObject(this.namespaceId, name, attributes); + } + +} + +exports.UnknownNamespace = UnknownNamespace; + +/***/ }), +/* 100 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.DatasetReader = void 0; + +var _util = __w_pdfjs_require__(2); + +var _core_utils = __w_pdfjs_require__(6); + +var _xml_parser = __w_pdfjs_require__(66); + +function decodeString(str) { + try { + return (0, _util.stringToUTF8String)(str); + } catch (ex) { + (0, _util.warn)(`UTF-8 decoding failed: "${ex}".`); + return str; + } +} + +class DatasetXMLParser extends _xml_parser.SimpleXMLParser { + constructor(options) { + super(options); + this.node = null; + } + + onEndElement(name) { + const node = super.onEndElement(name); + + if (node && name === "xfa:datasets") { + this.node = node; + throw new Error("Aborting DatasetXMLParser."); + } + } + +} + +class DatasetReader { + constructor(data) { + if (data.datasets) { + this.node = new _xml_parser.SimpleXMLParser({ + hasAttributes: true + }).parseFromString(data.datasets).documentElement; + } else { + const parser = new DatasetXMLParser({ + hasAttributes: true + }); + + try { + parser.parseFromString(data["xdp:xdp"]); + } catch (_) {} + + this.node = parser.node; + } + } + + getValue(path) { + if (!this.node || !path) { + return ""; + } + + const node = this.node.searchNode((0, _core_utils.parseXFAPath)(path), 0); + + if (!node) { + return ""; + } + + const first = node.firstChild; + + if (first && first.nodeName === "value") { + return node.children.map(child => decodeString(child.textContent)); + } + + return decodeString(node.textContent); + } + +} + +exports.DatasetReader = DatasetReader; + +/***/ }), +/* 101 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XRef = void 0; + +var _util = __w_pdfjs_require__(2); + +var _primitives = __w_pdfjs_require__(5); + +var _core_utils = __w_pdfjs_require__(6); + +var _parser = __w_pdfjs_require__(17); + +var _base_stream = __w_pdfjs_require__(7); + +var _crypto = __w_pdfjs_require__(67); + +class XRef { + constructor(stream, pdfManager) { + this.stream = stream; + this.pdfManager = pdfManager; + this.entries = []; + this.xrefstms = Object.create(null); + this._cacheMap = new Map(); + this._pendingRefs = new _primitives.RefSet(); + this.stats = new _core_utils.DocStats(pdfManager.msgHandler); + this._newRefNum = null; + } + + getNewRef() { + if (this._newRefNum === null) { + this._newRefNum = this.entries.length || 1; + } + + return _primitives.Ref.get(this._newRefNum++, 0); + } + + resetNewRef() { + this._newRefNum = null; + } + + setStartXRef(startXRef) { + this.startXRefQueue = [startXRef]; + } + + parse(recoveryMode = false) { + let trailerDict; + + if (!recoveryMode) { + trailerDict = this.readXRef(); + } else { + (0, _util.warn)("Indexing all PDF objects"); + trailerDict = this.indexObjects(); + } + + trailerDict.assignXref(this); + this.trailer = trailerDict; + let encrypt; + + try { + encrypt = trailerDict.get("Encrypt"); + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)(`XRef.parse - Invalid "Encrypt" reference: "${ex}".`); + } + + if (encrypt instanceof _primitives.Dict) { + const ids = trailerDict.get("ID"); + const fileId = ids && ids.length ? ids[0] : ""; + encrypt.suppressEncryption = true; + this.encrypt = new _crypto.CipherTransformFactory(encrypt, fileId, this.pdfManager.password); + } + + let root; + + try { + root = trailerDict.get("Root"); + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)(`XRef.parse - Invalid "Root" reference: "${ex}".`); + } + + if (root instanceof _primitives.Dict) { + try { + const pages = root.get("Pages"); + + if (pages instanceof _primitives.Dict) { + this.root = root; + return; + } + } catch (ex) { + if (ex instanceof _core_utils.MissingDataException) { + throw ex; + } + + (0, _util.warn)(`XRef.parse - Invalid "Pages" reference: "${ex}".`); + } + } + + if (!recoveryMode) { + throw new _core_utils.XRefParseException(); + } + + throw new _util.InvalidPDFException("Invalid Root reference."); + } + + processXRefTable(parser) { + if (!("tableState" in this)) { + this.tableState = { + entryNum: 0, + streamPos: parser.lexer.stream.pos, + parserBuf1: parser.buf1, + parserBuf2: parser.buf2 + }; + } + + const obj = this.readXRefTable(parser); + + if (!(0, _primitives.isCmd)(obj, "trailer")) { + throw new _util.FormatError("Invalid XRef table: could not find trailer dictionary"); + } + + let dict = parser.getObj(); + + if (!(dict instanceof _primitives.Dict) && dict.dict) { + dict = dict.dict; + } + + if (!(dict instanceof _primitives.Dict)) { + throw new _util.FormatError("Invalid XRef table: could not parse trailer dictionary"); + } + + delete this.tableState; + return dict; + } + + readXRefTable(parser) { + const stream = parser.lexer.stream; + const tableState = this.tableState; + stream.pos = tableState.streamPos; + parser.buf1 = tableState.parserBuf1; + parser.buf2 = tableState.parserBuf2; + let obj; + + while (true) { + if (!("firstEntryNum" in tableState) || !("entryCount" in tableState)) { + if ((0, _primitives.isCmd)(obj = parser.getObj(), "trailer")) { + break; + } + + tableState.firstEntryNum = obj; + tableState.entryCount = parser.getObj(); + } + + let first = tableState.firstEntryNum; + const count = tableState.entryCount; + + if (!Number.isInteger(first) || !Number.isInteger(count)) { + throw new _util.FormatError("Invalid XRef table: wrong types in subsection header"); + } + + for (let i = tableState.entryNum; i < count; i++) { + tableState.streamPos = stream.pos; + tableState.entryNum = i; + tableState.parserBuf1 = parser.buf1; + tableState.parserBuf2 = parser.buf2; + const entry = {}; + entry.offset = parser.getObj(); + entry.gen = parser.getObj(); + const type = parser.getObj(); + + if (type instanceof _primitives.Cmd) { + switch (type.cmd) { + case "f": + entry.free = true; + break; + + case "n": + entry.uncompressed = true; + break; + } + } + + if (!Number.isInteger(entry.offset) || !Number.isInteger(entry.gen) || !(entry.free || entry.uncompressed)) { + throw new _util.FormatError(`Invalid entry in XRef subsection: ${first}, ${count}`); + } + + if (i === 0 && entry.free && first === 1) { + first = 0; + } + + if (!this.entries[i + first]) { + this.entries[i + first] = entry; + } + } + + tableState.entryNum = 0; + tableState.streamPos = stream.pos; + tableState.parserBuf1 = parser.buf1; + tableState.parserBuf2 = parser.buf2; + delete tableState.firstEntryNum; + delete tableState.entryCount; + } + + if (this.entries[0] && !this.entries[0].free) { + throw new _util.FormatError("Invalid XRef table: unexpected first object"); + } + + return obj; + } + + processXRefStream(stream) { + if (!("streamState" in this)) { + const streamParameters = stream.dict; + const byteWidths = streamParameters.get("W"); + let range = streamParameters.get("Index"); + + if (!range) { + range = [0, streamParameters.get("Size")]; + } + + this.streamState = { + entryRanges: range, + byteWidths, + entryNum: 0, + streamPos: stream.pos + }; + } + + this.readXRefStream(stream); + delete this.streamState; + return stream.dict; + } + + readXRefStream(stream) { + const streamState = this.streamState; + stream.pos = streamState.streamPos; + const [typeFieldWidth, offsetFieldWidth, generationFieldWidth] = streamState.byteWidths; + const entryRanges = streamState.entryRanges; + + while (entryRanges.length > 0) { + const [first, n] = entryRanges; + + if (!Number.isInteger(first) || !Number.isInteger(n)) { + throw new _util.FormatError(`Invalid XRef range fields: ${first}, ${n}`); + } + + if (!Number.isInteger(typeFieldWidth) || !Number.isInteger(offsetFieldWidth) || !Number.isInteger(generationFieldWidth)) { + throw new _util.FormatError(`Invalid XRef entry fields length: ${first}, ${n}`); + } + + for (let i = streamState.entryNum; i < n; ++i) { + streamState.entryNum = i; + streamState.streamPos = stream.pos; + let type = 0, + offset = 0, + generation = 0; + + for (let j = 0; j < typeFieldWidth; ++j) { + const typeByte = stream.getByte(); + + if (typeByte === -1) { + throw new _util.FormatError("Invalid XRef byteWidths 'type'."); + } + + type = type << 8 | typeByte; + } + + if (typeFieldWidth === 0) { + type = 1; + } + + for (let j = 0; j < offsetFieldWidth; ++j) { + const offsetByte = stream.getByte(); + + if (offsetByte === -1) { + throw new _util.FormatError("Invalid XRef byteWidths 'offset'."); + } + + offset = offset << 8 | offsetByte; + } + + for (let j = 0; j < generationFieldWidth; ++j) { + const generationByte = stream.getByte(); + + if (generationByte === -1) { + throw new _util.FormatError("Invalid XRef byteWidths 'generation'."); + } + + generation = generation << 8 | generationByte; + } + + const entry = {}; + entry.offset = offset; + entry.gen = generation; + + switch (type) { + case 0: + entry.free = true; + break; + + case 1: + entry.uncompressed = true; + break; + + case 2: + break; + + default: + throw new _util.FormatError(`Invalid XRef entry type: ${type}`); + } + + if (!this.entries[first + i]) { + this.entries[first + i] = entry; + } + } + + streamState.entryNum = 0; + streamState.streamPos = stream.pos; + entryRanges.splice(0, 2); + } + } + + indexObjects() { + const TAB = 0x9, + LF = 0xa, + CR = 0xd, + SPACE = 0x20; + const PERCENT = 0x25, + LT = 0x3c; + + function readToken(data, offset) { + let token = "", + ch = data[offset]; + + while (ch !== LF && ch !== CR && ch !== LT) { + if (++offset >= data.length) { + break; + } + + token += String.fromCharCode(ch); + ch = data[offset]; + } + + return token; + } + + function skipUntil(data, offset, what) { + const length = what.length, + dataLength = data.length; + let skipped = 0; + + while (offset < dataLength) { + let i = 0; + + while (i < length && data[offset + i] === what[i]) { + ++i; + } + + if (i >= length) { + break; + } + + offset++; + skipped++; + } + + return skipped; + } + + const objRegExp = /^(\d+)\s+(\d+)\s+obj\b/; + const endobjRegExp = /\bendobj[\b\s]$/; + const nestedObjRegExp = /\s+(\d+\s+\d+\s+obj[\b\s<])$/; + const CHECK_CONTENT_LENGTH = 25; + const trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]); + const startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114, 101, 102]); + const objBytes = new Uint8Array([111, 98, 106]); + const xrefBytes = new Uint8Array([47, 88, 82, 101, 102]); + this.entries.length = 0; + + this._cacheMap.clear(); + + const stream = this.stream; + stream.pos = 0; + const buffer = stream.getBytes(), + length = buffer.length; + let position = stream.start; + const trailers = [], + xrefStms = []; + + while (position < length) { + let ch = buffer[position]; + + if (ch === TAB || ch === LF || ch === CR || ch === SPACE) { + ++position; + continue; + } + + if (ch === PERCENT) { + do { + ++position; + + if (position >= length) { + break; + } + + ch = buffer[position]; + } while (ch !== LF && ch !== CR); + + continue; + } + + const token = readToken(buffer, position); + let m; + + if (token.startsWith("xref") && (token.length === 4 || /\s/.test(token[4]))) { + position += skipUntil(buffer, position, trailerBytes); + trailers.push(position); + position += skipUntil(buffer, position, startxrefBytes); + } else if (m = objRegExp.exec(token)) { + const num = m[1] | 0, + gen = m[2] | 0; + let contentLength, + startPos = position + token.length, + updateEntries = false; + + if (!this.entries[num]) { + updateEntries = true; + } else if (this.entries[num].gen === gen) { + try { + const parser = new _parser.Parser({ + lexer: new _parser.Lexer(stream.makeSubStream(startPos)) + }); + parser.getObj(); + updateEntries = true; + } catch (ex) { + if (ex instanceof _core_utils.ParserEOFException) { + (0, _util.warn)(`indexObjects -- checking object (${token}): "${ex}".`); + } else { + updateEntries = true; + } + } + } + + if (updateEntries) { + this.entries[num] = { + offset: position - stream.start, + gen, + uncompressed: true + }; + } + + while (startPos < buffer.length) { + const endPos = startPos + skipUntil(buffer, startPos, objBytes) + 4; + contentLength = endPos - position; + const checkPos = Math.max(endPos - CHECK_CONTENT_LENGTH, startPos); + const tokenStr = (0, _util.bytesToString)(buffer.subarray(checkPos, endPos)); + + if (endobjRegExp.test(tokenStr)) { + break; + } else { + const objToken = nestedObjRegExp.exec(tokenStr); + + if (objToken && objToken[1]) { + (0, _util.warn)('indexObjects: Found new "obj" inside of another "obj", ' + 'caused by missing "endobj" -- trying to recover.'); + contentLength -= objToken[1].length; + break; + } + } + + startPos = endPos; + } + + const content = buffer.subarray(position, position + contentLength); + const xrefTagOffset = skipUntil(content, 0, xrefBytes); + + if (xrefTagOffset < contentLength && content[xrefTagOffset + 5] < 64) { + xrefStms.push(position - stream.start); + this.xrefstms[position - stream.start] = 1; + } + + position += contentLength; + } else if (token.startsWith("trailer") && (token.length === 7 || /\s/.test(token[7]))) { + trailers.push(position); + position += skipUntil(buffer, position, startxrefBytes); + } else { + position += token.length + 1; + } + } + + for (let i = 0, ii = xrefStms.length; i < ii; ++i) { + this.startXRefQueue.push(xrefStms[i]); + this.readXRef(true); + } + + let trailerDict; + + for (let i = 0, ii = trailers.length; i < ii; ++i) { + stream.pos = trailers[i]; + const parser = new _parser.Parser({ + lexer: new _parser.Lexer(stream), + xref: this, + allowStreams: true, + recoveryMode: true + }); + const obj = parser.getObj(); + + if (!(0, _primitives.isCmd)(obj, "trailer")) { + continue; + } + + const dict = parser.getObj(); + + if (!(dict instanceof _primitives.Dict)) { + continue; + } + + try { + const rootDict = dict.get("Root"); + + if (!(rootDict instanceof _primitives.Dict)) { + continue; + } + + const pagesDict = rootDict.get("Pages"); + + if (!(pagesDict instanceof _primitives.Dict)) { + continue; + } + + const pagesCount = pagesDict.get("Count"); + + if (!Number.isInteger(pagesCount)) { + continue; + } + } catch (ex) { + continue; + } + + if (dict.has("ID")) { + return dict; + } + + trailerDict = dict; + } + + if (trailerDict) { + return trailerDict; + } + + if (this.topDict) { + return this.topDict; + } + + throw new _util.InvalidPDFException("Invalid PDF structure."); + } + + readXRef(recoveryMode = false) { + const stream = this.stream; + const startXRefParsedCache = new Set(); + + try { + while (this.startXRefQueue.length) { + const startXRef = this.startXRefQueue[0]; + + if (startXRefParsedCache.has(startXRef)) { + (0, _util.warn)("readXRef - skipping XRef table since it was already parsed."); + this.startXRefQueue.shift(); + continue; + } + + startXRefParsedCache.add(startXRef); + stream.pos = startXRef + stream.start; + const parser = new _parser.Parser({ + lexer: new _parser.Lexer(stream), + xref: this, + allowStreams: true + }); + let obj = parser.getObj(); + let dict; + + if ((0, _primitives.isCmd)(obj, "xref")) { + dict = this.processXRefTable(parser); + + if (!this.topDict) { + this.topDict = dict; + } + + obj = dict.get("XRefStm"); + + if (Number.isInteger(obj)) { + const pos = obj; + + if (!(pos in this.xrefstms)) { + this.xrefstms[pos] = 1; + this.startXRefQueue.push(pos); + } + } + } else if (Number.isInteger(obj)) { + if (!Number.isInteger(parser.getObj()) || !(0, _primitives.isCmd)(parser.getObj(), "obj") || !((obj = parser.getObj()) instanceof _base_stream.BaseStream)) { + throw new _util.FormatError("Invalid XRef stream"); + } + + dict = this.processXRefStream(obj); + + if (!this.topDict) { + this.topDict = dict; + } + + if (!dict) { + throw new _util.FormatError("Failed to read XRef stream"); + } + } else { + throw new _util.FormatError("Invalid XRef stream header"); + } + + obj = dict.get("Prev"); + + if (Number.isInteger(obj)) { + this.startXRefQueue.push(obj); + } else if (obj instanceof _primitives.Ref) { + this.startXRefQueue.push(obj.num); + } + + this.startXRefQueue.shift(); + } + + return this.topDict; + } catch (e) { + if (e instanceof _core_utils.MissingDataException) { + throw e; + } + + (0, _util.info)("(while reading XRef): " + e); + this.startXRefQueue.shift(); + } + + if (recoveryMode) { + return undefined; + } + + throw new _core_utils.XRefParseException(); + } + + getEntry(i) { + const xrefEntry = this.entries[i]; + + if (xrefEntry && !xrefEntry.free && xrefEntry.offset) { + return xrefEntry; + } + + return null; + } + + fetchIfRef(obj, suppressEncryption = false) { + if (obj instanceof _primitives.Ref) { + return this.fetch(obj, suppressEncryption); + } + + return obj; + } + + fetch(ref, suppressEncryption = false) { + if (!(ref instanceof _primitives.Ref)) { + throw new Error("ref object is not a reference"); + } + + const num = ref.num; + + const cacheEntry = this._cacheMap.get(num); + + if (cacheEntry !== undefined) { + if (cacheEntry instanceof _primitives.Dict && !cacheEntry.objId) { + cacheEntry.objId = ref.toString(); + } + + return cacheEntry; + } + + let xrefEntry = this.getEntry(num); + + if (xrefEntry === null) { + this._cacheMap.set(num, xrefEntry); + + return xrefEntry; + } + + if (this._pendingRefs.has(ref)) { + this._pendingRefs.remove(ref); + + (0, _util.warn)(`Ignoring circular reference: ${ref}.`); + return _primitives.CIRCULAR_REF; + } + + this._pendingRefs.put(ref); + + try { + if (xrefEntry.uncompressed) { + xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption); + } else { + xrefEntry = this.fetchCompressed(ref, xrefEntry, suppressEncryption); + } + + this._pendingRefs.remove(ref); + } catch (ex) { + this._pendingRefs.remove(ref); + + throw ex; + } + + if (xrefEntry instanceof _primitives.Dict) { + xrefEntry.objId = ref.toString(); + } else if (xrefEntry instanceof _base_stream.BaseStream) { + xrefEntry.dict.objId = ref.toString(); + } + + return xrefEntry; + } + + fetchUncompressed(ref, xrefEntry, suppressEncryption = false) { + const gen = ref.gen; + let num = ref.num; + + if (xrefEntry.gen !== gen) { + throw new _core_utils.XRefEntryException(`Inconsistent generation in XRef: ${ref}`); + } + + const stream = this.stream.makeSubStream(xrefEntry.offset + this.stream.start); + const parser = new _parser.Parser({ + lexer: new _parser.Lexer(stream), + xref: this, + allowStreams: true + }); + const obj1 = parser.getObj(); + const obj2 = parser.getObj(); + const obj3 = parser.getObj(); + + if (obj1 !== num || obj2 !== gen || !(obj3 instanceof _primitives.Cmd)) { + throw new _core_utils.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`); + } + + if (obj3.cmd !== "obj") { + if (obj3.cmd.startsWith("obj")) { + num = parseInt(obj3.cmd.substring(3), 10); + + if (!Number.isNaN(num)) { + return num; + } + } + + throw new _core_utils.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`); + } + + if (this.encrypt && !suppressEncryption) { + xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen)); + } else { + xrefEntry = parser.getObj(); + } + + if (!(xrefEntry instanceof _base_stream.BaseStream)) { + this._cacheMap.set(num, xrefEntry); + } + + return xrefEntry; + } + + fetchCompressed(ref, xrefEntry, suppressEncryption = false) { + const tableOffset = xrefEntry.offset; + const stream = this.fetch(_primitives.Ref.get(tableOffset, 0)); + + if (!(stream instanceof _base_stream.BaseStream)) { + throw new _util.FormatError("bad ObjStm stream"); + } + + const first = stream.dict.get("First"); + const n = stream.dict.get("N"); + + if (!Number.isInteger(first) || !Number.isInteger(n)) { + throw new _util.FormatError("invalid first and n parameters for ObjStm stream"); + } + + let parser = new _parser.Parser({ + lexer: new _parser.Lexer(stream), + xref: this, + allowStreams: true + }); + const nums = new Array(n); + const offsets = new Array(n); + + for (let i = 0; i < n; ++i) { + const num = parser.getObj(); + + if (!Number.isInteger(num)) { + throw new _util.FormatError(`invalid object number in the ObjStm stream: ${num}`); + } + + const offset = parser.getObj(); + + if (!Number.isInteger(offset)) { + throw new _util.FormatError(`invalid object offset in the ObjStm stream: ${offset}`); + } + + nums[i] = num; + offsets[i] = offset; + } + + const start = (stream.start || 0) + first; + const entries = new Array(n); + + for (let i = 0; i < n; ++i) { + const length = i < n - 1 ? offsets[i + 1] - offsets[i] : undefined; + + if (length < 0) { + throw new _util.FormatError("Invalid offset in the ObjStm stream."); + } + + parser = new _parser.Parser({ + lexer: new _parser.Lexer(stream.makeSubStream(start + offsets[i], length, stream.dict)), + xref: this, + allowStreams: true + }); + const obj = parser.getObj(); + entries[i] = obj; + + if (obj instanceof _base_stream.BaseStream) { + continue; + } + + const num = nums[i], + entry = this.entries[num]; + + if (entry && entry.offset === tableOffset && entry.gen === i) { + this._cacheMap.set(num, obj); + } + } + + xrefEntry = entries[xrefEntry.gen]; + + if (xrefEntry === undefined) { + throw new _core_utils.XRefEntryException(`Bad (compressed) XRef entry: ${ref}`); + } + + return xrefEntry; + } + + async fetchIfRefAsync(obj, suppressEncryption) { + if (obj instanceof _primitives.Ref) { + return this.fetchAsync(obj, suppressEncryption); + } + + return obj; + } + + async fetchAsync(ref, suppressEncryption) { + try { + return this.fetch(ref, suppressEncryption); + } catch (ex) { + if (!(ex instanceof _core_utils.MissingDataException)) { + throw ex; + } + + await this.pdfManager.requestRange(ex.begin, ex.end); + return this.fetchAsync(ref, suppressEncryption); + } + } + + getCatalogObj() { + return this.root; + } + +} + +exports.XRef = XRef; + +/***/ }), +/* 102 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.MessageHandler = void 0; var _util = __w_pdfjs_require__(2); @@ -47010,8 +74699,8 @@ const StreamKind = { }; function wrapReason(reason) { - if (typeof reason !== "object" || reason === null) { - return reason; + if (!(reason instanceof Error || typeof reason === "object" && reason !== null)) { + (0, _util.unreachable)('wrapReason: Expected "reason" to be a (possibly cloned) Error.'); } switch (reason.name) { @@ -47021,6 +74710,9 @@ function wrapReason(reason) { case "MissingPDFException": return new _util.MissingPDFException(reason.message); + case "PasswordException": + return new _util.PasswordException(reason.message, reason.code); + case "UnexpectedResponseException": return new _util.UnexpectedResponseException(reason.message, reason.status); @@ -47039,7 +74731,6 @@ class MessageHandler { this.comObj = comObj; this.callbackId = 1; this.streamId = 1; - this.postMessageTransfers = true; this.streamSinks = Object.create(null); this.streamControllers = Object.create(null); this.callbackCapabilities = Object.create(null); @@ -47133,7 +74824,7 @@ class MessageHandler { } send(actionName, data, transfers) { - this._postMessage({ + this.comObj.postMessage({ sourceName: this.sourceName, targetName: this.targetName, action: actionName, @@ -47147,7 +74838,7 @@ class MessageHandler { this.callbackCapabilities[callbackId] = capability; try { - this._postMessage({ + this.comObj.postMessage({ sourceName: this.sourceName, targetName: this.targetName, action: actionName, @@ -47162,10 +74853,10 @@ class MessageHandler { } sendWithStream(actionName, data, queueingStrategy, transfers) { - const streamId = this.streamId++; - const sourceName = this.sourceName; - const targetName = this.targetName; - const comObj = this.comObj; + const streamId = this.streamId++, + sourceName = this.sourceName, + targetName = this.targetName, + comObj = this.comObj; return new ReadableStream({ start: controller => { const startCapability = (0, _util.createPromiseCapability)(); @@ -47176,8 +74867,7 @@ class MessageHandler { cancelCall: null, isClosed: false }; - - this._postMessage({ + comObj.postMessage({ sourceName, targetName, action: actionName, @@ -47185,7 +74875,6 @@ class MessageHandler { data, desiredSize: controller.desiredSize }, transfers); - return startCapability.promise; }, pull: controller => { @@ -47218,12 +74907,12 @@ class MessageHandler { } _createStreamSink(data) { - const self = this; - const action = this.actionHandler[data.action]; - const streamId = data.streamId; - const sourceName = this.sourceName; - const targetName = data.sourceName; - const comObj = this.comObj; + const streamId = data.streamId, + sourceName = this.sourceName, + targetName = data.sourceName, + comObj = this.comObj; + const self = this, + action = this.actionHandler[data.action]; const streamSink = { enqueue(chunk, size = 1, transfers) { if (this.isCancelled) { @@ -47238,7 +74927,7 @@ class MessageHandler { this.ready = this.sinkCapability.promise; } - self._postMessage({ + comObj.postMessage({ sourceName, targetName, stream: StreamKind.ENQUEUE, @@ -47311,32 +75000,34 @@ class MessageHandler { } _processStreamMessage(data) { - const streamId = data.streamId; - const sourceName = this.sourceName; - const targetName = data.sourceName; - const comObj = this.comObj; + const streamId = data.streamId, + sourceName = this.sourceName, + targetName = data.sourceName, + comObj = this.comObj; + const streamController = this.streamControllers[streamId], + streamSink = this.streamSinks[streamId]; switch (data.stream) { case StreamKind.START_COMPLETE: if (data.success) { - this.streamControllers[streamId].startCall.resolve(); + streamController.startCall.resolve(); } else { - this.streamControllers[streamId].startCall.reject(wrapReason(data.reason)); + streamController.startCall.reject(wrapReason(data.reason)); } break; case StreamKind.PULL_COMPLETE: if (data.success) { - this.streamControllers[streamId].pullCall.resolve(); + streamController.pullCall.resolve(); } else { - this.streamControllers[streamId].pullCall.reject(wrapReason(data.reason)); + streamController.pullCall.reject(wrapReason(data.reason)); } break; case StreamKind.PULL: - if (!this.streamSinks[streamId]) { + if (!streamSink) { comObj.postMessage({ sourceName, targetName, @@ -47347,16 +75038,13 @@ class MessageHandler { break; } - if (this.streamSinks[streamId].desiredSize <= 0 && data.desiredSize > 0) { - this.streamSinks[streamId].sinkCapability.resolve(); + if (streamSink.desiredSize <= 0 && data.desiredSize > 0) { + streamSink.sinkCapability.resolve(); } - this.streamSinks[streamId].desiredSize = data.desiredSize; - const { - onPull - } = this.streamSinks[data.streamId]; + streamSink.desiredSize = data.desiredSize; new Promise(function (resolve) { - resolve(onPull && onPull()); + resolve(streamSink.onPull && streamSink.onPull()); }).then(function () { comObj.postMessage({ sourceName, @@ -47377,58 +75065,55 @@ class MessageHandler { break; case StreamKind.ENQUEUE: - (0, _util.assert)(this.streamControllers[streamId], "enqueue should have stream controller"); + (0, _util.assert)(streamController, "enqueue should have stream controller"); - if (this.streamControllers[streamId].isClosed) { + if (streamController.isClosed) { break; } - this.streamControllers[streamId].controller.enqueue(data.chunk); + streamController.controller.enqueue(data.chunk); break; case StreamKind.CLOSE: - (0, _util.assert)(this.streamControllers[streamId], "close should have stream controller"); + (0, _util.assert)(streamController, "close should have stream controller"); - if (this.streamControllers[streamId].isClosed) { + if (streamController.isClosed) { break; } - this.streamControllers[streamId].isClosed = true; - this.streamControllers[streamId].controller.close(); + streamController.isClosed = true; + streamController.controller.close(); - this._deleteStreamController(streamId); + this._deleteStreamController(streamController, streamId); break; case StreamKind.ERROR: - (0, _util.assert)(this.streamControllers[streamId], "error should have stream controller"); - this.streamControllers[streamId].controller.error(wrapReason(data.reason)); + (0, _util.assert)(streamController, "error should have stream controller"); + streamController.controller.error(wrapReason(data.reason)); - this._deleteStreamController(streamId); + this._deleteStreamController(streamController, streamId); break; case StreamKind.CANCEL_COMPLETE: if (data.success) { - this.streamControllers[streamId].cancelCall.resolve(); + streamController.cancelCall.resolve(); } else { - this.streamControllers[streamId].cancelCall.reject(wrapReason(data.reason)); + streamController.cancelCall.reject(wrapReason(data.reason)); } - this._deleteStreamController(streamId); + this._deleteStreamController(streamController, streamId); break; case StreamKind.CANCEL: - if (!this.streamSinks[streamId]) { + if (!streamSink) { break; } - const { - onCancel - } = this.streamSinks[data.streamId]; new Promise(function (resolve) { - resolve(onCancel && onCancel(wrapReason(data.reason))); + resolve(streamSink.onCancel && streamSink.onCancel(wrapReason(data.reason))); }).then(function () { comObj.postMessage({ sourceName, @@ -47446,8 +75131,8 @@ class MessageHandler { reason: wrapReason(reason) }); }); - this.streamSinks[streamId].sinkCapability.reject(wrapReason(data.reason)); - this.streamSinks[streamId].isCancelled = true; + streamSink.sinkCapability.reject(wrapReason(data.reason)); + streamSink.isCancelled = true; delete this.streamSinks[streamId]; break; @@ -47456,21 +75141,11 @@ class MessageHandler { } } - async _deleteStreamController(streamId) { - await Promise.allSettled([this.streamControllers[streamId].startCall, this.streamControllers[streamId].pullCall, this.streamControllers[streamId].cancelCall].map(function (capability) { - return capability && capability.promise; - })); + async _deleteStreamController(streamController, streamId) { + await Promise.allSettled([streamController.startCall && streamController.startCall.promise, streamController.pullCall && streamController.pullCall.promise, streamController.cancelCall && streamController.cancelCall.promise]); delete this.streamControllers[streamId]; } - _postMessage(message, transfers) { - if (transfers && this.postMessageTransfers) { - this.comObj.postMessage(message, transfers); - } else { - this.comObj.postMessage(message); - } - } - destroy() { this.comObj.removeEventListener("message", this._onComObjOnMessage); } @@ -47480,15 +75155,14 @@ class MessageHandler { exports.MessageHandler = MessageHandler; /***/ }), -/* 47 */ -/***/ (function(module, exports, __w_pdfjs_require__) { - -"use strict"; +/* 103 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFWorkerStream = void 0; var _util = __w_pdfjs_require__(2); @@ -47520,11 +75194,9 @@ class PDFWorkerStream { this._fullRequestReader.cancel(reason); } - const readers = this._rangeRequestReaders.slice(0); - - readers.forEach(function (reader) { + for (const reader of this._rangeRequestReaders.slice(0)) { reader.cancel(reason); - }); + } } } @@ -47633,6 +75305,86 @@ class PDFWorkerStreamRangeReader { } /***/ }) -/******/ ]); +/******/ ]); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __w_pdfjs_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __w_pdfjs_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __w_pdfjs_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__w_pdfjs_require__.o(definition, key) && !__w_pdfjs_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __w_pdfjs_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __w_pdfjs_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +var exports = __webpack_exports__; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +Object.defineProperty(exports, "WorkerMessageHandler", ({ + enumerable: true, + get: function () { + return _worker.WorkerMessageHandler; + } +})); + +var _worker = __w_pdfjs_require__(1); + +const pdfjsVersion = '2.16.105'; +const pdfjsBuild = '172ccdbe5'; +})(); + +/******/ return __webpack_exports__; +/******/ })() +; }); //# sourceMappingURL=pdf.worker.js.map \ No newline at end of file diff --git a/cps/static/js/libs/tinymce/langs/ko.js b/cps/static/js/libs/tinymce/langs/ko.js new file mode 100644 index 000000000..c6b3f2667 --- /dev/null +++ b/cps/static/js/libs/tinymce/langs/ko.js @@ -0,0 +1,261 @@ +tinymce.addI18n('ko_KR',{ +"Redo": "\ub2e4\uc2dc\uc2e4\ud589", +"Undo": "\uc2e4\ud589\ucde8\uc18c", +"Cut": "\uc798\ub77c\ub0b4\uae30", +"Copy": "\ubcf5\uc0ac\ud558\uae30", +"Paste": "\ubd99\uc5ec\ub123\uae30", +"Select all": "\uc804\uccb4\uc120\ud0dd", +"New document": "\uc0c8 \ubb38\uc11c", +"Ok": "\ud655\uc778", +"Cancel": "\ucde8\uc18c", +"Visual aids": "\uc2dc\uac01\uad50\uc7ac", +"Bold": "\uad75\uac8c", +"Italic": "\uae30\uc6b8\uc784\uaf34", +"Underline": "\ubc11\uc904", +"Strikethrough": "\ucde8\uc18c\uc120", +"Superscript": "\uc717\ucca8\uc790", +"Subscript": "\uc544\ub798\ucca8\uc790", +"Clear formatting": "\ud3ec\ub9f7\ucd08\uae30\ud654", +"Align left": "\uc67c\ucabd\uc815\ub82c", +"Align center": "\uac00\uc6b4\ub370\uc815\ub82c", +"Align right": "\uc624\ub978\ucabd\uc815\ub82c", +"Justify": "\uc591\ucabd\uc815\ub82c", +"Bullet list": "\uc810\ub9ac\uc2a4\ud2b8", +"Numbered list": "\uc22b\uc790\ub9ac\uc2a4\ud2b8", +"Decrease indent": "\ub0b4\uc5b4\uc4f0\uae30", +"Increase indent": "\ub4e4\uc5ec\uc4f0\uae30", +"Close": "\ub2eb\uae30", +"Formats": "\ud3ec\ub9f7", +"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\ube0c\ub77c\uc6b0\uc838\uac00 \ud074\ub9bd\ubcf4\ub4dc \uc811\uadfc\uc744 \ud5c8\uc6a9\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. Ctrl+X\/C\/V \ud0a4\ub97c \uc774\uc6a9\ud574 \uc8fc\uc138\uc694.", +"Headers": "\uc2a4\ud0c0\uc77c", +"Header 1": "\uc81c\ubaa9 1", +"Header 2": "\uc81c\ubaa9 2", +"Header 3": "\uc81c\ubaa9 3", +"Header 4": "\uc81c\ubaa9 4", +"Header 5": "\uc81c\ubaa9 5", +"Header 6": "\uc81c\ubaa9 6", +"Headings": "\uc81c\ubaa9", +"Heading 1": "\uc81c\ubaa9 1", +"Heading 2": "\uc81c\ubaa9 2", +"Heading 3": "\uc81c\ubaa9 3", +"Heading 4": "\uc81c\ubaa9 4", +"Heading 5": "\uc81c\ubaa9 5", +"Heading 6": "\uc81c\ubaa9 6", +"Preformatted": "Preformatted", +"Div": "\uad6c\ubd84", +"Pre": "Pre", +"Code": "\ucf54\ub4dc", +"Paragraph": "\ub2e8\ub77d", +"Blockquote": "\uad6c\ud68d", +"Inline": "\ub77c\uc778 \uc124\uc815", +"Blocks": "\ube14\ub85d \uc124\uc815", +"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\uc2a4\ud0c0\uc77c\ubcf5\uc0ac \ub044\uae30. \uc774 \uc635\uc158\uc744 \ub044\uae30 \uc804\uc5d0\ub294 \ubcf5\uc0ac \uc2dc, \uc2a4\ud0c0\uc77c\uc774 \ubcf5\uc0ac\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.", +"Font Family": "\uae00\uaf34", +"Font Sizes": "\ud3f0\ud2b8 \uc0ac\uc774\uc988", +"Class": "\ud074\ub798\uc2a4", +"Browse for an image": "\uc774\ubbf8\uc9c0 \ucc3e\uae30", +"OR": "\ud639\uc740", +"Drop an image here": "\uc774\ubbf8\uc9c0 \ub4dc\ub86d", +"Upload": "\uc5c5\ub85c\ub4dc", +"Block": "\ube14\ub85d", +"Align": "\uc815\ub82c", +"Default": "\uae30\ubcf8", +"Circle": "\uc6d0", +"Disc": "\uc6d0\ubc18", +"Square": "\uc0ac\uac01", +"Lower Alpha": "\uc54c\ud30c\ubcb3 \uc18c\ubb38\uc790", +"Lower Greek": "\uadf8\ub9ac\uc2a4\uc5b4 \uc18c\ubb38\uc790", +"Lower Roman": "\ub85c\ub9c8\uc790 \uc18c\ubb38\uc790", +"Upper Alpha": "\uc54c\ud30c\ubcb3 \uc18c\ubb38\uc790", +"Upper Roman": "\ub85c\ub9c8\uc790 \ub300\ubb38\uc790", +"Anchor": "\uc575\ucee4", +"Name": "\uc774\ub984", +"Id": "\uc544\uc774\ub514", +"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\uc544\uc774\ub514\ub294 \ubb38\uc790, \uc22b\uc790, \ub300\uc2dc, \uc810, \ucf5c\ub860 \ub610\ub294 \ubc11\uc904\ub85c \uc2dc\uc791\ud574\uc57c\ud569\ub2c8\ub2e4.", +"You have unsaved changes are you sure you want to navigate away?": "\uc800\uc7a5\ud558\uc9c0 \uc54a\uc740 \uc815\ubcf4\uac00 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \ud398\uc774\uc9c0\ub97c \ubc97\uc5b4\ub098\uc2dc\uaca0\uc2b5\ub2c8\uae4c?", +"Restore last draft": "\ub9c8\uc9c0\ub9c9 \ucd08\uc548 \ubcf5\uc6d0", +"Special character": "\ud2b9\uc218\ubb38\uc790", +"Source code": "\uc18c\uc2a4\ucf54\ub4dc", +"Insert\/Edit code sample": "\ucf54\ub4dc\uc0d8\ud50c \uc0bd\uc785\/\ud3b8\uc9d1", +"Language": "\uc5b8\uc5b4", +"Code sample": "\ucf54\ub4dc\uc0d8\ud50c", +"Color": "\uc0c9\uc0c1", +"R": "R", +"G": "G", +"B": "B", +"Left to right": "\uc67c\ucabd\uc5d0\uc11c \uc624\ub978\ucabd", +"Right to left": "\uc624\ub978\ucabd\uc5d0\uc11c \uc67c\ucabd", +"Emoticons": "\uc774\ubaa8\ud2f0\ucf58", +"Document properties": "\ubb38\uc11c \uc18d\uc131", +"Title": "\uc81c\ubaa9", +"Keywords": "\ud0a4\uc6cc\ub4dc", +"Description": "\uc124\uba85", +"Robots": "\ub85c\ubd07", +"Author": "\uc800\uc790", +"Encoding": "\uc778\ucf54\ub529", +"Fullscreen": "\uc804\uccb4\ud654\uba74", +"Action": "\ub3d9\uc791", +"Shortcut": "\ub2e8\ucd95\ud0a4", +"Help": "\ub3c4\uc6c0\ub9d0", +"Address": "\uc8fc\uc18c", +"Focus to menubar": "\uba54\ub274\uc5d0 \ud3ec\ucee4\uc2a4", +"Focus to toolbar": "\ud234\ubc14\uc5d0 \ud3ec\ucee4\uc2a4", +"Focus to element path": "element path\uc5d0 \ud3ec\ucee4\uc2a4", +"Focus to contextual toolbar": "\ucf04\ud14d\uc2a4\ud2b8 \ud234\ubc14\uc5d0 \ud3ec\ucee4\uc2a4", +"Insert link (if link plugin activated)": "\ub9c1\ud06c \uc0bd\uc785 (link \ud50c\ub7ec\uadf8\uc778\uc774 \ud65c\uc131\ud654\ub41c \uc0c1\ud0dc\uc5d0\uc11c)", +"Save (if save plugin activated)": "\uc800\uc7a5 (save \ud50c\ub7ec\uadf8\uc778\uc774 \ud65c\uc131\ud654\ub41c \uc0c1\ud0dc\uc5d0\uc11c)", +"Find (if searchreplace plugin activated)": "\ucc3e\uae30(searchreplace \ud50c\ub7ec\uadf8\uc778\uc774 \ud65c\uc131\ud654\ub41c \uc0c1\ud0dc\uc5d0\uc11c)", +"Plugins installed ({0}):": "\uc124\uce58\ub41c \ud50c\ub7ec\uadf8\uc778 ({0}):", +"Premium plugins:": "\uace0\uae09 \ud50c\ub7ec\uadf8\uc778", +"Learn more...": "\uc880 \ub354 \uc0b4\ud3b4\ubcf4\uae30", +"You are using {0}": "{0}\ub97c \uc0ac\uc6a9\uc911", +"Plugins": "\ud50c\ub7ec\uadf8\uc778", +"Handy Shortcuts": "\ub2e8\ucd95\ud0a4", +"Horizontal line": "\uac00\ub85c", +"Insert\/edit image": "\uc774\ubbf8\uc9c0 \uc0bd\uc785\/\uc218\uc815", +"Image description": "\uc774\ubbf8\uc9c0 \uc124\uba85", +"Source": "\uc18c\uc2a4", +"Dimensions": "\ud06c\uae30", +"Constrain proportions": "\uc791\uc5c5 \uc81c\ud55c", +"General": "\uc77c\ubc18", +"Advanced": "\uace0\uae09", +"Style": "\uc2a4\ud0c0\uc77c", +"Vertical space": "\uc218\uc9c1 \uacf5\ubc31", +"Horizontal space": "\uc218\ud3c9 \uacf5\ubc31", +"Border": "\ud14c\ub450\ub9ac", +"Insert image": "\uc774\ubbf8\uc9c0 \uc0bd\uc785", +"Image": "\uc774\ubbf8\uc9c0", +"Image list": "\uc774\ubbf8\uc9c0 \ubaa9\ub85d", +"Rotate counterclockwise": "\uc2dc\uacc4\ubc18\ub300\ubc29\ud5a5\uc73c\ub85c \ud68c\uc804", +"Rotate clockwise": "\uc2dc\uacc4\ubc29\ud5a5\uc73c\ub85c \ud68c\uc804", +"Flip vertically": "\uc218\uc9c1 \ub4a4\uc9d1\uae30", +"Flip horizontally": "\uc218\ud3c9 \ub4a4\uc9d1\uae30", +"Edit image": "\uc774\ubbf8\uc9c0 \ud3b8\uc9d1", +"Image options": "\uc774\ubbf8\uc9c0 \uc635\uc158", +"Zoom in": "\ud655\ub300", +"Zoom out": "\ucd95\uc18c", +"Crop": "\uc790\ub974\uae30", +"Resize": "\ud06c\uae30 \uc870\uc808", +"Orientation": "\ubc29\ud5a5", +"Brightness": "\ubc1d\uae30", +"Sharpen": "\uc120\uba85\ud558\uac8c", +"Contrast": "\ub300\ube44", +"Color levels": "\uc0c9\uc0c1\ub808\ubca8", +"Gamma": "\uac10\ub9c8", +"Invert": "\ubc18\uc804", +"Apply": "\uc801\uc6a9", +"Back": "\ub4a4\ub85c", +"Insert date\/time": "\ub0a0\uc9dc\/\uc2dc\uac04\uc0bd\uc785", +"Date\/time": "\ub0a0\uc9dc\/\uc2dc\uac04", +"Insert link": "\ub9c1\ud06c \uc0bd\uc785 ", +"Insert\/edit link": "\ub9c1\ud06c \uc0bd\uc785\/\uc218\uc815", +"Text to display": "\ubcf8\ubb38", +"Url": "\uc8fc\uc18c", +"Target": "\ub300\uc0c1", +"None": "\uc5c6\uc74c", +"New window": "\uc0c8\ucc3d", +"Remove link": "\ub9c1\ud06c\uc0ad\uc81c", +"Anchors": "\ucc45\uac08\ud53c", +"Link": "\ub9c1\ud06c", +"Paste or type a link": "\ub9c1\ud06c\ub97c \ubd99\uc5ec\ub123\uac70\ub098 \uc785\ub825\ud558\uc138\uc694", +"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\ud604\uc7ac E-mail\uc8fc\uc18c\ub97c \uc785\ub825\ud558\uc168\uc2b5\ub2c8\ub2e4. E-mail \uc8fc\uc18c\uc5d0 \ub9c1\ud06c\ub97c \uac78\uae4c\uc694?", +"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\ud604\uc7ac \uc6f9\uc0ac\uc774\ud2b8 \uc8fc\uc18c\ub97c \uc785\ub825\ud558\uc168\uc2b5\ub2c8\ub2e4. \ud574\ub2f9 \uc8fc\uc18c\uc5d0 \ub9c1\ud06c\ub97c \uac78\uae4c\uc694?", +"Link list": "\ub9c1\ud06c \ub9ac\uc2a4\ud2b8", +"Insert video": "\ube44\ub514\uc624 \uc0bd\uc785", +"Insert\/edit video": "\ube44\ub514\uc624 \uc0bd\uc785\/\uc218\uc815", +"Insert\/edit media": "\ubbf8\ub514\uc5b4 \uc0bd\uc785\/\uc218\uc815", +"Alternative source": "\ub300\uccb4 \uc18c\uc2a4", +"Poster": "\ud3ec\uc2a4\ud130", +"Paste your embed code below:": "\uc544\ub798\uc5d0 \ucf54\ub4dc\ub97c \ubd99\uc5ec\ub123\uc73c\uc138\uc694:", +"Embed": "\uc0bd\uc785", +"Media": "\ubbf8\ub514\uc5b4", +"Nonbreaking space": "\ub744\uc5b4\uc4f0\uae30", +"Page break": "\ud398\uc774\uc9c0 \uad6c\ubd84\uc790", +"Paste as text": "\ud14d\uc2a4\ud2b8\ub85c \ubd99\uc5ec\ub123\uae30", +"Preview": "\ubbf8\ub9ac\ubcf4\uae30", +"Print": "\ucd9c\ub825", +"Save": "\uc800\uc7a5", +"Find": "\ucc3e\uae30", +"Replace with": "\uad50\uccb4", +"Replace": "\uad50\uccb4", +"Replace all": "\uc804\uccb4 \uad50\uccb4", +"Prev": "\uc774\uc804", +"Next": "\ub2e4\uc74c", +"Find and replace": "\ucc3e\uc544\uc11c \uad50\uccb4", +"Could not find the specified string.": "\ubb38\uc790\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", +"Match case": "\ub300\uc18c\ubb38\uc790 \uc77c\uce58", +"Whole words": "\uc804\uccb4 \ub2e8\uc5b4", +"Spellcheck": "\ubb38\ubc95\uccb4\ud06c", +"Ignore": "\ubb34\uc2dc", +"Ignore all": "\uc804\uccb4\ubb34\uc2dc", +"Finish": "\uc644\ub8cc", +"Add to Dictionary": "\uc0ac\uc804\uc5d0 \ucd94\uac00", +"Insert table": "\ud14c\uc774\ube14 \uc0bd\uc785", +"Table properties": "\ud14c\uc774\ube14 \uc18d\uc131", +"Delete table": "\ud14c\uc774\ube14 \uc0ad\uc81c", +"Cell": "\uc140", +"Row": "\uc5f4", +"Column": "\ud589", +"Cell properties": "\uc140 \uc18d", +"Merge cells": "\uc140 \ud569\uce58\uae30", +"Split cell": "\uc140 \ub098\ub204\uae30", +"Insert row before": "\uc774\uc804\uc5d0 \ud589 \uc0bd\uc785", +"Insert row after": "\ub2e4\uc74c\uc5d0 \ud589 \uc0bd\uc785", +"Delete row": "\ud589 \uc9c0\uc6b0\uae30", +"Row properties": "\ud589 \uc18d\uc131", +"Cut row": "\ud589 \uc798\ub77c\ub0b4\uae30", +"Copy row": "\ud589 \ubcf5\uc0ac", +"Paste row before": "\uc774\uc804\uc5d0 \ud589 \ubd99\uc5ec\ub123\uae30", +"Paste row after": "\ub2e4\uc74c\uc5d0 \ud589 \ubd99\uc5ec\ub123\uae30", +"Insert column before": "\uc774\uc804\uc5d0 \ud589 \uc0bd\uc785", +"Insert column after": "\ub2e4\uc74c\uc5d0 \uc5f4 \uc0bd\uc785", +"Delete column": "\uc5f4 \uc9c0\uc6b0\uae30", +"Cols": "\uc5f4", +"Rows": "\ud589", +"Width": "\ub113\uc774", +"Height": "\ub192\uc774", +"Cell spacing": "\uc140 \uac04\uaca9", +"Cell padding": "\uc140 \uc548\ucabd \uc5ec\ubc31", +"Caption": "\ucea1\uc158", +"Left": "\uc67c\ucabd", +"Center": "\uac00\uc6b4\ub370", +"Right": "\uc624\ub978\ucabd", +"Cell type": "\uc140 \ud0c0\uc785", +"Scope": "\ubc94\uc704", +"Alignment": "\uc815\ub82c", +"H Align": "\uac00\ub85c \uc815\ub82c", +"V Align": "\uc138\ub85c \uc815\ub82c", +"Top": "\uc0c1\ub2e8", +"Middle": "\uc911\uac04", +"Bottom": "\ud558\ub2e8", +"Header cell": "\ud5e4\ub354 \uc140", +"Row group": "\ud589 \uadf8\ub8f9", +"Column group": "\uc5f4 \uadf8\ub8f9", +"Row type": "\ud589 \ud0c0\uc785", +"Header": "\ud5e4\ub354", +"Body": "\ubc14\ub514", +"Footer": "\ud478\ud130", +"Border color": "\ud14c\ub450\ub9ac \uc0c9", +"Insert template": "\ud15c\ud50c\ub9bf \uc0bd\uc785", +"Templates": "\ud15c\ud50c\ub9bf", +"Template": "\ud15c\ud50c\ub9bf", +"Text color": "\ubb38\uc790 \uc0c9\uae54", +"Background color": "\ubc30\uacbd\uc0c9", +"Custom...": "\uc9c1\uc811 \uc0c9\uae54 \uc9c0\uc815\ud558\uae30", +"Custom color": "\uc9c1\uc811 \uc9c0\uc815\ud55c \uc0c9\uae54", +"No color": "\uc0c9\uc0c1 \uc5c6\uc74c", +"Table of Contents": "\ubaa9\ucc28", +"Show blocks": "\ube14\ub7ed \ubcf4\uc5ec\uc8fc\uae30", +"Show invisible characters": "\uc548\ubcf4\uc774\ub294 \ubb38\uc790 \ubcf4\uc774\uae30", +"Words: {0}": "\ub2e8\uc5b4: {0}", +"{0} words": "{0} \ub2e8\uc5b4", +"File": "\ud30c\uc77c", +"Edit": "\uc218\uc815", +"Insert": "\uc0bd\uc785", +"View": "\ubcf4\uae30", +"Format": "\ud3ec\ub9f7", +"Table": "\ud14c\uc774\ube14", +"Tools": "\ub3c4\uad6c", +"Powered by {0}": "Powered by {0}", +"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\uc11c\uc2dd \uc788\ub294 \ud14d\uc2a4\ud2b8 \ud3b8\uc9d1\uae30 \uc785\ub2c8\ub2e4. ALT-F9\ub97c \ub204\ub974\uba74 \uba54\ub274, ALT-F10\ub97c \ub204\ub974\uba74 \ud234\ubc14, ALT-0\uc744 \ub204\ub974\uba74 \ub3c4\uc6c0\ub9d0\uc744 \ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4." +}); diff --git a/cps/static/js/libs/tinymce/langs/no.js b/cps/static/js/libs/tinymce/langs/no.js new file mode 100644 index 000000000..621fc6835 --- /dev/null +++ b/cps/static/js/libs/tinymce/langs/no.js @@ -0,0 +1,412 @@ +/*! + * TinyMCE Language Pack + * + * Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc. + * Licensed under the Tiny commercial license. See https://www.tiny.cloud/legal/ + */ +tinymce.addI18n('nb_NO', { +"Redo": "Gjør om", +"Undo": "Angre", +"Cut": "Klipp ut", +"Copy": "Kopier", +"Paste": "Lim inn", +"Select all": "Marker alt", +"New document": "Nytt dokument", +"Ok": "", +"Cancel": "Avbryt", +"Visual aids": "Visuelle hjelpemidler", +"Bold": "Fet", +"Italic": "Kursiv", +"Underline": "Understreking", +"Strikethrough": "Gjennomstreking", +"Superscript": "Hevet skrift", +"Subscript": "Senket skrift", +"Clear formatting": "Fjern formateringer", +"Remove": "", +"Align left": "Venstrejuster", +"Align center": "Midtstill", +"Align right": "Høyrejuster", +"No alignment": "", +"Justify": "Blokkjuster", +"Bullet list": "Punktliste", +"Numbered list": "Nummerliste", +"Decrease indent": "Reduser innrykk", +"Increase indent": "Øk innrykk", +"Close": "Lukk", +"Formats": "Stiler", +"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.": "Nettleseren din støtter ikke direkte tilgang til utklippsboken. Bruk istedet tastatursnarveiene Ctrl+X/C/V.", +"Headings": "Overskrifter", +"Heading 1": "Overskrift 1", +"Heading 2": "Overskrift 2", +"Heading 3": "Overskrift 3", +"Heading 4": "Overskrift 4", +"Heading 5": "Overskrift 5", +"Heading 6": "Overskrift 6", +"Preformatted": "Forhåndsformatert", +"Div": "", +"Pre": "", +"Code": "Kode", +"Paragraph": "Avsnitt", +"Blockquote": "", +"Inline": "Innkapslet", +"Blocks": "Blokker", +"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Lim inn er nå i ren tekst-modus. Kopiert innhold vil bli limt inn som ren tekst inntil du slår av dette valget.", +"Fonts": "Fonter", +"Font sizes": "", +"Class": "Klasse", +"Browse for an image": "Søk etter bilde", +"OR": "", +"Drop an image here": "Slipp et bilde her", +"Upload": "Last opp", +"Uploading image": "", +"Block": "Blokk", +"Align": "Juster", +"Default": "Standard", +"Circle": "Sirkel", +"Disc": "Disk", +"Square": "Firkant", +"Lower Alpha": "Små bokstaver", +"Lower Greek": "Greske minuskler", +"Lower Roman": "Små romertall", +"Upper Alpha": "Store bokstaver", +"Upper Roman": "Store romertall", +"Anchor...": "Lenke", +"Anchor": "", +"Name": "Navn", +"ID": "", +"ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "", +"You have unsaved changes are you sure you want to navigate away?": "Du har ikke arkivert endringene. Vil du fortsette uten å arkivere?", +"Restore last draft": "Gjenopprett siste utkast", +"Special character...": "Spesialtegn...", +"Special Character": "", +"Source code": "Kildekode", +"Insert/Edit code sample": "Sett inn / endre kodeeksempel", +"Language": "Språk", +"Code sample...": "Kodeeksempel", +"Left to right": "Venstre til høyre", +"Right to left": "Høyre til venstre", +"Title": "Tittel", +"Fullscreen": "Fullskjerm", +"Action": "Handling", +"Shortcut": "Snarvei", +"Help": "Hjelp", +"Address": "Adresse", +"Focus to menubar": "Fokus på menylinje", +"Focus to toolbar": "Fokus på verktøylinje", +"Focus to element path": "Fokus på elementsti", +"Focus to contextual toolbar": "Fokus på kontekstuell verktøylinje", +"Insert link (if link plugin activated)": "Sett inn lenke (dersom lenketillegg er aktivert)", +"Save (if save plugin activated)": "Lagre (dersom lagretillegg er aktivert)", +"Find (if searchreplace plugin activated)": "Finn (dersom tillegg for søk og erstatt er aktivert)", +"Plugins installed ({0}):": "Installerte tillegg ({0}):", +"Premium plugins:": "Premiumtillegg:", +"Learn more...": "Les mer ...", +"You are using {0}": "Du bruker {0}", +"Plugins": "Programtillegg", +"Handy Shortcuts": "Nyttige snarveier", +"Horizontal line": "Horisontal linje", +"Insert/edit image": "Sett inn / rediger bilde", +"Alternative description": "Alternativ beskrivelse", +"Accessibility": "Tilgjengelighet", +"Image is decorative": "Bilde er dekorasjon", +"Source": "Kilde", +"Dimensions": "Størrelser", +"Constrain proportions": "Begrens proporsjoner", +"General": "Generelt", +"Advanced": "Avansert", +"Style": "Stil", +"Vertical space": "Vertikal avstand", +"Horizontal space": "Horisontal avstand", +"Border": "Ramme", +"Insert image": "Sett inn bilde", +"Image...": "Bilde...", +"Image list": "Bildeliste", +"Resize": "Skaler", +"Insert date/time": "Sett inn dato/tid", +"Date/time": "Dato/tid", +"Insert/edit link": "Sett inn / rediger lenke", +"Text to display": "Tekst som skal vises", +"Url": "", +"Open link in...": "Åpne lenke i..", +"Current window": "Nåværende vindu", +"None": "Ingen", +"New window": "Nytt vindu", +"Open link": "Åpne lenke", +"Remove link": "Fjern lenke", +"Anchors": "Forankringspunkter", +"Link...": "Lenke...", +"Paste or type a link": "Lim inn eller skriv en lenke", +"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "Oppgitt URL ser ut til å være en e-postadresse. Ønsker du å sette inn påkrevet mailto: prefiks foran e-postadressen?", +"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": "URL du skrev inn ser ut som en ekstern adresse. Vil du legge til det obligatoriske prefikset http://?", +"The URL you entered seems to be an external link. Do you want to add the required https:// prefix?": "Nettadressen du fylte inn ser ut til å være en ekstern. Ønsker du å legge til påkrevd 'https://'-prefiks?", +"Link list": "Liste over lenker", +"Insert video": "Sett inn video", +"Insert/edit video": "Sett inn / rediger video", +"Insert/edit media": "Sett inn / endre media", +"Alternative source": "Alternativ kilde", +"Alternative source URL": "Alternativ kilde URL", +"Media poster (Image URL)": "Mediaposter (bilde-URL)", +"Paste your embed code below:": "Lim inn inkluderingskoden nedenfor:", +"Embed": "Inkluder", +"Media...": "Media..", +"Nonbreaking space": "Hardt mellomrom", +"Page break": "Sideskifte", +"Paste as text": "Lim inn som tekst", +"Preview": "Forhåndsvis", +"Print": "", +"Print...": "Skriv ut...", +"Save": "Lagre", +"Find": "Søk etter", +"Replace with": "Erstatt med", +"Replace": "Erstatt", +"Replace all": "Erstatt alle", +"Previous": "Forrige", +"Next": "Neste", +"Find and Replace": "Finn og erstatt", +"Find and replace...": "Finn og erstatt...", +"Could not find the specified string.": "Kunne ikke finne den spesifiserte teksten", +"Match case": "Skill mellom store / små bokstaver", +"Find whole words only": "Finn kun hele ord", +"Find in selection": "Finn i utvalg", +"Insert table": "Sett inn tabell", +"Table properties": "Tabellegenskaper", +"Delete table": "Slett tabell", +"Cell": "Celle", +"Row": "Rad", +"Column": "Kolonne", +"Cell properties": "Celleegenskaper", +"Merge cells": "Slå sammen celler", +"Split cell": "Splitt celle", +"Insert row before": "Sett inn rad før", +"Insert row after": "Sett inn rad etter", +"Delete row": "Slett rad", +"Row properties": "Radegenskaper", +"Cut row": "Klipp ut rad", +"Cut column": "", +"Copy row": "Kopier rad", +"Copy column": "", +"Paste row before": "Lim inn rad før", +"Paste column before": "", +"Paste row after": "Lim inn rad etter", +"Paste column after": "", +"Insert column before": "Sett inn kolonne før", +"Insert column after": "Sett inn kolonne etter", +"Delete column": "Slett kolonne", +"Cols": "Kolonner", +"Rows": "Rader", +"Width": "Bredde", +"Height": "Høyde", +"Cell spacing": "Celleavstand", +"Cell padding": "Cellemarg", +"Row clipboard actions": "", +"Column clipboard actions": "", +"Table styles": "", +"Cell styles": "", +"Column header": "", +"Row header": "", +"Table caption": "", +"Caption": "Bildetekst", +"Show caption": "Vis bildetekst", +"Left": "Venstre", +"Center": "Senter", +"Right": "Høyre", +"Cell type": "Celletype", +"Scope": "Omfang", +"Alignment": "Justering", +"Horizontal align": "", +"Vertical align": "", +"Top": "Topp", +"Middle": "Sentrert", +"Bottom": "Bunn", +"Header cell": "Overskriftscelle", +"Row group": "Radgruppe", +"Column group": "Kolonnegruppe", +"Row type": "Radtype", +"Header": "", +"Body": "Brødtekst", +"Footer": "Bunntekst", +"Border color": "Rammefarge", +"Solid": "", +"Dotted": "", +"Dashed": "", +"Double": "", +"Groove": "", +"Ridge": "", +"Inset": "", +"Outset": "", +"Hidden": "", +"Insert template...": "Sett inn mal..", +"Templates": "Maler", +"Template": "Mal", +"Insert Template": "", +"Text color": "Tekstfarge", +"Background color": "Bakgrunnsfarge", +"Custom...": "Tilpasset...", +"Custom color": "Tilpasset farge", +"No color": "Ingen farge", +"Remove color": "Fjern farge", +"Show blocks": "Vis blokker", +"Show invisible characters": "Vis skjulte tegn", +"Word count": "Ordtelling", +"Count": "Opptelling", +"Document": "Dokument", +"Selection": "Utvalg", +"Words": "Ord", +"Words: {0}": "Ord: {0}", +"{0} words": "{0} ord", +"File": "Fil", +"Edit": "Rediger", +"Insert": "Sett inn", +"View": "Vis", +"Format": "", +"Table": "Tabell", +"Tools": "Verktøy", +"Powered by {0}": "Drevet av {0}", +"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Tekstredigering. Tast ALT-F9 for meny. Tast ALT-F10 for verktøylinje. Tast ALT-0 for hjelp.", +"Image title": "Bildetittel", +"Border width": "Bordbredde", +"Border style": "Bordstil", +"Error": "Feil", +"Warn": "Advarsel", +"Valid": "Gyldig", +"To open the popup, press Shift+Enter": "For å åpne popup, trykk Shift+Enter", +"Rich Text Area": "", +"Rich Text Area. Press ALT-0 for help.": "Rik-tekstområde. Trykk ALT-0 for hjelp.", +"System Font": "Systemfont", +"Failed to upload image: {0}": "Opplasting av bilde feilet: {0}", +"Failed to load plugin: {0} from url {1}": "Kunne ikke laste tillegg: {0} from url {1}", +"Failed to load plugin url: {0}": "Kunne ikke laste tillegg url: {0}", +"Failed to initialize plugin: {0}": "Kunne ikke initialisere tillegg: {0}", +"example": "eksempel", +"Search": "Søk", +"All": "Alle", +"Currency": "Valuta", +"Text": "Tekst", +"Quotations": "Sitater", +"Mathematical": "Matematisk", +"Extended Latin": "Utvidet latin", +"Symbols": "Symboler", +"Arrows": "Piler", +"User Defined": "Brukerdefinert", +"dollar sign": "dollartegn", +"currency sign": "valutasymbol", +"euro-currency sign": "Euro-valutasymbol", +"colon sign": "kolon-symbol", +"cruzeiro sign": "cruzeiro-symbol", +"french franc sign": "franske franc-symbol", +"lira sign": "lire-symbol", +"mill sign": "mill-symbol", +"naira sign": "naira-symbol", +"peseta sign": "peseta-symbol", +"rupee sign": "rupee-symbol", +"won sign": "won-symbol", +"new sheqel sign": "Ny sheqel-symbol", +"dong sign": "dong-symbol", +"kip sign": "kip-symbol", +"tugrik sign": "tugrik-symbol", +"drachma sign": "drachma-symbol", +"german penny symbol": "tysk penny-symbol", +"peso sign": "peso-symbol", +"guarani sign": "quarani-symbol", +"austral sign": "austral-symbol", +"hryvnia sign": "hryvina-symbol", +"cedi sign": "credi-symbol", +"livre tournois sign": "livre tournois-symbol", +"spesmilo sign": "spesmilo-symbol", +"tenge sign": "tenge-symbol", +"indian rupee sign": "indisk rupee-symbol", +"turkish lira sign": "tyrkisk lire-symbol", +"nordic mark sign": "nordisk mark-symbol", +"manat sign": "manat-symbol", +"ruble sign": "ruble-symbol", +"yen character": "yen-symbol", +"yuan character": "yuan-symbol", +"yuan character, in hong kong and taiwan": "yuan-symbol, i Hongkong og Taiwan", +"yen/yuan character variant one": "yen/yuan-symbol variant en", +"Emojis": "", +"Emojis...": "", +"Loading emojis...": "", +"Could not load emojis": "", +"People": "Mennesker", +"Animals and Nature": "Dyr og natur", +"Food and Drink": "Mat og drikke", +"Activity": "Aktivitet", +"Travel and Places": "Reise og steder", +"Objects": "Objekter", +"Flags": "Flagg", +"Characters": "Tegn", +"Characters (no spaces)": "Tegn (uten mellomrom)", +"{0} characters": "{0} tegn", +"Error: Form submit field collision.": "Feil: Skjemafelt innsendingskollisjon.", +"Error: No form element found.": "Feil: Intet skjemafelt funnet.", +"Color swatch": "Fargepalett", +"Color Picker": "Fargevelger", +"Invalid hex color code: {0}": "", +"Invalid input": "", +"R": "", +"Red component": "", +"G": "", +"Green component": "", +"B": "", +"Blue component": "", +"#": "", +"Hex color code": "", +"Range 0 to 255": "", +"Turquoise": "Turkis", +"Green": "Grønn", +"Blue": "Blå", +"Purple": "Lilla", +"Navy Blue": "Marineblå", +"Dark Turquoise": "Mørk turkis", +"Dark Green": "Mørkegrønn", +"Medium Blue": "Mellomblå", +"Medium Purple": "Medium lilla", +"Midnight Blue": "Midnattblå", +"Yellow": "Gul", +"Orange": "Oransje", +"Red": "Rød", +"Light Gray": "Lys grå", +"Gray": "Grå", +"Dark Yellow": "Mørk gul", +"Dark Orange": "Mørk oransje", +"Dark Red": "Mørkerød", +"Medium Gray": "Medium grå", +"Dark Gray": "Mørk grå", +"Light Green": "Lys grønn", +"Light Yellow": "Lys gul", +"Light Red": "Lys rød", +"Light Purple": "Lys lilla", +"Light Blue": "Lys blå", +"Dark Purple": "Mørk lilla", +"Dark Blue": "Mørk blå", +"Black": "Svart", +"White": "Hvit", +"Switch to or from fullscreen mode": "Bytt til eller fra fullskjermmodus", +"Open help dialog": "Åpne hjelp-dialog", +"history": "historikk", +"styles": "stiler", +"formatting": "formatering", +"alignment": "justering", +"indentation": "innrykk", +"Font": "Skrift", +"Size": "Størrelse", +"More...": "Mer...", +"Select...": "Velg...", +"Preferences": "Innstillinger", +"Yes": "Ja", +"No": "Nei", +"Keyboard Navigation": "Navigering med tastaturet", +"Version": "Versjon", +"Code view": "Kodevisning", +"Open popup menu for split buttons": "Åpne sprettoppmeny for splitt-knapper", +"List Properties": "Listeegenskaper", +"List properties...": "Listeegenskaper ...", +"Start list at number": "Start liste på nummer", +"Line height": "Linjehøyde", +"Dropped file type is not supported": "", +"Loading...": "", +"ImageProxy HTTP error: Rejected request": "", +"ImageProxy HTTP error: Could not find Image Proxy": "", +"ImageProxy HTTP error: Incorrect Image Proxy URL": "", +"ImageProxy HTTP error: Unknown ImageProxy error": "" +}); \ No newline at end of file diff --git a/cps/static/js/libs/tinymce/langs/zh_Hans_CN.js b/cps/static/js/libs/tinymce/langs/zh_Hans_CN.js index 2a784f579..981c90909 100644 --- a/cps/static/js/libs/tinymce/langs/zh_Hans_CN.js +++ b/cps/static/js/libs/tinymce/langs/zh_Hans_CN.js @@ -1,4 +1,4 @@ -tinymce.addI18n('zh_CN',{ +tinymce.addI18n('zh_Hans_CN',{ "Redo": "\u91cd\u505a", "Undo": "\u64a4\u9500", "Cut": "\u526a\u5207", diff --git a/cps/static/js/libs/tinymce/langs/zh_Hant_TW.js b/cps/static/js/libs/tinymce/langs/zh_Hant_TW.js index 1987486c3..f6e7e2485 100644 --- a/cps/static/js/libs/tinymce/langs/zh_Hant_TW.js +++ b/cps/static/js/libs/tinymce/langs/zh_Hant_TW.js @@ -1,4 +1,4 @@ -tinymce.addI18n('zh_TW',{ +tinymce.addI18n('zh_Hant_TW',{ "Redo": "\u91cd\u505a", "Undo": "\u64a4\u92b7", "Cut": "\u526a\u4e0b", @@ -416,4 +416,4 @@ tinymce.addI18n('zh_TW',{ "Spellcheck": "\u62fc\u5b57\u6aa2\u67e5", "Caption": "\u8868\u683c\u6a19\u984c", "Insert template": "\u63d2\u5165\u6a23\u7248" -}); \ No newline at end of file +}); diff --git a/cps/static/js/libs/viewer.js b/cps/static/js/libs/viewer.js index 26fd0f82e..bd33b5a04 100644 --- a/cps/static/js/libs/viewer.js +++ b/cps/static/js/libs/viewer.js @@ -1,8 +1,8 @@ /** * @licstart The following is the entire license notice for the - * Javascript code in this page + * JavaScript code in this page * - * Copyright 2020 Mozilla Foundation + * Copyright 2022 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,3006 +17,49 @@ * limitations under the License. * * @licend The above is the entire license notice for the - * Javascript code in this page + * JavaScript code in this page */ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -; -let pdfjsWebApp, pdfjsWebAppOptions; -{ - pdfjsWebApp = __webpack_require__(1); - pdfjsWebAppOptions = __webpack_require__(3); -} -; -{ - __webpack_require__(35); -} -; -{ - __webpack_require__(40); -} - -function getViewerConfiguration() { - return { - appContainer: document.body, - mainContainer: document.getElementById("viewerContainer"), - viewerContainer: document.getElementById("viewer"), - eventBus: null, - toolbar: { - container: document.getElementById("toolbarViewer"), - numPages: document.getElementById("numPages"), - pageNumber: document.getElementById("pageNumber"), - scaleSelectContainer: document.getElementById("scaleSelectContainer"), - scaleSelect: document.getElementById("scaleSelect"), - customScaleOption: document.getElementById("customScaleOption"), - previous: document.getElementById("previous"), - next: document.getElementById("next"), - zoomIn: document.getElementById("zoomIn"), - zoomOut: document.getElementById("zoomOut"), - viewFind: document.getElementById("viewFind"), - openFile: document.getElementById("openFile"), - print: document.getElementById("print"), - presentationModeButton: document.getElementById("presentationMode"), - download: document.getElementById("download"), - viewBookmark: document.getElementById("viewBookmark") - }, - secondaryToolbar: { - toolbar: document.getElementById("secondaryToolbar"), - toggleButton: document.getElementById("secondaryToolbarToggle"), - toolbarButtonContainer: document.getElementById("secondaryToolbarButtonContainer"), - presentationModeButton: document.getElementById("secondaryPresentationMode"), - openFileButton: document.getElementById("secondaryOpenFile"), - printButton: document.getElementById("secondaryPrint"), - downloadButton: document.getElementById("secondaryDownload"), - viewBookmarkButton: document.getElementById("secondaryViewBookmark"), - firstPageButton: document.getElementById("firstPage"), - lastPageButton: document.getElementById("lastPage"), - pageRotateCwButton: document.getElementById("pageRotateCw"), - pageRotateCcwButton: document.getElementById("pageRotateCcw"), - cursorSelectToolButton: document.getElementById("cursorSelectTool"), - cursorHandToolButton: document.getElementById("cursorHandTool"), - scrollVerticalButton: document.getElementById("scrollVertical"), - scrollHorizontalButton: document.getElementById("scrollHorizontal"), - scrollWrappedButton: document.getElementById("scrollWrapped"), - spreadNoneButton: document.getElementById("spreadNone"), - spreadOddButton: document.getElementById("spreadOdd"), - spreadEvenButton: document.getElementById("spreadEven"), - documentPropertiesButton: document.getElementById("documentProperties") - }, - fullscreen: { - contextFirstPage: document.getElementById("contextFirstPage"), - contextLastPage: document.getElementById("contextLastPage"), - contextPageRotateCw: document.getElementById("contextPageRotateCw"), - contextPageRotateCcw: document.getElementById("contextPageRotateCcw") - }, - sidebar: { - outerContainer: document.getElementById("outerContainer"), - viewerContainer: document.getElementById("viewerContainer"), - toggleButton: document.getElementById("sidebarToggle"), - thumbnailButton: document.getElementById("viewThumbnail"), - outlineButton: document.getElementById("viewOutline"), - attachmentsButton: document.getElementById("viewAttachments"), - layersButton: document.getElementById("viewLayers"), - thumbnailView: document.getElementById("thumbnailView"), - outlineView: document.getElementById("outlineView"), - attachmentsView: document.getElementById("attachmentsView"), - layersView: document.getElementById("layersView") - }, - sidebarResizer: { - outerContainer: document.getElementById("outerContainer"), - resizer: document.getElementById("sidebarResizer") - }, - findBar: { - bar: document.getElementById("findbar"), - toggleButton: document.getElementById("viewFind"), - findField: document.getElementById("findInput"), - highlightAllCheckbox: document.getElementById("findHighlightAll"), - caseSensitiveCheckbox: document.getElementById("findMatchCase"), - entireWordCheckbox: document.getElementById("findEntireWord"), - findMsg: document.getElementById("findMsg"), - findResultsCount: document.getElementById("findResultsCount"), - findPreviousButton: document.getElementById("findPrevious"), - findNextButton: document.getElementById("findNext") - }, - passwordOverlay: { - overlayName: "passwordOverlay", - container: document.getElementById("passwordOverlay"), - label: document.getElementById("passwordText"), - input: document.getElementById("password"), - submitButton: document.getElementById("passwordSubmit"), - cancelButton: document.getElementById("passwordCancel") - }, - documentProperties: { - overlayName: "documentPropertiesOverlay", - container: document.getElementById("documentPropertiesOverlay"), - closeButton: document.getElementById("documentPropertiesClose"), - fields: { - fileName: document.getElementById("fileNameField"), - fileSize: document.getElementById("fileSizeField"), - title: document.getElementById("titleField"), - author: document.getElementById("authorField"), - subject: document.getElementById("subjectField"), - keywords: document.getElementById("keywordsField"), - creationDate: document.getElementById("creationDateField"), - modificationDate: document.getElementById("modificationDateField"), - creator: document.getElementById("creatorField"), - producer: document.getElementById("producerField"), - version: document.getElementById("versionField"), - pageCount: document.getElementById("pageCountField"), - pageSize: document.getElementById("pageSizeField"), - linearized: document.getElementById("linearizedField") - } - }, - errorWrapper: { - container: document.getElementById("errorWrapper"), - errorMessage: document.getElementById("errorMessage"), - closeButton: document.getElementById("errorClose"), - errorMoreInfo: document.getElementById("errorMoreInfo"), - moreInfoButton: document.getElementById("errorShowMore"), - lessInfoButton: document.getElementById("errorShowLess") - }, - printContainer: document.getElementById("printContainer"), - openFileInputName: "fileInput", - debuggerScriptPath: "./debugger.js" - }; -} - -function webViewerLoad() { - const config = getViewerConfiguration(); - window.PDFViewerApplication = pdfjsWebApp.PDFViewerApplication; - window.PDFViewerApplicationOptions = pdfjsWebAppOptions.AppOptions; - const event = document.createEvent("CustomEvent"); - event.initCustomEvent("webviewerloaded", true, true, { - source: window - }); - - try { - parent.document.dispatchEvent(event); - } catch (ex) { - console.error(`webviewerloaded: ${ex}`); - document.dispatchEvent(event); - } - - pdfjsWebApp.PDFViewerApplication.run(config); -} - -if (document.readyState === "interactive" || document.readyState === "complete") { - webViewerLoad(); -} else { - document.addEventListener("DOMContentLoaded", webViewerLoad, true); -} - -/***/ }), +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ([ +/* 0 */, /* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.PDFPrintServiceFactory = exports.DefaultExternalServices = exports.PDFViewerApplication = void 0; - -var _ui_utils = __webpack_require__(2); - -var _app_options = __webpack_require__(3); - -var _pdfjsLib = __webpack_require__(5); - -var _pdf_cursor_tools = __webpack_require__(6); - -var _pdf_rendering_queue = __webpack_require__(8); - -var _pdf_sidebar = __webpack_require__(9); - -var _overlay_manager = __webpack_require__(10); - -var _password_prompt = __webpack_require__(11); - -var _pdf_attachment_viewer = __webpack_require__(12); - -var _pdf_document_properties = __webpack_require__(14); - -var _pdf_find_bar = __webpack_require__(15); - -var _pdf_find_controller = __webpack_require__(16); - -var _pdf_history = __webpack_require__(18); - -var _pdf_layer_viewer = __webpack_require__(19); - -var _pdf_link_service = __webpack_require__(20); - -var _pdf_outline_viewer = __webpack_require__(21); - -var _pdf_presentation_mode = __webpack_require__(22); - -var _pdf_sidebar_resizer = __webpack_require__(23); - -var _pdf_thumbnail_viewer = __webpack_require__(24); - -var _pdf_viewer = __webpack_require__(26); - -var _secondary_toolbar = __webpack_require__(31); - -var _toolbar = __webpack_require__(33); - -var _viewer_compatibility = __webpack_require__(4); - -var _view_history = __webpack_require__(34); - -const DEFAULT_SCALE_DELTA = 1.1; -const DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; -const FORCE_PAGES_LOADED_TIMEOUT = 10000; -const WHEEL_ZOOM_DISABLED_TIMEOUT = 1000; -const ENABLE_PERMISSIONS_CLASS = "enablePermissions"; -const ViewOnLoad = { - UNKNOWN: -1, - PREVIOUS: 0, - INITIAL: 1 -}; -const KNOWN_VERSIONS = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3"]; -const KNOWN_GENERATORS = ["acrobat distiller", "acrobat pdfwriter", "adobe livecycle", "adobe pdf library", "adobe photoshop", "ghostscript", "tcpdf", "cairo", "dvipdfm", "dvips", "pdftex", "pdfkit", "itext", "prince", "quarkxpress", "mac os x", "microsoft", "openoffice", "oracle", "luradocument", "pdf-xchange", "antenna house", "aspose.cells", "fpdf"]; - -class DefaultExternalServices { - constructor() { - throw new Error("Cannot initialize DefaultExternalServices."); - } - - static updateFindControlState(data) {} - - static updateFindMatchesCount(data) {} - - static initPassiveLoading(callbacks) {} - - static fallback(data, callback) {} - - static reportTelemetry(data) {} - - static createDownloadManager(options) { - throw new Error("Not implemented: createDownloadManager"); - } - - static createPreferences() { - throw new Error("Not implemented: createPreferences"); - } - - static createL10n(options) { - throw new Error("Not implemented: createL10n"); - } - - static get supportsIntegratedFind() { - return (0, _pdfjsLib.shadow)(this, "supportsIntegratedFind", false); - } - - static get supportsDocumentFonts() { - return (0, _pdfjsLib.shadow)(this, "supportsDocumentFonts", true); - } - - static get supportedMouseWheelZoomModifierKeys() { - return (0, _pdfjsLib.shadow)(this, "supportedMouseWheelZoomModifierKeys", { - ctrlKey: true, - metaKey: true - }); - } - - static get isInAutomation() { - return (0, _pdfjsLib.shadow)(this, "isInAutomation", false); - } - -} - -exports.DefaultExternalServices = DefaultExternalServices; -const PDFViewerApplication = { - initialBookmark: document.location.hash.substring(1), - _initializedCapability: (0, _pdfjsLib.createPromiseCapability)(), - fellback: false, - appConfig: null, - pdfDocument: null, - pdfLoadingTask: null, - printService: null, - pdfViewer: null, - pdfThumbnailViewer: null, - pdfRenderingQueue: null, - pdfPresentationMode: null, - pdfDocumentProperties: null, - pdfLinkService: null, - pdfHistory: null, - pdfSidebar: null, - pdfSidebarResizer: null, - pdfOutlineViewer: null, - pdfAttachmentViewer: null, - pdfLayerViewer: null, - pdfCursorTools: null, - store: null, - downloadManager: null, - overlayManager: null, - preferences: null, - toolbar: null, - secondaryToolbar: null, - eventBus: null, - l10n: null, - isInitialViewSet: false, - downloadComplete: false, - isViewerEmbedded: window.parent !== window, - url: "", - baseUrl: "", - externalServices: DefaultExternalServices, - _boundEvents: {}, - contentDispositionFilename: null, - triggerDelayedFallback: null, - _saveInProgress: false, - _wheelUnusedTicks: 0, - - async initialize(appConfig) { - this.preferences = this.externalServices.createPreferences(); - this.appConfig = appConfig; - await this._readPreferences(); - await this._parseHashParameters(); - await this._initializeL10n(); - - if (this.isViewerEmbedded && _app_options.AppOptions.get("externalLinkTarget") === _pdfjsLib.LinkTarget.NONE) { - _app_options.AppOptions.set("externalLinkTarget", _pdfjsLib.LinkTarget.TOP); - } - - await this._initializeViewerComponents(); - this.bindEvents(); - this.bindWindowEvents(); - const appContainer = appConfig.appContainer || document.documentElement; - this.l10n.translate(appContainer).then(() => { - this.eventBus.dispatch("localized", { - source: this - }); - }); - - this._initializedCapability.resolve(); - }, - - async _readPreferences() { - if (_app_options.AppOptions.get("disablePreferences")) { - return; - } - - try { - const prefs = await this.preferences.getAll(); - - for (const name in prefs) { - _app_options.AppOptions.set(name, prefs[name]); - } - } catch (reason) { - console.error(`_readPreferences: "${reason.message}".`); - } - }, - - async _parseHashParameters() { - if (!_app_options.AppOptions.get("pdfBugEnabled")) { - return undefined; - } - - const hash = document.location.hash.substring(1); - - if (!hash) { - return undefined; - } - - const hashParams = (0, _ui_utils.parseQueryString)(hash), - waitOn = []; - - if ("disableworker" in hashParams && hashParams.disableworker === "true") { - waitOn.push(loadFakeWorker()); - } - - if ("disablerange" in hashParams) { - _app_options.AppOptions.set("disableRange", hashParams.disablerange === "true"); - } - - if ("disablestream" in hashParams) { - _app_options.AppOptions.set("disableStream", hashParams.disablestream === "true"); - } - - if ("disableautofetch" in hashParams) { - _app_options.AppOptions.set("disableAutoFetch", hashParams.disableautofetch === "true"); - } - - if ("disablefontface" in hashParams) { - _app_options.AppOptions.set("disableFontFace", hashParams.disablefontface === "true"); - } - - if ("disablehistory" in hashParams) { - _app_options.AppOptions.set("disableHistory", hashParams.disablehistory === "true"); - } - - if ("webgl" in hashParams) { - _app_options.AppOptions.set("enableWebGL", hashParams.webgl === "true"); - } - - if ("verbosity" in hashParams) { - _app_options.AppOptions.set("verbosity", hashParams.verbosity | 0); - } - - if ("textlayer" in hashParams) { - switch (hashParams.textlayer) { - case "off": - _app_options.AppOptions.set("textLayerMode", _ui_utils.TextLayerMode.DISABLE); - - break; - - case "visible": - case "shadow": - case "hover": - const viewer = this.appConfig.viewerContainer; - viewer.classList.add("textLayer-" + hashParams.textlayer); - break; - } - } - - if ("pdfbug" in hashParams) { - _app_options.AppOptions.set("pdfBug", true); - - _app_options.AppOptions.set("fontExtraProperties", true); - - const enabled = hashParams.pdfbug.split(","); - waitOn.push(loadAndEnablePDFBug(enabled)); - } - - if ("locale" in hashParams) { - _app_options.AppOptions.set("locale", hashParams.locale); - } - - return Promise.all(waitOn).catch(reason => { - console.error(`_parseHashParameters: "${reason.message}".`); - }); - }, - - async _initializeL10n() { - this.l10n = this.externalServices.createL10n({ - locale: _app_options.AppOptions.get("locale") - }); - const dir = await this.l10n.getDirection(); - document.getElementsByTagName("html")[0].dir = dir; - }, - - async _initializeViewerComponents() { - const appConfig = this.appConfig; - const eventBus = appConfig.eventBus || new _ui_utils.EventBus({ - isInAutomation: this.externalServices.isInAutomation - }); - this.eventBus = eventBus; - this.overlayManager = new _overlay_manager.OverlayManager(); - const pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); - pdfRenderingQueue.onIdle = this.cleanup.bind(this); - this.pdfRenderingQueue = pdfRenderingQueue; - const pdfLinkService = new _pdf_link_service.PDFLinkService({ - eventBus, - externalLinkTarget: _app_options.AppOptions.get("externalLinkTarget"), - externalLinkRel: _app_options.AppOptions.get("externalLinkRel"), - ignoreDestinationZoom: _app_options.AppOptions.get("ignoreDestinationZoom") - }); - this.pdfLinkService = pdfLinkService; - const downloadManager = this.externalServices.createDownloadManager(); - this.downloadManager = downloadManager; - const findController = new _pdf_find_controller.PDFFindController({ - linkService: pdfLinkService, - eventBus - }); - this.findController = findController; - const container = appConfig.mainContainer; - const viewer = appConfig.viewerContainer; - this.pdfViewer = new _pdf_viewer.PDFViewer({ - container, - viewer, - eventBus, - renderingQueue: pdfRenderingQueue, - linkService: pdfLinkService, - downloadManager, - findController, - renderer: _app_options.AppOptions.get("renderer"), - enableWebGL: _app_options.AppOptions.get("enableWebGL"), - l10n: this.l10n, - textLayerMode: _app_options.AppOptions.get("textLayerMode"), - imageResourcesPath: _app_options.AppOptions.get("imageResourcesPath"), - renderInteractiveForms: _app_options.AppOptions.get("renderInteractiveForms"), - enablePrintAutoRotate: _app_options.AppOptions.get("enablePrintAutoRotate"), - useOnlyCssZoom: _app_options.AppOptions.get("useOnlyCssZoom"), - maxCanvasPixels: _app_options.AppOptions.get("maxCanvasPixels") - }); - pdfRenderingQueue.setViewer(this.pdfViewer); - pdfLinkService.setViewer(this.pdfViewer); - this.pdfThumbnailViewer = new _pdf_thumbnail_viewer.PDFThumbnailViewer({ - container: appConfig.sidebar.thumbnailView, - eventBus, - renderingQueue: pdfRenderingQueue, - linkService: pdfLinkService, - l10n: this.l10n - }); - pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer); - this.pdfHistory = new _pdf_history.PDFHistory({ - linkService: pdfLinkService, - eventBus - }); - pdfLinkService.setHistory(this.pdfHistory); - - if (!this.supportsIntegratedFind) { - this.findBar = new _pdf_find_bar.PDFFindBar(appConfig.findBar, eventBus, this.l10n); - } - - this.pdfDocumentProperties = new _pdf_document_properties.PDFDocumentProperties(appConfig.documentProperties, this.overlayManager, eventBus, this.l10n); - this.pdfCursorTools = new _pdf_cursor_tools.PDFCursorTools({ - container, - eventBus, - cursorToolOnLoad: _app_options.AppOptions.get("cursorToolOnLoad") - }); - this.toolbar = new _toolbar.Toolbar(appConfig.toolbar, eventBus, this.l10n); - this.secondaryToolbar = new _secondary_toolbar.SecondaryToolbar(appConfig.secondaryToolbar, container, eventBus); - - if (this.supportsFullscreen) { - this.pdfPresentationMode = new _pdf_presentation_mode.PDFPresentationMode({ - container, - pdfViewer: this.pdfViewer, - eventBus, - contextMenuItems: appConfig.fullscreen - }); - } - - this.passwordPrompt = new _password_prompt.PasswordPrompt(appConfig.passwordOverlay, this.overlayManager, this.l10n); - this.pdfOutlineViewer = new _pdf_outline_viewer.PDFOutlineViewer({ - container: appConfig.sidebar.outlineView, - eventBus, - linkService: pdfLinkService - }); - this.pdfAttachmentViewer = new _pdf_attachment_viewer.PDFAttachmentViewer({ - container: appConfig.sidebar.attachmentsView, - eventBus, - downloadManager - }); - this.pdfLayerViewer = new _pdf_layer_viewer.PDFLayerViewer({ - container: appConfig.sidebar.layersView, - eventBus, - l10n: this.l10n - }); - this.pdfSidebar = new _pdf_sidebar.PDFSidebar({ - elements: appConfig.sidebar, - pdfViewer: this.pdfViewer, - pdfThumbnailViewer: this.pdfThumbnailViewer, - eventBus, - l10n: this.l10n - }); - this.pdfSidebar.onToggled = this.forceRendering.bind(this); - this.pdfSidebarResizer = new _pdf_sidebar_resizer.PDFSidebarResizer(appConfig.sidebarResizer, eventBus, this.l10n); - }, - - run(config) { - this.initialize(config).then(webViewerInitialized); - }, - - get initialized() { - return this._initializedCapability.settled; - }, - - get initializedPromise() { - return this._initializedCapability.promise; - }, - - zoomIn(ticks) { - if (this.pdfViewer.isInPresentationMode) { - return; - } - - let newScale = this.pdfViewer.currentScale; - - do { - newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2); - newScale = Math.ceil(newScale * 10) / 10; - newScale = Math.min(_ui_utils.MAX_SCALE, newScale); - } while (--ticks > 0 && newScale < _ui_utils.MAX_SCALE); - - this.pdfViewer.currentScaleValue = newScale; - }, - - zoomOut(ticks) { - if (this.pdfViewer.isInPresentationMode) { - return; - } - - let newScale = this.pdfViewer.currentScale; - - do { - newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2); - newScale = Math.floor(newScale * 10) / 10; - newScale = Math.max(_ui_utils.MIN_SCALE, newScale); - } while (--ticks > 0 && newScale > _ui_utils.MIN_SCALE); - - this.pdfViewer.currentScaleValue = newScale; - }, - - zoomReset() { - if (this.pdfViewer.isInPresentationMode) { - return; - } - - this.pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; - }, - - get pagesCount() { - return this.pdfDocument ? this.pdfDocument.numPages : 0; - }, - - get page() { - return this.pdfViewer.currentPageNumber; - }, - - set page(val) { - this.pdfViewer.currentPageNumber = val; - }, - - get printing() { - return !!this.printService; - }, - - get supportsPrinting() { - return PDFPrintServiceFactory.instance.supportsPrinting; - }, - - get supportsFullscreen() { - let support; - const doc = document.documentElement; - support = !!(doc.requestFullscreen || doc.mozRequestFullScreen || doc.webkitRequestFullScreen || doc.msRequestFullscreen); - - if (document.fullscreenEnabled === false || document.mozFullScreenEnabled === false || document.webkitFullscreenEnabled === false || document.msFullscreenEnabled === false) { - support = false; - } - - return (0, _pdfjsLib.shadow)(this, "supportsFullscreen", support); - }, - - get supportsIntegratedFind() { - return this.externalServices.supportsIntegratedFind; - }, - - get supportsDocumentFonts() { - return this.externalServices.supportsDocumentFonts; - }, - - get loadingBar() { - const bar = new _ui_utils.ProgressBar("#loadingBar"); - return (0, _pdfjsLib.shadow)(this, "loadingBar", bar); - }, - - get supportedMouseWheelZoomModifierKeys() { - return this.externalServices.supportedMouseWheelZoomModifierKeys; - }, - - initPassiveLoading() { - throw new Error("Not implemented: initPassiveLoading"); - }, - - setTitleUsingUrl(url = "") { - this.url = url; - this.baseUrl = url.split("#")[0]; - let title = (0, _ui_utils.getPDFFileNameFromURL)(url, ""); - - if (!title) { - try { - title = decodeURIComponent((0, _pdfjsLib.getFilenameFromUrl)(url)) || url; - } catch (ex) { - title = url; - } - } - - this.setTitle(title); - }, - - setTitle(title) { - if (this.isViewerEmbedded) { - return; - } - - document.title = title; - }, - - async close() { - const errorWrapper = this.appConfig.errorWrapper.container; - errorWrapper.setAttribute("hidden", "true"); - - if (!this.pdfLoadingTask) { - return undefined; - } - - const promise = this.pdfLoadingTask.destroy(); - this.pdfLoadingTask = null; - - if (this.pdfDocument) { - this.pdfDocument = null; - this.pdfThumbnailViewer.setDocument(null); - this.pdfViewer.setDocument(null); - this.pdfLinkService.setDocument(null); - this.pdfDocumentProperties.setDocument(null); - } - - webViewerResetPermissions(); - this.store = null; - this.isInitialViewSet = false; - this.downloadComplete = false; - this.url = ""; - this.baseUrl = ""; - this.contentDispositionFilename = null; - this.triggerDelayedFallback = null; - this._saveInProgress = false; - this.pdfSidebar.reset(); - this.pdfOutlineViewer.reset(); - this.pdfAttachmentViewer.reset(); - this.pdfLayerViewer.reset(); - - if (this.pdfHistory) { - this.pdfHistory.reset(); - } - - if (this.findBar) { - this.findBar.reset(); - } - - this.toolbar.reset(); - this.secondaryToolbar.reset(); - - if (typeof PDFBug !== "undefined") { - PDFBug.cleanup(); - } - - return promise; - }, - - async open(file, args) { - if (this.pdfLoadingTask) { - await this.close(); - } - - const workerParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.WORKER); - - for (const key in workerParameters) { - _pdfjsLib.GlobalWorkerOptions[key] = workerParameters[key]; - } - - const parameters = Object.create(null); - - if (typeof file === "string") { - this.setTitleUsingUrl(file); - parameters.url = file; - } else if (file && "byteLength" in file) { - parameters.data = file; - } else if (file.url && file.originalUrl) { - this.setTitleUsingUrl(file.originalUrl); - parameters.url = file.url; - } - - const apiParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.API); - - for (const key in apiParameters) { - let value = apiParameters[key]; - - if (key === "docBaseUrl" && !value) {} - - parameters[key] = value; - } - - if (args) { - for (const key in args) { - const value = args[key]; - - if (key === "length") { - this.pdfDocumentProperties.setFileSize(value); - } - - parameters[key] = value; - } - } - - const loadingTask = (0, _pdfjsLib.getDocument)(parameters); - this.pdfLoadingTask = loadingTask; - - loadingTask.onPassword = (updateCallback, reason) => { - this.pdfLinkService.externalLinkEnabled = false; - this.passwordPrompt.setUpdateCallback(updateCallback, reason); - this.passwordPrompt.open(); - }; - - loadingTask.onProgress = ({ - loaded, - total - }) => { - this.progress(loaded / total); - }; - - loadingTask.onUnsupportedFeature = this.fallback.bind(this); - return loadingTask.promise.then(pdfDocument => { - this.load(pdfDocument); - }, exception => { - if (loadingTask !== this.pdfLoadingTask) { - return undefined; - } - - const message = exception && exception.message; - let loadingErrorMessage; - - if (exception instanceof _pdfjsLib.InvalidPDFException) { - loadingErrorMessage = this.l10n.get("invalid_file_error", null, "Invalid or corrupted PDF file."); - } else if (exception instanceof _pdfjsLib.MissingPDFException) { - loadingErrorMessage = this.l10n.get("missing_file_error", null, "Missing PDF file."); - } else if (exception instanceof _pdfjsLib.UnexpectedResponseException) { - loadingErrorMessage = this.l10n.get("unexpected_response_error", null, "Unexpected server response."); - } else { - loadingErrorMessage = this.l10n.get("loading_error", null, "An error occurred while loading the PDF."); - } - - return loadingErrorMessage.then(msg => { - this.error(msg, { - message - }); - throw exception; - }); - }); - }, - - download({ - sourceEventType = "download" - } = {}) { - function downloadByUrl() { - downloadManager.downloadUrl(url, filename); - } - - const url = this.baseUrl; - const filename = this.contentDispositionFilename || (0, _ui_utils.getPDFFileNameFromURL)(this.url); - const downloadManager = this.downloadManager; - - downloadManager.onerror = err => { - this.error(`PDF failed to download: ${err}`); - }; - - if (!this.pdfDocument || !this.downloadComplete) { - downloadByUrl(); - return; - } - - this.pdfDocument.getData().then(function (data) { - const blob = new Blob([data], { - type: "application/pdf" - }); - downloadManager.download(blob, url, filename, sourceEventType); - }).catch(downloadByUrl); - }, - - save({ - sourceEventType = "download" - } = {}) { - if (this._saveInProgress) { - return; - } - - const url = this.baseUrl; - const filename = this.contentDispositionFilename || (0, _ui_utils.getPDFFileNameFromURL)(this.url); - const downloadManager = this.downloadManager; - - downloadManager.onerror = err => { - this.error(`PDF failed to be saved: ${err}`); - }; - - if (!this.pdfDocument || !this.downloadComplete) { - this.download({ - sourceEventType - }); - return; - } - - this._saveInProgress = true; - this.pdfDocument.saveDocument(this.pdfDocument.annotationStorage).then(data => { - const blob = new Blob([data], { - type: "application/pdf" - }); - downloadManager.download(blob, url, filename, sourceEventType); - }).catch(() => { - this.download({ - sourceEventType - }); - }).finally(() => { - this._saveInProgress = false; - }); - }, - - _delayedFallback(featureId) { - this.externalServices.reportTelemetry({ - type: "unsupportedFeature", - featureId - }); - - if (!this.triggerDelayedFallback) { - this.triggerDelayedFallback = () => { - this.fallback(featureId); - this.triggerDelayedFallback = null; - }; - } - }, - - fallback(featureId) { - this.externalServices.reportTelemetry({ - type: "unsupportedFeature", - featureId - }); - - if (this.fellback) { - return; - } - - this.fellback = true; - this.externalServices.fallback({ - featureId, - url: this.baseUrl - }, function response(download) { - if (!download) { - return; - } - - PDFViewerApplication.download({ - sourceEventType: "download" - }); - }); - }, - - error(message, moreInfo) { - const moreInfoText = [this.l10n.get("error_version_info", { - version: _pdfjsLib.version || "?", - build: _pdfjsLib.build || "?" - }, "PDF.js v{{version}} (build: {{build}})")]; - - if (moreInfo) { - moreInfoText.push(this.l10n.get("error_message", { - message: moreInfo.message - }, "Message: {{message}}")); - - if (moreInfo.stack) { - moreInfoText.push(this.l10n.get("error_stack", { - stack: moreInfo.stack - }, "Stack: {{stack}}")); - } else { - if (moreInfo.filename) { - moreInfoText.push(this.l10n.get("error_file", { - file: moreInfo.filename - }, "File: {{file}}")); - } - - if (moreInfo.lineNumber) { - moreInfoText.push(this.l10n.get("error_line", { - line: moreInfo.lineNumber - }, "Line: {{line}}")); - } - } - } - - const errorWrapperConfig = this.appConfig.errorWrapper; - const errorWrapper = errorWrapperConfig.container; - errorWrapper.removeAttribute("hidden"); - const errorMessage = errorWrapperConfig.errorMessage; - errorMessage.textContent = message; - const closeButton = errorWrapperConfig.closeButton; - - closeButton.onclick = function () { - errorWrapper.setAttribute("hidden", "true"); - }; - - const errorMoreInfo = errorWrapperConfig.errorMoreInfo; - const moreInfoButton = errorWrapperConfig.moreInfoButton; - const lessInfoButton = errorWrapperConfig.lessInfoButton; - - moreInfoButton.onclick = function () { - errorMoreInfo.removeAttribute("hidden"); - moreInfoButton.setAttribute("hidden", "true"); - lessInfoButton.removeAttribute("hidden"); - errorMoreInfo.style.height = errorMoreInfo.scrollHeight + "px"; - }; - - lessInfoButton.onclick = function () { - errorMoreInfo.setAttribute("hidden", "true"); - moreInfoButton.removeAttribute("hidden"); - lessInfoButton.setAttribute("hidden", "true"); - }; - - moreInfoButton.oncontextmenu = _ui_utils.noContextMenuHandler; - lessInfoButton.oncontextmenu = _ui_utils.noContextMenuHandler; - closeButton.oncontextmenu = _ui_utils.noContextMenuHandler; - moreInfoButton.removeAttribute("hidden"); - lessInfoButton.setAttribute("hidden", "true"); - Promise.all(moreInfoText).then(parts => { - errorMoreInfo.value = parts.join("\n"); - }); - }, - - progress(level) { - if (this.downloadComplete) { - return; - } - - const percent = Math.round(level * 100); - - if (percent > this.loadingBar.percent || isNaN(percent)) { - this.loadingBar.percent = percent; - const disableAutoFetch = this.pdfDocument ? this.pdfDocument.loadingParams.disableAutoFetch : _app_options.AppOptions.get("disableAutoFetch"); - - if (disableAutoFetch && percent) { - if (this.disableAutoFetchLoadingBarTimeout) { - clearTimeout(this.disableAutoFetchLoadingBarTimeout); - this.disableAutoFetchLoadingBarTimeout = null; - } - - this.loadingBar.show(); - this.disableAutoFetchLoadingBarTimeout = setTimeout(() => { - this.loadingBar.hide(); - this.disableAutoFetchLoadingBarTimeout = null; - }, DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT); - } - } - }, - - load(pdfDocument) { - this.pdfDocument = pdfDocument; - pdfDocument.getDownloadInfo().then(() => { - this.downloadComplete = true; - this.loadingBar.hide(); - firstPagePromise.then(() => { - this.eventBus.dispatch("documentloaded", { - source: this - }); - }); - }); - const pageLayoutPromise = pdfDocument.getPageLayout().catch(function () {}); - const pageModePromise = pdfDocument.getPageMode().catch(function () {}); - const openActionPromise = pdfDocument.getOpenAction().catch(function () {}); - this.toolbar.setPagesCount(pdfDocument.numPages, false); - this.secondaryToolbar.setPagesCount(pdfDocument.numPages); - let baseDocumentUrl; - baseDocumentUrl = null; - this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl); - this.pdfDocumentProperties.setDocument(pdfDocument, this.url); - const annotationStorage = pdfDocument.annotationStorage; - - annotationStorage.onSetModified = function () { - window.addEventListener("beforeunload", beforeUnload); - }; - - annotationStorage.onResetModified = function () { - window.removeEventListener("beforeunload", beforeUnload); - }; - - const pdfViewer = this.pdfViewer; - pdfViewer.setDocument(pdfDocument); - const { - firstPagePromise, - onePageRendered, - pagesPromise - } = pdfViewer; - const pdfThumbnailViewer = this.pdfThumbnailViewer; - pdfThumbnailViewer.setDocument(pdfDocument); - const storedPromise = (this.store = new _view_history.ViewHistory(pdfDocument.fingerprint)).getMultiple({ - page: null, - zoom: _ui_utils.DEFAULT_SCALE_VALUE, - scrollLeft: "0", - scrollTop: "0", - rotation: null, - sidebarView: _pdf_sidebar.SidebarView.UNKNOWN, - scrollMode: _ui_utils.ScrollMode.UNKNOWN, - spreadMode: _ui_utils.SpreadMode.UNKNOWN - }).catch(() => { - return Object.create(null); - }); - firstPagePromise.then(pdfPage => { - this.loadingBar.setWidth(this.appConfig.viewerContainer); - Promise.all([_ui_utils.animationStarted, storedPromise, pageLayoutPromise, pageModePromise, openActionPromise]).then(async ([timeStamp, stored, pageLayout, pageMode, openAction]) => { - const viewOnLoad = _app_options.AppOptions.get("viewOnLoad"); - - this._initializePdfHistory({ - fingerprint: pdfDocument.fingerprint, - viewOnLoad, - initialDest: openAction && openAction.dest - }); - - const initialBookmark = this.initialBookmark; - - const zoom = _app_options.AppOptions.get("defaultZoomValue"); - - let hash = zoom ? `zoom=${zoom}` : null; - let rotation = null; - - let sidebarView = _app_options.AppOptions.get("sidebarViewOnLoad"); - - let scrollMode = _app_options.AppOptions.get("scrollModeOnLoad"); - - let spreadMode = _app_options.AppOptions.get("spreadModeOnLoad"); - - if (stored.page && viewOnLoad !== ViewOnLoad.INITIAL) { - hash = `page=${stored.page}&zoom=${zoom || stored.zoom},` + `${stored.scrollLeft},${stored.scrollTop}`; - rotation = parseInt(stored.rotation, 10); - - if (sidebarView === _pdf_sidebar.SidebarView.UNKNOWN) { - sidebarView = stored.sidebarView | 0; - } - - if (scrollMode === _ui_utils.ScrollMode.UNKNOWN) { - scrollMode = stored.scrollMode | 0; - } - - if (spreadMode === _ui_utils.SpreadMode.UNKNOWN) { - spreadMode = stored.spreadMode | 0; - } - } - - if (pageMode && sidebarView === _pdf_sidebar.SidebarView.UNKNOWN) { - sidebarView = apiPageModeToSidebarView(pageMode); - } - - if (pageLayout && spreadMode === _ui_utils.SpreadMode.UNKNOWN) { - spreadMode = apiPageLayoutToSpreadMode(pageLayout); - } - - this.setInitialView(hash, { - rotation, - sidebarView, - scrollMode, - spreadMode - }); - this.eventBus.dispatch("documentinit", { - source: this - }); - - if (!this.isViewerEmbedded) { - pdfViewer.focus(); - } - - this._initializePermissions(pdfDocument); - - await Promise.race([pagesPromise, new Promise(resolve => { - setTimeout(resolve, FORCE_PAGES_LOADED_TIMEOUT); - })]); - - if (!initialBookmark && !hash) { - return; - } - - if (pdfViewer.hasEqualPageSizes) { - return; - } - - this.initialBookmark = initialBookmark; - pdfViewer.currentScaleValue = pdfViewer.currentScaleValue; - this.setInitialView(hash); - }).catch(() => { - this.setInitialView(); - }).then(function () { - pdfViewer.update(); - }); - }); - pagesPromise.then(() => { - this._initializeAutoPrint(pdfDocument, openActionPromise); - }); - onePageRendered.then(() => { - pdfDocument.getOutline().then(outline => { - this.pdfOutlineViewer.render({ - outline - }); - }); - pdfDocument.getAttachments().then(attachments => { - this.pdfAttachmentViewer.render({ - attachments - }); - }); - pdfViewer.optionalContentConfigPromise.then(optionalContentConfig => { - this.pdfLayerViewer.render({ - optionalContentConfig, - pdfDocument - }); - }); - }); - - this._initializePageLabels(pdfDocument); - - this._initializeMetadata(pdfDocument); - }, - - async _initializeAutoPrint(pdfDocument, openActionPromise) { - const [openAction, javaScript] = await Promise.all([openActionPromise, pdfDocument.getJavaScript()]); - - if (pdfDocument !== this.pdfDocument) { - return; - } - - let triggerAutoPrint = false; - - if (openAction && openAction.action === "Print") { - triggerAutoPrint = true; - } - - if (javaScript) { - javaScript.some(js => { - if (!js) { - return false; - } - - console.warn("Warning: JavaScript is not supported"); - - this._delayedFallback(_pdfjsLib.UNSUPPORTED_FEATURES.javaScript); - - return true; - }); - - if (!triggerAutoPrint) { - for (const js of javaScript) { - if (js && _ui_utils.AutoPrintRegExp.test(js)) { - triggerAutoPrint = true; - break; - } - } - } - } - - if (!this.supportsPrinting) { - return; - } - - if (triggerAutoPrint) { - setTimeout(function () { - window.print(); - }); - } - }, - - async _initializeMetadata(pdfDocument) { - const { - info, - metadata, - contentDispositionFilename - } = await pdfDocument.getMetadata(); - - if (pdfDocument !== this.pdfDocument) { - return; - } - - this.documentInfo = info; - this.metadata = metadata; - this.contentDispositionFilename = contentDispositionFilename; - console.log(`PDF ${pdfDocument.fingerprint} [${info.PDFFormatVersion} ` + `${(info.Producer || "-").trim()} / ${(info.Creator || "-").trim()}] ` + `(PDF.js: ${_pdfjsLib.version || "-"}` + `${this.pdfViewer.enableWebGL ? " [WebGL]" : ""})`); - let pdfTitle; - const infoTitle = info && info.Title; - - if (infoTitle) { - pdfTitle = infoTitle; - } - - const metadataTitle = metadata && metadata.get("dc:title"); - - if (metadataTitle) { - if (metadataTitle !== "Untitled" && !/[\uFFF0-\uFFFF]/g.test(metadataTitle)) { - pdfTitle = metadataTitle; - } - } - - if (pdfTitle) { - this.setTitle(`${pdfTitle} - ${contentDispositionFilename || document.title}`); - } else if (contentDispositionFilename) { - this.setTitle(contentDispositionFilename); - } - - if (info.IsXFAPresent && !info.IsAcroFormPresent) { - console.warn("Warning: XFA is not supported"); - - this._delayedFallback(_pdfjsLib.UNSUPPORTED_FEATURES.forms); - } else if ((info.IsAcroFormPresent || info.IsXFAPresent) && !this.pdfViewer.renderInteractiveForms) { - console.warn("Warning: Interactive form support is not enabled"); - - this._delayedFallback(_pdfjsLib.UNSUPPORTED_FEATURES.forms); - } - - let versionId = "other"; - - if (KNOWN_VERSIONS.includes(info.PDFFormatVersion)) { - versionId = `v${info.PDFFormatVersion.replace(".", "_")}`; - } - - let generatorId = "other"; - - if (info.Producer) { - const producer = info.Producer.toLowerCase(); - KNOWN_GENERATORS.some(function (generator) { - if (!producer.includes(generator)) { - return false; - } - - generatorId = generator.replace(/[ .\-]/g, "_"); - return true; - }); - } - - let formType = null; - - if (info.IsXFAPresent) { - formType = "xfa"; - } else if (info.IsAcroFormPresent) { - formType = "acroform"; - } - - this.externalServices.reportTelemetry({ - type: "documentInfo", - version: versionId, - generator: generatorId, - formType - }); - }, - - async _initializePageLabels(pdfDocument) { - const labels = await pdfDocument.getPageLabels(); - - if (pdfDocument !== this.pdfDocument) { - return; - } - - if (!labels || _app_options.AppOptions.get("disablePageLabels")) { - return; - } - - const numLabels = labels.length; - - if (numLabels !== this.pagesCount) { - console.error("The number of Page Labels does not match the number of pages in the document."); - return; - } - - let i = 0; - - while (i < numLabels && labels[i] === (i + 1).toString()) { - i++; - } - - if (i === numLabels) { - return; - } - - const { - pdfViewer, - pdfThumbnailViewer, - toolbar - } = this; - pdfViewer.setPageLabels(labels); - pdfThumbnailViewer.setPageLabels(labels); - toolbar.setPagesCount(numLabels, true); - toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); - }, - - _initializePdfHistory({ - fingerprint, - viewOnLoad, - initialDest = null - }) { - if (this.isViewerEmbedded || _app_options.AppOptions.get("disableHistory")) { - return; - } - - this.pdfHistory.initialize({ - fingerprint, - resetHistory: viewOnLoad === ViewOnLoad.INITIAL, - updateUrl: _app_options.AppOptions.get("historyUpdateUrl") - }); - - if (this.pdfHistory.initialBookmark) { - this.initialBookmark = this.pdfHistory.initialBookmark; - this.initialRotation = this.pdfHistory.initialRotation; - } - - if (initialDest && !this.initialBookmark && viewOnLoad === ViewOnLoad.UNKNOWN) { - this.initialBookmark = JSON.stringify(initialDest); - this.pdfHistory.push({ - explicitDest: initialDest, - pageNumber: null - }); - } - }, - - async _initializePermissions(pdfDocument) { - const permissions = await pdfDocument.getPermissions(); - - if (pdfDocument !== this.pdfDocument) { - return; - } - - if (!permissions || !_app_options.AppOptions.get("enablePermissions")) { - return; - } - - if (!permissions.includes(_pdfjsLib.PermissionFlag.COPY)) { - this.appConfig.viewerContainer.classList.add(ENABLE_PERMISSIONS_CLASS); - } - }, - - setInitialView(storedHash, { - rotation, - sidebarView, - scrollMode, - spreadMode - } = {}) { - const setRotation = angle => { - if ((0, _ui_utils.isValidRotation)(angle)) { - this.pdfViewer.pagesRotation = angle; - } - }; - - const setViewerModes = (scroll, spread) => { - if ((0, _ui_utils.isValidScrollMode)(scroll)) { - this.pdfViewer.scrollMode = scroll; - } - - if ((0, _ui_utils.isValidSpreadMode)(spread)) { - this.pdfViewer.spreadMode = spread; - } - }; - - this.isInitialViewSet = true; - this.pdfSidebar.setInitialView(sidebarView); - setViewerModes(scrollMode, spreadMode); - - if (this.initialBookmark) { - setRotation(this.initialRotation); - delete this.initialRotation; - this.pdfLinkService.setHash(this.initialBookmark); - this.initialBookmark = null; - } else if (storedHash) { - setRotation(rotation); - this.pdfLinkService.setHash(storedHash); - } - - this.toolbar.setPageNumber(this.pdfViewer.currentPageNumber, this.pdfViewer.currentPageLabel); - this.secondaryToolbar.setPageNumber(this.pdfViewer.currentPageNumber); - - if (!this.pdfViewer.currentScaleValue) { - this.pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; - } - }, - - cleanup() { - if (!this.pdfDocument) { - return; - } - - this.pdfViewer.cleanup(); - this.pdfThumbnailViewer.cleanup(); - - if (this.pdfViewer.renderer !== _ui_utils.RendererType.SVG) { - this.pdfDocument.cleanup(); - } - }, - - forceRendering() { - this.pdfRenderingQueue.printing = this.printing; - this.pdfRenderingQueue.isThumbnailViewEnabled = this.pdfSidebar.isThumbnailViewVisible; - this.pdfRenderingQueue.renderHighestPriority(); - }, - - beforePrint() { - if (this.printService) { - return; - } - - if (!this.supportsPrinting) { - this.l10n.get("printing_not_supported", null, "Warning: Printing is not fully supported by this browser.").then(printMessage => { - this.error(printMessage); - }); - return; - } - - if (!this.pdfViewer.pageViewsReady) { - this.l10n.get("printing_not_ready", null, "Warning: The PDF is not fully loaded for printing.").then(notReadyMessage => { - window.alert(notReadyMessage); - }); - return; - } - - const pagesOverview = this.pdfViewer.getPagesOverview(); - const printContainer = this.appConfig.printContainer; - - const printResolution = _app_options.AppOptions.get("printResolution"); - - const optionalContentConfigPromise = this.pdfViewer.optionalContentConfigPromise; - const printService = PDFPrintServiceFactory.instance.createPrintService(this.pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, this.l10n); - this.printService = printService; - this.forceRendering(); - printService.layout(); - this.externalServices.reportTelemetry({ - type: "print" - }); - }, - - afterPrint() { - if (this.printService) { - this.printService.destroy(); - this.printService = null; - - if (this.pdfDocument) { - this.pdfDocument.annotationStorage.resetModified(); - } - } - - this.forceRendering(); - }, - - rotatePages(delta) { - if (!this.pdfDocument) { - return; - } - - const newRotation = (this.pdfViewer.pagesRotation + 360 + delta) % 360; - this.pdfViewer.pagesRotation = newRotation; - }, - - requestPresentationMode() { - if (!this.pdfPresentationMode) { - return; - } - - this.pdfPresentationMode.request(); - }, - - bindEvents() { - const { - eventBus, - _boundEvents - } = this; - _boundEvents.beforePrint = this.beforePrint.bind(this); - _boundEvents.afterPrint = this.afterPrint.bind(this); - - eventBus._on("resize", webViewerResize); - - eventBus._on("hashchange", webViewerHashchange); - - eventBus._on("beforeprint", _boundEvents.beforePrint); - - eventBus._on("afterprint", _boundEvents.afterPrint); - - eventBus._on("pagerendered", webViewerPageRendered); - - eventBus._on("updateviewarea", webViewerUpdateViewarea); - - eventBus._on("pagechanging", webViewerPageChanging); - - eventBus._on("scalechanging", webViewerScaleChanging); - - eventBus._on("rotationchanging", webViewerRotationChanging); - - eventBus._on("sidebarviewchanged", webViewerSidebarViewChanged); - - eventBus._on("pagemode", webViewerPageMode); - - eventBus._on("namedaction", webViewerNamedAction); - - eventBus._on("presentationmodechanged", webViewerPresentationModeChanged); - - eventBus._on("presentationmode", webViewerPresentationMode); - - eventBus._on("print", webViewerPrint); - - eventBus._on("download", webViewerDownload); - - eventBus._on("save", webViewerSave); - - eventBus._on("firstpage", webViewerFirstPage); - - eventBus._on("lastpage", webViewerLastPage); - - eventBus._on("nextpage", webViewerNextPage); - - eventBus._on("previouspage", webViewerPreviousPage); - - eventBus._on("zoomin", webViewerZoomIn); - - eventBus._on("zoomout", webViewerZoomOut); - - eventBus._on("zoomreset", webViewerZoomReset); - - eventBus._on("pagenumberchanged", webViewerPageNumberChanged); - - eventBus._on("scalechanged", webViewerScaleChanged); - - eventBus._on("rotatecw", webViewerRotateCw); - - eventBus._on("rotateccw", webViewerRotateCcw); - - eventBus._on("optionalcontentconfig", webViewerOptionalContentConfig); - - eventBus._on("switchscrollmode", webViewerSwitchScrollMode); - - eventBus._on("scrollmodechanged", webViewerScrollModeChanged); - - eventBus._on("switchspreadmode", webViewerSwitchSpreadMode); - - eventBus._on("spreadmodechanged", webViewerSpreadModeChanged); - - eventBus._on("documentproperties", webViewerDocumentProperties); - - eventBus._on("find", webViewerFind); - - eventBus._on("findfromurlhash", webViewerFindFromUrlHash); - - eventBus._on("updatefindmatchescount", webViewerUpdateFindMatchesCount); - - eventBus._on("updatefindcontrolstate", webViewerUpdateFindControlState); - - eventBus._on("fileinputchange", webViewerFileInputChange); - - eventBus._on("openfile", webViewerOpenFile); - }, - - bindWindowEvents() { - const { - eventBus, - _boundEvents - } = this; - - _boundEvents.windowResize = () => { - eventBus.dispatch("resize", { - source: window - }); - }; - - _boundEvents.windowHashChange = () => { - eventBus.dispatch("hashchange", { - source: window, - hash: document.location.hash.substring(1) - }); - }; - - _boundEvents.windowBeforePrint = () => { - eventBus.dispatch("beforeprint", { - source: window - }); - }; - - _boundEvents.windowAfterPrint = () => { - eventBus.dispatch("afterprint", { - source: window - }); - }; - - window.addEventListener("visibilitychange", webViewerVisibilityChange); - window.addEventListener("wheel", webViewerWheel, { - passive: false - }); - window.addEventListener("touchstart", webViewerTouchStart, { - passive: false - }); - window.addEventListener("click", webViewerClick); - window.addEventListener("keydown", webViewerKeyDown); - window.addEventListener("keyup", webViewerKeyUp); - window.addEventListener("resize", _boundEvents.windowResize); - window.addEventListener("hashchange", _boundEvents.windowHashChange); - window.addEventListener("beforeprint", _boundEvents.windowBeforePrint); - window.addEventListener("afterprint", _boundEvents.windowAfterPrint); - }, - - unbindEvents() { - const { - eventBus, - _boundEvents - } = this; - - eventBus._off("resize", webViewerResize); - - eventBus._off("hashchange", webViewerHashchange); - - eventBus._off("beforeprint", _boundEvents.beforePrint); - - eventBus._off("afterprint", _boundEvents.afterPrint); - - eventBus._off("pagerendered", webViewerPageRendered); - - eventBus._off("updateviewarea", webViewerUpdateViewarea); - - eventBus._off("pagechanging", webViewerPageChanging); - - eventBus._off("scalechanging", webViewerScaleChanging); - - eventBus._off("rotationchanging", webViewerRotationChanging); - - eventBus._off("sidebarviewchanged", webViewerSidebarViewChanged); - - eventBus._off("pagemode", webViewerPageMode); - - eventBus._off("namedaction", webViewerNamedAction); - - eventBus._off("presentationmodechanged", webViewerPresentationModeChanged); - - eventBus._off("presentationmode", webViewerPresentationMode); - - eventBus._off("print", webViewerPrint); - - eventBus._off("download", webViewerDownload); - - eventBus._off("save", webViewerSave); - - eventBus._off("firstpage", webViewerFirstPage); - - eventBus._off("lastpage", webViewerLastPage); - - eventBus._off("nextpage", webViewerNextPage); - - eventBus._off("previouspage", webViewerPreviousPage); - - eventBus._off("zoomin", webViewerZoomIn); - - eventBus._off("zoomout", webViewerZoomOut); - - eventBus._off("zoomreset", webViewerZoomReset); - - eventBus._off("pagenumberchanged", webViewerPageNumberChanged); - - eventBus._off("scalechanged", webViewerScaleChanged); - - eventBus._off("rotatecw", webViewerRotateCw); - - eventBus._off("rotateccw", webViewerRotateCcw); - - eventBus._off("optionalcontentconfig", webViewerOptionalContentConfig); - - eventBus._off("switchscrollmode", webViewerSwitchScrollMode); - - eventBus._off("scrollmodechanged", webViewerScrollModeChanged); - - eventBus._off("switchspreadmode", webViewerSwitchSpreadMode); - - eventBus._off("spreadmodechanged", webViewerSpreadModeChanged); - - eventBus._off("documentproperties", webViewerDocumentProperties); - - eventBus._off("find", webViewerFind); - - eventBus._off("findfromurlhash", webViewerFindFromUrlHash); - - eventBus._off("updatefindmatchescount", webViewerUpdateFindMatchesCount); - - eventBus._off("updatefindcontrolstate", webViewerUpdateFindControlState); - - eventBus._off("fileinputchange", webViewerFileInputChange); - - eventBus._off("openfile", webViewerOpenFile); - - _boundEvents.beforePrint = null; - _boundEvents.afterPrint = null; - }, - - unbindWindowEvents() { - const { - _boundEvents - } = this; - window.removeEventListener("visibilitychange", webViewerVisibilityChange); - window.removeEventListener("wheel", webViewerWheel, { - passive: false - }); - window.removeEventListener("touchstart", webViewerTouchStart, { - passive: false - }); - window.removeEventListener("click", webViewerClick); - window.removeEventListener("keydown", webViewerKeyDown); - window.removeEventListener("keyup", webViewerKeyUp); - window.removeEventListener("resize", _boundEvents.windowResize); - window.removeEventListener("hashchange", _boundEvents.windowHashChange); - window.removeEventListener("beforeprint", _boundEvents.windowBeforePrint); - window.removeEventListener("afterprint", _boundEvents.windowAfterPrint); - _boundEvents.windowResize = null; - _boundEvents.windowHashChange = null; - _boundEvents.windowBeforePrint = null; - _boundEvents.windowAfterPrint = null; - }, - - accumulateWheelTicks(ticks) { - if (this._wheelUnusedTicks > 0 && ticks < 0 || this._wheelUnusedTicks < 0 && ticks > 0) { - this._wheelUnusedTicks = 0; - } - - this._wheelUnusedTicks += ticks; - const wholeTicks = Math.sign(this._wheelUnusedTicks) * Math.floor(Math.abs(this._wheelUnusedTicks)); - this._wheelUnusedTicks -= wholeTicks; - return wholeTicks; - } - -}; -exports.PDFViewerApplication = PDFViewerApplication; -let validateFileURL; -{ - const HOSTED_VIEWER_ORIGINS = ["null", "http://mozilla.github.io", "https://mozilla.github.io"]; - - validateFileURL = function (file) { - if (file === undefined) { - return; - } - - try { - const viewerOrigin = new URL(window.location.href).origin || "null"; - - if (HOSTED_VIEWER_ORIGINS.includes(viewerOrigin)) { - return; - } - - const { - origin, - protocol - } = new URL(file, window.location.href); - - if (origin !== viewerOrigin && protocol !== "blob:") { - throw new Error("file origin does not match viewer's"); - } - } catch (ex) { - const message = ex && ex.message; - PDFViewerApplication.l10n.get("loading_error", null, "An error occurred while loading the PDF.").then(loadingErrorMessage => { - PDFViewerApplication.error(loadingErrorMessage, { - message - }); - }); - throw ex; - } - }; -} - -async function loadFakeWorker() { - if (!_pdfjsLib.GlobalWorkerOptions.workerSrc) { - _pdfjsLib.GlobalWorkerOptions.workerSrc = _app_options.AppOptions.get("workerSrc"); - } - - return (0, _pdfjsLib.loadScript)(_pdfjsLib.PDFWorker.getWorkerSrc()); -} - -function loadAndEnablePDFBug(enabledTabs) { - const appConfig = PDFViewerApplication.appConfig; - return (0, _pdfjsLib.loadScript)(appConfig.debuggerScriptPath).then(function () { - PDFBug.enable(enabledTabs); - PDFBug.init({ - OPS: _pdfjsLib.OPS - }, appConfig.mainContainer); - }); -} - -function webViewerInitialized() { - const appConfig = PDFViewerApplication.appConfig; - let file; - const queryString = document.location.search.substring(1); - const params = (0, _ui_utils.parseQueryString)(queryString); - file = "file" in params ? params.file : _app_options.AppOptions.get("defaultUrl"); - validateFileURL(file); - const fileInput = document.createElement("input"); - fileInput.id = appConfig.openFileInputName; - fileInput.className = "fileInput"; - fileInput.setAttribute("type", "file"); - fileInput.oncontextmenu = _ui_utils.noContextMenuHandler; - document.body.appendChild(fileInput); - - if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { - appConfig.toolbar.openFile.setAttribute("hidden", "true"); - appConfig.secondaryToolbar.openFileButton.setAttribute("hidden", "true"); - } else { - fileInput.value = null; - } - - fileInput.addEventListener("change", function (evt) { - const files = evt.target.files; - - if (!files || files.length === 0) { - return; - } - - PDFViewerApplication.eventBus.dispatch("fileinputchange", { - source: this, - fileInput: evt.target - }); - }); - appConfig.mainContainer.addEventListener("dragover", function (evt) { - evt.preventDefault(); - evt.dataTransfer.dropEffect = "move"; - }); - appConfig.mainContainer.addEventListener("drop", function (evt) { - evt.preventDefault(); - const files = evt.dataTransfer.files; - - if (!files || files.length === 0) { - return; - } - - PDFViewerApplication.eventBus.dispatch("fileinputchange", { - source: this, - fileInput: evt.dataTransfer - }); - }); - - if (!PDFViewerApplication.supportsDocumentFonts) { - _app_options.AppOptions.set("disableFontFace", true); - - PDFViewerApplication.l10n.get("web_fonts_disabled", null, "Web fonts are disabled: unable to use embedded PDF fonts.").then(msg => { - console.warn(msg); - }); - } - - if (!PDFViewerApplication.supportsPrinting) { - appConfig.toolbar.print.classList.add("hidden"); - appConfig.secondaryToolbar.printButton.classList.add("hidden"); - } - - if (!PDFViewerApplication.supportsFullscreen) { - appConfig.toolbar.presentationModeButton.classList.add("hidden"); - appConfig.secondaryToolbar.presentationModeButton.classList.add("hidden"); - } - - if (PDFViewerApplication.supportsIntegratedFind) { - appConfig.toolbar.viewFind.classList.add("hidden"); - } - - appConfig.mainContainer.addEventListener("transitionend", function (evt) { - if (evt.target === this) { - PDFViewerApplication.eventBus.dispatch("resize", { - source: this - }); - } - }, true); - - try { - webViewerOpenFileViaURL(file); - } catch (reason) { - PDFViewerApplication.l10n.get("loading_error", null, "An error occurred while loading the PDF.").then(msg => { - PDFViewerApplication.error(msg, reason); - }); - } -} - -let webViewerOpenFileViaURL; -{ - webViewerOpenFileViaURL = function (file) { - if (file && file.lastIndexOf("file:", 0) === 0) { - PDFViewerApplication.setTitleUsingUrl(file); - const xhr = new XMLHttpRequest(); - - xhr.onload = function () { - PDFViewerApplication.open(new Uint8Array(xhr.response)); - }; - - xhr.open("GET", file); - xhr.responseType = "arraybuffer"; - xhr.send(); - return; - } - - if (file) { - PDFViewerApplication.open(file); - } - }; -} - -function webViewerResetPermissions() { - const { - appConfig - } = PDFViewerApplication; - - if (!appConfig) { - return; - } - - appConfig.viewerContainer.classList.remove(ENABLE_PERMISSIONS_CLASS); -} - -function webViewerPageRendered(evt) { - const pageNumber = evt.pageNumber; - const pageIndex = pageNumber - 1; - const pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex); - - if (pageNumber === PDFViewerApplication.page) { - PDFViewerApplication.toolbar.updateLoadingIndicatorState(false); - } - - if (!pageView) { - return; - } - - if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) { - const thumbnailView = PDFViewerApplication.pdfThumbnailViewer.getThumbnail(pageIndex); - thumbnailView.setImage(pageView); - } - - if (typeof Stats !== "undefined" && Stats.enabled && pageView.stats) { - Stats.add(pageNumber, pageView.stats); - } - - if (pageView.error) { - PDFViewerApplication.l10n.get("rendering_error", null, "An error occurred while rendering the page.").then(msg => { - PDFViewerApplication.error(msg, pageView.error); - }); - } - - PDFViewerApplication.externalServices.reportTelemetry({ - type: "pageInfo", - timestamp: evt.timestamp - }); - PDFViewerApplication.pdfDocument.getStats().then(function (stats) { - PDFViewerApplication.externalServices.reportTelemetry({ - type: "documentStats", - stats - }); - }); -} - -function webViewerPageMode({ - mode -}) { - let view; - - switch (mode) { - case "thumbs": - view = _pdf_sidebar.SidebarView.THUMBS; - break; - - case "bookmarks": - case "outline": - view = _pdf_sidebar.SidebarView.OUTLINE; - break; - - case "attachments": - view = _pdf_sidebar.SidebarView.ATTACHMENTS; - break; - - case "layers": - view = _pdf_sidebar.SidebarView.LAYERS; - break; - - case "none": - view = _pdf_sidebar.SidebarView.NONE; - break; - - default: - console.error('Invalid "pagemode" hash parameter: ' + mode); - return; - } - - PDFViewerApplication.pdfSidebar.switchView(view, true); -} - -function webViewerNamedAction(evt) { - switch (evt.action) { - case "GoToPage": - PDFViewerApplication.appConfig.toolbar.pageNumber.select(); - break; - - case "Find": - if (!PDFViewerApplication.supportsIntegratedFind) { - PDFViewerApplication.findBar.toggle(); - } - - break; - - case "Print": - if (PDFViewerApplication.supportsPrinting) { - webViewerPrint(); - } - - break; - - case "SaveAs": - webViewerSave(); - break; - } -} - -function webViewerPresentationModeChanged({ - active, - switchInProgress -}) { - let state = _ui_utils.PresentationModeState.NORMAL; - - if (switchInProgress) { - state = _ui_utils.PresentationModeState.CHANGING; - } else if (active) { - state = _ui_utils.PresentationModeState.FULLSCREEN; - } - - PDFViewerApplication.pdfViewer.presentationModeState = state; -} - -function webViewerSidebarViewChanged(evt) { - PDFViewerApplication.pdfRenderingQueue.isThumbnailViewEnabled = PDFViewerApplication.pdfSidebar.isThumbnailViewVisible; - const store = PDFViewerApplication.store; - - if (store && PDFViewerApplication.isInitialViewSet) { - store.set("sidebarView", evt.view).catch(function () {}); - } -} - -function webViewerUpdateViewarea(evt) { - const location = evt.location, - store = PDFViewerApplication.store; - - if (store && PDFViewerApplication.isInitialViewSet) { - store.setMultiple({ - page: location.pageNumber, - zoom: location.scale, - scrollLeft: location.left, - scrollTop: location.top, - rotation: location.rotation - }).catch(function () {}); - } - - const href = PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams); - PDFViewerApplication.appConfig.toolbar.viewBookmark.href = href; - PDFViewerApplication.appConfig.secondaryToolbar.viewBookmarkButton.href = href; - const currentPage = PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1); - const loading = currentPage.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED; - PDFViewerApplication.toolbar.updateLoadingIndicatorState(loading); -} - -function webViewerScrollModeChanged(evt) { - const store = PDFViewerApplication.store; - - if (store && PDFViewerApplication.isInitialViewSet) { - store.set("scrollMode", evt.mode).catch(function () {}); - } -} - -function webViewerSpreadModeChanged(evt) { - const store = PDFViewerApplication.store; - - if (store && PDFViewerApplication.isInitialViewSet) { - store.set("spreadMode", evt.mode).catch(function () {}); - } -} - -function webViewerResize() { - const { - pdfDocument, - pdfViewer - } = PDFViewerApplication; - - if (!pdfDocument) { - return; - } - - const currentScaleValue = pdfViewer.currentScaleValue; - - if (currentScaleValue === "auto" || currentScaleValue === "page-fit" || currentScaleValue === "page-width") { - pdfViewer.currentScaleValue = currentScaleValue; - } - - pdfViewer.update(); -} - -function webViewerHashchange(evt) { - const hash = evt.hash; - - if (!hash) { - return; - } - - if (!PDFViewerApplication.isInitialViewSet) { - PDFViewerApplication.initialBookmark = hash; - } else if (!PDFViewerApplication.pdfHistory.popStateInProgress) { - PDFViewerApplication.pdfLinkService.setHash(hash); - } -} - -let webViewerFileInputChange, webViewerOpenFile; -{ - webViewerFileInputChange = function (evt) { - if (PDFViewerApplication.pdfViewer && PDFViewerApplication.pdfViewer.isInPresentationMode) { - return; - } - - const file = evt.fileInput.files[0]; - - if (!_viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL) { - let url = URL.createObjectURL(file); - - if (file.name) { - url = { - url, - originalUrl: file.name - }; - } - - PDFViewerApplication.open(url); - } else { - PDFViewerApplication.setTitleUsingUrl(file.name); - const fileReader = new FileReader(); - - fileReader.onload = function webViewerChangeFileReaderOnload(event) { - const buffer = event.target.result; - PDFViewerApplication.open(new Uint8Array(buffer)); - }; - - fileReader.readAsArrayBuffer(file); - } - - const appConfig = PDFViewerApplication.appConfig; - appConfig.toolbar.viewBookmark.setAttribute("hidden", "true"); - appConfig.secondaryToolbar.viewBookmarkButton.setAttribute("hidden", "true"); - appConfig.toolbar.download.setAttribute("hidden", "true"); - appConfig.secondaryToolbar.downloadButton.setAttribute("hidden", "true"); - }; - - webViewerOpenFile = function (evt) { - const openFileInputName = PDFViewerApplication.appConfig.openFileInputName; - document.getElementById(openFileInputName).click(); - }; -} - -function webViewerPresentationMode() { - PDFViewerApplication.requestPresentationMode(); -} - -function webViewerPrint() { - window.print(); -} - -function webViewerDownloadOrSave(sourceEventType) { - if (PDFViewerApplication.pdfDocument && PDFViewerApplication.pdfDocument.annotationStorage.size > 0) { - PDFViewerApplication.save({ - sourceEventType - }); - } else { - PDFViewerApplication.download({ - sourceEventType - }); - } -} - -function webViewerDownload() { - webViewerDownloadOrSave("download"); -} - -function webViewerSave() { - webViewerDownloadOrSave("save"); -} - -function webViewerFirstPage() { - if (PDFViewerApplication.pdfDocument) { - PDFViewerApplication.page = 1; - } -} - -function webViewerLastPage() { - if (PDFViewerApplication.pdfDocument) { - PDFViewerApplication.page = PDFViewerApplication.pagesCount; - } -} - -function webViewerNextPage() { - PDFViewerApplication.page++; -} - -function webViewerPreviousPage() { - PDFViewerApplication.page--; -} - -function webViewerZoomIn() { - PDFViewerApplication.zoomIn(); -} - -function webViewerZoomOut() { - PDFViewerApplication.zoomOut(); -} - -function webViewerZoomReset() { - PDFViewerApplication.zoomReset(); -} - -function webViewerPageNumberChanged(evt) { - const pdfViewer = PDFViewerApplication.pdfViewer; - - if (evt.value !== "") { - pdfViewer.currentPageLabel = evt.value; - } - - if (evt.value !== pdfViewer.currentPageNumber.toString() && evt.value !== pdfViewer.currentPageLabel) { - PDFViewerApplication.toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); - } -} - -function webViewerScaleChanged(evt) { - PDFViewerApplication.pdfViewer.currentScaleValue = evt.value; -} - -function webViewerRotateCw() { - PDFViewerApplication.rotatePages(90); -} - -function webViewerRotateCcw() { - PDFViewerApplication.rotatePages(-90); -} - -function webViewerOptionalContentConfig(evt) { - PDFViewerApplication.pdfViewer.optionalContentConfigPromise = evt.promise; -} - -function webViewerSwitchScrollMode(evt) { - PDFViewerApplication.pdfViewer.scrollMode = evt.mode; -} - -function webViewerSwitchSpreadMode(evt) { - PDFViewerApplication.pdfViewer.spreadMode = evt.mode; -} - -function webViewerDocumentProperties() { - PDFViewerApplication.pdfDocumentProperties.open(); -} - -function webViewerFind(evt) { - PDFViewerApplication.findController.executeCommand("find" + evt.type, { - query: evt.query, - phraseSearch: evt.phraseSearch, - caseSensitive: evt.caseSensitive, - entireWord: evt.entireWord, - highlightAll: evt.highlightAll, - findPrevious: evt.findPrevious - }); -} - -function webViewerFindFromUrlHash(evt) { - PDFViewerApplication.findController.executeCommand("find", { - query: evt.query, - phraseSearch: evt.phraseSearch, - caseSensitive: false, - entireWord: false, - highlightAll: true, - findPrevious: false - }); -} - -function webViewerUpdateFindMatchesCount({ - matchesCount -}) { - if (PDFViewerApplication.supportsIntegratedFind) { - PDFViewerApplication.externalServices.updateFindMatchesCount(matchesCount); - } else { - PDFViewerApplication.findBar.updateResultsCount(matchesCount); - } -} - -function webViewerUpdateFindControlState({ - state, - previous, - matchesCount, - rawQuery -}) { - if (PDFViewerApplication.supportsIntegratedFind) { - PDFViewerApplication.externalServices.updateFindControlState({ - result: state, - findPrevious: previous, - matchesCount, - rawQuery - }); - } else { - PDFViewerApplication.findBar.updateUIState(state, previous, matchesCount); - } -} - -function webViewerScaleChanging(evt) { - PDFViewerApplication.toolbar.setPageScale(evt.presetValue, evt.scale); - PDFViewerApplication.pdfViewer.update(); -} - -function webViewerRotationChanging(evt) { - PDFViewerApplication.pdfThumbnailViewer.pagesRotation = evt.pagesRotation; - PDFViewerApplication.forceRendering(); - PDFViewerApplication.pdfViewer.currentPageNumber = evt.pageNumber; -} - -function webViewerPageChanging(evt) { - const page = evt.pageNumber; - PDFViewerApplication.toolbar.setPageNumber(page, evt.pageLabel || null); - PDFViewerApplication.secondaryToolbar.setPageNumber(page); - - if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) { - PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page); - } - - if (typeof Stats !== "undefined" && Stats.enabled) { - const pageView = PDFViewerApplication.pdfViewer.getPageView(page - 1); - - if (pageView && pageView.stats) { - Stats.add(page, pageView.stats); - } - } -} - -function webViewerVisibilityChange(evt) { - if (document.visibilityState === "visible") { - setZoomDisabledTimeout(); - } -} - -let zoomDisabledTimeout = null; - -function setZoomDisabledTimeout() { - if (zoomDisabledTimeout) { - clearTimeout(zoomDisabledTimeout); - } - - zoomDisabledTimeout = setTimeout(function () { - zoomDisabledTimeout = null; - }, WHEEL_ZOOM_DISABLED_TIMEOUT); -} - -function webViewerWheel(evt) { - const { - pdfViewer, - supportedMouseWheelZoomModifierKeys - } = PDFViewerApplication; - - if (pdfViewer.isInPresentationMode) { - return; - } - - if (evt.ctrlKey && supportedMouseWheelZoomModifierKeys.ctrlKey || evt.metaKey && supportedMouseWheelZoomModifierKeys.metaKey) { - evt.preventDefault(); - - if (zoomDisabledTimeout || document.visibilityState === "hidden") { - return; - } - - const previousScale = pdfViewer.currentScale; - const delta = (0, _ui_utils.normalizeWheelEventDirection)(evt); - let ticks = 0; - - if (evt.deltaMode === WheelEvent.DOM_DELTA_LINE || evt.deltaMode === WheelEvent.DOM_DELTA_PAGE) { - if (Math.abs(delta) >= 1) { - ticks = Math.sign(delta); - } else { - ticks = PDFViewerApplication.accumulateWheelTicks(delta); - } - } else { - const PIXELS_PER_LINE_SCALE = 30; - ticks = PDFViewerApplication.accumulateWheelTicks(delta / PIXELS_PER_LINE_SCALE); - } - - if (ticks < 0) { - PDFViewerApplication.zoomOut(-ticks); - } else if (ticks > 0) { - PDFViewerApplication.zoomIn(ticks); - } - - const currentScale = pdfViewer.currentScale; - - if (previousScale !== currentScale) { - const scaleCorrectionFactor = currentScale / previousScale - 1; - const rect = pdfViewer.container.getBoundingClientRect(); - const dx = evt.clientX - rect.left; - const dy = evt.clientY - rect.top; - pdfViewer.container.scrollLeft += dx * scaleCorrectionFactor; - pdfViewer.container.scrollTop += dy * scaleCorrectionFactor; - } - } else { - setZoomDisabledTimeout(); - } -} - -function webViewerTouchStart(evt) { - if (evt.touches.length > 1) { - evt.preventDefault(); - } -} - -function webViewerClick(evt) { - if (PDFViewerApplication.triggerDelayedFallback && PDFViewerApplication.pdfViewer.containsElement(evt.target)) { - PDFViewerApplication.triggerDelayedFallback(); - } - - if (!PDFViewerApplication.secondaryToolbar.isOpen) { - return; - } - - const appConfig = PDFViewerApplication.appConfig; - - if (PDFViewerApplication.pdfViewer.containsElement(evt.target) || appConfig.toolbar.container.contains(evt.target) && evt.target !== appConfig.secondaryToolbar.toggleButton) { - PDFViewerApplication.secondaryToolbar.close(); - } -} - -function webViewerKeyUp(evt) { - if (evt.keyCode === 9) { - if (PDFViewerApplication.triggerDelayedFallback) { - PDFViewerApplication.triggerDelayedFallback(); - } - } -} - -function webViewerKeyDown(evt) { - if (PDFViewerApplication.overlayManager.active) { - return; - } - - let handled = false, - ensureViewerFocused = false; - const cmd = (evt.ctrlKey ? 1 : 0) | (evt.altKey ? 2 : 0) | (evt.shiftKey ? 4 : 0) | (evt.metaKey ? 8 : 0); - const pdfViewer = PDFViewerApplication.pdfViewer; - const isViewerInPresentationMode = pdfViewer && pdfViewer.isInPresentationMode; - - if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) { - switch (evt.keyCode) { - case 70: - if (!PDFViewerApplication.supportsIntegratedFind) { - PDFViewerApplication.findBar.open(); - handled = true; - } - - break; - - case 71: - if (!PDFViewerApplication.supportsIntegratedFind) { - const findState = PDFViewerApplication.findController.state; - - if (findState) { - PDFViewerApplication.findController.executeCommand("findagain", { - query: findState.query, - phraseSearch: findState.phraseSearch, - caseSensitive: findState.caseSensitive, - entireWord: findState.entireWord, - highlightAll: findState.highlightAll, - findPrevious: cmd === 5 || cmd === 12 - }); - } - - handled = true; - } - - break; - - case 61: - case 107: - case 187: - case 171: - if (!isViewerInPresentationMode) { - PDFViewerApplication.zoomIn(); - } - - handled = true; - break; - - case 173: - case 109: - case 189: - if (!isViewerInPresentationMode) { - PDFViewerApplication.zoomOut(); - } - - handled = true; - break; - - case 48: - case 96: - if (!isViewerInPresentationMode) { - setTimeout(function () { - PDFViewerApplication.zoomReset(); - }); - handled = false; - } - - break; - - case 38: - if (isViewerInPresentationMode || PDFViewerApplication.page > 1) { - PDFViewerApplication.page = 1; - handled = true; - ensureViewerFocused = true; - } - - break; - - case 40: - if (isViewerInPresentationMode || PDFViewerApplication.page < PDFViewerApplication.pagesCount) { - PDFViewerApplication.page = PDFViewerApplication.pagesCount; - handled = true; - ensureViewerFocused = true; - } - - break; - } - } - - const { - eventBus - } = PDFViewerApplication; - - if (cmd === 1 || cmd === 8) { - switch (evt.keyCode) { - case 83: - eventBus.dispatch("download", { - source: window - }); - handled = true; - break; - - case 79: - { - eventBus.dispatch("openfile", { - source: window - }); - handled = true; - } - break; - } - } - - if (cmd === 3 || cmd === 10) { - switch (evt.keyCode) { - case 80: - PDFViewerApplication.requestPresentationMode(); - handled = true; - break; - - case 71: - PDFViewerApplication.appConfig.toolbar.pageNumber.select(); - handled = true; - break; - } - } - - if (handled) { - if (ensureViewerFocused && !isViewerInPresentationMode) { - pdfViewer.focus(); - } - - evt.preventDefault(); - return; - } - - const curElement = document.activeElement || document.querySelector(":focus"); - const curElementTagName = curElement && curElement.tagName.toUpperCase(); - - if (curElementTagName === "INPUT" || curElementTagName === "TEXTAREA" || curElementTagName === "SELECT" || curElement && curElement.isContentEditable) { - if (evt.keyCode !== 27) { - return; - } - } - - if (cmd === 0) { - let turnPage = 0, - turnOnlyIfPageFit = false; - - switch (evt.keyCode) { - case 38: - case 33: - if (pdfViewer.isVerticalScrollbarEnabled) { - turnOnlyIfPageFit = true; - } - - turnPage = -1; - break; - - case 8: - if (!isViewerInPresentationMode) { - turnOnlyIfPageFit = true; - } - - turnPage = -1; - break; - - case 37: - if (pdfViewer.isHorizontalScrollbarEnabled) { - turnOnlyIfPageFit = true; - } - - case 75: - case 80: - turnPage = -1; - break; - - case 27: - if (PDFViewerApplication.secondaryToolbar.isOpen) { - PDFViewerApplication.secondaryToolbar.close(); - handled = true; - } - - if (!PDFViewerApplication.supportsIntegratedFind && PDFViewerApplication.findBar.opened) { - PDFViewerApplication.findBar.close(); - handled = true; - } - - break; - - case 40: - case 34: - if (pdfViewer.isVerticalScrollbarEnabled) { - turnOnlyIfPageFit = true; - } - - turnPage = 1; - break; - - case 13: - case 32: - if (!isViewerInPresentationMode) { - turnOnlyIfPageFit = true; - } - - turnPage = 1; - break; - - case 39: - if (pdfViewer.isHorizontalScrollbarEnabled) { - turnOnlyIfPageFit = true; - } - - case 74: - case 78: - turnPage = 1; - break; - - case 36: - if (isViewerInPresentationMode || PDFViewerApplication.page > 1) { - PDFViewerApplication.page = 1; - handled = true; - ensureViewerFocused = true; - } - - break; - - case 35: - if (isViewerInPresentationMode || PDFViewerApplication.page < PDFViewerApplication.pagesCount) { - PDFViewerApplication.page = PDFViewerApplication.pagesCount; - handled = true; - ensureViewerFocused = true; - } - - break; - - case 83: - PDFViewerApplication.pdfCursorTools.switchTool(_pdf_cursor_tools.CursorTool.SELECT); - break; - - case 72: - PDFViewerApplication.pdfCursorTools.switchTool(_pdf_cursor_tools.CursorTool.HAND); - break; - - case 82: - PDFViewerApplication.rotatePages(90); - break; - - case 115: - PDFViewerApplication.pdfSidebar.toggle(); - break; - } - - if (turnPage !== 0 && (!turnOnlyIfPageFit || pdfViewer.currentScaleValue === "page-fit")) { - if (turnPage > 0) { - if (PDFViewerApplication.page < PDFViewerApplication.pagesCount) { - PDFViewerApplication.page++; - } - } else { - if (PDFViewerApplication.page > 1) { - PDFViewerApplication.page--; - } - } - - handled = true; - } - } - - if (cmd === 4) { - switch (evt.keyCode) { - case 13: - case 32: - if (!isViewerInPresentationMode && pdfViewer.currentScaleValue !== "page-fit") { - break; - } - - if (PDFViewerApplication.page > 1) { - PDFViewerApplication.page--; - } - - handled = true; - break; - - case 82: - PDFViewerApplication.rotatePages(-90); - break; - } - } - - if (!handled && !isViewerInPresentationMode) { - if (evt.keyCode >= 33 && evt.keyCode <= 40 || evt.keyCode === 32 && curElementTagName !== "BUTTON") { - ensureViewerFocused = true; - } - } - - if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) { - pdfViewer.focus(); - } - - if (handled) { - evt.preventDefault(); - } -} - -function beforeUnload(evt) { - evt.preventDefault(); - evt.returnValue = ""; - return false; -} - -function apiPageLayoutToSpreadMode(layout) { - switch (layout) { - case "SinglePage": - case "OneColumn": - return _ui_utils.SpreadMode.NONE; - - case "TwoColumnLeft": - case "TwoPageLeft": - return _ui_utils.SpreadMode.ODD; - - case "TwoColumnRight": - case "TwoPageRight": - return _ui_utils.SpreadMode.EVEN; - } - - return _ui_utils.SpreadMode.NONE; -} - -function apiPageModeToSidebarView(mode) { - switch (mode) { - case "UseNone": - return _pdf_sidebar.SidebarView.NONE; - - case "UseThumbs": - return _pdf_sidebar.SidebarView.THUMBS; - - case "UseOutlines": - return _pdf_sidebar.SidebarView.OUTLINE; - - case "UseAttachments": - return _pdf_sidebar.SidebarView.ATTACHMENTS; - - case "UseOC": - return _pdf_sidebar.SidebarView.LAYERS; - } - - return _pdf_sidebar.SidebarView.NONE; -} - -const PDFPrintServiceFactory = { - instance: { - supportsPrinting: false, - - createPrintService() { - throw new Error("Not implemented: createPrintService"); - } - - } -}; -exports.PDFPrintServiceFactory = PDFPrintServiceFactory; - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); +})); +exports.animationStarted = exports.VERTICAL_PADDING = exports.UNKNOWN_SCALE = exports.TextLayerMode = exports.SpreadMode = exports.SidebarView = exports.ScrollMode = exports.SCROLLBAR_PADDING = exports.RenderingStates = exports.RendererType = exports.ProgressBar = exports.PresentationModeState = exports.OutputScale = exports.MIN_SCALE = exports.MAX_SCALE = exports.MAX_AUTO_SCALE = exports.DEFAULT_SCALE_VALUE = exports.DEFAULT_SCALE_DELTA = exports.DEFAULT_SCALE = exports.AutoPrintRegExp = void 0; +exports.apiPageLayoutToViewerModes = apiPageLayoutToViewerModes; +exports.apiPageModeToSidebarView = apiPageModeToSidebarView; +exports.approximateFraction = approximateFraction; +exports.backtrackBeforeAllVisibleElements = backtrackBeforeAllVisibleElements; +exports.binarySearchFirstItem = binarySearchFirstItem; +exports.docStyle = void 0; +exports.getActiveOrFocusedElement = getActiveOrFocusedElement; +exports.getPageSizeInches = getPageSizeInches; +exports.getVisibleElements = getVisibleElements; +exports.isPortraitOrientation = isPortraitOrientation; exports.isValidRotation = isValidRotation; exports.isValidScrollMode = isValidScrollMode; exports.isValidSpreadMode = isValidSpreadMode; -exports.isPortraitOrientation = isPortraitOrientation; -exports.clamp = clamp; -exports.getPDFFileNameFromURL = getPDFFileNameFromURL; exports.noContextMenuHandler = noContextMenuHandler; +exports.normalizeWheelEventDelta = normalizeWheelEventDelta; +exports.normalizeWheelEventDirection = normalizeWheelEventDirection; exports.parseQueryString = parseQueryString; -exports.backtrackBeforeAllVisibleElements = backtrackBeforeAllVisibleElements; -exports.getVisibleElements = getVisibleElements; +exports.removeNullCharacters = removeNullCharacters; exports.roundToDivide = roundToDivide; -exports.getPageSizeInches = getPageSizeInches; -exports.approximateFraction = approximateFraction; -exports.getOutputScale = getOutputScale; exports.scrollIntoView = scrollIntoView; exports.watchScroll = watchScroll; -exports.binarySearchFirstItem = binarySearchFirstItem; -exports.normalizeWheelEventDirection = normalizeWheelEventDirection; -exports.normalizeWheelEventDelta = normalizeWheelEventDelta; -exports.waitOnEventOrTimeout = waitOnEventOrTimeout; -exports.moveToEndOfArray = moveToEndOfArray; -exports.WaitOnType = exports.animationStarted = exports.ProgressBar = exports.EventBus = exports.NullL10n = exports.SpreadMode = exports.ScrollMode = exports.TextLayerMode = exports.RendererType = exports.PresentationModeState = exports.VERTICAL_PADDING = exports.SCROLLBAR_PADDING = exports.MAX_AUTO_SCALE = exports.UNKNOWN_SCALE = exports.MAX_SCALE = exports.MIN_SCALE = exports.DEFAULT_SCALE = exports.DEFAULT_SCALE_VALUE = exports.CSS_UNITS = exports.AutoPrintRegExp = void 0; -const CSS_UNITS = 96.0 / 72.0; -exports.CSS_UNITS = CSS_UNITS; const DEFAULT_SCALE_VALUE = "auto"; exports.DEFAULT_SCALE_VALUE = DEFAULT_SCALE_VALUE; const DEFAULT_SCALE = 1.0; exports.DEFAULT_SCALE = DEFAULT_SCALE; +const DEFAULT_SCALE_DELTA = 1.1; +exports.DEFAULT_SCALE_DELTA = DEFAULT_SCALE_DELTA; const MIN_SCALE = 0.1; exports.MIN_SCALE = MIN_SCALE; const MAX_SCALE = 10.0; @@ -3029,6 +72,13 @@ const SCROLLBAR_PADDING = 40; exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING; const VERTICAL_PADDING = 5; exports.VERTICAL_PADDING = VERTICAL_PADDING; +const RenderingStates = { + INITIAL: 0, + RUNNING: 1, + PAUSED: 2, + FINISHED: 3 +}; +exports.RenderingStates = RenderingStates; const PresentationModeState = { UNKNOWN: 0, NORMAL: 1, @@ -3036,6 +86,15 @@ const PresentationModeState = { FULLSCREEN: 3 }; exports.PresentationModeState = PresentationModeState; +const SidebarView = { + UNKNOWN: -1, + NONE: 0, + THUMBS: 1, + OUTLINE: 2, + ATTACHMENTS: 3, + LAYERS: 4 +}; +exports.SidebarView = SidebarView; const RendererType = { CANVAS: "canvas", SVG: "svg" @@ -3051,7 +110,8 @@ const ScrollMode = { UNKNOWN: -1, VERTICAL: 0, HORIZONTAL: 1, - WRAPPED: 2 + WRAPPED: 2, + PAGE: 3 }; exports.ScrollMode = ScrollMode; const SpreadMode = { @@ -3064,46 +124,22 @@ exports.SpreadMode = SpreadMode; const AutoPrintRegExp = /\bprint\s*\(/; exports.AutoPrintRegExp = AutoPrintRegExp; -function formatL10nValue(text, args) { - if (!args) { - return text; +class OutputScale { + constructor() { + const pixelRatio = window.devicePixelRatio || 1; + this.sx = pixelRatio; + this.sy = pixelRatio; + } + + get scaled() { + return this.sx !== 1 || this.sy !== 1; } - return text.replace(/\{\{\s*(\w+)\s*\}\}/g, (all, name) => { - return name in args ? args[name] : "{{" + name + "}}"; - }); } -const NullL10n = { - async getLanguage() { - return "en-us"; - }, +exports.OutputScale = OutputScale; - async getDirection() { - return "ltr"; - }, - - async get(property, args, fallback) { - return formatL10nValue(fallback, args); - }, - - async translate(element) {} - -}; -exports.NullL10n = NullL10n; - -function getOutputScale(ctx) { - const devicePixelRatio = window.devicePixelRatio || 1; - const backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; - const pixelRatio = devicePixelRatio / backingStoreRatio; - return { - sx: pixelRatio, - sy: pixelRatio, - scaled: pixelRatio !== 1 - }; -} - -function scrollIntoView(element, spot, skipOverflowHiddenElements = false) { +function scrollIntoView(element, spot, scrollMatches = false) { let parent = element.offsetParent; if (!parent) { @@ -3114,12 +150,7 @@ function scrollIntoView(element, spot, skipOverflowHiddenElements = false) { let offsetY = element.offsetTop + element.clientTop; let offsetX = element.offsetLeft + element.clientLeft; - while (parent.clientHeight === parent.scrollHeight && parent.clientWidth === parent.scrollWidth || skipOverflowHiddenElements && getComputedStyle(parent).overflow === "hidden") { - if (parent.dataset._scaleY) { - offsetY /= parent.dataset._scaleY; - offsetX /= parent.dataset._scaleX; - } - + while (parent.clientHeight === parent.scrollHeight && parent.clientWidth === parent.scrollWidth || scrollMatches && (parent.classList.contains("markedContent") || getComputedStyle(parent).overflow === "hidden")) { offsetY += parent.offsetTop; offsetX += parent.offsetLeft; parent = parent.offsetParent; @@ -3184,21 +215,33 @@ function watchScroll(viewAreaElement, callback) { } function parseQueryString(query) { - const parts = query.split("&"); - const params = Object.create(null); + const params = new Map(); - for (let i = 0, ii = parts.length; i < ii; ++i) { - const param = parts[i].split("="); - const key = param[0].toLowerCase(); - const value = param.length > 1 ? param[1] : null; - params[decodeURIComponent(key)] = decodeURIComponent(value); + for (const [key, value] of new URLSearchParams(query)) { + params.set(key.toLowerCase(), value); } return params; } -function binarySearchFirstItem(items, condition) { - let minIndex = 0; +const NullCharactersRegExp = /\x00/g; +const InvisibleCharactersRegExp = /[\x01-\x1F]/g; + +function removeNullCharacters(str, replaceInvisible = false) { + if (typeof str !== "string") { + console.error(`The argument must be a string.`); + return str; + } + + if (replaceInvisible) { + str = str.replace(InvisibleCharactersRegExp, " "); + } + + return str.replace(NullCharactersRegExp, ""); +} + +function binarySearchFirstItem(items, condition, start = 0) { + let minIndex = start; let maxIndex = items.length - 1; if (maxIndex < 0 || !condition(items[maxIndex])) { @@ -3317,7 +360,13 @@ function backtrackBeforeAllVisibleElements(index, views, top) { return index; } -function getVisibleElements(scrollEl, views, sortByVisibility = false, horizontal = false) { +function getVisibleElements({ + scrollEl, + views, + sortByVisibility = false, + horizontal = false, + rtl = false +}) { const top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight; const left = scrollEl.scrollLeft, @@ -3329,15 +378,17 @@ function getVisibleElements(scrollEl, views, sortByVisibility = false, horizonta return elementBottom > top; } - function isElementRightAfterViewLeft(view) { + function isElementNextAfterViewHorizontally(view) { const element = view.div; - const elementRight = element.offsetLeft + element.clientLeft + element.clientWidth; - return elementRight > left; + const elementLeft = element.offsetLeft + element.clientLeft; + const elementRight = elementLeft + element.clientWidth; + return rtl ? elementLeft < right : elementRight > left; } const visible = [], + ids = new Set(), numViews = views.length; - let firstVisibleElementInd = numViews === 0 ? 0 : binarySearchFirstItem(views, horizontal ? isElementRightAfterViewLeft : isElementBottomAfterViewTop); + let firstVisibleElementInd = binarySearchFirstItem(views, horizontal ? isElementNextAfterViewHorizontally : isElementBottomAfterViewTop); if (firstVisibleElementInd > 0 && firstVisibleElementInd < numViews && !horizontal) { firstVisibleElementInd = backtrackBeforeAllVisibleElements(firstVisibleElementInd, views, top); @@ -3369,18 +420,22 @@ function getVisibleElements(scrollEl, views, sortByVisibility = false, horizonta const hiddenHeight = Math.max(0, top - currentHeight) + Math.max(0, viewBottom - bottom); const hiddenWidth = Math.max(0, left - currentWidth) + Math.max(0, viewRight - right); - const percent = (viewHeight - hiddenHeight) * (viewWidth - hiddenWidth) * 100 / viewHeight / viewWidth | 0; + const fractionHeight = (viewHeight - hiddenHeight) / viewHeight, + fractionWidth = (viewWidth - hiddenWidth) / viewWidth; + const percent = fractionHeight * fractionWidth * 100 | 0; visible.push({ id: view.id, x: currentWidth, y: currentHeight, view, - percent + percent, + widthPercent: fractionWidth * 100 | 0 }); + ids.add(view.id); } const first = visible[0], - last = visible[visible.length - 1]; + last = visible.at(-1); if (sortByVisibility) { visible.sort(function (a, b) { @@ -3397,7 +452,8 @@ function getVisibleElements(scrollEl, views, sortByVisibility = false, horizonta return { first, last, - views: visible + views: visible, + ids }; } @@ -3405,47 +461,8 @@ function noContextMenuHandler(evt) { evt.preventDefault(); } -function isDataSchema(url) { - let i = 0; - const ii = url.length; - - while (i < ii && url[i].trim() === "") { - i++; - } - - return url.substring(i, i + 5).toLowerCase() === "data:"; -} - -function getPDFFileNameFromURL(url, defaultFilename = "document.pdf") { - if (typeof url !== "string") { - return defaultFilename; - } - - if (isDataSchema(url)) { - console.warn("getPDFFileNameFromURL: " + 'ignoring "data:" URL for performance reasons.'); - return defaultFilename; - } - - const reURI = /^(?:(?:[^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/; - const reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i; - const splitURI = reURI.exec(url); - let suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]); - - if (suggestedFilename) { - suggestedFilename = suggestedFilename[0]; - - if (suggestedFilename.includes("%")) { - try { - suggestedFilename = reFilename.exec(decodeURIComponent(suggestedFilename))[0]; - } catch (ex) {} - } - } - - return suggestedFilename || defaultFilename; -} - function normalizeWheelEventDirection(evt) { - let delta = Math.sqrt(evt.deltaX * evt.deltaX + evt.deltaY * evt.deltaY); + let delta = Math.hypot(evt.deltaX, evt.deltaY); const angle = Math.atan2(evt.deltaY, evt.deltaX); if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) { @@ -3487,6 +504,3848 @@ function isPortraitOrientation(size) { return size.width <= size.height; } +const animationStarted = new Promise(function (resolve) { + window.requestAnimationFrame(resolve); +}); +exports.animationStarted = animationStarted; +const docStyle = document.documentElement.style; +exports.docStyle = docStyle; + +function clamp(v, min, max) { + return Math.min(Math.max(v, min), max); +} + +class ProgressBar { + #classList = null; + #percent = 0; + #visible = true; + + constructor(id) { + if (arguments.length > 1) { + throw new Error("ProgressBar no longer accepts any additional options, " + "please use CSS rules to modify its appearance instead."); + } + + const bar = document.getElementById(id); + this.#classList = bar.classList; + } + + get percent() { + return this.#percent; + } + + set percent(val) { + this.#percent = clamp(val, 0, 100); + + if (isNaN(val)) { + this.#classList.add("indeterminate"); + return; + } + + this.#classList.remove("indeterminate"); + docStyle.setProperty("--progressBar-percent", `${this.#percent}%`); + } + + setWidth(viewer) { + if (!viewer) { + return; + } + + const container = viewer.parentNode; + const scrollbarWidth = container.offsetWidth - viewer.offsetWidth; + + if (scrollbarWidth > 0) { + docStyle.setProperty("--progressBar-end-offset", `${scrollbarWidth}px`); + } + } + + hide() { + if (!this.#visible) { + return; + } + + this.#visible = false; + this.#classList.add("hidden"); + } + + show() { + if (this.#visible) { + return; + } + + this.#visible = true; + this.#classList.remove("hidden"); + } + +} + +exports.ProgressBar = ProgressBar; + +function getActiveOrFocusedElement() { + let curRoot = document; + let curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); + + while (curActiveOrFocused?.shadowRoot) { + curRoot = curActiveOrFocused.shadowRoot; + curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); + } + + return curActiveOrFocused; +} + +function apiPageLayoutToViewerModes(layout) { + let scrollMode = ScrollMode.VERTICAL, + spreadMode = SpreadMode.NONE; + + switch (layout) { + case "SinglePage": + scrollMode = ScrollMode.PAGE; + break; + + case "OneColumn": + break; + + case "TwoPageLeft": + scrollMode = ScrollMode.PAGE; + + case "TwoColumnLeft": + spreadMode = SpreadMode.ODD; + break; + + case "TwoPageRight": + scrollMode = ScrollMode.PAGE; + + case "TwoColumnRight": + spreadMode = SpreadMode.EVEN; + break; + } + + return { + scrollMode, + spreadMode + }; +} + +function apiPageModeToSidebarView(mode) { + switch (mode) { + case "UseNone": + return SidebarView.NONE; + + case "UseThumbs": + return SidebarView.THUMBS; + + case "UseOutlines": + return SidebarView.OUTLINE; + + case "UseAttachments": + return SidebarView.ATTACHMENTS; + + case "UseOC": + return SidebarView.LAYERS; + } + + return SidebarView.NONE; +} + +/***/ }), +/* 2 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.compatibilityParams = exports.OptionKind = exports.AppOptions = void 0; +const compatibilityParams = Object.create(null); +exports.compatibilityParams = compatibilityParams; +{ + const userAgent = navigator.userAgent || ""; + const platform = navigator.platform || ""; + const maxTouchPoints = navigator.maxTouchPoints || 1; + const isAndroid = /Android/.test(userAgent); + const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || platform === "MacIntel" && maxTouchPoints > 1; + + (function checkCanvasSizeLimitation() { + if (isIOS || isAndroid) { + compatibilityParams.maxCanvasPixels = 5242880; + } + })(); +} +const OptionKind = { + VIEWER: 0x02, + API: 0x04, + WORKER: 0x08, + PREFERENCE: 0x80 +}; +exports.OptionKind = OptionKind; +const defaultOptions = { + annotationEditorMode: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + annotationMode: { + value: 2, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + cursorToolOnLoad: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + defaultZoomValue: { + value: "", + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + disableHistory: { + value: false, + kind: OptionKind.VIEWER + }, + disablePageLabels: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + enablePermissions: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + enablePrintAutoRotate: { + value: true, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + enableScripting: { + value: true, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + externalLinkRel: { + value: "noopener noreferrer nofollow", + kind: OptionKind.VIEWER + }, + externalLinkTarget: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + historyUpdateUrl: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + ignoreDestinationZoom: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + imageResourcesPath: { + value: "./images/", + kind: OptionKind.VIEWER + }, + maxCanvasPixels: { + value: 16777216, + kind: OptionKind.VIEWER + }, + forcePageColors: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + pageColorsBackground: { + value: "Canvas", + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + pageColorsForeground: { + value: "CanvasText", + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + pdfBugEnabled: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + printResolution: { + value: 150, + kind: OptionKind.VIEWER + }, + sidebarViewOnLoad: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + scrollModeOnLoad: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + spreadModeOnLoad: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + textLayerMode: { + value: 1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + useOnlyCssZoom: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + viewerCssTheme: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + viewOnLoad: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + cMapPacked: { + value: true, + kind: OptionKind.API + }, + cMapUrl: { + value: "../web/cmaps/", + kind: OptionKind.API + }, + disableAutoFetch: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + disableFontFace: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + disableRange: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + disableStream: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + docBaseUrl: { + value: "", + kind: OptionKind.API + }, + enableXfa: { + value: true, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + fontExtraProperties: { + value: false, + kind: OptionKind.API + }, + isEvalSupported: { + value: true, + kind: OptionKind.API + }, + maxImageSize: { + value: -1, + kind: OptionKind.API + }, + pdfBug: { + value: false, + kind: OptionKind.API + }, + standardFontDataUrl: { + value: "../web/standard_fonts/", + kind: OptionKind.API + }, + verbosity: { + value: 1, + kind: OptionKind.API + }, + workerPort: { + value: null, + kind: OptionKind.WORKER + }, + workerSrc: { + value: "../build/pdf.worker.js", + kind: OptionKind.WORKER + } +}; +{ + defaultOptions.defaultUrl = { + value: "compressed.tracemonkey-pldi-09.pdf", + kind: OptionKind.VIEWER + }; + defaultOptions.disablePreferences = { + value: false, + kind: OptionKind.VIEWER + }; + defaultOptions.locale = { + value: navigator.language || "en-US", + kind: OptionKind.VIEWER + }; + defaultOptions.renderer = { + value: "canvas", + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }; + defaultOptions.sandboxBundleSrc = { + value: "../build/pdf.sandbox.js", + kind: OptionKind.VIEWER + }; +} +const userOptions = Object.create(null); + +class AppOptions { + constructor() { + throw new Error("Cannot initialize AppOptions."); + } + + static get(name) { + const userOption = userOptions[name]; + + if (userOption !== undefined) { + return userOption; + } + + const defaultOption = defaultOptions[name]; + + if (defaultOption !== undefined) { + return compatibilityParams[name] ?? defaultOption.value; + } + + return undefined; + } + + static getAll(kind = null) { + const options = Object.create(null); + + for (const name in defaultOptions) { + const defaultOption = defaultOptions[name]; + + if (kind) { + if ((kind & defaultOption.kind) === 0) { + continue; + } + + if (kind === OptionKind.PREFERENCE) { + const value = defaultOption.value, + valueType = typeof value; + + if (valueType === "boolean" || valueType === "string" || valueType === "number" && Number.isInteger(value)) { + options[name] = value; + continue; + } + + throw new Error(`Invalid type for preference: ${name}`); + } + } + + const userOption = userOptions[name]; + options[name] = userOption !== undefined ? userOption : compatibilityParams[name] ?? defaultOption.value; + } + + return options; + } + + static set(name, value) { + userOptions[name] = value; + } + + static setAll(options) { + for (const name in options) { + userOptions[name] = options[name]; + } + } + + static remove(name) { + delete userOptions[name]; + } + + static _hasUserOptions() { + return Object.keys(userOptions).length > 0; + } + +} + +exports.AppOptions = AppOptions; + +/***/ }), +/* 3 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.SimpleLinkService = exports.PDFLinkService = exports.LinkTarget = void 0; + +var _ui_utils = __webpack_require__(1); + +const DEFAULT_LINK_REL = "noopener noreferrer nofollow"; +const LinkTarget = { + NONE: 0, + SELF: 1, + BLANK: 2, + PARENT: 3, + TOP: 4 +}; +exports.LinkTarget = LinkTarget; + +function addLinkAttributes(link, { + url, + target, + rel, + enabled = true +} = {}) { + if (!url || typeof url !== "string") { + throw new Error('A valid "url" parameter must provided.'); + } + + const urlNullRemoved = (0, _ui_utils.removeNullCharacters)(url); + + if (enabled) { + link.href = link.title = urlNullRemoved; + } else { + link.href = ""; + link.title = `Disabled: ${urlNullRemoved}`; + + link.onclick = () => { + return false; + }; + } + + let targetStr = ""; + + switch (target) { + case LinkTarget.NONE: + break; + + case LinkTarget.SELF: + targetStr = "_self"; + break; + + case LinkTarget.BLANK: + targetStr = "_blank"; + break; + + case LinkTarget.PARENT: + targetStr = "_parent"; + break; + + case LinkTarget.TOP: + targetStr = "_top"; + break; + } + + link.target = targetStr; + link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL; +} + +class PDFLinkService { + #pagesRefCache = new Map(); + + constructor({ + eventBus, + externalLinkTarget = null, + externalLinkRel = null, + ignoreDestinationZoom = false + } = {}) { + this.eventBus = eventBus; + this.externalLinkTarget = externalLinkTarget; + this.externalLinkRel = externalLinkRel; + this.externalLinkEnabled = true; + this._ignoreDestinationZoom = ignoreDestinationZoom; + this.baseUrl = null; + this.pdfDocument = null; + this.pdfViewer = null; + this.pdfHistory = null; + } + + setDocument(pdfDocument, baseUrl = null) { + this.baseUrl = baseUrl; + this.pdfDocument = pdfDocument; + this.#pagesRefCache.clear(); + } + + setViewer(pdfViewer) { + this.pdfViewer = pdfViewer; + } + + setHistory(pdfHistory) { + this.pdfHistory = pdfHistory; + } + + get pagesCount() { + return this.pdfDocument ? this.pdfDocument.numPages : 0; + } + + get page() { + return this.pdfViewer.currentPageNumber; + } + + set page(value) { + this.pdfViewer.currentPageNumber = value; + } + + get rotation() { + return this.pdfViewer.pagesRotation; + } + + set rotation(value) { + this.pdfViewer.pagesRotation = value; + } + + #goToDestinationHelper(rawDest, namedDest = null, explicitDest) { + const destRef = explicitDest[0]; + let pageNumber; + + if (typeof destRef === "object" && destRef !== null) { + pageNumber = this._cachedPageNumber(destRef); + + if (!pageNumber) { + this.pdfDocument.getPageIndex(destRef).then(pageIndex => { + this.cachePageRef(pageIndex + 1, destRef); + this.#goToDestinationHelper(rawDest, namedDest, explicitDest); + }).catch(() => { + console.error(`PDFLinkService.#goToDestinationHelper: "${destRef}" is not ` + `a valid page reference, for dest="${rawDest}".`); + }); + return; + } + } else if (Number.isInteger(destRef)) { + pageNumber = destRef + 1; + } else { + console.error(`PDFLinkService.#goToDestinationHelper: "${destRef}" is not ` + `a valid destination reference, for dest="${rawDest}".`); + return; + } + + if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) { + console.error(`PDFLinkService.#goToDestinationHelper: "${pageNumber}" is not ` + `a valid page number, for dest="${rawDest}".`); + return; + } + + if (this.pdfHistory) { + this.pdfHistory.pushCurrentPosition(); + this.pdfHistory.push({ + namedDest, + explicitDest, + pageNumber + }); + } + + this.pdfViewer.scrollPageIntoView({ + pageNumber, + destArray: explicitDest, + ignoreDestinationZoom: this._ignoreDestinationZoom + }); + } + + async goToDestination(dest) { + if (!this.pdfDocument) { + return; + } + + let namedDest, explicitDest; + + if (typeof dest === "string") { + namedDest = dest; + explicitDest = await this.pdfDocument.getDestination(dest); + } else { + namedDest = null; + explicitDest = await dest; + } + + if (!Array.isArray(explicitDest)) { + console.error(`PDFLinkService.goToDestination: "${explicitDest}" is not ` + `a valid destination array, for dest="${dest}".`); + return; + } + + this.#goToDestinationHelper(dest, namedDest, explicitDest); + } + + goToPage(val) { + if (!this.pdfDocument) { + return; + } + + const pageNumber = typeof val === "string" && this.pdfViewer.pageLabelToPageNumber(val) || val | 0; + + if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { + console.error(`PDFLinkService.goToPage: "${val}" is not a valid page.`); + return; + } + + if (this.pdfHistory) { + this.pdfHistory.pushCurrentPosition(); + this.pdfHistory.pushPage(pageNumber); + } + + this.pdfViewer.scrollPageIntoView({ + pageNumber + }); + } + + addLinkAttributes(link, url, newWindow = false) { + addLinkAttributes(link, { + url, + target: newWindow ? LinkTarget.BLANK : this.externalLinkTarget, + rel: this.externalLinkRel, + enabled: this.externalLinkEnabled + }); + } + + getDestinationHash(dest) { + if (typeof dest === "string") { + if (dest.length > 0) { + return this.getAnchorUrl("#" + escape(dest)); + } + } else if (Array.isArray(dest)) { + const str = JSON.stringify(dest); + + if (str.length > 0) { + return this.getAnchorUrl("#" + escape(str)); + } + } + + return this.getAnchorUrl(""); + } + + getAnchorUrl(anchor) { + return (this.baseUrl || "") + anchor; + } + + setHash(hash) { + if (!this.pdfDocument) { + return; + } + + let pageNumber, dest; + + if (hash.includes("=")) { + const params = (0, _ui_utils.parseQueryString)(hash); + + if (params.has("search")) { + this.eventBus.dispatch("findfromurlhash", { + source: this, + query: params.get("search").replace(/"/g, ""), + phraseSearch: params.get("phrase") === "true" + }); + } + + if (params.has("page")) { + pageNumber = params.get("page") | 0 || 1; + } + + if (params.has("zoom")) { + const zoomArgs = params.get("zoom").split(","); + const zoomArg = zoomArgs[0]; + const zoomArgNumber = parseFloat(zoomArg); + + if (!zoomArg.includes("Fit")) { + dest = [null, { + name: "XYZ" + }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null, zoomArgs.length > 2 ? zoomArgs[2] | 0 : null, zoomArgNumber ? zoomArgNumber / 100 : zoomArg]; + } else { + if (zoomArg === "Fit" || zoomArg === "FitB") { + dest = [null, { + name: zoomArg + }]; + } else if (zoomArg === "FitH" || zoomArg === "FitBH" || zoomArg === "FitV" || zoomArg === "FitBV") { + dest = [null, { + name: zoomArg + }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null]; + } else if (zoomArg === "FitR") { + if (zoomArgs.length !== 5) { + console.error('PDFLinkService.setHash: Not enough parameters for "FitR".'); + } else { + dest = [null, { + name: zoomArg + }, zoomArgs[1] | 0, zoomArgs[2] | 0, zoomArgs[3] | 0, zoomArgs[4] | 0]; + } + } else { + console.error(`PDFLinkService.setHash: "${zoomArg}" is not a valid zoom value.`); + } + } + } + + if (dest) { + this.pdfViewer.scrollPageIntoView({ + pageNumber: pageNumber || this.page, + destArray: dest, + allowNegativeOffset: true + }); + } else if (pageNumber) { + this.page = pageNumber; + } + + if (params.has("pagemode")) { + this.eventBus.dispatch("pagemode", { + source: this, + mode: params.get("pagemode") + }); + } + + if (params.has("nameddest")) { + this.goToDestination(params.get("nameddest")); + } + } else { + dest = unescape(hash); + + try { + dest = JSON.parse(dest); + + if (!Array.isArray(dest)) { + dest = dest.toString(); + } + } catch (ex) {} + + if (typeof dest === "string" || PDFLinkService.#isValidExplicitDestination(dest)) { + this.goToDestination(dest); + return; + } + + console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not a valid destination.`); + } + } + + executeNamedAction(action) { + switch (action) { + case "GoBack": + this.pdfHistory?.back(); + break; + + case "GoForward": + this.pdfHistory?.forward(); + break; + + case "NextPage": + this.pdfViewer.nextPage(); + break; + + case "PrevPage": + this.pdfViewer.previousPage(); + break; + + case "LastPage": + this.page = this.pagesCount; + break; + + case "FirstPage": + this.page = 1; + break; + + default: + break; + } + + this.eventBus.dispatch("namedaction", { + source: this, + action + }); + } + + cachePageRef(pageNum, pageRef) { + if (!pageRef) { + return; + } + + const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; + this.#pagesRefCache.set(refStr, pageNum); + } + + _cachedPageNumber(pageRef) { + if (!pageRef) { + return null; + } + + const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; + return this.#pagesRefCache.get(refStr) || null; + } + + isPageVisible(pageNumber) { + return this.pdfViewer.isPageVisible(pageNumber); + } + + isPageCached(pageNumber) { + return this.pdfViewer.isPageCached(pageNumber); + } + + static #isValidExplicitDestination(dest) { + if (!Array.isArray(dest)) { + return false; + } + + const destLength = dest.length; + + if (destLength < 2) { + return false; + } + + const page = dest[0]; + + if (!(typeof page === "object" && Number.isInteger(page.num) && Number.isInteger(page.gen)) && !(Number.isInteger(page) && page >= 0)) { + return false; + } + + const zoom = dest[1]; + + if (!(typeof zoom === "object" && typeof zoom.name === "string")) { + return false; + } + + let allowNull = true; + + switch (zoom.name) { + case "XYZ": + if (destLength !== 5) { + return false; + } + + break; + + case "Fit": + case "FitB": + return destLength === 2; + + case "FitH": + case "FitBH": + case "FitV": + case "FitBV": + if (destLength !== 3) { + return false; + } + + break; + + case "FitR": + if (destLength !== 6) { + return false; + } + + allowNull = false; + break; + + default: + return false; + } + + for (let i = 2; i < destLength; i++) { + const param = dest[i]; + + if (!(typeof param === "number" || allowNull && param === null)) { + return false; + } + } + + return true; + } + +} + +exports.PDFLinkService = PDFLinkService; + +class SimpleLinkService { + constructor() { + this.externalLinkEnabled = true; + } + + get pagesCount() { + return 0; + } + + get page() { + return 0; + } + + set page(value) {} + + get rotation() { + return 0; + } + + set rotation(value) {} + + async goToDestination(dest) {} + + goToPage(val) {} + + addLinkAttributes(link, url, newWindow = false) { + addLinkAttributes(link, { + url, + enabled: this.externalLinkEnabled + }); + } + + getDestinationHash(dest) { + return "#"; + } + + getAnchorUrl(hash) { + return "#"; + } + + setHash(hash) {} + + executeNamedAction(action) {} + + cachePageRef(pageNum, pageRef) {} + + isPageVisible(pageNumber) { + return true; + } + + isPageCached(pageNumber) { + return true; + } + +} + +exports.SimpleLinkService = SimpleLinkService; + +/***/ }), +/* 4 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFViewerApplication = exports.PDFPrintServiceFactory = exports.DefaultExternalServices = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdfjsLib = __webpack_require__(5); + +var _app_options = __webpack_require__(2); + +var _event_utils = __webpack_require__(6); + +var _pdf_cursor_tools = __webpack_require__(7); + +var _pdf_link_service = __webpack_require__(3); + +var _annotation_editor_params = __webpack_require__(9); + +var _overlay_manager = __webpack_require__(10); + +var _password_prompt = __webpack_require__(11); + +var _pdf_attachment_viewer = __webpack_require__(12); + +var _pdf_document_properties = __webpack_require__(14); + +var _pdf_find_bar = __webpack_require__(15); + +var _pdf_find_controller = __webpack_require__(16); + +var _pdf_history = __webpack_require__(18); + +var _pdf_layer_viewer = __webpack_require__(19); + +var _pdf_outline_viewer = __webpack_require__(20); + +var _pdf_presentation_mode = __webpack_require__(21); + +var _pdf_rendering_queue = __webpack_require__(22); + +var _pdf_scripting_manager = __webpack_require__(23); + +var _pdf_sidebar = __webpack_require__(24); + +var _pdf_sidebar_resizer = __webpack_require__(25); + +var _pdf_thumbnail_viewer = __webpack_require__(26); + +var _pdf_viewer = __webpack_require__(28); + +var _secondary_toolbar = __webpack_require__(39); + +var _toolbar = __webpack_require__(40); + +var _view_history = __webpack_require__(41); + +const DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; +const FORCE_PAGES_LOADED_TIMEOUT = 10000; +const WHEEL_ZOOM_DISABLED_TIMEOUT = 1000; +const ViewOnLoad = { + UNKNOWN: -1, + PREVIOUS: 0, + INITIAL: 1 +}; +const ViewerCssTheme = { + AUTOMATIC: 0, + LIGHT: 1, + DARK: 2 +}; +const KNOWN_VERSIONS = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3"]; +const KNOWN_GENERATORS = ["acrobat distiller", "acrobat pdfwriter", "adobe livecycle", "adobe pdf library", "adobe photoshop", "ghostscript", "tcpdf", "cairo", "dvipdfm", "dvips", "pdftex", "pdfkit", "itext", "prince", "quarkxpress", "mac os x", "microsoft", "openoffice", "oracle", "luradocument", "pdf-xchange", "antenna house", "aspose.cells", "fpdf"]; + +class DefaultExternalServices { + constructor() { + throw new Error("Cannot initialize DefaultExternalServices."); + } + + static updateFindControlState(data) {} + + static updateFindMatchesCount(data) {} + + static initPassiveLoading(callbacks) {} + + static reportTelemetry(data) {} + + static createDownloadManager(options) { + throw new Error("Not implemented: createDownloadManager"); + } + + static createPreferences() { + throw new Error("Not implemented: createPreferences"); + } + + static createL10n(options) { + throw new Error("Not implemented: createL10n"); + } + + static createScripting(options) { + throw new Error("Not implemented: createScripting"); + } + + static get supportsIntegratedFind() { + return (0, _pdfjsLib.shadow)(this, "supportsIntegratedFind", false); + } + + static get supportsDocumentFonts() { + return (0, _pdfjsLib.shadow)(this, "supportsDocumentFonts", true); + } + + static get supportedMouseWheelZoomModifierKeys() { + return (0, _pdfjsLib.shadow)(this, "supportedMouseWheelZoomModifierKeys", { + ctrlKey: true, + metaKey: true + }); + } + + static get isInAutomation() { + return (0, _pdfjsLib.shadow)(this, "isInAutomation", false); + } + + static updateEditorStates(data) { + throw new Error("Not implemented: updateEditorStates"); + } + +} + +exports.DefaultExternalServices = DefaultExternalServices; +const PDFViewerApplication = { + initialBookmark: document.location.hash.substring(1), + _initializedCapability: (0, _pdfjsLib.createPromiseCapability)(), + appConfig: null, + pdfDocument: null, + pdfLoadingTask: null, + printService: null, + pdfViewer: null, + pdfThumbnailViewer: null, + pdfRenderingQueue: null, + pdfPresentationMode: null, + pdfDocumentProperties: null, + pdfLinkService: null, + pdfHistory: null, + pdfSidebar: null, + pdfSidebarResizer: null, + pdfOutlineViewer: null, + pdfAttachmentViewer: null, + pdfLayerViewer: null, + pdfCursorTools: null, + pdfScriptingManager: null, + store: null, + downloadManager: null, + overlayManager: null, + preferences: null, + toolbar: null, + secondaryToolbar: null, + eventBus: null, + l10n: null, + annotationEditorParams: null, + isInitialViewSet: false, + downloadComplete: false, + isViewerEmbedded: window.parent !== window, + url: "", + baseUrl: "", + _downloadUrl: "", + externalServices: DefaultExternalServices, + _boundEvents: Object.create(null), + documentInfo: null, + metadata: null, + _contentDispositionFilename: null, + _contentLength: null, + _saveInProgress: false, + _docStats: null, + _wheelUnusedTicks: 0, + _idleCallbacks: new Set(), + _PDFBug: null, + _hasAnnotationEditors: false, + _title: document.title, + _printAnnotationStoragePromise: null, + + async initialize(appConfig) { + this.preferences = this.externalServices.createPreferences(); + this.appConfig = appConfig; + await this._readPreferences(); + await this._parseHashParameters(); + + this._forceCssTheme(); + + await this._initializeL10n(); + + if (this.isViewerEmbedded && _app_options.AppOptions.get("externalLinkTarget") === _pdf_link_service.LinkTarget.NONE) { + _app_options.AppOptions.set("externalLinkTarget", _pdf_link_service.LinkTarget.TOP); + } + + await this._initializeViewerComponents(); + this.bindEvents(); + this.bindWindowEvents(); + const appContainer = appConfig.appContainer || document.documentElement; + this.l10n.translate(appContainer).then(() => { + this.eventBus.dispatch("localized", { + source: this + }); + }); + + this._initializedCapability.resolve(); + }, + + async _readPreferences() { + if (_app_options.AppOptions.get("disablePreferences")) { + return; + } + + if (_app_options.AppOptions._hasUserOptions()) { + console.warn("_readPreferences: The Preferences may override manually set AppOptions; " + 'please use the "disablePreferences"-option in order to prevent that.'); + } + + try { + _app_options.AppOptions.setAll(await this.preferences.getAll()); + } catch (reason) { + console.error(`_readPreferences: "${reason?.message}".`); + } + }, + + async _parseHashParameters() { + if (!_app_options.AppOptions.get("pdfBugEnabled")) { + return; + } + + const hash = document.location.hash.substring(1); + + if (!hash) { + return; + } + + const { + mainContainer, + viewerContainer + } = this.appConfig, + params = (0, _ui_utils.parseQueryString)(hash); + + if (params.get("disableworker") === "true") { + try { + await loadFakeWorker(); + } catch (ex) { + console.error(`_parseHashParameters: "${ex.message}".`); + } + } + + if (params.has("disablerange")) { + _app_options.AppOptions.set("disableRange", params.get("disablerange") === "true"); + } + + if (params.has("disablestream")) { + _app_options.AppOptions.set("disableStream", params.get("disablestream") === "true"); + } + + if (params.has("disableautofetch")) { + _app_options.AppOptions.set("disableAutoFetch", params.get("disableautofetch") === "true"); + } + + if (params.has("disablefontface")) { + _app_options.AppOptions.set("disableFontFace", params.get("disablefontface") === "true"); + } + + if (params.has("disablehistory")) { + _app_options.AppOptions.set("disableHistory", params.get("disablehistory") === "true"); + } + + if (params.has("verbosity")) { + _app_options.AppOptions.set("verbosity", params.get("verbosity") | 0); + } + + if (params.has("textlayer")) { + switch (params.get("textlayer")) { + case "off": + _app_options.AppOptions.set("textLayerMode", _ui_utils.TextLayerMode.DISABLE); + + break; + + case "visible": + case "shadow": + case "hover": + viewerContainer.classList.add(`textLayer-${params.get("textlayer")}`); + + try { + await loadPDFBug(this); + + this._PDFBug.loadCSS(); + } catch (ex) { + console.error(`_parseHashParameters: "${ex.message}".`); + } + + break; + } + } + + if (params.has("pdfbug")) { + _app_options.AppOptions.set("pdfBug", true); + + _app_options.AppOptions.set("fontExtraProperties", true); + + const enabled = params.get("pdfbug").split(","); + + try { + await loadPDFBug(this); + + this._PDFBug.init({ + OPS: _pdfjsLib.OPS + }, mainContainer, enabled); + } catch (ex) { + console.error(`_parseHashParameters: "${ex.message}".`); + } + } + + if (params.has("locale")) { + _app_options.AppOptions.set("locale", params.get("locale")); + } + }, + + async _initializeL10n() { + this.l10n = this.externalServices.createL10n({ + locale: _app_options.AppOptions.get("locale") + }); + const dir = await this.l10n.getDirection(); + document.getElementsByTagName("html")[0].dir = dir; + }, + + _forceCssTheme() { + const cssTheme = _app_options.AppOptions.get("viewerCssTheme"); + + if (cssTheme === ViewerCssTheme.AUTOMATIC || !Object.values(ViewerCssTheme).includes(cssTheme)) { + return; + } + + try { + const styleSheet = document.styleSheets[0]; + const cssRules = styleSheet?.cssRules || []; + + for (let i = 0, ii = cssRules.length; i < ii; i++) { + const rule = cssRules[i]; + + if (rule instanceof CSSMediaRule && rule.media?.[0] === "(prefers-color-scheme: dark)") { + if (cssTheme === ViewerCssTheme.LIGHT) { + styleSheet.deleteRule(i); + return; + } + + const darkRules = /^@media \(prefers-color-scheme: dark\) {\n\s*([\w\s-.,:;/\\{}()]+)\n}$/.exec(rule.cssText); + + if (darkRules?.[1]) { + styleSheet.deleteRule(i); + styleSheet.insertRule(darkRules[1], i); + } + + return; + } + } + } catch (reason) { + console.error(`_forceCssTheme: "${reason?.message}".`); + } + }, + + async _initializeViewerComponents() { + const { + appConfig, + externalServices + } = this; + const eventBus = externalServices.isInAutomation ? new _event_utils.AutomationEventBus() : new _event_utils.EventBus(); + this.eventBus = eventBus; + this.overlayManager = new _overlay_manager.OverlayManager(); + const pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); + pdfRenderingQueue.onIdle = this._cleanup.bind(this); + this.pdfRenderingQueue = pdfRenderingQueue; + const pdfLinkService = new _pdf_link_service.PDFLinkService({ + eventBus, + externalLinkTarget: _app_options.AppOptions.get("externalLinkTarget"), + externalLinkRel: _app_options.AppOptions.get("externalLinkRel"), + ignoreDestinationZoom: _app_options.AppOptions.get("ignoreDestinationZoom") + }); + this.pdfLinkService = pdfLinkService; + const downloadManager = externalServices.createDownloadManager(); + this.downloadManager = downloadManager; + const findController = new _pdf_find_controller.PDFFindController({ + linkService: pdfLinkService, + eventBus + }); + this.findController = findController; + const pdfScriptingManager = new _pdf_scripting_manager.PDFScriptingManager({ + eventBus, + sandboxBundleSrc: _app_options.AppOptions.get("sandboxBundleSrc"), + scriptingFactory: externalServices, + docPropertiesLookup: this._scriptingDocProperties.bind(this) + }); + this.pdfScriptingManager = pdfScriptingManager; + const container = appConfig.mainContainer, + viewer = appConfig.viewerContainer; + + const annotationEditorMode = _app_options.AppOptions.get("annotationEditorMode"); + + const pageColors = _app_options.AppOptions.get("forcePageColors") || window.matchMedia("(forced-colors: active)").matches ? { + background: _app_options.AppOptions.get("pageColorsBackground"), + foreground: _app_options.AppOptions.get("pageColorsForeground") + } : null; + this.pdfViewer = new _pdf_viewer.PDFViewer({ + container, + viewer, + eventBus, + renderingQueue: pdfRenderingQueue, + linkService: pdfLinkService, + downloadManager, + findController, + scriptingManager: _app_options.AppOptions.get("enableScripting") && pdfScriptingManager, + renderer: _app_options.AppOptions.get("renderer"), + l10n: this.l10n, + textLayerMode: _app_options.AppOptions.get("textLayerMode"), + annotationMode: _app_options.AppOptions.get("annotationMode"), + annotationEditorMode, + imageResourcesPath: _app_options.AppOptions.get("imageResourcesPath"), + enablePrintAutoRotate: _app_options.AppOptions.get("enablePrintAutoRotate"), + useOnlyCssZoom: _app_options.AppOptions.get("useOnlyCssZoom"), + maxCanvasPixels: _app_options.AppOptions.get("maxCanvasPixels"), + enablePermissions: _app_options.AppOptions.get("enablePermissions"), + pageColors + }); + pdfRenderingQueue.setViewer(this.pdfViewer); + pdfLinkService.setViewer(this.pdfViewer); + pdfScriptingManager.setViewer(this.pdfViewer); + this.pdfThumbnailViewer = new _pdf_thumbnail_viewer.PDFThumbnailViewer({ + container: appConfig.sidebar.thumbnailView, + eventBus, + renderingQueue: pdfRenderingQueue, + linkService: pdfLinkService, + l10n: this.l10n, + pageColors + }); + pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer); + + if (!this.isViewerEmbedded && !_app_options.AppOptions.get("disableHistory")) { + this.pdfHistory = new _pdf_history.PDFHistory({ + linkService: pdfLinkService, + eventBus + }); + pdfLinkService.setHistory(this.pdfHistory); + } + + if (!this.supportsIntegratedFind) { + this.findBar = new _pdf_find_bar.PDFFindBar(appConfig.findBar, eventBus, this.l10n); + } + + if (annotationEditorMode !== _pdfjsLib.AnnotationEditorType.DISABLE) { + this.annotationEditorParams = new _annotation_editor_params.AnnotationEditorParams(appConfig.annotationEditorParams, eventBus); + + for (const element of [document.getElementById("editorModeButtons"), document.getElementById("editorModeSeparator")]) { + element.classList.remove("hidden"); + } + } + + this.pdfDocumentProperties = new _pdf_document_properties.PDFDocumentProperties(appConfig.documentProperties, this.overlayManager, eventBus, this.l10n, () => { + return this._docFilename; + }); + this.pdfCursorTools = new _pdf_cursor_tools.PDFCursorTools({ + container, + eventBus, + cursorToolOnLoad: _app_options.AppOptions.get("cursorToolOnLoad") + }); + this.toolbar = new _toolbar.Toolbar(appConfig.toolbar, eventBus, this.l10n); + this.secondaryToolbar = new _secondary_toolbar.SecondaryToolbar(appConfig.secondaryToolbar, eventBus); + + if (this.supportsFullscreen) { + this.pdfPresentationMode = new _pdf_presentation_mode.PDFPresentationMode({ + container, + pdfViewer: this.pdfViewer, + eventBus + }); + } + + this.passwordPrompt = new _password_prompt.PasswordPrompt(appConfig.passwordOverlay, this.overlayManager, this.l10n, this.isViewerEmbedded); + this.pdfOutlineViewer = new _pdf_outline_viewer.PDFOutlineViewer({ + container: appConfig.sidebar.outlineView, + eventBus, + linkService: pdfLinkService + }); + this.pdfAttachmentViewer = new _pdf_attachment_viewer.PDFAttachmentViewer({ + container: appConfig.sidebar.attachmentsView, + eventBus, + downloadManager + }); + this.pdfLayerViewer = new _pdf_layer_viewer.PDFLayerViewer({ + container: appConfig.sidebar.layersView, + eventBus, + l10n: this.l10n + }); + this.pdfSidebar = new _pdf_sidebar.PDFSidebar({ + elements: appConfig.sidebar, + pdfViewer: this.pdfViewer, + pdfThumbnailViewer: this.pdfThumbnailViewer, + eventBus, + l10n: this.l10n + }); + this.pdfSidebar.onToggled = this.forceRendering.bind(this); + this.pdfSidebarResizer = new _pdf_sidebar_resizer.PDFSidebarResizer(appConfig.sidebarResizer, eventBus, this.l10n); + }, + + run(config) { + this.initialize(config).then(webViewerInitialized); + }, + + get initialized() { + return this._initializedCapability.settled; + }, + + get initializedPromise() { + return this._initializedCapability.promise; + }, + + zoomIn(steps) { + if (this.pdfViewer.isInPresentationMode) { + return; + } + + this.pdfViewer.increaseScale(steps); + }, + + zoomOut(steps) { + if (this.pdfViewer.isInPresentationMode) { + return; + } + + this.pdfViewer.decreaseScale(steps); + }, + + zoomReset() { + if (this.pdfViewer.isInPresentationMode) { + return; + } + + this.pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; + }, + + get pagesCount() { + return this.pdfDocument ? this.pdfDocument.numPages : 0; + }, + + get page() { + return this.pdfViewer.currentPageNumber; + }, + + set page(val) { + this.pdfViewer.currentPageNumber = val; + }, + + get supportsPrinting() { + return PDFPrintServiceFactory.instance.supportsPrinting; + }, + + get supportsFullscreen() { + return (0, _pdfjsLib.shadow)(this, "supportsFullscreen", document.fullscreenEnabled); + }, + + get supportsIntegratedFind() { + return this.externalServices.supportsIntegratedFind; + }, + + get supportsDocumentFonts() { + return this.externalServices.supportsDocumentFonts; + }, + + get loadingBar() { + const bar = new _ui_utils.ProgressBar("loadingBar"); + return (0, _pdfjsLib.shadow)(this, "loadingBar", bar); + }, + + get supportedMouseWheelZoomModifierKeys() { + return this.externalServices.supportedMouseWheelZoomModifierKeys; + }, + + initPassiveLoading() { + throw new Error("Not implemented: initPassiveLoading"); + }, + + setTitleUsingUrl(url = "", downloadUrl = null) { + this.url = url; + this.baseUrl = url.split("#")[0]; + + if (downloadUrl) { + this._downloadUrl = downloadUrl === url ? this.baseUrl : downloadUrl.split("#")[0]; + } + + let title = (0, _pdfjsLib.getPdfFilenameFromUrl)(url, ""); + + if (!title) { + try { + title = decodeURIComponent((0, _pdfjsLib.getFilenameFromUrl)(url)) || url; + } catch (ex) { + title = url; + } + } + + this.setTitle(title); + }, + + setTitle(title = this._title) { + this._title = title; + + if (this.isViewerEmbedded) { + return; + } + + document.title = `${this._hasAnnotationEditors ? "* " : ""}${title}`; + }, + + get _docFilename() { + return this._contentDispositionFilename || (0, _pdfjsLib.getPdfFilenameFromUrl)(this.url); + }, + + _hideViewBookmark() { + const { + toolbar, + secondaryToolbar + } = this.appConfig; + toolbar.viewBookmark.hidden = true; + secondaryToolbar.viewBookmarkButton.hidden = true; + }, + + _cancelIdleCallbacks() { + if (!this._idleCallbacks.size) { + return; + } + + for (const callback of this._idleCallbacks) { + window.cancelIdleCallback(callback); + } + + this._idleCallbacks.clear(); + }, + + async close() { + this._unblockDocumentLoadEvent(); + + this._hideViewBookmark(); + + const { + container + } = this.appConfig.errorWrapper; + container.hidden = true; + + if (!this.pdfLoadingTask) { + return; + } + + if (this.pdfDocument?.annotationStorage.size > 0 && this._annotationStorageModified) { + try { + await this.save(); + } catch (reason) {} + } + + const promises = []; + promises.push(this.pdfLoadingTask.destroy()); + this.pdfLoadingTask = null; + + if (this.pdfDocument) { + this.pdfDocument = null; + this.pdfThumbnailViewer.setDocument(null); + this.pdfViewer.setDocument(null); + this.pdfLinkService.setDocument(null); + this.pdfDocumentProperties.setDocument(null); + } + + this.pdfLinkService.externalLinkEnabled = true; + this.store = null; + this.isInitialViewSet = false; + this.downloadComplete = false; + this.url = ""; + this.baseUrl = ""; + this._downloadUrl = ""; + this.documentInfo = null; + this.metadata = null; + this._contentDispositionFilename = null; + this._contentLength = null; + this._saveInProgress = false; + this._docStats = null; + this._hasAnnotationEditors = false; + + this._cancelIdleCallbacks(); + + promises.push(this.pdfScriptingManager.destroyPromise); + this.setTitle(); + this.pdfSidebar.reset(); + this.pdfOutlineViewer.reset(); + this.pdfAttachmentViewer.reset(); + this.pdfLayerViewer.reset(); + this.pdfHistory?.reset(); + this.findBar?.reset(); + this.toolbar.reset(); + this.secondaryToolbar.reset(); + this._PDFBug?.cleanup(); + await Promise.all(promises); + }, + + async open(file, args) { + if (this.pdfLoadingTask) { + await this.close(); + } + + const workerParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.WORKER); + + for (const key in workerParameters) { + _pdfjsLib.GlobalWorkerOptions[key] = workerParameters[key]; + } + + const parameters = Object.create(null); + + if (typeof file === "string") { + this.setTitleUsingUrl(file, file); + parameters.url = file; + } else if (file && "byteLength" in file) { + parameters.data = file; + } else if (file.url && file.originalUrl) { + this.setTitleUsingUrl(file.originalUrl, file.url); + parameters.url = file.url; + } + + const apiParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.API); + + for (const key in apiParameters) { + let value = apiParameters[key]; + + if (key === "docBaseUrl" && !value) {} + + parameters[key] = value; + } + + if (args) { + for (const key in args) { + parameters[key] = args[key]; + } + } + + const loadingTask = (0, _pdfjsLib.getDocument)(parameters); + this.pdfLoadingTask = loadingTask; + + loadingTask.onPassword = (updateCallback, reason) => { + this.pdfLinkService.externalLinkEnabled = false; + this.passwordPrompt.setUpdateCallback(updateCallback, reason); + this.passwordPrompt.open(); + }; + + loadingTask.onProgress = ({ + loaded, + total + }) => { + this.progress(loaded / total); + }; + + loadingTask.onUnsupportedFeature = this.fallback.bind(this); + return loadingTask.promise.then(pdfDocument => { + this.load(pdfDocument); + }, reason => { + if (loadingTask !== this.pdfLoadingTask) { + return undefined; + } + + let key = "loading_error"; + + if (reason instanceof _pdfjsLib.InvalidPDFException) { + key = "invalid_file_error"; + } else if (reason instanceof _pdfjsLib.MissingPDFException) { + key = "missing_file_error"; + } else if (reason instanceof _pdfjsLib.UnexpectedResponseException) { + key = "unexpected_response_error"; + } + + return this.l10n.get(key).then(msg => { + this._documentError(msg, { + message: reason?.message + }); + + throw reason; + }); + }); + }, + + _ensureDownloadComplete() { + if (this.pdfDocument && this.downloadComplete) { + return; + } + + throw new Error("PDF document not downloaded."); + }, + + async download() { + const url = this._downloadUrl, + filename = this._docFilename; + + try { + this._ensureDownloadComplete(); + + const data = await this.pdfDocument.getData(); + const blob = new Blob([data], { + type: "application/pdf" + }); + await this.downloadManager.download(blob, url, filename); + } catch (reason) { + await this.downloadManager.downloadUrl(url, filename); + } + }, + + async save() { + if (this._saveInProgress) { + return; + } + + this._saveInProgress = true; + await this.pdfScriptingManager.dispatchWillSave(); + const url = this._downloadUrl, + filename = this._docFilename; + + try { + this._ensureDownloadComplete(); + + const data = await this.pdfDocument.saveDocument(); + const blob = new Blob([data], { + type: "application/pdf" + }); + await this.downloadManager.download(blob, url, filename); + } catch (reason) { + console.error(`Error when saving the document: ${reason.message}`); + await this.download(); + } finally { + await this.pdfScriptingManager.dispatchDidSave(); + this._saveInProgress = false; + } + + if (this._hasAnnotationEditors) { + this.externalServices.reportTelemetry({ + type: "editing", + data: { + type: "save" + } + }); + } + }, + + downloadOrSave() { + if (this.pdfDocument?.annotationStorage.size > 0) { + this.save(); + } else { + this.download(); + } + }, + + fallback(featureId) { + this.externalServices.reportTelemetry({ + type: "unsupportedFeature", + featureId + }); + }, + + _documentError(message, moreInfo = null) { + this._unblockDocumentLoadEvent(); + + this._otherError(message, moreInfo); + + this.eventBus.dispatch("documenterror", { + source: this, + message, + reason: moreInfo?.message ?? null + }); + }, + + _otherError(message, moreInfo = null) { + const moreInfoText = [this.l10n.get("error_version_info", { + version: _pdfjsLib.version || "?", + build: _pdfjsLib.build || "?" + })]; + + if (moreInfo) { + moreInfoText.push(this.l10n.get("error_message", { + message: moreInfo.message + })); + + if (moreInfo.stack) { + moreInfoText.push(this.l10n.get("error_stack", { + stack: moreInfo.stack + })); + } else { + if (moreInfo.filename) { + moreInfoText.push(this.l10n.get("error_file", { + file: moreInfo.filename + })); + } + + if (moreInfo.lineNumber) { + moreInfoText.push(this.l10n.get("error_line", { + line: moreInfo.lineNumber + })); + } + } + } + + const errorWrapperConfig = this.appConfig.errorWrapper; + const errorWrapper = errorWrapperConfig.container; + errorWrapper.hidden = false; + const errorMessage = errorWrapperConfig.errorMessage; + errorMessage.textContent = message; + const closeButton = errorWrapperConfig.closeButton; + + closeButton.onclick = function () { + errorWrapper.hidden = true; + }; + + const errorMoreInfo = errorWrapperConfig.errorMoreInfo; + const moreInfoButton = errorWrapperConfig.moreInfoButton; + const lessInfoButton = errorWrapperConfig.lessInfoButton; + + moreInfoButton.onclick = function () { + errorMoreInfo.hidden = false; + moreInfoButton.hidden = true; + lessInfoButton.hidden = false; + errorMoreInfo.style.height = errorMoreInfo.scrollHeight + "px"; + }; + + lessInfoButton.onclick = function () { + errorMoreInfo.hidden = true; + moreInfoButton.hidden = false; + lessInfoButton.hidden = true; + }; + + moreInfoButton.oncontextmenu = _ui_utils.noContextMenuHandler; + lessInfoButton.oncontextmenu = _ui_utils.noContextMenuHandler; + closeButton.oncontextmenu = _ui_utils.noContextMenuHandler; + moreInfoButton.hidden = false; + lessInfoButton.hidden = true; + Promise.all(moreInfoText).then(parts => { + errorMoreInfo.value = parts.join("\n"); + }); + }, + + progress(level) { + if (this.downloadComplete) { + return; + } + + const percent = Math.round(level * 100); + + if (percent <= this.loadingBar.percent) { + return; + } + + this.loadingBar.percent = percent; + + const disableAutoFetch = this.pdfDocument?.loadingParams.disableAutoFetch ?? _app_options.AppOptions.get("disableAutoFetch"); + + if (!disableAutoFetch || isNaN(percent)) { + return; + } + + if (this.disableAutoFetchLoadingBarTimeout) { + clearTimeout(this.disableAutoFetchLoadingBarTimeout); + this.disableAutoFetchLoadingBarTimeout = null; + } + + this.loadingBar.show(); + this.disableAutoFetchLoadingBarTimeout = setTimeout(() => { + this.loadingBar.hide(); + this.disableAutoFetchLoadingBarTimeout = null; + }, DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT); + }, + + load(pdfDocument) { + this.pdfDocument = pdfDocument; + pdfDocument.getDownloadInfo().then(({ + length + }) => { + this._contentLength = length; + this.downloadComplete = true; + this.loadingBar.hide(); + firstPagePromise.then(() => { + this.eventBus.dispatch("documentloaded", { + source: this + }); + }); + }); + const pageLayoutPromise = pdfDocument.getPageLayout().catch(function () {}); + const pageModePromise = pdfDocument.getPageMode().catch(function () {}); + const openActionPromise = pdfDocument.getOpenAction().catch(function () {}); + this.toolbar.setPagesCount(pdfDocument.numPages, false); + this.secondaryToolbar.setPagesCount(pdfDocument.numPages); + let baseDocumentUrl; + baseDocumentUrl = null; + this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl); + this.pdfDocumentProperties.setDocument(pdfDocument); + const pdfViewer = this.pdfViewer; + pdfViewer.setDocument(pdfDocument); + const { + firstPagePromise, + onePageRendered, + pagesPromise + } = pdfViewer; + const pdfThumbnailViewer = this.pdfThumbnailViewer; + pdfThumbnailViewer.setDocument(pdfDocument); + const storedPromise = (this.store = new _view_history.ViewHistory(pdfDocument.fingerprints[0])).getMultiple({ + page: null, + zoom: _ui_utils.DEFAULT_SCALE_VALUE, + scrollLeft: "0", + scrollTop: "0", + rotation: null, + sidebarView: _ui_utils.SidebarView.UNKNOWN, + scrollMode: _ui_utils.ScrollMode.UNKNOWN, + spreadMode: _ui_utils.SpreadMode.UNKNOWN + }).catch(() => { + return Object.create(null); + }); + firstPagePromise.then(pdfPage => { + this.loadingBar.setWidth(this.appConfig.viewerContainer); + + this._initializeAnnotationStorageCallbacks(pdfDocument); + + Promise.all([_ui_utils.animationStarted, storedPromise, pageLayoutPromise, pageModePromise, openActionPromise]).then(async ([timeStamp, stored, pageLayout, pageMode, openAction]) => { + const viewOnLoad = _app_options.AppOptions.get("viewOnLoad"); + + this._initializePdfHistory({ + fingerprint: pdfDocument.fingerprints[0], + viewOnLoad, + initialDest: openAction?.dest + }); + + const initialBookmark = this.initialBookmark; + + const zoom = _app_options.AppOptions.get("defaultZoomValue"); + + let hash = zoom ? `zoom=${zoom}` : null; + let rotation = null; + + let sidebarView = _app_options.AppOptions.get("sidebarViewOnLoad"); + + let scrollMode = _app_options.AppOptions.get("scrollModeOnLoad"); + + let spreadMode = _app_options.AppOptions.get("spreadModeOnLoad"); + + if (stored.page && viewOnLoad !== ViewOnLoad.INITIAL) { + hash = `page=${stored.page}&zoom=${zoom || stored.zoom},` + `${stored.scrollLeft},${stored.scrollTop}`; + rotation = parseInt(stored.rotation, 10); + + if (sidebarView === _ui_utils.SidebarView.UNKNOWN) { + sidebarView = stored.sidebarView | 0; + } + + if (scrollMode === _ui_utils.ScrollMode.UNKNOWN) { + scrollMode = stored.scrollMode | 0; + } + + if (spreadMode === _ui_utils.SpreadMode.UNKNOWN) { + spreadMode = stored.spreadMode | 0; + } + } + + if (pageMode && sidebarView === _ui_utils.SidebarView.UNKNOWN) { + sidebarView = (0, _ui_utils.apiPageModeToSidebarView)(pageMode); + } + + if (pageLayout && scrollMode === _ui_utils.ScrollMode.UNKNOWN && spreadMode === _ui_utils.SpreadMode.UNKNOWN) { + const modes = (0, _ui_utils.apiPageLayoutToViewerModes)(pageLayout); + spreadMode = modes.spreadMode; + } + + this.setInitialView(hash, { + rotation, + sidebarView, + scrollMode, + spreadMode + }); + this.eventBus.dispatch("documentinit", { + source: this + }); + + if (!this.isViewerEmbedded) { + pdfViewer.focus(); + } + + await Promise.race([pagesPromise, new Promise(resolve => { + setTimeout(resolve, FORCE_PAGES_LOADED_TIMEOUT); + })]); + + if (!initialBookmark && !hash) { + return; + } + + if (pdfViewer.hasEqualPageSizes) { + return; + } + + this.initialBookmark = initialBookmark; + pdfViewer.currentScaleValue = pdfViewer.currentScaleValue; + this.setInitialView(hash); + }).catch(() => { + this.setInitialView(); + }).then(function () { + pdfViewer.update(); + }); + }); + pagesPromise.then(() => { + this._unblockDocumentLoadEvent(); + + this._initializeAutoPrint(pdfDocument, openActionPromise); + }, reason => { + this.l10n.get("loading_error").then(msg => { + this._documentError(msg, { + message: reason?.message + }); + }); + }); + onePageRendered.then(data => { + this.externalServices.reportTelemetry({ + type: "pageInfo", + timestamp: data.timestamp + }); + pdfDocument.getOutline().then(outline => { + if (pdfDocument !== this.pdfDocument) { + return; + } + + this.pdfOutlineViewer.render({ + outline, + pdfDocument + }); + }); + pdfDocument.getAttachments().then(attachments => { + if (pdfDocument !== this.pdfDocument) { + return; + } + + this.pdfAttachmentViewer.render({ + attachments + }); + }); + pdfViewer.optionalContentConfigPromise.then(optionalContentConfig => { + if (pdfDocument !== this.pdfDocument) { + return; + } + + this.pdfLayerViewer.render({ + optionalContentConfig, + pdfDocument + }); + }); + + if ("requestIdleCallback" in window) { + const callback = window.requestIdleCallback(() => { + this._collectTelemetry(pdfDocument); + + this._idleCallbacks.delete(callback); + }, { + timeout: 1000 + }); + + this._idleCallbacks.add(callback); + } + }); + + this._initializePageLabels(pdfDocument); + + this._initializeMetadata(pdfDocument); + }, + + async _scriptingDocProperties(pdfDocument) { + if (!this.documentInfo) { + await new Promise(resolve => { + this.eventBus._on("metadataloaded", resolve, { + once: true + }); + }); + + if (pdfDocument !== this.pdfDocument) { + return null; + } + } + + if (!this._contentLength) { + await new Promise(resolve => { + this.eventBus._on("documentloaded", resolve, { + once: true + }); + }); + + if (pdfDocument !== this.pdfDocument) { + return null; + } + } + + return { ...this.documentInfo, + baseURL: this.baseUrl, + filesize: this._contentLength, + filename: this._docFilename, + metadata: this.metadata?.getRaw(), + authors: this.metadata?.get("dc:creator"), + numPages: this.pagesCount, + URL: this.url + }; + }, + + async _collectTelemetry(pdfDocument) { + const markInfo = await this.pdfDocument.getMarkInfo(); + + if (pdfDocument !== this.pdfDocument) { + return; + } + + const tagged = markInfo?.Marked || false; + this.externalServices.reportTelemetry({ + type: "tagged", + tagged + }); + }, + + async _initializeAutoPrint(pdfDocument, openActionPromise) { + const [openAction, javaScript] = await Promise.all([openActionPromise, !this.pdfViewer.enableScripting ? pdfDocument.getJavaScript() : null]); + + if (pdfDocument !== this.pdfDocument) { + return; + } + + let triggerAutoPrint = false; + + if (openAction?.action === "Print") { + triggerAutoPrint = true; + } + + if (javaScript) { + javaScript.some(js => { + if (!js) { + return false; + } + + console.warn("Warning: JavaScript support is not enabled"); + this.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.javaScript); + return true; + }); + + if (!triggerAutoPrint) { + for (const js of javaScript) { + if (js && _ui_utils.AutoPrintRegExp.test(js)) { + triggerAutoPrint = true; + break; + } + } + } + } + + if (triggerAutoPrint) { + this.triggerPrinting(); + } + }, + + async _initializeMetadata(pdfDocument) { + const { + info, + metadata, + contentDispositionFilename, + contentLength + } = await pdfDocument.getMetadata(); + + if (pdfDocument !== this.pdfDocument) { + return; + } + + this.documentInfo = info; + this.metadata = metadata; + this._contentDispositionFilename ??= contentDispositionFilename; + this._contentLength ??= contentLength; + console.log(`PDF ${pdfDocument.fingerprints[0]} [${info.PDFFormatVersion} ` + `${(info.Producer || "-").trim()} / ${(info.Creator || "-").trim()}] ` + `(PDF.js: ${_pdfjsLib.version || "-"})`); + let pdfTitle = info.Title; + const metadataTitle = metadata?.get("dc:title"); + + if (metadataTitle) { + if (metadataTitle !== "Untitled" && !/[\uFFF0-\uFFFF]/g.test(metadataTitle)) { + pdfTitle = metadataTitle; + } + } + + if (pdfTitle) { + this.setTitle(`${pdfTitle} - ${this._contentDispositionFilename || this._title}`); + } else if (this._contentDispositionFilename) { + this.setTitle(this._contentDispositionFilename); + } + + if (info.IsXFAPresent && !info.IsAcroFormPresent && !pdfDocument.isPureXfa) { + if (pdfDocument.loadingParams.enableXfa) { + console.warn("Warning: XFA Foreground documents are not supported"); + } else { + console.warn("Warning: XFA support is not enabled"); + } + + this.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.forms); + } else if ((info.IsAcroFormPresent || info.IsXFAPresent) && !this.pdfViewer.renderForms) { + console.warn("Warning: Interactive form support is not enabled"); + this.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.forms); + } + + if (info.IsSignaturesPresent) { + console.warn("Warning: Digital signatures validation is not supported"); + this.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.signatures); + } + + let versionId = "other"; + + if (KNOWN_VERSIONS.includes(info.PDFFormatVersion)) { + versionId = `v${info.PDFFormatVersion.replace(".", "_")}`; + } + + let generatorId = "other"; + + if (info.Producer) { + const producer = info.Producer.toLowerCase(); + KNOWN_GENERATORS.some(function (generator) { + if (!producer.includes(generator)) { + return false; + } + + generatorId = generator.replace(/[ .-]/g, "_"); + return true; + }); + } + + let formType = null; + + if (info.IsXFAPresent) { + formType = "xfa"; + } else if (info.IsAcroFormPresent) { + formType = "acroform"; + } + + this.externalServices.reportTelemetry({ + type: "documentInfo", + version: versionId, + generator: generatorId, + formType + }); + this.eventBus.dispatch("metadataloaded", { + source: this + }); + }, + + async _initializePageLabels(pdfDocument) { + const labels = await pdfDocument.getPageLabels(); + + if (pdfDocument !== this.pdfDocument) { + return; + } + + if (!labels || _app_options.AppOptions.get("disablePageLabels")) { + return; + } + + const numLabels = labels.length; + let standardLabels = 0, + emptyLabels = 0; + + for (let i = 0; i < numLabels; i++) { + const label = labels[i]; + + if (label === (i + 1).toString()) { + standardLabels++; + } else if (label === "") { + emptyLabels++; + } else { + break; + } + } + + if (standardLabels >= numLabels || emptyLabels >= numLabels) { + return; + } + + const { + pdfViewer, + pdfThumbnailViewer, + toolbar + } = this; + pdfViewer.setPageLabels(labels); + pdfThumbnailViewer.setPageLabels(labels); + toolbar.setPagesCount(numLabels, true); + toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); + }, + + _initializePdfHistory({ + fingerprint, + viewOnLoad, + initialDest = null + }) { + if (!this.pdfHistory) { + return; + } + + this.pdfHistory.initialize({ + fingerprint, + resetHistory: viewOnLoad === ViewOnLoad.INITIAL, + updateUrl: _app_options.AppOptions.get("historyUpdateUrl") + }); + + if (this.pdfHistory.initialBookmark) { + this.initialBookmark = this.pdfHistory.initialBookmark; + this.initialRotation = this.pdfHistory.initialRotation; + } + + if (initialDest && !this.initialBookmark && viewOnLoad === ViewOnLoad.UNKNOWN) { + this.initialBookmark = JSON.stringify(initialDest); + this.pdfHistory.push({ + explicitDest: initialDest, + pageNumber: null + }); + } + }, + + _initializeAnnotationStorageCallbacks(pdfDocument) { + if (pdfDocument !== this.pdfDocument) { + return; + } + + const { + annotationStorage + } = pdfDocument; + + annotationStorage.onSetModified = () => { + window.addEventListener("beforeunload", beforeUnload); + this._annotationStorageModified = true; + }; + + annotationStorage.onResetModified = () => { + window.removeEventListener("beforeunload", beforeUnload); + delete this._annotationStorageModified; + }; + + annotationStorage.onAnnotationEditor = typeStr => { + this._hasAnnotationEditors = !!typeStr; + this.setTitle(); + + if (typeStr) { + this.externalServices.reportTelemetry({ + type: "editing", + data: { + type: typeStr + } + }); + } + }; + }, + + setInitialView(storedHash, { + rotation, + sidebarView, + scrollMode, + spreadMode + } = {}) { + const setRotation = angle => { + if ((0, _ui_utils.isValidRotation)(angle)) { + this.pdfViewer.pagesRotation = angle; + } + }; + + const setViewerModes = (scroll, spread) => { + if ((0, _ui_utils.isValidScrollMode)(scroll)) { + this.pdfViewer.scrollMode = scroll; + } + + if ((0, _ui_utils.isValidSpreadMode)(spread)) { + this.pdfViewer.spreadMode = spread; + } + }; + + this.isInitialViewSet = true; + this.pdfSidebar.setInitialView(sidebarView); + setViewerModes(scrollMode, spreadMode); + + if (this.initialBookmark) { + setRotation(this.initialRotation); + delete this.initialRotation; + this.pdfLinkService.setHash(this.initialBookmark); + this.initialBookmark = null; + } else if (storedHash) { + setRotation(rotation); + this.pdfLinkService.setHash(storedHash); + } + + this.toolbar.setPageNumber(this.pdfViewer.currentPageNumber, this.pdfViewer.currentPageLabel); + this.secondaryToolbar.setPageNumber(this.pdfViewer.currentPageNumber); + + if (!this.pdfViewer.currentScaleValue) { + this.pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; + } + }, + + _cleanup() { + if (!this.pdfDocument) { + return; + } + + this.pdfViewer.cleanup(); + this.pdfThumbnailViewer.cleanup(); + this.pdfDocument.cleanup(this.pdfViewer.renderer === _ui_utils.RendererType.SVG); + }, + + forceRendering() { + this.pdfRenderingQueue.printing = !!this.printService; + this.pdfRenderingQueue.isThumbnailViewEnabled = this.pdfSidebar.visibleView === _ui_utils.SidebarView.THUMBS; + this.pdfRenderingQueue.renderHighestPriority(); + }, + + beforePrint() { + this._printAnnotationStoragePromise = this.pdfScriptingManager.dispatchWillPrint().catch(() => {}).then(() => { + return this.pdfDocument?.annotationStorage.print; + }); + + if (this.printService) { + return; + } + + if (!this.supportsPrinting) { + this.l10n.get("printing_not_supported").then(msg => { + this._otherError(msg); + }); + return; + } + + if (!this.pdfViewer.pageViewsReady) { + this.l10n.get("printing_not_ready").then(msg => { + window.alert(msg); + }); + return; + } + + const pagesOverview = this.pdfViewer.getPagesOverview(); + const printContainer = this.appConfig.printContainer; + + const printResolution = _app_options.AppOptions.get("printResolution"); + + const optionalContentConfigPromise = this.pdfViewer.optionalContentConfigPromise; + const printService = PDFPrintServiceFactory.instance.createPrintService(this.pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, this._printAnnotationStoragePromise, this.l10n); + this.printService = printService; + this.forceRendering(); + printService.layout(); + this.externalServices.reportTelemetry({ + type: "print" + }); + + if (this._hasAnnotationEditors) { + this.externalServices.reportTelemetry({ + type: "editing", + data: { + type: "print" + } + }); + } + }, + + afterPrint() { + if (this._printAnnotationStoragePromise) { + this._printAnnotationStoragePromise.then(() => { + this.pdfScriptingManager.dispatchDidPrint(); + }); + + this._printAnnotationStoragePromise = null; + } + + if (this.printService) { + this.printService.destroy(); + this.printService = null; + this.pdfDocument?.annotationStorage.resetModified(); + } + + this.forceRendering(); + }, + + rotatePages(delta) { + this.pdfViewer.pagesRotation += delta; + }, + + requestPresentationMode() { + this.pdfPresentationMode?.request(); + }, + + triggerPrinting() { + if (!this.supportsPrinting) { + return; + } + + window.print(); + }, + + bindEvents() { + const { + eventBus, + _boundEvents + } = this; + _boundEvents.beforePrint = this.beforePrint.bind(this); + _boundEvents.afterPrint = this.afterPrint.bind(this); + + eventBus._on("resize", webViewerResize); + + eventBus._on("hashchange", webViewerHashchange); + + eventBus._on("beforeprint", _boundEvents.beforePrint); + + eventBus._on("afterprint", _boundEvents.afterPrint); + + eventBus._on("pagerendered", webViewerPageRendered); + + eventBus._on("updateviewarea", webViewerUpdateViewarea); + + eventBus._on("pagechanging", webViewerPageChanging); + + eventBus._on("scalechanging", webViewerScaleChanging); + + eventBus._on("rotationchanging", webViewerRotationChanging); + + eventBus._on("sidebarviewchanged", webViewerSidebarViewChanged); + + eventBus._on("pagemode", webViewerPageMode); + + eventBus._on("namedaction", webViewerNamedAction); + + eventBus._on("presentationmodechanged", webViewerPresentationModeChanged); + + eventBus._on("presentationmode", webViewerPresentationMode); + + eventBus._on("switchannotationeditormode", webViewerSwitchAnnotationEditorMode); + + eventBus._on("switchannotationeditorparams", webViewerSwitchAnnotationEditorParams); + + eventBus._on("print", webViewerPrint); + + eventBus._on("download", webViewerDownload); + + eventBus._on("firstpage", webViewerFirstPage); + + eventBus._on("lastpage", webViewerLastPage); + + eventBus._on("nextpage", webViewerNextPage); + + eventBus._on("previouspage", webViewerPreviousPage); + + eventBus._on("zoomin", webViewerZoomIn); + + eventBus._on("zoomout", webViewerZoomOut); + + eventBus._on("zoomreset", webViewerZoomReset); + + eventBus._on("pagenumberchanged", webViewerPageNumberChanged); + + eventBus._on("scalechanged", webViewerScaleChanged); + + eventBus._on("rotatecw", webViewerRotateCw); + + eventBus._on("rotateccw", webViewerRotateCcw); + + eventBus._on("optionalcontentconfig", webViewerOptionalContentConfig); + + eventBus._on("switchscrollmode", webViewerSwitchScrollMode); + + eventBus._on("scrollmodechanged", webViewerScrollModeChanged); + + eventBus._on("switchspreadmode", webViewerSwitchSpreadMode); + + eventBus._on("spreadmodechanged", webViewerSpreadModeChanged); + + eventBus._on("documentproperties", webViewerDocumentProperties); + + eventBus._on("findfromurlhash", webViewerFindFromUrlHash); + + eventBus._on("updatefindmatchescount", webViewerUpdateFindMatchesCount); + + eventBus._on("updatefindcontrolstate", webViewerUpdateFindControlState); + + if (_app_options.AppOptions.get("pdfBug")) { + _boundEvents.reportPageStatsPDFBug = reportPageStatsPDFBug; + + eventBus._on("pagerendered", _boundEvents.reportPageStatsPDFBug); + + eventBus._on("pagechanging", _boundEvents.reportPageStatsPDFBug); + } + + // eventBus._on("fileinputchange", webViewerFileInputChange); + + // eventBus._on("openfile", webViewerOpenFile); + }, + + bindWindowEvents() { + const { + eventBus, + _boundEvents + } = this; + + function addWindowResolutionChange(evt = null) { + if (evt) { + webViewerResolutionChange(evt); + } + + const mediaQueryList = window.matchMedia(`(resolution: ${window.devicePixelRatio || 1}dppx)`); + mediaQueryList.addEventListener("change", addWindowResolutionChange, { + once: true + }); + + _boundEvents.removeWindowResolutionChange ||= function () { + mediaQueryList.removeEventListener("change", addWindowResolutionChange); + _boundEvents.removeWindowResolutionChange = null; + }; + } + + addWindowResolutionChange(); + + _boundEvents.windowResize = () => { + eventBus.dispatch("resize", { + source: window + }); + }; + + _boundEvents.windowHashChange = () => { + eventBus.dispatch("hashchange", { + source: window, + hash: document.location.hash.substring(1) + }); + }; + + _boundEvents.windowBeforePrint = () => { + eventBus.dispatch("beforeprint", { + source: window + }); + }; + + _boundEvents.windowAfterPrint = () => { + eventBus.dispatch("afterprint", { + source: window + }); + }; + + _boundEvents.windowUpdateFromSandbox = event => { + eventBus.dispatch("updatefromsandbox", { + source: window, + detail: event.detail + }); + }; + + window.addEventListener("visibilitychange", webViewerVisibilityChange); + window.addEventListener("wheel", webViewerWheel, { + passive: false + }); + window.addEventListener("touchstart", webViewerTouchStart, { + passive: false + }); + window.addEventListener("click", webViewerClick); + window.addEventListener("keydown", webViewerKeyDown); + window.addEventListener("resize", _boundEvents.windowResize); + window.addEventListener("hashchange", _boundEvents.windowHashChange); + window.addEventListener("beforeprint", _boundEvents.windowBeforePrint); + window.addEventListener("afterprint", _boundEvents.windowAfterPrint); + window.addEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); + }, + + unbindEvents() { + const { + eventBus, + _boundEvents + } = this; + + eventBus._off("resize", webViewerResize); + + eventBus._off("hashchange", webViewerHashchange); + + eventBus._off("beforeprint", _boundEvents.beforePrint); + + eventBus._off("afterprint", _boundEvents.afterPrint); + + eventBus._off("pagerendered", webViewerPageRendered); + + eventBus._off("updateviewarea", webViewerUpdateViewarea); + + eventBus._off("pagechanging", webViewerPageChanging); + + eventBus._off("scalechanging", webViewerScaleChanging); + + eventBus._off("rotationchanging", webViewerRotationChanging); + + eventBus._off("sidebarviewchanged", webViewerSidebarViewChanged); + + eventBus._off("pagemode", webViewerPageMode); + + eventBus._off("namedaction", webViewerNamedAction); + + eventBus._off("presentationmodechanged", webViewerPresentationModeChanged); + + eventBus._off("presentationmode", webViewerPresentationMode); + + eventBus._off("print", webViewerPrint); + + eventBus._off("download", webViewerDownload); + + eventBus._off("firstpage", webViewerFirstPage); + + eventBus._off("lastpage", webViewerLastPage); + + eventBus._off("nextpage", webViewerNextPage); + + eventBus._off("previouspage", webViewerPreviousPage); + + eventBus._off("zoomin", webViewerZoomIn); + + eventBus._off("zoomout", webViewerZoomOut); + + eventBus._off("zoomreset", webViewerZoomReset); + + eventBus._off("pagenumberchanged", webViewerPageNumberChanged); + + eventBus._off("scalechanged", webViewerScaleChanged); + + eventBus._off("rotatecw", webViewerRotateCw); + + eventBus._off("rotateccw", webViewerRotateCcw); + + eventBus._off("optionalcontentconfig", webViewerOptionalContentConfig); + + eventBus._off("switchscrollmode", webViewerSwitchScrollMode); + + eventBus._off("scrollmodechanged", webViewerScrollModeChanged); + + eventBus._off("switchspreadmode", webViewerSwitchSpreadMode); + + eventBus._off("spreadmodechanged", webViewerSpreadModeChanged); + + eventBus._off("documentproperties", webViewerDocumentProperties); + + eventBus._off("findfromurlhash", webViewerFindFromUrlHash); + + eventBus._off("updatefindmatchescount", webViewerUpdateFindMatchesCount); + + eventBus._off("updatefindcontrolstate", webViewerUpdateFindControlState); + + if (_boundEvents.reportPageStatsPDFBug) { + eventBus._off("pagerendered", _boundEvents.reportPageStatsPDFBug); + + eventBus._off("pagechanging", _boundEvents.reportPageStatsPDFBug); + + _boundEvents.reportPageStatsPDFBug = null; + } + + eventBus._off("fileinputchange", webViewerFileInputChange); + + eventBus._off("openfile", webViewerOpenFile); + + _boundEvents.beforePrint = null; + _boundEvents.afterPrint = null; + }, + + unbindWindowEvents() { + const { + _boundEvents + } = this; + window.removeEventListener("visibilitychange", webViewerVisibilityChange); + window.removeEventListener("wheel", webViewerWheel, { + passive: false + }); + window.removeEventListener("touchstart", webViewerTouchStart, { + passive: false + }); + window.removeEventListener("click", webViewerClick); + window.removeEventListener("keydown", webViewerKeyDown); + window.removeEventListener("resize", _boundEvents.windowResize); + window.removeEventListener("hashchange", _boundEvents.windowHashChange); + window.removeEventListener("beforeprint", _boundEvents.windowBeforePrint); + window.removeEventListener("afterprint", _boundEvents.windowAfterPrint); + window.removeEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); + _boundEvents.removeWindowResolutionChange?.(); + _boundEvents.windowResize = null; + _boundEvents.windowHashChange = null; + _boundEvents.windowBeforePrint = null; + _boundEvents.windowAfterPrint = null; + _boundEvents.windowUpdateFromSandbox = null; + }, + + accumulateWheelTicks(ticks) { + if (this._wheelUnusedTicks > 0 && ticks < 0 || this._wheelUnusedTicks < 0 && ticks > 0) { + this._wheelUnusedTicks = 0; + } + + this._wheelUnusedTicks += ticks; + const wholeTicks = Math.sign(this._wheelUnusedTicks) * Math.floor(Math.abs(this._wheelUnusedTicks)); + this._wheelUnusedTicks -= wholeTicks; + return wholeTicks; + }, + + _unblockDocumentLoadEvent() { + document.blockUnblockOnload?.(false); + + this._unblockDocumentLoadEvent = () => {}; + }, + + _reportDocumentStatsTelemetry() { + const { + stats + } = this.pdfDocument; + + if (stats !== this._docStats) { + this._docStats = stats; + this.externalServices.reportTelemetry({ + type: "documentStats", + stats + }); + } + }, + + get scriptingReady() { + return this.pdfScriptingManager.ready; + } + +}; +exports.PDFViewerApplication = PDFViewerApplication; +let validateFileURL; +{ + const HOSTED_VIEWER_ORIGINS = ["null", "http://mozilla.github.io", "https://mozilla.github.io"]; + + validateFileURL = function (file) { + if (!file) { + return; + } + + try { + const viewerOrigin = new URL(window.location.href).origin || "null"; + + if (HOSTED_VIEWER_ORIGINS.includes(viewerOrigin)) { + return; + } + + const fileOrigin = new URL(file, window.location.href).origin; + + if (fileOrigin !== viewerOrigin) { + throw new Error("file origin does not match viewer's"); + } + } catch (ex) { + PDFViewerApplication.l10n.get("loading_error").then(msg => { + PDFViewerApplication._documentError(msg, { + message: ex?.message + }); + }); + throw ex; + } + }; +} + +async function loadFakeWorker() { + _pdfjsLib.GlobalWorkerOptions.workerSrc ||= _app_options.AppOptions.get("workerSrc"); + await (0, _pdfjsLib.loadScript)(_pdfjsLib.PDFWorker.workerSrc); +} + +async function loadPDFBug(self) { + const { + debuggerScriptPath + } = self.appConfig; + const { + PDFBug + } = await import(debuggerScriptPath); + self._PDFBug = PDFBug; +} + +function reportPageStatsPDFBug({ + pageNumber +}) { + if (!globalThis.Stats?.enabled) { + return; + } + + const pageView = PDFViewerApplication.pdfViewer.getPageView(pageNumber - 1); + globalThis.Stats.add(pageNumber, pageView?.pdfPage?.stats); +} + +function webViewerInitialized() { + const { + appConfig, + eventBus + } = PDFViewerApplication; + let file; + const queryString = document.location.search.substring(1); + const params = (0, _ui_utils.parseQueryString)(queryString); + file = params.get("file") ?? _app_options.AppOptions.get("defaultUrl"); + validateFileURL(file); + /*const fileInput = appConfig.openFileInput; + fileInput.value = null; + fileInput.addEventListener("change", function (evt) { + const { + files + } = evt.target; + + if (!files || files.length === 0) { + return; + } + + eventBus.dispatch("fileinputchange", { + source: this, + fileInput: evt.target + }); + });*/ + appConfig.mainContainer.addEventListener("dragover", function (evt) { + evt.preventDefault(); + evt.dataTransfer.dropEffect = evt.dataTransfer.effectAllowed === "copy" ? "copy" : "move"; + }); + appConfig.mainContainer.addEventListener("drop", function (evt) { + evt.preventDefault(); + const { + files + } = evt.dataTransfer; + + if (!files || files.length === 0) { + return; + } + + /*eventBus.dispatch("fileinputchange", { + source: this, + fileInput: evt.dataTransfer + });*/ + }); + + if (!PDFViewerApplication.supportsDocumentFonts) { + _app_options.AppOptions.set("disableFontFace", true); + + PDFViewerApplication.l10n.get("web_fonts_disabled").then(msg => { + console.warn(msg); + }); + } + + if (!PDFViewerApplication.supportsPrinting) { + appConfig.toolbar.print.classList.add("hidden"); + appConfig.secondaryToolbar.printButton.classList.add("hidden"); + } + + if (!PDFViewerApplication.supportsFullscreen) { + appConfig.toolbar.presentationModeButton.classList.add("hidden"); + appConfig.secondaryToolbar.presentationModeButton.classList.add("hidden"); + } + + if (PDFViewerApplication.supportsIntegratedFind) { + appConfig.toolbar.viewFind.classList.add("hidden"); + } + + appConfig.mainContainer.addEventListener("transitionend", function (evt) { + if (evt.target === this) { + eventBus.dispatch("resize", { + source: this + }); + } + }, true); + + try { + if (file) { + PDFViewerApplication.open(file); + } else { + PDFViewerApplication._hideViewBookmark(); + } + } catch (reason) { + PDFViewerApplication.l10n.get("loading_error").then(msg => { + PDFViewerApplication._documentError(msg, reason); + }); + } +} + +function webViewerPageRendered({ + pageNumber, + error +}) { + if (pageNumber === PDFViewerApplication.page) { + PDFViewerApplication.toolbar.updateLoadingIndicatorState(false); + } + + if (PDFViewerApplication.pdfSidebar.visibleView === _ui_utils.SidebarView.THUMBS) { + const pageView = PDFViewerApplication.pdfViewer.getPageView(pageNumber - 1); + const thumbnailView = PDFViewerApplication.pdfThumbnailViewer.getThumbnail(pageNumber - 1); + + if (pageView && thumbnailView) { + thumbnailView.setImage(pageView); + } + } + + if (error) { + PDFViewerApplication.l10n.get("rendering_error").then(msg => { + PDFViewerApplication._otherError(msg, error); + }); + } + + PDFViewerApplication._reportDocumentStatsTelemetry(); +} + +function webViewerPageMode({ + mode +}) { + let view; + + switch (mode) { + case "thumbs": + view = _ui_utils.SidebarView.THUMBS; + break; + + case "bookmarks": + case "outline": + view = _ui_utils.SidebarView.OUTLINE; + break; + + case "attachments": + view = _ui_utils.SidebarView.ATTACHMENTS; + break; + + case "layers": + view = _ui_utils.SidebarView.LAYERS; + break; + + case "none": + view = _ui_utils.SidebarView.NONE; + break; + + default: + console.error('Invalid "pagemode" hash parameter: ' + mode); + return; + } + + PDFViewerApplication.pdfSidebar.switchView(view, true); +} + +function webViewerNamedAction(evt) { + switch (evt.action) { + case "GoToPage": + PDFViewerApplication.appConfig.toolbar.pageNumber.select(); + break; + + case "Find": + if (!PDFViewerApplication.supportsIntegratedFind) { + PDFViewerApplication.findBar.toggle(); + } + + break; + + case "Print": + PDFViewerApplication.triggerPrinting(); + break; + + case "SaveAs": + PDFViewerApplication.downloadOrSave(); + break; + } +} + +function webViewerPresentationModeChanged(evt) { + PDFViewerApplication.pdfViewer.presentationModeState = evt.state; +} + +function webViewerSidebarViewChanged({ + view +}) { + PDFViewerApplication.pdfRenderingQueue.isThumbnailViewEnabled = view === _ui_utils.SidebarView.THUMBS; + + if (PDFViewerApplication.isInitialViewSet) { + PDFViewerApplication.store?.set("sidebarView", view).catch(() => {}); + } +} + +function webViewerUpdateViewarea({ + location +}) { + if (PDFViewerApplication.isInitialViewSet) { + PDFViewerApplication.store?.setMultiple({ + page: location.pageNumber, + zoom: location.scale, + scrollLeft: location.left, + scrollTop: location.top, + rotation: location.rotation + }).catch(() => {}); + } + + const href = PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams); + PDFViewerApplication.appConfig.toolbar.viewBookmark.href = href; + PDFViewerApplication.appConfig.secondaryToolbar.viewBookmarkButton.href = href; + const currentPage = PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1); + const loading = currentPage?.renderingState !== _ui_utils.RenderingStates.FINISHED; + PDFViewerApplication.toolbar.updateLoadingIndicatorState(loading); +} + +function webViewerScrollModeChanged(evt) { + if (PDFViewerApplication.isInitialViewSet) { + PDFViewerApplication.store?.set("scrollMode", evt.mode).catch(() => {}); + } +} + +function webViewerSpreadModeChanged(evt) { + if (PDFViewerApplication.isInitialViewSet) { + PDFViewerApplication.store?.set("spreadMode", evt.mode).catch(() => {}); + } +} + +function webViewerResize() { + const { + pdfDocument, + pdfViewer, + pdfRenderingQueue + } = PDFViewerApplication; + + if (pdfRenderingQueue.printing && window.matchMedia("print").matches) { + return; + } + + pdfViewer.updateContainerHeightCss(); + + if (!pdfDocument) { + return; + } + + const currentScaleValue = pdfViewer.currentScaleValue; + + if (currentScaleValue === "auto" || currentScaleValue === "page-fit" || currentScaleValue === "page-width") { + pdfViewer.currentScaleValue = currentScaleValue; + } + + pdfViewer.update(); +} + +function webViewerHashchange(evt) { + const hash = evt.hash; + + if (!hash) { + return; + } + + if (!PDFViewerApplication.isInitialViewSet) { + PDFViewerApplication.initialBookmark = hash; + } else if (!PDFViewerApplication.pdfHistory?.popStateInProgress) { + PDFViewerApplication.pdfLinkService.setHash(hash); + } +} + +{ + /*var webViewerFileInputChange = function (evt) { + if (PDFViewerApplication.pdfViewer?.isInPresentationMode) { + return; + } + + const file = evt.fileInput.files[0]; + let url = URL.createObjectURL(file); + + if (file.name) { + url = { + url, + originalUrl: file.name + }; + } + + PDFViewerApplication.open(url); + }; + + var webViewerOpenFile = function (evt) { + const fileInput = PDFViewerApplication.appConfig.openFileInput; + fileInput.click(); + };*/ +} + +function webViewerPresentationMode() { + PDFViewerApplication.requestPresentationMode(); +} + +function webViewerSwitchAnnotationEditorMode(evt) { + PDFViewerApplication.pdfViewer.annotationEditorMode = evt.mode; +} + +function webViewerSwitchAnnotationEditorParams(evt) { + PDFViewerApplication.pdfViewer.annotationEditorParams = evt; +} + +function webViewerPrint() { + PDFViewerApplication.triggerPrinting(); +} + +function webViewerDownload() { + PDFViewerApplication.downloadOrSave(); +} + +function webViewerFirstPage() { + if (PDFViewerApplication.pdfDocument) { + PDFViewerApplication.page = 1; + } +} + +function webViewerLastPage() { + if (PDFViewerApplication.pdfDocument) { + PDFViewerApplication.page = PDFViewerApplication.pagesCount; + } +} + +function webViewerNextPage() { + PDFViewerApplication.pdfViewer.nextPage(); +} + +function webViewerPreviousPage() { + PDFViewerApplication.pdfViewer.previousPage(); +} + +function webViewerZoomIn() { + PDFViewerApplication.zoomIn(); +} + +function webViewerZoomOut() { + PDFViewerApplication.zoomOut(); +} + +function webViewerZoomReset() { + PDFViewerApplication.zoomReset(); +} + +function webViewerPageNumberChanged(evt) { + const pdfViewer = PDFViewerApplication.pdfViewer; + + if (evt.value !== "") { + PDFViewerApplication.pdfLinkService.goToPage(evt.value); + } + + if (evt.value !== pdfViewer.currentPageNumber.toString() && evt.value !== pdfViewer.currentPageLabel) { + PDFViewerApplication.toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); + } +} + +function webViewerScaleChanged(evt) { + PDFViewerApplication.pdfViewer.currentScaleValue = evt.value; +} + +function webViewerRotateCw() { + PDFViewerApplication.rotatePages(90); +} + +function webViewerRotateCcw() { + PDFViewerApplication.rotatePages(-90); +} + +function webViewerOptionalContentConfig(evt) { + PDFViewerApplication.pdfViewer.optionalContentConfigPromise = evt.promise; +} + +function webViewerSwitchScrollMode(evt) { + PDFViewerApplication.pdfViewer.scrollMode = evt.mode; +} + +function webViewerSwitchSpreadMode(evt) { + PDFViewerApplication.pdfViewer.spreadMode = evt.mode; +} + +function webViewerDocumentProperties() { + PDFViewerApplication.pdfDocumentProperties.open(); +} + +function webViewerFindFromUrlHash(evt) { + PDFViewerApplication.eventBus.dispatch("find", { + source: evt.source, + type: "", + query: evt.query, + phraseSearch: evt.phraseSearch, + caseSensitive: false, + entireWord: false, + highlightAll: true, + findPrevious: false, + matchDiacritics: true + }); +} + +function webViewerUpdateFindMatchesCount({ + matchesCount +}) { + if (PDFViewerApplication.supportsIntegratedFind) { + PDFViewerApplication.externalServices.updateFindMatchesCount(matchesCount); + } else { + PDFViewerApplication.findBar.updateResultsCount(matchesCount); + } +} + +function webViewerUpdateFindControlState({ + state, + previous, + matchesCount, + rawQuery +}) { + if (PDFViewerApplication.supportsIntegratedFind) { + PDFViewerApplication.externalServices.updateFindControlState({ + result: state, + findPrevious: previous, + matchesCount, + rawQuery + }); + } else { + PDFViewerApplication.findBar.updateUIState(state, previous, matchesCount); + } +} + +function webViewerScaleChanging(evt) { + PDFViewerApplication.toolbar.setPageScale(evt.presetValue, evt.scale); + PDFViewerApplication.pdfViewer.update(); +} + +function webViewerRotationChanging(evt) { + PDFViewerApplication.pdfThumbnailViewer.pagesRotation = evt.pagesRotation; + PDFViewerApplication.forceRendering(); + PDFViewerApplication.pdfViewer.currentPageNumber = evt.pageNumber; +} + +function webViewerPageChanging({ + pageNumber, + pageLabel +}) { + PDFViewerApplication.toolbar.setPageNumber(pageNumber, pageLabel); + PDFViewerApplication.secondaryToolbar.setPageNumber(pageNumber); + + if (PDFViewerApplication.pdfSidebar.visibleView === _ui_utils.SidebarView.THUMBS) { + PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(pageNumber); + } +} + +function webViewerResolutionChange(evt) { + PDFViewerApplication.pdfViewer.refresh(); +} + +function webViewerVisibilityChange(evt) { + if (document.visibilityState === "visible") { + setZoomDisabledTimeout(); + } +} + +let zoomDisabledTimeout = null; + +function setZoomDisabledTimeout() { + if (zoomDisabledTimeout) { + clearTimeout(zoomDisabledTimeout); + } + + zoomDisabledTimeout = setTimeout(function () { + zoomDisabledTimeout = null; + }, WHEEL_ZOOM_DISABLED_TIMEOUT); +} + +function webViewerWheel(evt) { + const { + pdfViewer, + supportedMouseWheelZoomModifierKeys + } = PDFViewerApplication; + + if (pdfViewer.isInPresentationMode) { + return; + } + + if (evt.ctrlKey && supportedMouseWheelZoomModifierKeys.ctrlKey || evt.metaKey && supportedMouseWheelZoomModifierKeys.metaKey) { + evt.preventDefault(); + + if (zoomDisabledTimeout || document.visibilityState === "hidden") { + return; + } + + const deltaMode = evt.deltaMode; + const delta = (0, _ui_utils.normalizeWheelEventDirection)(evt); + const previousScale = pdfViewer.currentScale; + let ticks = 0; + + if (deltaMode === WheelEvent.DOM_DELTA_LINE || deltaMode === WheelEvent.DOM_DELTA_PAGE) { + if (Math.abs(delta) >= 1) { + ticks = Math.sign(delta); + } else { + ticks = PDFViewerApplication.accumulateWheelTicks(delta); + } + } else { + const PIXELS_PER_LINE_SCALE = 30; + ticks = PDFViewerApplication.accumulateWheelTicks(delta / PIXELS_PER_LINE_SCALE); + } + + if (ticks < 0) { + PDFViewerApplication.zoomOut(-ticks); + } else if (ticks > 0) { + PDFViewerApplication.zoomIn(ticks); + } + + const currentScale = pdfViewer.currentScale; + + if (previousScale !== currentScale) { + const scaleCorrectionFactor = currentScale / previousScale - 1; + const rect = pdfViewer.container.getBoundingClientRect(); + const dx = evt.clientX - rect.left; + const dy = evt.clientY - rect.top; + pdfViewer.container.scrollLeft += dx * scaleCorrectionFactor; + pdfViewer.container.scrollTop += dy * scaleCorrectionFactor; + } + } else { + setZoomDisabledTimeout(); + } +} + +function webViewerTouchStart(evt) { + if (evt.touches.length > 1) { + evt.preventDefault(); + } +} + +function webViewerClick(evt) { + if (!PDFViewerApplication.secondaryToolbar.isOpen) { + return; + } + + const appConfig = PDFViewerApplication.appConfig; + + if (PDFViewerApplication.pdfViewer.containsElement(evt.target) || appConfig.toolbar.container.contains(evt.target) && evt.target !== appConfig.secondaryToolbar.toggleButton) { + PDFViewerApplication.secondaryToolbar.close(); + } +} + +function webViewerKeyDown(evt) { + if (PDFViewerApplication.overlayManager.active) { + return; + } + + const { + eventBus, + pdfViewer + } = PDFViewerApplication; + const isViewerInPresentationMode = pdfViewer.isInPresentationMode; + let handled = false, + ensureViewerFocused = false; + const cmd = (evt.ctrlKey ? 1 : 0) | (evt.altKey ? 2 : 0) | (evt.shiftKey ? 4 : 0) | (evt.metaKey ? 8 : 0); + + if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) { + switch (evt.keyCode) { + case 70: + if (!PDFViewerApplication.supportsIntegratedFind && !evt.shiftKey) { + PDFViewerApplication.findBar.open(); + handled = true; + } + + break; + + case 71: + if (!PDFViewerApplication.supportsIntegratedFind) { + const { + state + } = PDFViewerApplication.findController; + + if (state) { + const eventState = Object.assign(Object.create(null), state, { + source: window, + type: "again", + findPrevious: cmd === 5 || cmd === 12 + }); + eventBus.dispatch("find", eventState); + } + + handled = true; + } + + break; + + case 61: + case 107: + case 187: + case 171: + if (!isViewerInPresentationMode) { + PDFViewerApplication.zoomIn(); + } + + handled = true; + break; + + case 173: + case 109: + case 189: + if (!isViewerInPresentationMode) { + PDFViewerApplication.zoomOut(); + } + + handled = true; + break; + + case 48: + case 96: + if (!isViewerInPresentationMode) { + setTimeout(function () { + PDFViewerApplication.zoomReset(); + }); + handled = false; + } + + break; + + case 38: + if (isViewerInPresentationMode || PDFViewerApplication.page > 1) { + PDFViewerApplication.page = 1; + handled = true; + ensureViewerFocused = true; + } + + break; + + case 40: + if (isViewerInPresentationMode || PDFViewerApplication.page < PDFViewerApplication.pagesCount) { + PDFViewerApplication.page = PDFViewerApplication.pagesCount; + handled = true; + ensureViewerFocused = true; + } + + break; + } + } + + if (cmd === 1 || cmd === 8) { + switch (evt.keyCode) { + case 83: + eventBus.dispatch("download", { + source: window + }); + handled = true; + break; + + case 79: + { + eventBus.dispatch("openfile", { + source: window + }); + handled = true; + } + break; + } + } + + if (cmd === 3 || cmd === 10) { + switch (evt.keyCode) { + case 80: + PDFViewerApplication.requestPresentationMode(); + handled = true; + break; + + case 71: + PDFViewerApplication.appConfig.toolbar.pageNumber.select(); + handled = true; + break; + } + } + + if (handled) { + if (ensureViewerFocused && !isViewerInPresentationMode) { + pdfViewer.focus(); + } + + evt.preventDefault(); + return; + } + + const curElement = (0, _ui_utils.getActiveOrFocusedElement)(); + const curElementTagName = curElement?.tagName.toUpperCase(); + + if (curElementTagName === "INPUT" || curElementTagName === "TEXTAREA" || curElementTagName === "SELECT" || curElement?.isContentEditable) { + if (evt.keyCode !== 27) { + return; + } + } + + if (cmd === 0) { + let turnPage = 0, + turnOnlyIfPageFit = false; + + switch (evt.keyCode) { + case 38: + case 33: + if (pdfViewer.isVerticalScrollbarEnabled) { + turnOnlyIfPageFit = true; + } + + turnPage = -1; + break; + + case 8: + if (!isViewerInPresentationMode) { + turnOnlyIfPageFit = true; + } + + turnPage = -1; + break; + + case 37: + if (pdfViewer.isHorizontalScrollbarEnabled) { + turnOnlyIfPageFit = true; + } + + case 75: + case 80: + turnPage = -1; + break; + + case 27: + if (PDFViewerApplication.secondaryToolbar.isOpen) { + PDFViewerApplication.secondaryToolbar.close(); + handled = true; + } + + if (!PDFViewerApplication.supportsIntegratedFind && PDFViewerApplication.findBar.opened) { + PDFViewerApplication.findBar.close(); + handled = true; + } + + break; + + case 40: + case 34: + if (pdfViewer.isVerticalScrollbarEnabled) { + turnOnlyIfPageFit = true; + } + + turnPage = 1; + break; + + case 13: + case 32: + if (!isViewerInPresentationMode) { + turnOnlyIfPageFit = true; + } + + turnPage = 1; + break; + + case 39: + if (pdfViewer.isHorizontalScrollbarEnabled) { + turnOnlyIfPageFit = true; + } + + case 74: + case 78: + turnPage = 1; + break; + + case 36: + if (isViewerInPresentationMode || PDFViewerApplication.page > 1) { + PDFViewerApplication.page = 1; + handled = true; + ensureViewerFocused = true; + } + + break; + + case 35: + if (isViewerInPresentationMode || PDFViewerApplication.page < PDFViewerApplication.pagesCount) { + PDFViewerApplication.page = PDFViewerApplication.pagesCount; + handled = true; + ensureViewerFocused = true; + } + + break; + + case 83: + PDFViewerApplication.pdfCursorTools.switchTool(_pdf_cursor_tools.CursorTool.SELECT); + break; + + case 72: + PDFViewerApplication.pdfCursorTools.switchTool(_pdf_cursor_tools.CursorTool.HAND); + break; + + case 82: + PDFViewerApplication.rotatePages(90); + break; + + case 115: + PDFViewerApplication.pdfSidebar.toggle(); + break; + } + + if (turnPage !== 0 && (!turnOnlyIfPageFit || pdfViewer.currentScaleValue === "page-fit")) { + if (turnPage > 0) { + pdfViewer.nextPage(); + } else { + pdfViewer.previousPage(); + } + + handled = true; + } + } + + if (cmd === 4) { + switch (evt.keyCode) { + case 13: + case 32: + if (!isViewerInPresentationMode && pdfViewer.currentScaleValue !== "page-fit") { + break; + } + + pdfViewer.previousPage(); + handled = true; + break; + + case 82: + PDFViewerApplication.rotatePages(-90); + break; + } + } + + if (!handled && !isViewerInPresentationMode) { + if (evt.keyCode >= 33 && evt.keyCode <= 40 || evt.keyCode === 32 && curElementTagName !== "BUTTON") { + ensureViewerFocused = true; + } + } + + if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) { + pdfViewer.focus(); + } + + if (handled) { + evt.preventDefault(); + } +} + +function beforeUnload(evt) { + evt.preventDefault(); + evt.returnValue = ""; + return false; +} + +function webViewerAnnotationEditorStatesChanged(data) { + PDFViewerApplication.externalServices.updateEditorStates(data); +} + +const PDFPrintServiceFactory = { + instance: { + supportsPrinting: false, + + createPrintService() { + throw new Error("Not implemented: createPrintService"); + } + + } +}; +exports.PDFPrintServiceFactory = PDFPrintServiceFactory; + +/***/ }), +/* 5 */ +/***/ ((module) => { + + + +let pdfjsLib; + +if (typeof window !== "undefined" && window["pdfjs-dist/build/pdf"]) { + pdfjsLib = window["pdfjs-dist/build/pdf"]; +} else { + pdfjsLib = require("../build/pdf.js"); +} + +module.exports = pdfjsLib; + +/***/ }), +/* 6 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.WaitOnType = exports.EventBus = exports.AutomationEventBus = void 0; +exports.waitOnEventOrTimeout = waitOnEventOrTimeout; const WaitOnType = { EVENT: "event", TIMEOUT: "timeout" @@ -3530,75 +4389,66 @@ function waitOnEventOrTimeout({ }); } -const animationStarted = new Promise(function (resolve) { - window.requestAnimationFrame(resolve); -}); -exports.animationStarted = animationStarted; - -function dispatchDOMEvent(eventName, args = null) { - throw new Error("Not implemented: dispatchDOMEvent"); -} - class EventBus { - constructor(options) { + constructor() { this._listeners = Object.create(null); } - on(eventName, listener) { + on(eventName, listener, options = null) { this._on(eventName, listener, { - external: true + external: true, + once: options?.once }); } - off(eventName, listener) { + off(eventName, listener, options = null) { this._off(eventName, listener, { - external: true + external: true, + once: options?.once }); } - dispatch(eventName) { + dispatch(eventName, data) { const eventListeners = this._listeners[eventName]; if (!eventListeners || eventListeners.length === 0) { return; } - const args = Array.prototype.slice.call(arguments, 1); let externalListeners; - eventListeners.slice(0).forEach(function ({ - listener, - external - }) { - if (external) { - if (!externalListeners) { - externalListeners = []; - } - externalListeners.push(listener); - return; + for (const { + listener, + external, + once + } of eventListeners.slice(0)) { + if (once) { + this._off(eventName, listener); } - listener.apply(null, args); - }); + if (external) { + (externalListeners ||= []).push(listener); + continue; + } + + listener(data); + } if (externalListeners) { - externalListeners.forEach(function (listener) { - listener.apply(null, args); - }); + for (const listener of externalListeners) { + listener(data); + } + externalListeners = null; } } _on(eventName, listener, options = null) { - let eventListeners = this._listeners[eventName]; - - if (!eventListeners) { - this._listeners[eventName] = eventListeners = []; - } - + const eventListeners = this._listeners[eventName] ||= []; eventListeners.push({ listener, - external: (options && options.external) === true + external: options?.external === true, + once: options?.once === true }); } @@ -3621,423 +4471,29 @@ class EventBus { exports.EventBus = EventBus; -function clamp(v, min, max) { - return Math.min(Math.max(v, min), max); -} - -class ProgressBar { - constructor(id, { - height, - width, - units - } = {}) { - this.visible = true; - this.div = document.querySelector(id + " .progress"); - this.bar = this.div.parentNode; - this.height = height || 100; - this.width = width || 100; - this.units = units || "%"; - this.div.style.height = this.height + this.units; - this.percent = 0; - } - - _updateBar() { - if (this._indeterminate) { - this.div.classList.add("indeterminate"); - this.div.style.width = this.width + this.units; - return; - } - - this.div.classList.remove("indeterminate"); - const progressSize = this.width * this._percent / 100; - this.div.style.width = progressSize + this.units; - } - - get percent() { - return this._percent; - } - - set percent(val) { - this._indeterminate = isNaN(val); - this._percent = clamp(val, 0, 100); - - this._updateBar(); - } - - setWidth(viewer) { - if (!viewer) { - return; - } - - const container = viewer.parentNode; - const scrollbarWidth = container.offsetWidth - viewer.offsetWidth; - - if (scrollbarWidth > 0) { - this.bar.style.width = `calc(100% - ${scrollbarWidth}px)`; - } - } - - hide() { - if (!this.visible) { - return; - } - - this.visible = false; - this.bar.classList.add("hidden"); - document.body.classList.remove("loadingInProgress"); - } - - show() { - if (this.visible) { - return; - } - - this.visible = true; - document.body.classList.add("loadingInProgress"); - this.bar.classList.remove("hidden"); +class AutomationEventBus extends EventBus { + dispatch(eventName, data) { + throw new Error("Not implemented: AutomationEventBus.dispatch"); } } -exports.ProgressBar = ProgressBar; - -function moveToEndOfArray(arr, condition) { - const moved = [], - len = arr.length; - let write = 0; - - for (let read = 0; read < len; ++read) { - if (condition(arr[read])) { - moved.push(arr[read]); - } else { - arr[write] = arr[read]; - ++write; - } - } - - for (let read = 0; write < len; ++read, ++write) { - arr[write] = moved[read]; - } -} +exports.AutomationEventBus = AutomationEventBus; /***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 7 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.OptionKind = exports.AppOptions = void 0; - -var _viewer_compatibility = __webpack_require__(4); - -const OptionKind = { - VIEWER: 0x02, - API: 0x04, - WORKER: 0x08, - PREFERENCE: 0x80 -}; -exports.OptionKind = OptionKind; -const defaultOptions = { - cursorToolOnLoad: { - value: 0, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - defaultUrl: { - value: "compressed.tracemonkey-pldi-09.pdf", - kind: OptionKind.VIEWER - }, - defaultZoomValue: { - value: "", - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - disableHistory: { - value: false, - kind: OptionKind.VIEWER - }, - disablePageLabels: { - value: false, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - enablePermissions: { - value: false, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - enablePrintAutoRotate: { - value: false, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - enableWebGL: { - value: false, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - externalLinkRel: { - value: "noopener noreferrer nofollow", - kind: OptionKind.VIEWER - }, - externalLinkTarget: { - value: 0, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - historyUpdateUrl: { - value: false, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - ignoreDestinationZoom: { - value: false, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - imageResourcesPath: { - value: "./images/", - kind: OptionKind.VIEWER - }, - maxCanvasPixels: { - value: 16777216, - compatibility: _viewer_compatibility.viewerCompatibilityParams.maxCanvasPixels, - kind: OptionKind.VIEWER - }, - pdfBugEnabled: { - value: false, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - printResolution: { - value: 150, - kind: OptionKind.VIEWER - }, - renderer: { - value: "canvas", - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - renderInteractiveForms: { - value: true, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - sidebarViewOnLoad: { - value: -1, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - scrollModeOnLoad: { - value: -1, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - spreadModeOnLoad: { - value: -1, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - textLayerMode: { - value: 1, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - useOnlyCssZoom: { - value: false, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - viewOnLoad: { - value: 0, - kind: OptionKind.VIEWER + OptionKind.PREFERENCE - }, - cMapPacked: { - value: true, - kind: OptionKind.API - }, - cMapUrl: { - value: "../web/cmaps/", - kind: OptionKind.API - }, - disableAutoFetch: { - value: false, - kind: OptionKind.API + OptionKind.PREFERENCE - }, - disableFontFace: { - value: false, - kind: OptionKind.API + OptionKind.PREFERENCE - }, - disableRange: { - value: false, - kind: OptionKind.API + OptionKind.PREFERENCE - }, - disableStream: { - value: false, - kind: OptionKind.API + OptionKind.PREFERENCE - }, - docBaseUrl: { - value: "", - kind: OptionKind.API - }, - fontExtraProperties: { - value: false, - kind: OptionKind.API - }, - isEvalSupported: { - value: true, - kind: OptionKind.API - }, - maxImageSize: { - value: -1, - kind: OptionKind.API - }, - pdfBug: { - value: false, - kind: OptionKind.API - }, - verbosity: { - value: 1, - kind: OptionKind.API - }, - workerPort: { - value: null, - kind: OptionKind.WORKER - }, - workerSrc: { - value: "../build/pdf.worker.js", - kind: OptionKind.WORKER - } -}; -{ - defaultOptions.disablePreferences = { - value: false, - kind: OptionKind.VIEWER - }; - defaultOptions.locale = { - value: typeof navigator !== "undefined" ? navigator.language : "en-US", - kind: OptionKind.VIEWER - }; -} -const userOptions = Object.create(null); - -class AppOptions { - constructor() { - throw new Error("Cannot initialize AppOptions."); - } - - static get(name) { - const userOption = userOptions[name]; - - if (userOption !== undefined) { - return userOption; - } - - const defaultOption = defaultOptions[name]; - - if (defaultOption !== undefined) { - return defaultOption.compatibility || defaultOption.value; - } - - return undefined; - } - - static getAll(kind = null) { - const options = Object.create(null); - - for (const name in defaultOptions) { - const defaultOption = defaultOptions[name]; - - if (kind) { - if ((kind & defaultOption.kind) === 0) { - continue; - } - - if (kind === OptionKind.PREFERENCE) { - const value = defaultOption.value, - valueType = typeof value; - - if (valueType === "boolean" || valueType === "string" || valueType === "number" && Number.isInteger(value)) { - options[name] = value; - continue; - } - - throw new Error(`Invalid type for preference: ${name}`); - } - } - - const userOption = userOptions[name]; - options[name] = userOption !== undefined ? userOption : defaultOption.compatibility || defaultOption.value; - } - - return options; - } - - static set(name, value) { - userOptions[name] = value; - } - - static remove(name) { - delete userOptions[name]; - } - -} - -exports.AppOptions = AppOptions; - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.viewerCompatibilityParams = void 0; -const compatibilityParams = Object.create(null); -{ - const userAgent = typeof navigator !== "undefined" && navigator.userAgent || ""; - const platform = typeof navigator !== "undefined" && navigator.platform || ""; - const maxTouchPoints = typeof navigator !== "undefined" && navigator.maxTouchPoints || 1; - const isAndroid = /Android/.test(userAgent); - const isIE = /Trident/.test(userAgent); - const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || platform === "MacIntel" && maxTouchPoints > 1; - const isIOSChrome = /CriOS/.test(userAgent); - - (function checkOnBlobSupport() { - if (isIE || isIOSChrome) { - compatibilityParams.disableCreateObjectURL = true; - } - })(); - - (function checkCanvasSizeLimitation() { - if (isIOS || isAndroid) { - compatibilityParams.maxCanvasPixels = 5242880; - } - })(); -} -const viewerCompatibilityParams = Object.freeze(compatibilityParams); -exports.viewerCompatibilityParams = viewerCompatibilityParams; - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -let pdfjsLib; - -if (typeof window !== "undefined" && window["pdfjs-dist/build/pdf"]) { - pdfjsLib = window["pdfjs-dist/build/pdf"]; -} else { - pdfjsLib = require("../build/pdf.js"); -} - -module.exports = pdfjsLib; - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); +})); exports.PDFCursorTools = exports.CursorTool = void 0; -var _grab_to_pan = __webpack_require__(7); +var _grab_to_pan = __webpack_require__(8); + +var _ui_utils = __webpack_require__(1); const CursorTool = { SELECT: 0, @@ -4059,9 +4515,7 @@ class PDFCursorTools { this.handTool = new _grab_to_pan.GrabToPan({ element: this.container }); - - this._addEventListeners(); - + this.#addEventListeners(); Promise.resolve().then(() => { this.switchTool(cursorToolOnLoad); }); @@ -4110,37 +4564,38 @@ class PDFCursorTools { } this.active = tool; - - this._dispatchEvent(); + this.#dispatchEvent(); } - _dispatchEvent() { + #dispatchEvent() { this.eventBus.dispatch("cursortoolchanged", { source: this, tool: this.active }); } - _addEventListeners() { + #addEventListeners() { this.eventBus._on("switchcursortool", evt => { this.switchTool(evt.tool); }); this.eventBus._on("presentationmodechanged", evt => { - if (evt.switchInProgress) { - return; - } + switch (evt.state) { + case _ui_utils.PresentationModeState.FULLSCREEN: + { + const previouslyActive = this.active; + this.switchTool(CursorTool.SELECT); + this.activeBeforePresentationMode = previouslyActive; + break; + } - let previouslyActive; - - if (evt.active) { - previouslyActive = this.active; - this.switchTool(CursorTool.SELECT); - this.activeBeforePresentationMode = previouslyActive; - } else { - previouslyActive = this.activeBeforePresentationMode; - this.activeBeforePresentationMode = null; - this.switchTool(previouslyActive); + case _ui_utils.PresentationModeState.NORMAL: + { + const previouslyActive = this.activeBeforePresentationMode; + this.activeBeforePresentationMode = null; + this.switchTool(previouslyActive); + break; + } } }); } @@ -4150,74 +4605,71 @@ class PDFCursorTools { exports.PDFCursorTools = PDFCursorTools; /***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 8 */ +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.GrabToPan = GrabToPan; +})); +exports.GrabToPan = void 0; +const CSS_CLASS_GRAB = "grab-to-pan-grab"; -function GrabToPan(options) { - this.element = options.element; - this.document = options.element.ownerDocument; +class GrabToPan { + constructor(options) { + this.element = options.element; + this.document = options.element.ownerDocument; - if (typeof options.ignoreTarget === "function") { - this.ignoreTarget = options.ignoreTarget; + if (typeof options.ignoreTarget === "function") { + this.ignoreTarget = options.ignoreTarget; + } + + this.onActiveChanged = options.onActiveChanged; + this.activate = this.activate.bind(this); + this.deactivate = this.deactivate.bind(this); + this.toggle = this.toggle.bind(this); + this._onMouseDown = this.#onMouseDown.bind(this); + this._onMouseMove = this.#onMouseMove.bind(this); + this._endPan = this.#endPan.bind(this); + const overlay = this.overlay = document.createElement("div"); + overlay.className = "grab-to-pan-grabbing"; } - this.onActiveChanged = options.onActiveChanged; - this.activate = this.activate.bind(this); - this.deactivate = this.deactivate.bind(this); - this.toggle = this.toggle.bind(this); - this._onmousedown = this._onmousedown.bind(this); - this._onmousemove = this._onmousemove.bind(this); - this._endPan = this._endPan.bind(this); - const overlay = this.overlay = document.createElement("div"); - overlay.className = "grab-to-pan-grabbing"; -} - -GrabToPan.prototype = { - CSS_CLASS_GRAB: "grab-to-pan-grab", - activate: function GrabToPan_activate() { + activate() { if (!this.active) { this.active = true; - this.element.addEventListener("mousedown", this._onmousedown, true); - this.element.classList.add(this.CSS_CLASS_GRAB); - - if (this.onActiveChanged) { - this.onActiveChanged(true); - } + this.element.addEventListener("mousedown", this._onMouseDown, true); + this.element.classList.add(CSS_CLASS_GRAB); + this.onActiveChanged?.(true); } - }, - deactivate: function GrabToPan_deactivate() { + } + + deactivate() { if (this.active) { this.active = false; - this.element.removeEventListener("mousedown", this._onmousedown, true); + this.element.removeEventListener("mousedown", this._onMouseDown, true); this._endPan(); - this.element.classList.remove(this.CSS_CLASS_GRAB); - - if (this.onActiveChanged) { - this.onActiveChanged(false); - } + this.element.classList.remove(CSS_CLASS_GRAB); + this.onActiveChanged?.(false); } - }, - toggle: function GrabToPan_toggle() { + } + + toggle() { if (this.active) { this.deactivate(); } else { this.activate(); } - }, - ignoreTarget: function GrabToPan_ignoreTarget(node) { - return node[matchesSelector]("a[href], a[href] *, input, textarea, button, button *, select, option"); - }, - _onmousedown: function GrabToPan__onmousedown(event) { + } + + ignoreTarget(node) { + return node.matches("a[href], a[href] *, input, textarea, button, button *, select, option"); + } + + #onMouseDown(event) { if (event.button !== 0 || this.ignoreTarget(event.target)) { return; } @@ -4234,7 +4686,7 @@ GrabToPan.prototype = { this.scrollTopStart = this.element.scrollTop; this.clientXStart = event.clientX; this.clientYStart = event.clientY; - this.document.addEventListener("mousemove", this._onmousemove, true); + this.document.addEventListener("mousemove", this._onMouseMove, true); this.document.addEventListener("mouseup", this._endPan, true); this.element.addEventListener("scroll", this._endPan, true); event.preventDefault(); @@ -4244,11 +4696,12 @@ GrabToPan.prototype = { if (focusedElement && !focusedElement.contains(event.target)) { focusedElement.blur(); } - }, - _onmousemove: function GrabToPan__onmousemove(event) { + } + + #onMouseMove(event) { this.element.removeEventListener("scroll", this._endPan, true); - if (isLeftMouseReleased(event)) { + if (!(event.buttons & 1)) { this._endPan(); return; @@ -4271,693 +4724,186 @@ GrabToPan.prototype = { } if (!this.overlay.parentNode) { - document.body.appendChild(this.overlay); + document.body.append(this.overlay); } - }, - _endPan: function GrabToPan__endPan() { + } + + #endPan() { this.element.removeEventListener("scroll", this._endPan, true); - this.document.removeEventListener("mousemove", this._onmousemove, true); + this.document.removeEventListener("mousemove", this._onMouseMove, true); this.document.removeEventListener("mouseup", this._endPan, true); this.overlay.remove(); } -}; -let matchesSelector; -["webkitM", "mozM", "msM", "oM", "m"].some(function (prefix) { - let name = prefix + "atches"; - - if (name in document.documentElement) { - matchesSelector = name; - } - - name += "Selector"; - - if (name in document.documentElement) { - matchesSelector = name; - } - - return matchesSelector; -}); -const isNotIEorIsIE10plus = !document.documentMode || document.documentMode > 9; -const chrome = window.chrome; -const isChrome15OrOpera15plus = chrome && (chrome.webstore || chrome.app); -const isSafari6plus = /Apple/.test(navigator.vendor) && /Version\/([6-9]\d*|[1-5]\d+)/.test(navigator.userAgent); - -function isLeftMouseReleased(event) { - if ("buttons" in event && isNotIEorIsIE10plus) { - return !(event.buttons & 1); - } - - if (isChrome15OrOpera15plus || isSafari6plus) { - return event.which === 0; - } - - return false; -} - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.PDFRenderingQueue = exports.RenderingStates = void 0; -const CLEANUP_TIMEOUT = 30000; -const RenderingStates = { - INITIAL: 0, - RUNNING: 1, - PAUSED: 2, - FINISHED: 3 -}; -exports.RenderingStates = RenderingStates; - -class PDFRenderingQueue { - constructor() { - this.pdfViewer = null; - this.pdfThumbnailViewer = null; - this.onIdle = null; - this.highestPriorityPage = null; - this.idleTimeout = null; - this.printing = false; - this.isThumbnailViewEnabled = false; - } - - setViewer(pdfViewer) { - this.pdfViewer = pdfViewer; - } - - setThumbnailViewer(pdfThumbnailViewer) { - this.pdfThumbnailViewer = pdfThumbnailViewer; - } - - isHighestPriority(view) { - return this.highestPriorityPage === view.renderingId; - } - - renderHighestPriority(currentlyVisiblePages) { - if (this.idleTimeout) { - clearTimeout(this.idleTimeout); - this.idleTimeout = null; - } - - if (this.pdfViewer.forceRendering(currentlyVisiblePages)) { - return; - } - - if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled) { - if (this.pdfThumbnailViewer.forceRendering()) { - return; - } - } - - if (this.printing) { - return; - } - - if (this.onIdle) { - this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT); - } - } - - getHighestPriority(visible, views, scrolledDown) { - const visibleViews = visible.views; - const numVisible = visibleViews.length; - - if (numVisible === 0) { - return null; - } - - for (let i = 0; i < numVisible; ++i) { - const view = visibleViews[i].view; - - if (!this.isViewFinished(view)) { - return view; - } - } - - if (scrolledDown) { - const nextPageIndex = visible.last.id; - - if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) { - return views[nextPageIndex]; - } - } else { - const previousPageIndex = visible.first.id - 2; - - if (views[previousPageIndex] && !this.isViewFinished(views[previousPageIndex])) { - return views[previousPageIndex]; - } - } - - return null; - } - - isViewFinished(view) { - return view.renderingState === RenderingStates.FINISHED; - } - - renderView(view) { - switch (view.renderingState) { - case RenderingStates.FINISHED: - return false; - - case RenderingStates.PAUSED: - this.highestPriorityPage = view.renderingId; - view.resume(); - break; - - case RenderingStates.RUNNING: - this.highestPriorityPage = view.renderingId; - break; - - case RenderingStates.INITIAL: - this.highestPriorityPage = view.renderingId; - view.draw().finally(() => { - this.renderHighestPriority(); - }).catch(reason => { - console.error(`renderView: "${reason}"`); - }); - break; - } - - return true; - } } -exports.PDFRenderingQueue = PDFRenderingQueue; +exports.GrabToPan = GrabToPan; /***/ }), /* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.PDFSidebar = exports.SidebarView = void 0; +})); +exports.AnnotationEditorParams = void 0; -var _ui_utils = __webpack_require__(2); +var _pdfjsLib = __webpack_require__(5); -var _pdf_rendering_queue = __webpack_require__(8); - -const UI_NOTIFICATION_CLASS = "pdfSidebarNotification"; -const SidebarView = { - UNKNOWN: -1, - NONE: 0, - THUMBS: 1, - OUTLINE: 2, - ATTACHMENTS: 3, - LAYERS: 4 -}; -exports.SidebarView = SidebarView; - -class PDFSidebar { - constructor({ - elements, - pdfViewer, - pdfThumbnailViewer, - eventBus, - l10n = _ui_utils.NullL10n, - disableNotification = false - }) { - this.isOpen = false; - this.active = SidebarView.THUMBS; - this.isInitialViewSet = false; - this.onToggled = null; - this.pdfViewer = pdfViewer; - this.pdfThumbnailViewer = pdfThumbnailViewer; - this.outerContainer = elements.outerContainer; - this.viewerContainer = elements.viewerContainer; - this.toggleButton = elements.toggleButton; - this.thumbnailButton = elements.thumbnailButton; - this.outlineButton = elements.outlineButton; - this.attachmentsButton = elements.attachmentsButton; - this.layersButton = elements.layersButton; - this.thumbnailView = elements.thumbnailView; - this.outlineView = elements.outlineView; - this.attachmentsView = elements.attachmentsView; - this.layersView = elements.layersView; +class AnnotationEditorParams { + constructor(options, eventBus) { this.eventBus = eventBus; - this.l10n = l10n; - this._disableNotification = disableNotification; - - this._addEventListeners(); + this.#bindListeners(options); } - reset() { - this.isInitialViewSet = false; - - this._hideUINotification(null); - - this.switchView(SidebarView.THUMBS); - this.outlineButton.disabled = false; - this.attachmentsButton.disabled = false; - this.layersButton.disabled = false; - } - - get visibleView() { - return this.isOpen ? this.active : SidebarView.NONE; - } - - get isThumbnailViewVisible() { - return this.isOpen && this.active === SidebarView.THUMBS; - } - - get isOutlineViewVisible() { - return this.isOpen && this.active === SidebarView.OUTLINE; - } - - get isAttachmentsViewVisible() { - return this.isOpen && this.active === SidebarView.ATTACHMENTS; - } - - get isLayersViewVisible() { - return this.isOpen && this.active === SidebarView.LAYERS; - } - - setInitialView(view = SidebarView.NONE) { - if (this.isInitialViewSet) { - return; - } - - this.isInitialViewSet = true; - - if (view === SidebarView.NONE || view === SidebarView.UNKNOWN) { - this._dispatchEvent(); - - return; - } - - if (!this._switchView(view, true)) { - this._dispatchEvent(); - } - } - - switchView(view, forceOpen = false) { - this._switchView(view, forceOpen); - } - - _switchView(view, forceOpen = false) { - const isViewChanged = view !== this.active; - let shouldForceRendering = false; - - switch (view) { - case SidebarView.NONE: - if (this.isOpen) { - this.close(); - return true; - } - - return false; - - case SidebarView.THUMBS: - if (this.isOpen && isViewChanged) { - shouldForceRendering = true; - } - - break; - - case SidebarView.OUTLINE: - if (this.outlineButton.disabled) { - return false; - } - - break; - - case SidebarView.ATTACHMENTS: - if (this.attachmentsButton.disabled) { - return false; - } - - break; - - case SidebarView.LAYERS: - if (this.layersButton.disabled) { - return false; - } - - break; - - default: - console.error(`PDFSidebar._switchView: "${view}" is not a valid view.`); - return false; - } - - this.active = view; - this.thumbnailButton.classList.toggle("toggled", view === SidebarView.THUMBS); - this.outlineButton.classList.toggle("toggled", view === SidebarView.OUTLINE); - this.attachmentsButton.classList.toggle("toggled", view === SidebarView.ATTACHMENTS); - this.layersButton.classList.toggle("toggled", view === SidebarView.LAYERS); - this.thumbnailView.classList.toggle("hidden", view !== SidebarView.THUMBS); - this.outlineView.classList.toggle("hidden", view !== SidebarView.OUTLINE); - this.attachmentsView.classList.toggle("hidden", view !== SidebarView.ATTACHMENTS); - this.layersView.classList.toggle("hidden", view !== SidebarView.LAYERS); - - if (forceOpen && !this.isOpen) { - this.open(); - return true; - } - - if (shouldForceRendering) { - this._updateThumbnailViewer(); - - this._forceRendering(); - } - - if (isViewChanged) { - this._dispatchEvent(); - } - - this._hideUINotification(this.active); - - return isViewChanged; - } - - open() { - if (this.isOpen) { - return; - } - - this.isOpen = true; - this.toggleButton.classList.add("toggled"); - this.outerContainer.classList.add("sidebarMoving", "sidebarOpen"); - - if (this.active === SidebarView.THUMBS) { - this._updateThumbnailViewer(); - } - - this._forceRendering(); - - this._dispatchEvent(); - - this._hideUINotification(this.active); - } - - close() { - if (!this.isOpen) { - return; - } - - this.isOpen = false; - this.toggleButton.classList.remove("toggled"); - this.outerContainer.classList.add("sidebarMoving"); - this.outerContainer.classList.remove("sidebarOpen"); - - this._forceRendering(); - - this._dispatchEvent(); - } - - toggle() { - if (this.isOpen) { - this.close(); - } else { - this.open(); - } - } - - _dispatchEvent() { - this.eventBus.dispatch("sidebarviewchanged", { - source: this, - view: this.visibleView - }); - } - - _forceRendering() { - if (this.onToggled) { - this.onToggled(); - } else { - this.pdfViewer.forceRendering(); - this.pdfThumbnailViewer.forceRendering(); - } - } - - _updateThumbnailViewer() { - const { - pdfViewer, - pdfThumbnailViewer - } = this; - const pagesCount = pdfViewer.pagesCount; - - for (let pageIndex = 0; pageIndex < pagesCount; pageIndex++) { - const pageView = pdfViewer.getPageView(pageIndex); - - if (pageView && pageView.renderingState === _pdf_rendering_queue.RenderingStates.FINISHED) { - const thumbnailView = pdfThumbnailViewer.getThumbnail(pageIndex); - thumbnailView.setImage(pageView); - } - } - - pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); - } - - _showUINotification(view) { - if (this._disableNotification) { - return; - } - - this.l10n.get("toggle_sidebar_notification2.title", null, "Toggle Sidebar (document contains outline/attachments/layers)").then(msg => { - this.toggleButton.title = msg; - }); - - if (!this.isOpen) { - this.toggleButton.classList.add(UI_NOTIFICATION_CLASS); - } else if (view === this.active) { - return; - } - - switch (view) { - case SidebarView.OUTLINE: - this.outlineButton.classList.add(UI_NOTIFICATION_CLASS); - break; - - case SidebarView.ATTACHMENTS: - this.attachmentsButton.classList.add(UI_NOTIFICATION_CLASS); - break; - - case SidebarView.LAYERS: - this.layersButton.classList.add(UI_NOTIFICATION_CLASS); - break; - } - } - - _hideUINotification(view) { - if (this._disableNotification) { - return; - } - - const removeNotification = sidebarView => { - switch (sidebarView) { - case SidebarView.OUTLINE: - this.outlineButton.classList.remove(UI_NOTIFICATION_CLASS); - break; - - case SidebarView.ATTACHMENTS: - this.attachmentsButton.classList.remove(UI_NOTIFICATION_CLASS); - break; - - case SidebarView.LAYERS: - this.layersButton.classList.remove(UI_NOTIFICATION_CLASS); - break; - } - }; - - if (!this.isOpen && view !== null) { - return; - } - - this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS); - - if (view !== null) { - removeNotification(view); - return; - } - - for (view in SidebarView) { - removeNotification(SidebarView[view]); - } - - this.l10n.get("toggle_sidebar.title", null, "Toggle Sidebar").then(msg => { - this.toggleButton.title = msg; - }); - } - - _addEventListeners() { - this.viewerContainer.addEventListener("transitionend", evt => { - if (evt.target === this.viewerContainer) { - this.outerContainer.classList.remove("sidebarMoving"); - } - }); - this.toggleButton.addEventListener("click", () => { - this.toggle(); - }); - this.thumbnailButton.addEventListener("click", () => { - this.switchView(SidebarView.THUMBS); - }); - this.outlineButton.addEventListener("click", () => { - this.switchView(SidebarView.OUTLINE); - }); - this.outlineButton.addEventListener("dblclick", () => { - this.eventBus.dispatch("toggleoutlinetree", { - source: this + #bindListeners({ + editorFreeTextFontSize, + editorFreeTextColor, + editorInkColor, + editorInkThickness, + editorInkOpacity + }) { + editorFreeTextFontSize.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.FREETEXT_SIZE, + value: editorFreeTextFontSize.valueAsNumber }); }); - this.attachmentsButton.addEventListener("click", () => { - this.switchView(SidebarView.ATTACHMENTS); + editorFreeTextColor.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.FREETEXT_COLOR, + value: editorFreeTextColor.value + }); }); - this.layersButton.addEventListener("click", () => { - this.switchView(SidebarView.LAYERS); + editorInkColor.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.INK_COLOR, + value: editorInkColor.value + }); }); - this.layersButton.addEventListener("dblclick", () => { - this.eventBus.dispatch("resetlayers", { - source: this + editorInkThickness.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.INK_THICKNESS, + value: editorInkThickness.valueAsNumber + }); + }); + editorInkOpacity.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.INK_OPACITY, + value: editorInkOpacity.valueAsNumber }); }); - const onTreeLoaded = (count, button, view) => { - button.disabled = !count; + this.eventBus._on("annotationeditorparamschanged", evt => { + for (const [type, value] of evt.details) { + switch (type) { + case _pdfjsLib.AnnotationEditorParamsType.FREETEXT_SIZE: + editorFreeTextFontSize.value = value; + break; - if (count) { - this._showUINotification(view); - } else if (this.active === view) { - this.switchView(SidebarView.THUMBS); - } - }; + case _pdfjsLib.AnnotationEditorParamsType.FREETEXT_COLOR: + editorFreeTextColor.value = value; + break; - this.eventBus._on("outlineloaded", evt => { - onTreeLoaded(evt.outlineCount, this.outlineButton, SidebarView.OUTLINE); - }); + case _pdfjsLib.AnnotationEditorParamsType.INK_COLOR: + editorInkColor.value = value; + break; - this.eventBus._on("attachmentsloaded", evt => { - onTreeLoaded(evt.attachmentsCount, this.attachmentsButton, SidebarView.ATTACHMENTS); - }); + case _pdfjsLib.AnnotationEditorParamsType.INK_THICKNESS: + editorInkThickness.value = value; + break; - this.eventBus._on("layersloaded", evt => { - onTreeLoaded(evt.layersCount, this.layersButton, SidebarView.LAYERS); - }); - - this.eventBus._on("presentationmodechanged", evt => { - if (!evt.active && !evt.switchInProgress && this.isThumbnailViewVisible) { - this._updateThumbnailViewer(); + case _pdfjsLib.AnnotationEditorParamsType.INK_OPACITY: + editorInkOpacity.value = value; + break; + } } }); } } -exports.PDFSidebar = PDFSidebar; +exports.AnnotationEditorParams = AnnotationEditorParams; /***/ }), /* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.OverlayManager = void 0; class OverlayManager { - constructor() { - this._overlays = {}; - this._active = null; - this._keyDownBound = this._keyDown.bind(this); - } + #overlays = new WeakMap(); + #active = null; get active() { - return this._active; + return this.#active; } - async register(name, element, callerCloseMethod = null, canForceClose = false) { - let container; - - if (!name || !element || !(container = element.parentNode)) { + async register(dialog, canForceClose = false) { + if (typeof dialog !== "object") { throw new Error("Not enough parameters."); - } else if (this._overlays[name]) { + } else if (this.#overlays.has(dialog)) { throw new Error("The overlay is already registered."); } - this._overlays[name] = { - element, - container, - callerCloseMethod, + this.#overlays.set(dialog, { canForceClose - }; + }); + dialog.addEventListener("cancel", evt => { + this.#active = null; + }); } - async unregister(name) { - if (!this._overlays[name]) { + async unregister(dialog) { + if (!this.#overlays.has(dialog)) { throw new Error("The overlay does not exist."); - } else if (this._active === name) { + } else if (this.#active === dialog) { throw new Error("The overlay cannot be removed while it is active."); } - delete this._overlays[name]; + this.#overlays.delete(dialog); } - async open(name) { - if (!this._overlays[name]) { + async open(dialog) { + if (!this.#overlays.has(dialog)) { throw new Error("The overlay does not exist."); - } else if (this._active) { - if (this._overlays[name].canForceClose) { - this._closeThroughCaller(); - } else if (this._active === name) { + } else if (this.#active) { + if (this.#active === dialog) { throw new Error("The overlay is already active."); + } else if (this.#overlays.get(dialog).canForceClose) { + await this.close(); } else { throw new Error("Another overlay is currently active."); } } - this._active = name; - - this._overlays[this._active].element.classList.remove("hidden"); - - this._overlays[this._active].container.classList.remove("hidden"); - - window.addEventListener("keydown", this._keyDownBound); + this.#active = dialog; + dialog.showModal(); } - async close(name) { - if (!this._overlays[name]) { + async close(dialog = this.#active) { + if (!this.#overlays.has(dialog)) { throw new Error("The overlay does not exist."); - } else if (!this._active) { + } else if (!this.#active) { throw new Error("The overlay is currently not active."); - } else if (this._active !== name) { + } else if (this.#active !== dialog) { throw new Error("Another overlay is currently active."); } - this._overlays[this._active].container.classList.add("hidden"); - - this._overlays[this._active].element.classList.add("hidden"); - - this._active = null; - window.removeEventListener("keydown", this._keyDownBound); - } - - _keyDown(evt) { - if (this._active && evt.keyCode === 27) { - this._closeThroughCaller(); - - evt.preventDefault(); - } - } - - _closeThroughCaller() { - if (this._overlays[this._active].callerCloseMethod) { - this._overlays[this._active].callerCloseMethod(); - } - - if (this._active) { - this.close(this._active); - } + dialog.close(); + this.#active = null; } } @@ -4966,77 +4912,102 @@ exports.OverlayManager = OverlayManager; /***/ }), /* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PasswordPrompt = void 0; -var _ui_utils = __webpack_require__(2); - var _pdfjsLib = __webpack_require__(5); class PasswordPrompt { - constructor(options, overlayManager, l10n = _ui_utils.NullL10n) { - this.overlayName = options.overlayName; - this.container = options.container; + #activeCapability = null; + #updateCallback = null; + #reason = null; + + constructor(options, overlayManager, l10n, isViewerEmbedded = false) { + this.dialog = options.dialog; this.label = options.label; this.input = options.input; this.submitButton = options.submitButton; this.cancelButton = options.cancelButton; this.overlayManager = overlayManager; this.l10n = l10n; - this.updateCallback = null; - this.reason = null; - this.submitButton.addEventListener("click", this.verify.bind(this)); + this._isViewerEmbedded = isViewerEmbedded; + this.submitButton.addEventListener("click", this.#verify.bind(this)); this.cancelButton.addEventListener("click", this.close.bind(this)); this.input.addEventListener("keydown", e => { if (e.keyCode === 13) { - this.verify(); + this.#verify(); } }); - this.overlayManager.register(this.overlayName, this.container, this.close.bind(this), true); + this.overlayManager.register(this.dialog, true); + this.dialog.addEventListener("close", this.#cancel.bind(this)); } - open() { - this.overlayManager.open(this.overlayName).then(() => { + async open() { + if (this.#activeCapability) { + await this.#activeCapability.promise; + } + + this.#activeCapability = (0, _pdfjsLib.createPromiseCapability)(); + + try { + await this.overlayManager.open(this.dialog); + } catch (ex) { + this.#activeCapability = null; + throw ex; + } + + const passwordIncorrect = this.#reason === _pdfjsLib.PasswordResponses.INCORRECT_PASSWORD; + + if (!this._isViewerEmbedded || passwordIncorrect) { this.input.focus(); - let promptString; + } - if (this.reason === _pdfjsLib.PasswordResponses.INCORRECT_PASSWORD) { - promptString = this.l10n.get("password_invalid", null, "Invalid password. Please try again."); - } else { - promptString = this.l10n.get("password_label", null, "Enter the password to open this PDF file."); - } - - promptString.then(msg => { - this.label.textContent = msg; - }); - }); + this.label.textContent = await this.l10n.get(`password_${passwordIncorrect ? "invalid" : "label"}`); } - close() { - this.overlayManager.close(this.overlayName).then(() => { - this.input.value = ""; - }); - } - - verify() { - const password = this.input.value; - - if (password && password.length > 0) { - this.close(); - this.updateCallback(password); + async close() { + if (this.overlayManager.active === this.dialog) { + this.overlayManager.close(this.dialog); } } - setUpdateCallback(updateCallback, reason) { - this.updateCallback = updateCallback; - this.reason = reason; + #verify() { + const password = this.input.value; + + if (password?.length > 0) { + this.#invokeCallback(password); + } + } + + #cancel() { + this.#invokeCallback(new Error("PasswordPrompt cancelled.")); + this.#activeCapability.resolve(); + } + + #invokeCallback(password) { + if (!this.#updateCallback) { + return; + } + + this.close(); + this.input.value = ""; + this.#updateCallback(password); + this.#updateCallback = null; + } + + async setUpdateCallback(updateCallback, reason) { + if (this.#activeCapability) { + await this.#activeCapability.promise; + } + + this.#updateCallback = updateCallback; + this.#reason = reason; } } @@ -5045,30 +5016,27 @@ exports.PasswordPrompt = PasswordPrompt; /***/ }), /* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFAttachmentViewer = void 0; var _pdfjsLib = __webpack_require__(5); var _base_tree_viewer = __webpack_require__(13); -var _viewer_compatibility = __webpack_require__(4); - -const PdfFileRegExp = /\.pdf$/i; +var _event_utils = __webpack_require__(6); class PDFAttachmentViewer extends _base_tree_viewer.BaseTreeViewer { constructor(options) { super(options); this.downloadManager = options.downloadManager; - this.eventBus._on("fileattachmentannotation", this._appendAttachment.bind(this)); + this.eventBus._on("fileattachmentannotation", this.#appendAttachment.bind(this)); } reset(keepRenderedCapability = false) { @@ -5079,74 +5047,38 @@ class PDFAttachmentViewer extends _base_tree_viewer.BaseTreeViewer { this._renderedCapability = (0, _pdfjsLib.createPromiseCapability)(); } - if (this._pendingDispatchEvent) { - clearTimeout(this._pendingDispatchEvent); - } - - this._pendingDispatchEvent = null; + this._pendingDispatchEvent = false; } - _dispatchEvent(attachmentsCount) { + async _dispatchEvent(attachmentsCount) { this._renderedCapability.resolve(); - if (this._pendingDispatchEvent) { - clearTimeout(this._pendingDispatchEvent); - this._pendingDispatchEvent = null; - } - - if (attachmentsCount === 0) { - this._pendingDispatchEvent = setTimeout(() => { - this.eventBus.dispatch("attachmentsloaded", { - source: this, - attachmentsCount: 0 - }); - this._pendingDispatchEvent = null; + if (attachmentsCount === 0 && !this._pendingDispatchEvent) { + this._pendingDispatchEvent = true; + await (0, _event_utils.waitOnEventOrTimeout)({ + target: this.eventBus, + name: "annotationlayerrendered", + delay: 1000 }); - return; + + if (!this._pendingDispatchEvent) { + return; + } } + this._pendingDispatchEvent = false; this.eventBus.dispatch("attachmentsloaded", { source: this, attachmentsCount }); } - _bindPdfLink(element, { - content, - filename - }) { - let blobUrl; - - element.onclick = () => { - if (!blobUrl) { - blobUrl = URL.createObjectURL(new Blob([content], { - type: "application/pdf" - })); - } - - let viewerUrl; - viewerUrl = "?file=" + encodeURIComponent(blobUrl + "#" + filename); - - try { - window.open(viewerUrl); - } catch (ex) { - console.error(`_bindPdfLink: ${ex}`); - URL.revokeObjectURL(blobUrl); - blobUrl = null; - this.downloadManager.downloadData(content, filename, "application/pdf"); - } - - return false; - }; - } - _bindLink(element, { content, filename }) { element.onclick = () => { - const contentType = PdfFileRegExp.test(filename) ? "application/pdf" : ""; - this.downloadManager.downloadData(content, filename, contentType); + this.downloadManager.openOrDownloadData(element, content, filename); return false; }; } @@ -5175,36 +5107,27 @@ class PDFAttachmentViewer extends _base_tree_viewer.BaseTreeViewer { for (const name of names) { const item = attachments[name]; - const filename = (0, _pdfjsLib.getFilenameFromUrl)(item.filename); + const content = item.content, + filename = (0, _pdfjsLib.getFilenameFromUrl)(item.filename); const div = document.createElement("div"); div.className = "treeItem"; const element = document.createElement("a"); - if (PdfFileRegExp.test(filename) && !_viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL) { - this._bindPdfLink(element, { - content: item.content, - filename - }); - } else { - this._bindLink(element, { - content: item.content, - filename - }); - } + this._bindLink(element, { + content, + filename + }); element.textContent = this._normalizeTextContent(filename); - div.appendChild(element); - fragment.appendChild(div); + div.append(element); + fragment.append(div); attachmentsCount++; } - this.container.appendChild(fragment); - - this._dispatchEvent(attachmentsCount); + this._finishRendering(fragment, attachmentsCount); } - _appendAttachment({ - id, + #appendAttachment({ filename, content }) { @@ -5214,19 +5137,15 @@ class PDFAttachmentViewer extends _base_tree_viewer.BaseTreeViewer { return; } - let attachments = this._attachments; + const attachments = this._attachments || Object.create(null); - if (!attachments) { - attachments = Object.create(null); - } else { - for (const name in attachments) { - if (id === name) { - return; - } + for (const name in attachments) { + if (filename === name) { + return; } } - attachments[id] = { + attachments[filename] = { filename, content }; @@ -5243,17 +5162,19 @@ exports.PDFAttachmentViewer = PDFAttachmentViewer; /***/ }), /* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.BaseTreeViewer = void 0; -var _pdfjsLib = __webpack_require__(5); +var _ui_utils = __webpack_require__(1); + +const TREEITEM_OFFSET_TOP = -100; +const TREEITEM_SELECTED_CLASS = "selected"; class BaseTreeViewer { constructor(options) { @@ -5267,7 +5188,9 @@ class BaseTreeViewer { } reset() { + this._pdfDocument = null; this._lastToggleIsShow = true; + this._currentTreeItem = null; this.container.textContent = ""; this.container.classList.remove("treeWithDeepNesting"); } @@ -5281,7 +5204,7 @@ class BaseTreeViewer { } _normalizeTextContent(str) { - return (0, _pdfjsLib.removeNullCharacters)(str) || "\u2013"; + return (0, _ui_utils.removeNullCharacters)(str, true) || "\u2013"; } _addToggleButton(div, hidden = false) { @@ -5303,7 +5226,7 @@ class BaseTreeViewer { } }; - div.insertBefore(toggler, div.firstChild); + div.prepend(toggler); } _toggleTreeItem(root, show = false) { @@ -5318,29 +5241,73 @@ class BaseTreeViewer { this._toggleTreeItem(this.container, !this._lastToggleIsShow); } + _finishRendering(fragment, count, hasAnyNesting = false) { + if (hasAnyNesting) { + this.container.classList.add("treeWithDeepNesting"); + this._lastToggleIsShow = !fragment.querySelector(".treeItemsHidden"); + } + + this.container.append(fragment); + + this._dispatchEvent(count); + } + render(params) { throw new Error("Not implemented: render"); } + _updateCurrentTreeItem(treeItem = null) { + if (this._currentTreeItem) { + this._currentTreeItem.classList.remove(TREEITEM_SELECTED_CLASS); + + this._currentTreeItem = null; + } + + if (treeItem) { + treeItem.classList.add(TREEITEM_SELECTED_CLASS); + this._currentTreeItem = treeItem; + } + } + + _scrollToCurrentTreeItem(treeItem) { + if (!treeItem) { + return; + } + + let currentNode = treeItem.parentNode; + + while (currentNode && currentNode !== this.container) { + if (currentNode.classList.contains("treeItem")) { + const toggler = currentNode.firstElementChild; + toggler?.classList.remove("treeItemsHidden"); + } + + currentNode = currentNode.parentNode; + } + + this._updateCurrentTreeItem(treeItem); + + this.container.scrollTo(treeItem.offsetLeft, treeItem.offsetTop + TREEITEM_OFFSET_TOP); + } + } exports.BaseTreeViewer = BaseTreeViewer; /***/ }), /* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFDocumentProperties = void 0; var _pdfjsLib = __webpack_require__(5); -var _ui_utils = __webpack_require__(2); +var _ui_utils = __webpack_require__(1); const DEFAULT_FIELD_CONTENT = "-"; const NON_METRIC_LOCALES = ["en-us", "en-lr", "my"]; @@ -5360,22 +5327,21 @@ function getPageName(size, isPortrait, pageNames) { } class PDFDocumentProperties { + #fieldData = null; + constructor({ - overlayName, + dialog, fields, - container, closeButton - }, overlayManager, eventBus, l10n = _ui_utils.NullL10n) { - this.overlayName = overlayName; + }, overlayManager, eventBus, l10n, fileNameLookup) { + this.dialog = dialog; this.fields = fields; - this.container = container; this.overlayManager = overlayManager; this.l10n = l10n; - - this._reset(); - + this._fileNameLookup = fileNameLookup; + this.#reset(); closeButton.addEventListener("click", this.close.bind(this)); - this.overlayManager.register(this.overlayName, this.container, this.close.bind(this)); + this.overlayManager.register(this.dialog); eventBus._on("pagechanging", evt => { this._currentPageNumber = evt.pageNumber; @@ -5391,85 +5357,64 @@ class PDFDocumentProperties { }); } - open() { - const freezeFieldData = data => { - Object.defineProperty(this, "fieldData", { - value: Object.freeze(data), - writable: false, - enumerable: true, - configurable: true - }); - }; + async open() { + await Promise.all([this.overlayManager.open(this.dialog), this._dataAvailableCapability.promise]); + const currentPageNumber = this._currentPageNumber; + const pagesRotation = this._pagesRotation; - Promise.all([this.overlayManager.open(this.overlayName), this._dataAvailableCapability.promise]).then(() => { - const currentPageNumber = this._currentPageNumber; - const pagesRotation = this._pagesRotation; + if (this.#fieldData && currentPageNumber === this.#fieldData._currentPageNumber && pagesRotation === this.#fieldData._pagesRotation) { + this.#updateUI(); + return; + } - if (this.fieldData && currentPageNumber === this.fieldData._currentPageNumber && pagesRotation === this.fieldData._pagesRotation) { - this._updateUI(); - - return; - } - - this.pdfDocument.getMetadata().then(({ - info, - metadata, - contentDispositionFilename - }) => { - return Promise.all([info, metadata, contentDispositionFilename || (0, _ui_utils.getPDFFileNameFromURL)(this.url), this._parseFileSize(this.maybeFileSize), this._parseDate(info.CreationDate), this._parseDate(info.ModDate), this.pdfDocument.getPage(currentPageNumber).then(pdfPage => { - return this._parsePageSize((0, _ui_utils.getPageSizeInches)(pdfPage), pagesRotation); - }), this._parseLinearization(info.IsLinearized)]); - }).then(([info, metadata, fileName, fileSize, creationDate, modDate, pageSize, isLinearized]) => { - freezeFieldData({ - fileName, - fileSize, - title: info.Title, - author: info.Author, - subject: info.Subject, - keywords: info.Keywords, - creationDate, - modificationDate: modDate, - creator: info.Creator, - producer: info.Producer, - version: info.PDFFormatVersion, - pageCount: this.pdfDocument.numPages, - pageSize, - linearized: isLinearized, - _currentPageNumber: currentPageNumber, - _pagesRotation: pagesRotation - }); - - this._updateUI(); - - return this.pdfDocument.getDownloadInfo(); - }).then(({ - length - }) => { - this.maybeFileSize = length; - return this._parseFileSize(length); - }).then(fileSize => { - if (fileSize === this.fieldData.fileSize) { - return; - } - - const data = Object.assign(Object.create(null), this.fieldData); - data.fileSize = fileSize; - freezeFieldData(data); - - this._updateUI(); - }); + const { + info, + contentLength + } = await this.pdfDocument.getMetadata(); + const [fileName, fileSize, creationDate, modificationDate, pageSize, isLinearized] = await Promise.all([this._fileNameLookup(), this.#parseFileSize(contentLength), this.#parseDate(info.CreationDate), this.#parseDate(info.ModDate), this.pdfDocument.getPage(currentPageNumber).then(pdfPage => { + return this.#parsePageSize((0, _ui_utils.getPageSizeInches)(pdfPage), pagesRotation); + }), this.#parseLinearization(info.IsLinearized)]); + this.#fieldData = Object.freeze({ + fileName, + fileSize, + title: info.Title, + author: info.Author, + subject: info.Subject, + keywords: info.Keywords, + creationDate, + modificationDate, + creator: info.Creator, + producer: info.Producer, + version: info.PDFFormatVersion, + pageCount: this.pdfDocument.numPages, + pageSize, + linearized: isLinearized, + _currentPageNumber: currentPageNumber, + _pagesRotation: pagesRotation }); + this.#updateUI(); + const { + length + } = await this.pdfDocument.getDownloadInfo(); + + if (contentLength === length) { + return; + } + + const data = Object.assign(Object.create(null), this.#fieldData); + data.fileSize = await this.#parseFileSize(length); + this.#fieldData = Object.freeze(data); + this.#updateUI(); } - close() { - this.overlayManager.close(this.overlayName); + async close() { + this.overlayManager.close(this.dialog); } - setDocument(pdfDocument, url = null) { + setDocument(pdfDocument) { if (this.pdfDocument) { - this._reset(); - - this._updateUI(true); + this.#reset(); + this.#updateUI(true); } if (!pdfDocument) { @@ -5477,29 +5422,20 @@ class PDFDocumentProperties { } this.pdfDocument = pdfDocument; - this.url = url; this._dataAvailableCapability.resolve(); } - setFileSize(fileSize) { - if (Number.isInteger(fileSize) && fileSize > 0) { - this.maybeFileSize = fileSize; - } - } - - _reset() { + #reset() { this.pdfDocument = null; - this.url = null; - this.maybeFileSize = 0; - delete this.fieldData; + this.#fieldData = null; this._dataAvailableCapability = (0, _pdfjsLib.createPromiseCapability)(); this._currentPageNumber = 1; this._pagesRotation = 0; } - _updateUI(reset = false) { - if (reset || !this.fieldData) { + #updateUI(reset = false) { + if (reset || !this.#fieldData) { for (const id in this.fields) { this.fields[id].textContent = DEFAULT_FIELD_CONTENT; } @@ -5507,35 +5443,32 @@ class PDFDocumentProperties { return; } - if (this.overlayManager.active !== this.overlayName) { + if (this.overlayManager.active !== this.dialog) { return; } for (const id in this.fields) { - const content = this.fieldData[id]; + const content = this.#fieldData[id]; this.fields[id].textContent = content || content === 0 ? content : DEFAULT_FIELD_CONTENT; } } - async _parseFileSize(fileSize = 0) { - const kb = fileSize / 1024; + async #parseFileSize(fileSize = 0) { + const kb = fileSize / 1024, + mb = kb / 1024; if (!kb) { return undefined; - } else if (kb < 1024) { - return this.l10n.get("document_properties_kb", { - size_kb: (+kb.toPrecision(3)).toLocaleString(), - size_b: fileSize.toLocaleString() - }, "{{size_kb}} KB ({{size_b}} bytes)"); } - return this.l10n.get("document_properties_mb", { - size_mb: (+(kb / 1024).toPrecision(3)).toLocaleString(), + return this.l10n.get(`document_properties_${mb >= 1 ? "mb" : "kb"}`, { + size_mb: mb >= 1 && (+mb.toPrecision(3)).toLocaleString(), + size_kb: mb < 1 && (+kb.toPrecision(3)).toLocaleString(), size_b: fileSize.toLocaleString() - }, "{{size_mb}} MB ({{size_b}} bytes)"); + }); } - async _parsePageSize(pageSizeInches, pagesRotation) { + async #parsePageSize(pageSizeInches, pagesRotation) { if (!pageSizeInches) { return undefined; } @@ -5556,7 +5489,6 @@ class PDFDocumentProperties { width: Math.round(pageSizeInches.width * 25.4 * 10) / 10, height: Math.round(pageSizeInches.height * 25.4 * 10) / 10 }; - let pageName = null; let rawName = getPageName(sizeInches, isPortrait, US_PAGE_NAMES) || getPageName(sizeMillimeters, isPortrait, METRIC_PAGE_NAMES); if (!rawName && !(Number.isInteger(sizeMillimeters.width) && Number.isInteger(sizeMillimeters.height))) { @@ -5582,25 +5514,20 @@ class PDFDocumentProperties { } } - if (rawName) { - pageName = this.l10n.get("document_properties_page_size_name_" + rawName.toLowerCase(), null, rawName); - } - - return Promise.all([this._isNonMetricLocale ? sizeInches : sizeMillimeters, this.l10n.get("document_properties_page_size_unit_" + (this._isNonMetricLocale ? "inches" : "millimeters"), null, this._isNonMetricLocale ? "in" : "mm"), pageName, this.l10n.get("document_properties_page_size_orientation_" + (isPortrait ? "portrait" : "landscape"), null, isPortrait ? "portrait" : "landscape")]).then(([{ + const [{ width, height - }, unit, name, orientation]) => { - return this.l10n.get("document_properties_page_size_dimension_" + (name ? "name_" : "") + "string", { - width: width.toLocaleString(), - height: height.toLocaleString(), - unit, - name, - orientation - }, "{{width}} × {{height}} {{unit}} (" + (name ? "{{name}}, " : "") + "{{orientation}})"); + }, unit, name, orientation] = await Promise.all([this._isNonMetricLocale ? sizeInches : sizeMillimeters, this.l10n.get(`document_properties_page_size_unit_${this._isNonMetricLocale ? "inches" : "millimeters"}`), rawName && this.l10n.get(`document_properties_page_size_name_${rawName.toLowerCase()}`), this.l10n.get(`document_properties_page_size_orientation_${isPortrait ? "portrait" : "landscape"}`)]); + return this.l10n.get(`document_properties_page_size_dimension_${name ? "name_" : ""}string`, { + width: width.toLocaleString(), + height: height.toLocaleString(), + unit, + name, + orientation }); } - async _parseDate(inputDate) { + async #parseDate(inputDate) { const dateObject = _pdfjsLib.PDFDateString.toDateObject(inputDate); if (!dateObject) { @@ -5610,11 +5537,11 @@ class PDFDocumentProperties { return this.l10n.get("document_properties_date_string", { date: dateObject.toLocaleDateString(), time: dateObject.toLocaleTimeString() - }, "{{date}}, {{time}}"); + }); } - _parseLinearization(isLinearized) { - return this.l10n.get("document_properties_linearized_" + (isLinearized ? "yes" : "no"), null, isLinearized ? "Yes" : "No"); + #parseLinearization(isLinearized) { + return this.l10n.get(`document_properties_linearized_${isLinearized ? "yes" : "no"}`); } } @@ -5623,35 +5550,33 @@ exports.PDFDocumentProperties = PDFDocumentProperties; /***/ }), /* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFFindBar = void 0; var _pdf_find_controller = __webpack_require__(16); -var _ui_utils = __webpack_require__(2); - const MATCHES_COUNT_LIMIT = 1000; class PDFFindBar { - constructor(options, eventBus, l10n = _ui_utils.NullL10n) { + constructor(options, eventBus, l10n) { this.opened = false; - this.bar = options.bar || null; - this.toggleButton = options.toggleButton || null; - this.findField = options.findField || null; - this.highlightAll = options.highlightAllCheckbox || null; - this.caseSensitive = options.caseSensitiveCheckbox || null; - this.entireWord = options.entireWordCheckbox || null; - this.findMsg = options.findMsg || null; - this.findResultsCount = options.findResultsCount || null; - this.findPreviousButton = options.findPreviousButton || null; - this.findNextButton = options.findNextButton || null; + this.bar = options.bar; + this.toggleButton = options.toggleButton; + this.findField = options.findField; + this.highlightAll = options.highlightAllCheckbox; + this.caseSensitive = options.caseSensitiveCheckbox; + this.matchDiacritics = options.matchDiacriticsCheckbox; + this.entireWord = options.entireWordCheckbox; + this.findMsg = options.findMsg; + this.findResultsCount = options.findResultsCount; + this.findPreviousButton = options.findPreviousButton; + this.findNextButton = options.findNextButton; this.eventBus = eventBus; this.l10n = l10n; this.toggleButton.addEventListener("click", () => { @@ -5689,15 +5614,18 @@ class PDFFindBar { this.entireWord.addEventListener("click", () => { this.dispatchEvent("entirewordchange"); }); + this.matchDiacritics.addEventListener("click", () => { + this.dispatchEvent("diacriticmatchingchange"); + }); - this.eventBus._on("resize", this._adjustWidth.bind(this)); + this.eventBus._on("resize", this.#adjustWidth.bind(this)); } reset() { this.updateUIState(); } - dispatchEvent(type, findPrev) { + dispatchEvent(type, findPrev = false) { this.eventBus.dispatch("find", { source: this, type, @@ -5706,13 +5634,13 @@ class PDFFindBar { caseSensitive: this.caseSensitive.checked, entireWord: this.entireWord.checked, highlightAll: this.highlightAll.checked, - findPrevious: findPrev + findPrevious: findPrev, + matchDiacritics: this.matchDiacritics.checked }); } updateUIState(state, previous, matchesCount) { - let notFound = false; - let findMsg = ""; + let findMsg = Promise.resolve(""); let status = ""; switch (state) { @@ -5724,26 +5652,20 @@ class PDFFindBar { break; case _pdf_find_controller.FindState.NOT_FOUND: - findMsg = this.l10n.get("find_not_found", null, "Phrase not found"); - notFound = true; + findMsg = this.l10n.get("find_not_found"); + status = "notFound"; break; case _pdf_find_controller.FindState.WRAPPED: - if (previous) { - findMsg = this.l10n.get("find_reached_top", null, "Reached top of document, continued from bottom"); - } else { - findMsg = this.l10n.get("find_reached_bottom", null, "Reached end of document, continued from top"); - } - + findMsg = this.l10n.get(`find_reached_${previous ? "top" : "bottom"}`); break; } - this.findField.classList.toggle("notFound", notFound); this.findField.setAttribute("data-status", status); - Promise.resolve(findMsg).then(msg => { + this.findField.setAttribute("aria-invalid", state === _pdf_find_controller.FindState.NOT_FOUND); + findMsg.then(msg => { this.findMsg.textContent = msg; - - this._adjustWidth(); + this.#adjustWidth(); }); this.updateResultsCount(matchesCount); } @@ -5752,31 +5674,27 @@ class PDFFindBar { current = 0, total = 0 } = {}) { - if (!this.findResultsCount) { - return; - } - const limit = MATCHES_COUNT_LIMIT; - let matchesCountMsg = ""; + let matchCountMsg = Promise.resolve(""); if (total > 0) { if (total > limit) { - matchesCountMsg = this.l10n.get("find_match_count_limit", { + let key = "find_match_count_limit"; + matchCountMsg = this.l10n.get(key, { limit - }, "More than {{limit}} match" + (limit !== 1 ? "es" : "")); + }); } else { - matchesCountMsg = this.l10n.get("find_match_count", { + let key = "find_match_count"; + matchCountMsg = this.l10n.get(key, { current, total - }, "{{current}} of {{total}} match" + (total !== 1 ? "es" : "")); + }); } } - Promise.resolve(matchesCountMsg).then(msg => { + matchCountMsg.then(msg => { this.findResultsCount.textContent = msg; - this.findResultsCount.classList.toggle("hidden", !total); - - this._adjustWidth(); + this.#adjustWidth(); }); } @@ -5784,13 +5702,13 @@ class PDFFindBar { if (!this.opened) { this.opened = true; this.toggleButton.classList.add("toggled"); + this.toggleButton.setAttribute("aria-expanded", "true"); this.bar.classList.remove("hidden"); } this.findField.select(); this.findField.focus(); - - this._adjustWidth(); + this.#adjustWidth(); } close() { @@ -5800,6 +5718,7 @@ class PDFFindBar { this.opened = false; this.toggleButton.classList.remove("toggled"); + this.toggleButton.setAttribute("aria-expanded", "false"); this.bar.classList.add("hidden"); this.eventBus.dispatch("findbarclose", { source: this @@ -5814,7 +5733,7 @@ class PDFFindBar { } } - _adjustWidth() { + #adjustWidth() { if (!this.opened) { return; } @@ -5834,22 +5753,21 @@ exports.PDFFindBar = PDFFindBar; /***/ }), /* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFFindController = exports.FindState = void 0; +var _ui_utils = __webpack_require__(1); + var _pdfjsLib = __webpack_require__(5); var _pdf_find_utils = __webpack_require__(17); -var _ui_utils = __webpack_require__(2); - const FindState = { FOUND: 0, NOT_FOUND: 1, @@ -5861,6 +5779,7 @@ const FIND_TIMEOUT = 250; const MATCH_SCROLL_OFFSET_TOP = -50; const MATCH_SCROLL_OFFSET_LEFT = -400; const CHARACTERS_TO_NORMALIZE = { + "\u2010": "-", "\u2018": "'", "\u2019": "'", "\u201A": "'", @@ -5873,17 +5792,169 @@ const CHARACTERS_TO_NORMALIZE = { "\u00BD": "1/2", "\u00BE": "3/4" }; -let normalizationRegex = null; +const DIACRITICS_EXCEPTION = new Set([0x3099, 0x309a, 0x094d, 0x09cd, 0x0a4d, 0x0acd, 0x0b4d, 0x0bcd, 0x0c4d, 0x0ccd, 0x0d3b, 0x0d3c, 0x0d4d, 0x0dca, 0x0e3a, 0x0eba, 0x0f84, 0x1039, 0x103a, 0x1714, 0x1734, 0x17d2, 0x1a60, 0x1b44, 0x1baa, 0x1bab, 0x1bf2, 0x1bf3, 0x2d7f, 0xa806, 0xa82c, 0xa8c4, 0xa953, 0xa9c0, 0xaaf6, 0xabed, 0x0c56, 0x0f71, 0x0f72, 0x0f7a, 0x0f7b, 0x0f7c, 0x0f7d, 0x0f80, 0x0f74]); +const DIACRITICS_EXCEPTION_STR = [...DIACRITICS_EXCEPTION.values()].map(x => String.fromCharCode(x)).join(""); +const DIACRITICS_REG_EXP = /\p{M}+/gu; +const SPECIAL_CHARS_REG_EXP = /([.*+?^${}()|[\]\\])|(\p{P})|(\s+)|(\p{M})|(\p{L})/gu; +const NOT_DIACRITIC_FROM_END_REG_EXP = /([^\p{M}])\p{M}*$/u; +const NOT_DIACRITIC_FROM_START_REG_EXP = /^\p{M}*([^\p{M}])/u; +const SYLLABLES_REG_EXP = /[\uAC00-\uD7AF\uFA6C\uFACF-\uFAD1\uFAD5-\uFAD7]+/g; +const SYLLABLES_LENGTHS = new Map(); +const FIRST_CHAR_SYLLABLES_REG_EXP = "[\\u1100-\\u1112\\ud7a4-\\ud7af\\ud84a\\ud84c\\ud850\\ud854\\ud857\\ud85f]"; +let noSyllablesRegExp = null; +let withSyllablesRegExp = null; function normalize(text) { - if (!normalizationRegex) { - const replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(""); - normalizationRegex = new RegExp(`[${replace}]`, "g"); + const syllablePositions = []; + let m; + + while ((m = SYLLABLES_REG_EXP.exec(text)) !== null) { + let { + index + } = m; + + for (const char of m[0]) { + let len = SYLLABLES_LENGTHS.get(char); + + if (!len) { + len = char.normalize("NFD").length; + SYLLABLES_LENGTHS.set(char, len); + } + + syllablePositions.push([len, index++]); + } } - return text.replace(normalizationRegex, function (ch) { - return CHARACTERS_TO_NORMALIZE[ch]; + let normalizationRegex; + + if (syllablePositions.length === 0 && noSyllablesRegExp) { + normalizationRegex = noSyllablesRegExp; + } else if (syllablePositions.length > 0 && withSyllablesRegExp) { + normalizationRegex = withSyllablesRegExp; + } else { + const replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(""); + const regexp = `([${replace}])|(\\p{M}+(?:-\\n)?)|(\\S-\\n)|(\\n)`; + + if (syllablePositions.length === 0) { + normalizationRegex = noSyllablesRegExp = new RegExp(regexp + "|(\\u0000)", "gum"); + } else { + normalizationRegex = withSyllablesRegExp = new RegExp(regexp + `|(${FIRST_CHAR_SYLLABLES_REG_EXP})`, "gum"); + } + } + + const rawDiacriticsPositions = []; + + while ((m = DIACRITICS_REG_EXP.exec(text)) !== null) { + rawDiacriticsPositions.push([m[0].length, m.index]); + } + + let normalized = text.normalize("NFD"); + const positions = [[0, 0]]; + let rawDiacriticsIndex = 0; + let syllableIndex = 0; + let shift = 0; + let shiftOrigin = 0; + let eol = 0; + let hasDiacritics = false; + normalized = normalized.replace(normalizationRegex, (match, p1, p2, p3, p4, p5, i) => { + i -= shiftOrigin; + + if (p1) { + const replacement = CHARACTERS_TO_NORMALIZE[match]; + const jj = replacement.length; + + for (let j = 1; j < jj; j++) { + positions.push([i - shift + j, shift - j]); + } + + shift -= jj - 1; + return replacement; + } + + if (p2) { + const hasTrailingDashEOL = p2.endsWith("\n"); + const len = hasTrailingDashEOL ? p2.length - 2 : p2.length; + hasDiacritics = true; + let jj = len; + + if (i + eol === rawDiacriticsPositions[rawDiacriticsIndex]?.[1]) { + jj -= rawDiacriticsPositions[rawDiacriticsIndex][0]; + ++rawDiacriticsIndex; + } + + for (let j = 1; j <= jj; j++) { + positions.push([i - 1 - shift + j, shift - j]); + } + + shift -= jj; + shiftOrigin += jj; + + if (hasTrailingDashEOL) { + i += len - 1; + positions.push([i - shift + 1, 1 + shift]); + shift += 1; + shiftOrigin += 1; + eol += 1; + return p2.slice(0, len); + } + + return p2; + } + + if (p3) { + positions.push([i - shift + 1, 1 + shift]); + shift += 1; + shiftOrigin += 1; + eol += 1; + return p3.charAt(0); + } + + if (p4) { + positions.push([i - shift + 1, shift - 1]); + shift -= 1; + shiftOrigin += 1; + eol += 1; + return " "; + } + + if (i + eol === syllablePositions[syllableIndex]?.[1]) { + const newCharLen = syllablePositions[syllableIndex][0] - 1; + ++syllableIndex; + + for (let j = 1; j <= newCharLen; j++) { + positions.push([i - (shift - j), shift - j]); + } + + shift -= newCharLen; + shiftOrigin += newCharLen; + } + + return p5; }); + positions.push([normalized.length, shift]); + return [normalized, positions, hasDiacritics]; +} + +function getOriginalIndex(diffs, pos, len) { + if (!diffs) { + return [pos, len]; + } + + const start = pos; + const end = pos + len; + let i = (0, _ui_utils.binarySearchFirstItem)(diffs, x => x[0] >= start); + + if (diffs[i][0] > start) { + --i; + } + + let j = (0, _ui_utils.binarySearchFirstItem)(diffs, x => x[0] >= end, i); + + if (diffs[j][0] > end) { + --j; + } + + return [start + diffs[i][1], len + diffs[j][1] - diffs[i][1]]; } class PDFFindController { @@ -5893,10 +5964,11 @@ class PDFFindController { }) { this._linkService = linkService; this._eventBus = eventBus; + this.#reset(); - this._reset(); + eventBus._on("find", this.#onFind.bind(this)); - eventBus._on("findbarclose", this._onFindBarClose.bind(this)); + eventBus._on("findbarclose", this.#onFindBarClose.bind(this)); } get highlightMatches() { @@ -5921,7 +5993,7 @@ class PDFFindController { setDocument(pdfDocument) { if (this._pdfDocument) { - this._reset(); + this.#reset(); } if (!pdfDocument) { @@ -5933,21 +6005,24 @@ class PDFFindController { this._firstPageCapability.resolve(); } - executeCommand(cmd, state) { + #onFind(state) { if (!state) { return; } const pdfDocument = this._pdfDocument; + const { + type + } = state; - if (this._state === null || this._shouldDirtyMatch(cmd, state)) { + if (this._state === null || this.#shouldDirtyMatch(state)) { this._dirtyMatch = true; } this._state = state; - if (cmd !== "findhighlightallchange") { - this._updateUIState(FindState.PENDING); + if (type !== "highlightallchange") { + this.#updateUIState(FindState.PENDING); } this._firstPageCapability.promise.then(() => { @@ -5955,8 +6030,7 @@ class PDFFindController { return; } - this._extractText(); - + this.#extractText(); const findbarClosed = !this._highlightMatches; const pendingTimeout = !!this._findTimeout; @@ -5965,36 +6039,36 @@ class PDFFindController { this._findTimeout = null; } - if (cmd === "find") { + if (!type) { this._findTimeout = setTimeout(() => { - this._nextMatch(); - + this.#nextMatch(); this._findTimeout = null; }, FIND_TIMEOUT); } else if (this._dirtyMatch) { - this._nextMatch(); - } else if (cmd === "findagain") { - this._nextMatch(); + this.#nextMatch(); + } else if (type === "again") { + this.#nextMatch(); if (findbarClosed && this._state.highlightAll) { - this._updateAllPages(); + this.#updateAllPages(); } - } else if (cmd === "findhighlightallchange") { + } else if (type === "highlightallchange") { if (pendingTimeout) { - this._nextMatch(); + this.#nextMatch(); } else { this._highlightMatches = true; } - this._updateAllPages(); + this.#updateAllPages(); } else { - this._nextMatch(); + this.#nextMatch(); } }); } scrollMatchIntoView({ element = null, + selectedLeft = 0, pageIndex = -1, matchIndex = -1 }) { @@ -6009,12 +6083,12 @@ class PDFFindController { this._scrollMatches = false; const spot = { top: MATCH_SCROLL_OFFSET_TOP, - left: MATCH_SCROLL_OFFSET_LEFT + left: selectedLeft + MATCH_SCROLL_OFFSET_LEFT }; (0, _ui_utils.scrollIntoView)(element, spot, true); } - _reset() { + #reset() { this._highlightMatches = false; this._scrollMatches = false; this._pdfDocument = null; @@ -6032,9 +6106,11 @@ class PDFFindController { }; this._extractTextPromises = []; this._pageContents = []; + this._pageDiffs = []; + this._hasDiacritics = []; this._matchesCountTotal = 0; this._pagesToSearch = null; - this._pendingFindMatches = Object.create(null); + this._pendingFindMatches = new Set(); this._resumePageIdx = null; this._dirtyMatch = false; clearTimeout(this._findTimeout); @@ -6042,22 +6118,22 @@ class PDFFindController { this._firstPageCapability = (0, _pdfjsLib.createPromiseCapability)(); } - get _query() { + get #query() { if (this._state.query !== this._rawQuery) { this._rawQuery = this._state.query; - this._normalizedQuery = normalize(this._state.query); + [this._normalizedQuery] = normalize(this._state.query); } return this._normalizedQuery; } - _shouldDirtyMatch(cmd, state) { + #shouldDirtyMatch(state) { if (state.query !== this._state.query) { return true; } - switch (cmd) { - case "findagain": + switch (state.type) { + case "again": const pageNumber = this._selected.pageIdx + 1; const linkService = this._linkService; @@ -6067,72 +6143,30 @@ class PDFFindController { return false; - case "findhighlightallchange": + case "highlightallchange": return false; } return true; } - _prepareMatches(matchesWithLength, matches, matchesLength) { - function isSubTerm(currentIndex) { - const currentElem = matchesWithLength[currentIndex]; - const nextElem = matchesWithLength[currentIndex + 1]; + #isEntireWord(content, startIdx, length) { + let match = content.slice(0, startIdx).match(NOT_DIACRITIC_FROM_END_REG_EXP); - if (currentIndex < matchesWithLength.length - 1 && currentElem.match === nextElem.match) { - currentElem.skipped = true; - return true; - } - - for (let i = currentIndex - 1; i >= 0; i--) { - const prevElem = matchesWithLength[i]; - - if (prevElem.skipped) { - continue; - } - - if (prevElem.match + prevElem.matchLength < currentElem.match) { - break; - } - - if (prevElem.match + prevElem.matchLength >= currentElem.match + currentElem.matchLength) { - currentElem.skipped = true; - return true; - } - } - - return false; - } - - matchesWithLength.sort(function (a, b) { - return a.match === b.match ? a.matchLength - b.matchLength : a.match - b.match; - }); - - for (let i = 0, len = matchesWithLength.length; i < len; i++) { - if (isSubTerm(i)) { - continue; - } - - matches.push(matchesWithLength[i].match); - matchesLength.push(matchesWithLength[i].matchLength); - } - } - - _isEntireWord(content, startIdx, length) { - if (startIdx > 0) { + if (match) { const first = content.charCodeAt(startIdx); - const limit = content.charCodeAt(startIdx - 1); + const limit = match[1].charCodeAt(0); if ((0, _pdf_find_utils.getCharacterType)(first) === (0, _pdf_find_utils.getCharacterType)(limit)) { return false; } } - const endIdx = startIdx + length - 1; + match = content.slice(startIdx + length).match(NOT_DIACRITIC_FROM_START_REG_EXP); - if (endIdx < content.length - 1) { - const last = content.charCodeAt(endIdx); - const limit = content.charCodeAt(endIdx + 1); + if (match) { + const last = content.charCodeAt(startIdx + length - 1); + const limit = match[1].charCodeAt(0); if ((0, _pdf_find_utils.getCharacterType)(last) === (0, _pdf_find_utils.getCharacterType)(limit)) { return false; @@ -6142,106 +6176,130 @@ class PDFFindController { return true; } - _calculatePhraseMatch(query, pageIndex, pageContent, entireWord) { - const matches = []; - const queryLen = query.length; - let matchIdx = -queryLen; + #calculateRegExpMatch(query, entireWord, pageIndex, pageContent) { + const matches = [], + matchesLength = []; + const diffs = this._pageDiffs[pageIndex]; + let match; - while (true) { - matchIdx = pageContent.indexOf(query, matchIdx + queryLen); - - if (matchIdx === -1) { - break; - } - - if (entireWord && !this._isEntireWord(pageContent, matchIdx, queryLen)) { + while ((match = query.exec(pageContent)) !== null) { + if (entireWord && !this.#isEntireWord(pageContent, match.index, match[0].length)) { continue; } - matches.push(matchIdx); - } + const [matchPos, matchLen] = getOriginalIndex(diffs, match.index, match[0].length); - this._pageMatches[pageIndex] = matches; - } - - _calculateWordMatch(query, pageIndex, pageContent, entireWord) { - const matchesWithLength = []; - const queryArray = query.match(/\S+/g); - - for (let i = 0, len = queryArray.length; i < len; i++) { - const subquery = queryArray[i]; - const subqueryLen = subquery.length; - let matchIdx = -subqueryLen; - - while (true) { - matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen); - - if (matchIdx === -1) { - break; - } - - if (entireWord && !this._isEntireWord(pageContent, matchIdx, subqueryLen)) { - continue; - } - - matchesWithLength.push({ - match: matchIdx, - matchLength: subqueryLen, - skipped: false - }); + if (matchLen) { + matches.push(matchPos); + matchesLength.push(matchLen); } } - this._pageMatchesLength[pageIndex] = []; - this._pageMatches[pageIndex] = []; - - this._prepareMatches(matchesWithLength, this._pageMatches[pageIndex], this._pageMatchesLength[pageIndex]); + this._pageMatches[pageIndex] = matches; + this._pageMatchesLength[pageIndex] = matchesLength; } - _calculateMatch(pageIndex) { - let pageContent = this._pageContents[pageIndex]; - let query = this._query; + #convertToRegExpString(query, hasDiacritics) { const { - caseSensitive, - entireWord, - phraseSearch + matchDiacritics } = this._state; + let isUnicode = false; + query = query.replace(SPECIAL_CHARS_REG_EXP, (match, p1, p2, p3, p4, p5) => { + if (p1) { + return `[ ]*\\${p1}[ ]*`; + } + + if (p2) { + return `[ ]*${p2}[ ]*`; + } + + if (p3) { + return "[ ]+"; + } + + if (matchDiacritics) { + return p4 || p5; + } + + if (p4) { + return DIACRITICS_EXCEPTION.has(p4.charCodeAt(0)) ? p4 : ""; + } + + if (hasDiacritics) { + isUnicode = true; + return `${p5}\\p{M}*`; + } + + return p5; + }); + const trailingSpaces = "[ ]*"; + + if (query.endsWith(trailingSpaces)) { + query = query.slice(0, query.length - trailingSpaces.length); + } + + if (matchDiacritics) { + if (hasDiacritics) { + isUnicode = true; + query = `${query}(?=[${DIACRITICS_EXCEPTION_STR}]|[^\\p{M}]|$)`; + } + } + + return [isUnicode, query]; + } + + #calculateMatch(pageIndex) { + let query = this.#query; if (query.length === 0) { return; } - if (!caseSensitive) { - pageContent = pageContent.toLowerCase(); - query = query.toLowerCase(); - } + const { + caseSensitive, + entireWord, + phraseSearch + } = this._state; + const pageContent = this._pageContents[pageIndex]; + const hasDiacritics = this._hasDiacritics[pageIndex]; + let isUnicode = false; if (phraseSearch) { - this._calculatePhraseMatch(query, pageIndex, pageContent, entireWord); + [isUnicode, query] = this.#convertToRegExpString(query, hasDiacritics); } else { - this._calculateWordMatch(query, pageIndex, pageContent, entireWord); + const match = query.match(/\S+/g); + + if (match) { + query = match.sort().reverse().map(q => { + const [isUnicodePart, queryPart] = this.#convertToRegExpString(q, hasDiacritics); + isUnicode ||= isUnicodePart; + return `(${queryPart})`; + }).join("|"); + } } + const flags = `g${isUnicode ? "u" : ""}${caseSensitive ? "" : "i"}`; + query = new RegExp(query, flags); + this.#calculateRegExpMatch(query, entireWord, pageIndex, pageContent); + if (this._state.highlightAll) { - this._updatePage(pageIndex); + this.#updatePage(pageIndex); } if (this._resumePageIdx === pageIndex) { this._resumePageIdx = null; - - this._nextPageMatch(); + this.#nextPageMatch(); } const pageMatchesCount = this._pageMatches[pageIndex].length; if (pageMatchesCount > 0) { this._matchesCountTotal += pageMatchesCount; - - this._updateUIResultsCount(); + this.#updateUIResultsCount(); } } - _extractText() { + #extractText() { if (this._extractTextPromises.length > 0) { return; } @@ -6253,29 +6311,32 @@ class PDFFindController { this._extractTextPromises[i] = extractTextCapability.promise; promise = promise.then(() => { return this._pdfDocument.getPage(i + 1).then(pdfPage => { - return pdfPage.getTextContent({ - normalizeWhitespace: true - }); + return pdfPage.getTextContent(); }).then(textContent => { - const textItems = textContent.items; const strBuf = []; - for (let j = 0, jj = textItems.length; j < jj; j++) { - strBuf.push(textItems[j].str); + for (const textItem of textContent.items) { + strBuf.push(textItem.str); + + if (textItem.hasEOL) { + strBuf.push("\n"); + } } - this._pageContents[i] = normalize(strBuf.join("")); - extractTextCapability.resolve(i); + [this._pageContents[i], this._pageDiffs[i], this._hasDiacritics[i]] = normalize(strBuf.join("")); + extractTextCapability.resolve(); }, reason => { console.error(`Unable to get text content for page ${i + 1}`, reason); this._pageContents[i] = ""; - extractTextCapability.resolve(i); + this._pageDiffs[i] = null; + this._hasDiacritics[i] = false; + extractTextCapability.resolve(); }); }); } } - _updatePage(index) { + #updatePage(index) { if (this._scrollMatches && this._selected.pageIdx === index) { this._linkService.page = index + 1; } @@ -6286,14 +6347,14 @@ class PDFFindController { }); } - _updateAllPages() { + #updateAllPages() { this._eventBus.dispatch("updatetextlayermatches", { source: this, pageIndex: -1 }); } - _nextMatch() { + #nextMatch() { const previous = this._state.findPrevious; const currentPageIndex = this._linkService.page - 1; const numPages = this._linkService.pagesCount; @@ -6309,27 +6370,25 @@ class PDFFindController { this._pageMatches.length = 0; this._pageMatchesLength.length = 0; this._matchesCountTotal = 0; - - this._updateAllPages(); + this.#updateAllPages(); for (let i = 0; i < numPages; i++) { - if (this._pendingFindMatches[i] === true) { + if (this._pendingFindMatches.has(i)) { continue; } - this._pendingFindMatches[i] = true; + this._pendingFindMatches.add(i); - this._extractTextPromises[i].then(pageIdx => { - delete this._pendingFindMatches[pageIdx]; + this._extractTextPromises[i].then(() => { + this._pendingFindMatches.delete(i); - this._calculateMatch(pageIdx); + this.#calculateMatch(i); }); } } - if (this._query === "") { - this._updateUIState(FindState.FOUND); - + if (this.#query === "") { + this.#updateUIState(FindState.FOUND); return; } @@ -6345,39 +6404,34 @@ class PDFFindController { if (!previous && offset.matchIdx + 1 < numPageMatches || previous && offset.matchIdx > 0) { offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1; - - this._updateMatch(true); - + this.#updateMatch(true); return; } - this._advanceOffsetPage(previous); + this.#advanceOffsetPage(previous); } - this._nextPageMatch(); + this.#nextPageMatch(); } - _matchesReady(matches) { + #matchesReady(matches) { const offset = this._offset; const numMatches = matches.length; const previous = this._state.findPrevious; if (numMatches) { offset.matchIdx = previous ? numMatches - 1 : 0; - - this._updateMatch(true); - + this.#updateMatch(true); return true; } - this._advanceOffsetPage(previous); + this.#advanceOffsetPage(previous); if (offset.wrapped) { offset.matchIdx = null; if (this._pagesToSearch < 0) { - this._updateMatch(false); - + this.#updateMatch(false); return true; } } @@ -6385,7 +6439,7 @@ class PDFFindController { return false; } - _nextPageMatch() { + #nextPageMatch() { if (this._resumePageIdx !== null) { console.error("There can only be one pending page."); } @@ -6400,10 +6454,10 @@ class PDFFindController { this._resumePageIdx = pageIdx; break; } - } while (!this._matchesReady(matches)); + } while (!this.#matchesReady(matches)); } - _advanceOffsetPage(previous) { + #advanceOffsetPage(previous) { const offset = this._offset; const numPages = this._linkService.pagesCount; offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1; @@ -6416,7 +6470,7 @@ class PDFFindController { } } - _updateMatch(found = false) { + #updateMatch(found = false) { let state = FindState.NOT_FOUND; const wrapped = this._offset.wrapped; this._offset.wrapped = false; @@ -6428,20 +6482,19 @@ class PDFFindController { state = wrapped ? FindState.WRAPPED : FindState.FOUND; if (previousPage !== -1 && previousPage !== this._selected.pageIdx) { - this._updatePage(previousPage); + this.#updatePage(previousPage); } } - this._updateUIState(state, this._state.findPrevious); + this.#updateUIState(state, this._state.findPrevious); if (this._selected.pageIdx !== -1) { this._scrollMatches = true; - - this._updatePage(this._selected.pageIdx); + this.#updatePage(this._selected.pageIdx); } } - _onFindBarClose(evt) { + #onFindBarClose(evt) { const pdfDocument = this._pdfDocument; this._firstPageCapability.promise.then(() => { @@ -6459,15 +6512,13 @@ class PDFFindController { this._dirtyMatch = true; } - this._updateUIState(FindState.FOUND); - + this.#updateUIState(FindState.FOUND); this._highlightMatches = false; - - this._updateAllPages(); + this.#updateAllPages(); }); } - _requestMatchesCount() { + #requestMatchesCount() { const { pageIdx, matchIdx @@ -6477,7 +6528,7 @@ class PDFFindController { if (matchIdx !== -1) { for (let i = 0; i < pageIdx; i++) { - current += this._pageMatches[i] && this._pageMatches[i].length || 0; + current += this._pageMatches[i]?.length || 0; } current += matchIdx + 1; @@ -6493,20 +6544,20 @@ class PDFFindController { }; } - _updateUIResultsCount() { + #updateUIResultsCount() { this._eventBus.dispatch("updatefindmatchescount", { source: this, - matchesCount: this._requestMatchesCount() + matchesCount: this.#requestMatchesCount() }); } - _updateUIState(state, previous) { + #updateUIState(state, previous = false) { this._eventBus.dispatch("updatefindcontrolstate", { source: this, state, previous, - matchesCount: this._requestMatchesCount(), - rawQuery: this._state ? this._state.query : null + matchesCount: this.#requestMatchesCount(), + rawQuery: this._state?.query ?? null }); } @@ -6516,16 +6567,15 @@ exports.PDFFindController = PDFFindController; /***/ }), /* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.getCharacterType = getCharacterType; +})); exports.CharacterType = void 0; +exports.getCharacterType = getCharacterType; const CharacterType = { SPACE: 0, ALPHA_LETTER: 1, @@ -6612,19 +6662,20 @@ function getCharacterType(charCode) { /***/ }), /* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.isDestHashesEqual = isDestHashesEqual; -exports.isDestArraysEqual = isDestArraysEqual; +})); exports.PDFHistory = void 0; +exports.isDestArraysEqual = isDestArraysEqual; +exports.isDestHashesEqual = isDestHashesEqual; -var _ui_utils = __webpack_require__(2); +var _ui_utils = __webpack_require__(1); + +var _event_utils = __webpack_require__(6); const HASH_CHANGE_TIMEOUT = 1000; const POSITION_UPDATED_THRESHOLD = 50; @@ -6645,22 +6696,15 @@ class PDFHistory { this._fingerprint = ""; this.reset(); this._boundEvents = null; - this._isViewerInPresentationMode = false; - - this.eventBus._on("presentationmodechanged", evt => { - this._isViewerInPresentationMode = evt.active || evt.switchInProgress; - }); this.eventBus._on("pagesinit", () => { this._isPagesLoaded = false; - const onPagesLoaded = evt => { - this.eventBus._off("pagesloaded", onPagesLoaded); - + this.eventBus._on("pagesloaded", evt => { this._isPagesLoaded = !!evt.pagesCount; - }; - - this.eventBus._on("pagesloaded", onPagesLoaded); + }, { + once: true + }); }); } @@ -6720,10 +6764,6 @@ class PDFHistory { this._updateInternalState(destination, state.uid, true); - if (this._uid > this._maxUid) { - this._maxUid = this._uid; - } - if (destination.rotation !== undefined) { this._initialRotation = destination.rotation; } @@ -6771,7 +6811,7 @@ class PDFHistory { } else if (!Array.isArray(explicitDest)) { console.error("PDFHistory.push: " + `"${explicitDest}" is not a valid explicitDest parameter.`); return; - } else if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.linkService.pagesCount)) { + } else if (!this._isValidPage(pageNumber)) { if (pageNumber !== null || this._destination) { console.error("PDFHistory.push: " + `"${pageNumber}" is not a valid pageNumber parameter.`); return; @@ -6813,6 +6853,39 @@ class PDFHistory { } } + pushPage(pageNumber) { + if (!this._initialized) { + return; + } + + if (!this._isValidPage(pageNumber)) { + console.error(`PDFHistory.pushPage: "${pageNumber}" is not a valid page number.`); + return; + } + + if (this._destination?.page === pageNumber) { + return; + } + + if (this._popStateInProgress) { + return; + } + + this._pushOrReplaceState({ + dest: null, + hash: `page=${pageNumber}`, + page: pageNumber, + rotation: this.linkService.rotation + }); + + if (!this._popStateInProgress) { + this._popStateInProgress = true; + Promise.resolve().then(() => { + this._popStateInProgress = false; + }); + } + } + pushCurrentPosition() { if (!this._initialized || this._popStateInProgress) { return; @@ -6869,7 +6942,7 @@ class PDFHistory { let newUrl; - if (this._updateUrl && destination && destination.hash) { + if (this._updateUrl && destination?.hash) { const baseUrl = document.location.href.split("#")[0]; if (!baseUrl.startsWith("file://")) { @@ -6880,7 +6953,6 @@ class PDFHistory { if (shouldReplace) { window.history.replaceState(newState, "", newUrl); } else { - this._maxUid = this._uid; window.history.pushState(newState, "", newUrl); } } @@ -6920,7 +6992,7 @@ class PDFHistory { let forceReplace = false; if (this._destination.page >= position.first && this._destination.page <= position.page) { - if (this._destination.dest || !this._destination.first) { + if (this._destination.dest !== undefined || !this._destination.first) { return; } @@ -6930,6 +7002,10 @@ class PDFHistory { this._pushOrReplaceState(position, forceReplace); } + _isValidPage(val) { + return Number.isInteger(val) && val > 0 && val <= this.linkService.pagesCount; + } + _isValidState(state, checkReload = false) { if (!state) { return false; @@ -6943,7 +7019,7 @@ class PDFHistory { const [perfEntry] = performance.getEntriesByType("navigation"); - if (!perfEntry || perfEntry.type !== "reload") { + if (perfEntry?.type !== "reload") { return false; } } else { @@ -6968,22 +7044,23 @@ class PDFHistory { this._updateViewareaTimeout = null; } - if (removeTemporary && destination && destination.temporary) { + if (removeTemporary && destination?.temporary) { delete destination.temporary; } this._destination = destination; this._uid = uid; + this._maxUid = Math.max(this._maxUid, uid); this._numPositionUpdates = 0; } _parseCurrentHash(checkNameddest = false) { const hash = unescape(getCurrentHash()).substring(1); const params = (0, _ui_utils.parseQueryString)(hash); - const nameddest = params.nameddest || ""; - let page = params.page | 0; + const nameddest = params.get("nameddest") || ""; + let page = params.get("page") | 0; - if (!(Number.isInteger(page) && page > 0 && page <= this.linkService.pagesCount) || checkNameddest && nameddest.length > 0) { + if (!this._isValidPage(page) || checkNameddest && nameddest.length > 0) { page = null; } @@ -7003,7 +7080,7 @@ class PDFHistory { } this._position = { - hash: this._isViewerInPresentationMode ? `page=${location.pageNumber}` : location.pdfOpenParams.substring(1), + hash: location.pdfOpenParams.substring(1), page: this.linkService.page, first: location.pageNumber, rotation: location.rotation @@ -7061,7 +7138,7 @@ class PDFHistory { if (hashChanged) { this._blockHashChange++; - (0, _ui_utils.waitOnEventOrTimeout)({ + (0, _event_utils.waitOnEventOrTimeout)({ target: window, name: "hashchange", delay: HASH_CHANGE_TIMEOUT @@ -7074,16 +7151,12 @@ class PDFHistory { this._updateInternalState(destination, state.uid, true); - if (this._uid > this._maxUid) { - this._maxUid = this._uid; - } - if ((0, _ui_utils.isValidRotation)(destination.rotation)) { this.linkService.rotation = destination.rotation; } if (destination.dest) { - this.linkService.navigateTo(destination.dest); + this.linkService.goToDestination(destination.dest); } else if (destination.hash) { this.linkService.setHash(destination.hash); } else if (destination.page) { @@ -7143,9 +7216,7 @@ function isDestHashesEqual(destHash, pushHash) { return true; } - const { - nameddest - } = (0, _ui_utils.parseQueryString)(destHash); + const nameddest = (0, _ui_utils.parseQueryString)(destHash).get("nameddest"); if (nameddest === pushHash) { return true; @@ -7200,14 +7271,13 @@ function isDestArraysEqual(firstDest, secondDest) { /***/ }), /* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFLayerViewer = void 0; var _base_tree_viewer = __webpack_require__(13); @@ -7225,7 +7295,6 @@ class PDFLayerViewer extends _base_tree_viewer.BaseTreeViewer { reset() { super.reset(); this._optionalContentConfig = null; - this._pdfDocument = null; } _dispatchEvent(layersCount) { @@ -7270,7 +7339,7 @@ class PDFLayerViewer extends _base_tree_viewer.BaseTreeViewer { return; } - element.textContent = await this.l10n.get("additional_layers", null, "Additional Layers"); + element.textContent = await this.l10n.get("additional_layers"); element.style.fontStyle = "italic"; } @@ -7298,7 +7367,7 @@ class PDFLayerViewer extends _base_tree_viewer.BaseTreeViewer { this._optionalContentConfig = optionalContentConfig || null; this._pdfDocument = pdfDocument || null; - const groups = optionalContentConfig && optionalContentConfig.getOrder(); + const groups = optionalContentConfig?.getOrder(); if (!groups) { this._dispatchEvent(0); @@ -7321,7 +7390,7 @@ class PDFLayerViewer extends _base_tree_viewer.BaseTreeViewer { const div = document.createElement("div"); div.className = "treeItem"; const element = document.createElement("a"); - div.appendChild(element); + div.append(element); if (typeof groupId === "object") { hasAnyNesting = true; @@ -7332,7 +7401,7 @@ class PDFLayerViewer extends _base_tree_viewer.BaseTreeViewer { const itemsDiv = document.createElement("div"); itemsDiv.className = "treeItems"; - div.appendChild(itemsDiv); + div.append(itemsDiv); queue.push({ parent: itemsDiv, groups: groupId.order @@ -7347,28 +7416,19 @@ class PDFLayerViewer extends _base_tree_viewer.BaseTreeViewer { }); input.type = "checkbox"; - input.id = groupId; input.checked = group.visible; const label = document.createElement("label"); - label.setAttribute("for", groupId); label.textContent = this._normalizeTextContent(group.name); - element.appendChild(input); - element.appendChild(label); + label.append(input); + element.append(label); layersCount++; } - levelData.parent.appendChild(div); + levelData.parent.append(div); } } - if (hasAnyNesting) { - this.container.classList.add("treeWithDeepNesting"); - this._lastToggleIsShow = fragment.querySelectorAll(".treeItemsHidden").length === 0; - } - - this.container.appendChild(fragment); - - this._dispatchEvent(layersCount); + this._finishRendering(fragment, layersCount, hasAnyNesting); } async _resetLayers() { @@ -7393,458 +7453,20 @@ exports.PDFLayerViewer = PDFLayerViewer; /***/ }), /* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.SimpleLinkService = exports.PDFLinkService = void 0; - -var _ui_utils = __webpack_require__(2); - -class PDFLinkService { - constructor({ - eventBus, - externalLinkTarget = null, - externalLinkRel = null, - externalLinkEnabled = true, - ignoreDestinationZoom = false - } = {}) { - this.eventBus = eventBus; - this.externalLinkTarget = externalLinkTarget; - this.externalLinkRel = externalLinkRel; - this.externalLinkEnabled = externalLinkEnabled; - this._ignoreDestinationZoom = ignoreDestinationZoom; - this.baseUrl = null; - this.pdfDocument = null; - this.pdfViewer = null; - this.pdfHistory = null; - this._pagesRefCache = null; - } - - setDocument(pdfDocument, baseUrl = null) { - this.baseUrl = baseUrl; - this.pdfDocument = pdfDocument; - this._pagesRefCache = Object.create(null); - } - - setViewer(pdfViewer) { - this.pdfViewer = pdfViewer; - } - - setHistory(pdfHistory) { - this.pdfHistory = pdfHistory; - } - - get pagesCount() { - return this.pdfDocument ? this.pdfDocument.numPages : 0; - } - - get page() { - return this.pdfViewer.currentPageNumber; - } - - set page(value) { - this.pdfViewer.currentPageNumber = value; - } - - get rotation() { - return this.pdfViewer.pagesRotation; - } - - set rotation(value) { - this.pdfViewer.pagesRotation = value; - } - - navigateTo(dest) { - const goToDestination = ({ - namedDest, - explicitDest - }) => { - const destRef = explicitDest[0]; - let pageNumber; - - if (destRef instanceof Object) { - pageNumber = this._cachedPageNumber(destRef); - - if (pageNumber === null) { - this.pdfDocument.getPageIndex(destRef).then(pageIndex => { - this.cachePageRef(pageIndex + 1, destRef); - goToDestination({ - namedDest, - explicitDest - }); - }).catch(() => { - console.error(`PDFLinkService.navigateTo: "${destRef}" is not ` + `a valid page reference, for dest="${dest}".`); - }); - return; - } - } else if (Number.isInteger(destRef)) { - pageNumber = destRef + 1; - } else { - console.error(`PDFLinkService.navigateTo: "${destRef}" is not ` + `a valid destination reference, for dest="${dest}".`); - return; - } - - if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) { - console.error(`PDFLinkService.navigateTo: "${pageNumber}" is not ` + `a valid page number, for dest="${dest}".`); - return; - } - - if (this.pdfHistory) { - this.pdfHistory.pushCurrentPosition(); - this.pdfHistory.push({ - namedDest, - explicitDest, - pageNumber - }); - } - - this.pdfViewer.scrollPageIntoView({ - pageNumber, - destArray: explicitDest, - ignoreDestinationZoom: this._ignoreDestinationZoom - }); - }; - - new Promise((resolve, reject) => { - if (typeof dest === "string") { - this.pdfDocument.getDestination(dest).then(destArray => { - resolve({ - namedDest: dest, - explicitDest: destArray - }); - }); - return; - } - - resolve({ - namedDest: "", - explicitDest: dest - }); - }).then(data => { - if (!Array.isArray(data.explicitDest)) { - console.error(`PDFLinkService.navigateTo: "${data.explicitDest}" is` + ` not a valid destination array, for dest="${dest}".`); - return; - } - - goToDestination(data); - }); - } - - getDestinationHash(dest) { - if (typeof dest === "string") { - return this.getAnchorUrl("#" + escape(dest)); - } - - if (Array.isArray(dest)) { - const str = JSON.stringify(dest); - return this.getAnchorUrl("#" + escape(str)); - } - - return this.getAnchorUrl(""); - } - - getAnchorUrl(anchor) { - return (this.baseUrl || "") + anchor; - } - - setHash(hash) { - let pageNumber, dest; - - if (hash.includes("=")) { - const params = (0, _ui_utils.parseQueryString)(hash); - - if ("search" in params) { - this.eventBus.dispatch("findfromurlhash", { - source: this, - query: params.search.replace(/"/g, ""), - phraseSearch: params.phrase === "true" - }); - } - - if ("page" in params) { - pageNumber = params.page | 0 || 1; - } - - if ("zoom" in params) { - const zoomArgs = params.zoom.split(","); - const zoomArg = zoomArgs[0]; - const zoomArgNumber = parseFloat(zoomArg); - - if (!zoomArg.includes("Fit")) { - dest = [null, { - name: "XYZ" - }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null, zoomArgs.length > 2 ? zoomArgs[2] | 0 : null, zoomArgNumber ? zoomArgNumber / 100 : zoomArg]; - } else { - if (zoomArg === "Fit" || zoomArg === "FitB") { - dest = [null, { - name: zoomArg - }]; - } else if (zoomArg === "FitH" || zoomArg === "FitBH" || zoomArg === "FitV" || zoomArg === "FitBV") { - dest = [null, { - name: zoomArg - }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null]; - } else if (zoomArg === "FitR") { - if (zoomArgs.length !== 5) { - console.error('PDFLinkService.setHash: Not enough parameters for "FitR".'); - } else { - dest = [null, { - name: zoomArg - }, zoomArgs[1] | 0, zoomArgs[2] | 0, zoomArgs[3] | 0, zoomArgs[4] | 0]; - } - } else { - console.error(`PDFLinkService.setHash: "${zoomArg}" is not ` + "a valid zoom value."); - } - } - } - - if (dest) { - this.pdfViewer.scrollPageIntoView({ - pageNumber: pageNumber || this.page, - destArray: dest, - allowNegativeOffset: true - }); - } else if (pageNumber) { - this.page = pageNumber; - } - - if ("pagemode" in params) { - this.eventBus.dispatch("pagemode", { - source: this, - mode: params.pagemode - }); - } - - if ("nameddest" in params) { - this.navigateTo(params.nameddest); - } - } else { - dest = unescape(hash); - - try { - dest = JSON.parse(dest); - - if (!Array.isArray(dest)) { - dest = dest.toString(); - } - } catch (ex) {} - - if (typeof dest === "string" || isValidExplicitDestination(dest)) { - this.navigateTo(dest); - return; - } - - console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not ` + "a valid destination."); - } - } - - executeNamedAction(action) { - switch (action) { - case "GoBack": - if (this.pdfHistory) { - this.pdfHistory.back(); - } - - break; - - case "GoForward": - if (this.pdfHistory) { - this.pdfHistory.forward(); - } - - break; - - case "NextPage": - if (this.page < this.pagesCount) { - this.page++; - } - - break; - - case "PrevPage": - if (this.page > 1) { - this.page--; - } - - break; - - case "LastPage": - this.page = this.pagesCount; - break; - - case "FirstPage": - this.page = 1; - break; - - default: - break; - } - - this.eventBus.dispatch("namedaction", { - source: this, - action - }); - } - - cachePageRef(pageNum, pageRef) { - if (!pageRef) { - return; - } - - const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; - this._pagesRefCache[refStr] = pageNum; - } - - _cachedPageNumber(pageRef) { - const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; - return this._pagesRefCache && this._pagesRefCache[refStr] || null; - } - - isPageVisible(pageNumber) { - return this.pdfViewer.isPageVisible(pageNumber); - } - -} - -exports.PDFLinkService = PDFLinkService; - -function isValidExplicitDestination(dest) { - if (!Array.isArray(dest)) { - return false; - } - - const destLength = dest.length; - - if (destLength < 2) { - return false; - } - - const page = dest[0]; - - if (!(typeof page === "object" && Number.isInteger(page.num) && Number.isInteger(page.gen)) && !(Number.isInteger(page) && page >= 0)) { - return false; - } - - const zoom = dest[1]; - - if (!(typeof zoom === "object" && typeof zoom.name === "string")) { - return false; - } - - let allowNull = true; - - switch (zoom.name) { - case "XYZ": - if (destLength !== 5) { - return false; - } - - break; - - case "Fit": - case "FitB": - return destLength === 2; - - case "FitH": - case "FitBH": - case "FitV": - case "FitBV": - if (destLength !== 3) { - return false; - } - - break; - - case "FitR": - if (destLength !== 6) { - return false; - } - - allowNull = false; - break; - - default: - return false; - } - - for (let i = 2; i < destLength; i++) { - const param = dest[i]; - - if (!(typeof param === "number" || allowNull && param === null)) { - return false; - } - } - - return true; -} - -class SimpleLinkService { - constructor() { - this.externalLinkTarget = null; - this.externalLinkRel = null; - this.externalLinkEnabled = true; - this._ignoreDestinationZoom = false; - } - - get pagesCount() { - return 0; - } - - get page() { - return 0; - } - - set page(value) {} - - get rotation() { - return 0; - } - - set rotation(value) {} - - navigateTo(dest) {} - - getDestinationHash(dest) { - return "#"; - } - - getAnchorUrl(hash) { - return "#"; - } - - setHash(hash) {} - - executeNamedAction(action) {} - - cachePageRef(pageNum, pageRef) {} - - isPageVisible(pageNumber) { - return true; - } - -} - -exports.SimpleLinkService = SimpleLinkService; - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); +})); exports.PDFOutlineViewer = void 0; +var _base_tree_viewer = __webpack_require__(13); + var _pdfjsLib = __webpack_require__(5); -var _base_tree_viewer = __webpack_require__(13); +var _ui_utils = __webpack_require__(1); class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { constructor(options) { @@ -7852,17 +7474,53 @@ class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { this.linkService = options.linkService; this.eventBus._on("toggleoutlinetree", this._toggleAllTreeItems.bind(this)); + + this.eventBus._on("currentoutlineitem", this._currentOutlineItem.bind(this)); + + this.eventBus._on("pagechanging", evt => { + this._currentPageNumber = evt.pageNumber; + }); + + this.eventBus._on("pagesloaded", evt => { + this._isPagesLoaded = !!evt.pagesCount; + + if (this._currentOutlineItemCapability && !this._currentOutlineItemCapability.settled) { + this._currentOutlineItemCapability.resolve(this._isPagesLoaded); + } + }); + + this.eventBus._on("sidebarviewchanged", evt => { + this._sidebarView = evt.view; + }); } reset() { super.reset(); this._outline = null; + this._pageNumberToDestHashCapability = null; + this._currentPageNumber = 1; + this._isPagesLoaded = null; + + if (this._currentOutlineItemCapability && !this._currentOutlineItemCapability.settled) { + this._currentOutlineItemCapability.resolve(false); + } + + this._currentOutlineItemCapability = null; } _dispatchEvent(outlineCount) { + this._currentOutlineItemCapability = (0, _pdfjsLib.createPromiseCapability)(); + + if (outlineCount === 0 || this._pdfDocument?.loadingParams.disableAutoFetch) { + this._currentOutlineItemCapability.resolve(false); + } else if (this._isPagesLoaded !== null) { + this._currentOutlineItemCapability.resolve(this._isPagesLoaded); + } + this.eventBus.dispatch("outlineloaded", { source: this, - outlineCount + outlineCount, + currentOutlineItemPromise: this._currentOutlineItemCapability.promise }); } @@ -7876,20 +7534,17 @@ class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { } = this; if (url) { - (0, _pdfjsLib.addLinkAttributes)(element, { - url, - target: newWindow ? _pdfjsLib.LinkTarget.BLANK : linkService.externalLinkTarget, - rel: linkService.externalLinkRel, - enabled: linkService.externalLinkEnabled - }); + linkService.addLinkAttributes(element, url, newWindow); return; } element.href = linkService.getDestinationHash(dest); - element.onclick = () => { + element.onclick = evt => { + this._updateCurrentTreeItem(evt.target.parentNode); + if (dest) { - linkService.navigateTo(dest); + linkService.goToDestination(dest); } return false; @@ -7913,7 +7568,31 @@ class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { count, items }) { - const hidden = count < 0 && Math.abs(count) === items.length; + let hidden = false; + + if (count < 0) { + let totalCount = items.length; + + if (totalCount > 0) { + const queue = [...items]; + + while (queue.length > 0) { + const { + count: nestedCount, + items: nestedItems + } = queue.shift(); + + if (nestedCount > 0 && nestedItems.length > 0) { + totalCount += nestedItems.length; + queue.push(...nestedItems); + } + } + } + + if (Math.abs(count) === totalCount) { + hidden = true; + } + } super._addToggleButton(div, hidden); } @@ -7927,13 +7606,15 @@ class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { } render({ - outline + outline, + pdfDocument }) { if (this._outline) { this.reset(); } this._outline = outline || null; + this._pdfDocument = pdfDocument || null; if (!outline) { this._dispatchEvent(0); @@ -7962,7 +7643,7 @@ class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { this._setStyles(element, item); element.textContent = this._normalizeTextContent(item.title); - div.appendChild(element); + div.append(element); if (item.items.length > 0) { hasAnyNesting = true; @@ -7971,26 +7652,134 @@ class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { const itemsDiv = document.createElement("div"); itemsDiv.className = "treeItems"; - div.appendChild(itemsDiv); + div.append(itemsDiv); queue.push({ parent: itemsDiv, items: item.items }); } - levelData.parent.appendChild(div); + levelData.parent.append(div); outlineCount++; } } - if (hasAnyNesting) { - this.container.classList.add("treeWithDeepNesting"); - this._lastToggleIsShow = fragment.querySelectorAll(".treeItemsHidden").length === 0; + this._finishRendering(fragment, outlineCount, hasAnyNesting); + } + + async _currentOutlineItem() { + if (!this._isPagesLoaded) { + throw new Error("_currentOutlineItem: All pages have not been loaded."); } - this.container.appendChild(fragment); + if (!this._outline || !this._pdfDocument) { + return; + } - this._dispatchEvent(outlineCount); + const pageNumberToDestHash = await this._getPageNumberToDestHash(this._pdfDocument); + + if (!pageNumberToDestHash) { + return; + } + + this._updateCurrentTreeItem(null); + + if (this._sidebarView !== _ui_utils.SidebarView.OUTLINE) { + return; + } + + for (let i = this._currentPageNumber; i > 0; i--) { + const destHash = pageNumberToDestHash.get(i); + + if (!destHash) { + continue; + } + + const linkElement = this.container.querySelector(`a[href="${destHash}"]`); + + if (!linkElement) { + continue; + } + + this._scrollToCurrentTreeItem(linkElement.parentNode); + + break; + } + } + + async _getPageNumberToDestHash(pdfDocument) { + if (this._pageNumberToDestHashCapability) { + return this._pageNumberToDestHashCapability.promise; + } + + this._pageNumberToDestHashCapability = (0, _pdfjsLib.createPromiseCapability)(); + const pageNumberToDestHash = new Map(), + pageNumberNesting = new Map(); + const queue = [{ + nesting: 0, + items: this._outline + }]; + + while (queue.length > 0) { + const levelData = queue.shift(), + currentNesting = levelData.nesting; + + for (const { + dest, + items + } of levelData.items) { + let explicitDest, pageNumber; + + if (typeof dest === "string") { + explicitDest = await pdfDocument.getDestination(dest); + + if (pdfDocument !== this._pdfDocument) { + return null; + } + } else { + explicitDest = dest; + } + + if (Array.isArray(explicitDest)) { + const [destRef] = explicitDest; + + if (typeof destRef === "object" && destRef !== null) { + pageNumber = this.linkService._cachedPageNumber(destRef); + + if (!pageNumber) { + try { + pageNumber = (await pdfDocument.getPageIndex(destRef)) + 1; + + if (pdfDocument !== this._pdfDocument) { + return null; + } + + this.linkService.cachePageRef(pageNumber, destRef); + } catch (ex) {} + } + } else if (Number.isInteger(destRef)) { + pageNumber = destRef + 1; + } + + if (Number.isInteger(pageNumber) && (!pageNumberToDestHash.has(pageNumber) || currentNesting > pageNumberNesting.get(pageNumber))) { + const destHash = this.linkService.getDestinationHash(dest); + pageNumberToDestHash.set(pageNumber, destHash); + pageNumberNesting.set(pageNumber, currentNesting); + } + } + + if (items.length > 0) { + queue.push({ + nesting: currentNesting + 1, + items + }); + } + } + } + + this._pageNumberToDestHashCapability.resolve(pageNumberToDestHash.size > 0 ? pageNumberToDestHash : null); + + return this._pageNumberToDestHashCapability.promise; } } @@ -7998,20 +7787,20 @@ class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { exports.PDFOutlineViewer = PDFOutlineViewer; /***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 21 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFPresentationMode = void 0; -var _ui_utils = __webpack_require__(2); +var _ui_utils = __webpack_require__(1); + +var _pdfjsLib = __webpack_require__(5); -const DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500; const DELAY_BEFORE_HIDING_CONTROLS = 3000; const ACTIVE_SELECTOR = "pdfPresentationMode"; const CONTROLS_SELECTOR = "pdfPresentationModeControls"; @@ -8021,88 +7810,77 @@ const SWIPE_MIN_DISTANCE_THRESHOLD = 50; const SWIPE_ANGLE_THRESHOLD = Math.PI / 6; class PDFPresentationMode { + #state = _ui_utils.PresentationModeState.UNKNOWN; + #args = null; + constructor({ container, pdfViewer, - eventBus, - contextMenuItems = null + eventBus }) { this.container = container; this.pdfViewer = pdfViewer; this.eventBus = eventBus; - this.active = false; - this.args = null; this.contextMenuOpen = false; this.mouseScrollTimeStamp = 0; this.mouseScrollDelta = 0; this.touchSwipeState = null; - - if (contextMenuItems) { - contextMenuItems.contextFirstPage.addEventListener("click", () => { - this.contextMenuOpen = false; - this.eventBus.dispatch("firstpage", { - source: this - }); - }); - contextMenuItems.contextLastPage.addEventListener("click", () => { - this.contextMenuOpen = false; - this.eventBus.dispatch("lastpage", { - source: this - }); - }); - contextMenuItems.contextPageRotateCw.addEventListener("click", () => { - this.contextMenuOpen = false; - this.eventBus.dispatch("rotatecw", { - source: this - }); - }); - contextMenuItems.contextPageRotateCcw.addEventListener("click", () => { - this.contextMenuOpen = false; - this.eventBus.dispatch("rotateccw", { - source: this - }); - }); - } } - request() { - if (this.switchInProgress || this.active || !this.pdfViewer.pagesCount) { + async request() { + const { + container, + pdfViewer + } = this; + + if (this.active || !pdfViewer.pagesCount || !container.requestFullscreen) { return false; } - this._addFullscreenChangeListeners(); - - this._setSwitchInProgress(); - - this._notifyStateChange(); - - if (this.container.requestFullscreen) { - this.container.requestFullscreen(); - } else if (this.container.mozRequestFullScreen) { - this.container.mozRequestFullScreen(); - } else if (this.container.webkitRequestFullscreen) { - this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } else if (this.container.msRequestFullscreen) { - this.container.msRequestFullscreen(); - } else { - return false; - } - - this.args = { - page: this.pdfViewer.currentPageNumber, - previousScale: this.pdfViewer.currentScaleValue + this.#addFullscreenChangeListeners(); + this.#notifyStateChange(_ui_utils.PresentationModeState.CHANGING); + const promise = container.requestFullscreen(); + this.#args = { + pageNumber: pdfViewer.currentPageNumber, + scaleValue: pdfViewer.currentScaleValue, + scrollMode: pdfViewer.scrollMode, + spreadMode: null, + annotationEditorMode: null }; - return true; + + if (pdfViewer.spreadMode !== _ui_utils.SpreadMode.NONE && !(pdfViewer.pageViewsReady && pdfViewer.hasEqualPageSizes)) { + console.warn("Ignoring Spread modes when entering PresentationMode, " + "since the document may contain varying page sizes."); + this.#args.spreadMode = pdfViewer.spreadMode; + } + + if (pdfViewer.annotationEditorMode !== _pdfjsLib.AnnotationEditorType.DISABLE) { + this.#args.annotationEditorMode = pdfViewer.annotationEditorMode; + } + + try { + await promise; + pdfViewer.focus(); + return true; + } catch (reason) { + this.#removeFullscreenChangeListeners(); + this.#notifyStateChange(_ui_utils.PresentationModeState.NORMAL); + } + + return false; } - _mouseWheel(evt) { + get active() { + return this.#state === _ui_utils.PresentationModeState.CHANGING || this.#state === _ui_utils.PresentationModeState.FULLSCREEN; + } + + #mouseWheel(evt) { if (!this.active) { return; } evt.preventDefault(); const delta = (0, _ui_utils.normalizeWheelEventDelta)(evt); - const currentTime = new Date().getTime(); + const currentTime = Date.now(); const storedTime = this.mouseScrollTimeStamp; if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) { @@ -8110,17 +7888,15 @@ class PDFPresentationMode { } if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) { - this._resetMouseScrollState(); + this.#resetMouseScrollState(); } this.mouseScrollDelta += delta; if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) { const totalDelta = this.mouseScrollDelta; - - this._resetMouseScrollState(); - - const success = totalDelta > 0 ? this._goToPreviousPage() : this._goToNextPage(); + this.#resetMouseScrollState(); + const success = totalDelta > 0 ? this.pdfViewer.previousPage() : this.pdfViewer.nextPage(); if (success) { this.mouseScrollTimeStamp = currentTime; @@ -8128,109 +7904,65 @@ class PDFPresentationMode { } } - get isFullscreen() { - return !!(document.fullscreenElement || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement); - } - - _goToPreviousPage() { - const page = this.pdfViewer.currentPageNumber; - - if (page <= 1) { - return false; - } - - this.pdfViewer.currentPageNumber = page - 1; - return true; - } - - _goToNextPage() { - const page = this.pdfViewer.currentPageNumber; - - if (page >= this.pdfViewer.pagesCount) { - return false; - } - - this.pdfViewer.currentPageNumber = page + 1; - return true; - } - - _notifyStateChange() { + #notifyStateChange(state) { + this.#state = state; this.eventBus.dispatch("presentationmodechanged", { source: this, - active: this.active, - switchInProgress: !!this.switchInProgress + state }); } - _setSwitchInProgress() { - if (this.switchInProgress) { - clearTimeout(this.switchInProgress); - } - - this.switchInProgress = setTimeout(() => { - this._removeFullscreenChangeListeners(); - - delete this.switchInProgress; - - this._notifyStateChange(); - }, DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); - } - - _resetSwitchInProgress() { - if (this.switchInProgress) { - clearTimeout(this.switchInProgress); - delete this.switchInProgress; - } - } - - _enter() { - this.active = true; - - this._resetSwitchInProgress(); - - this._notifyStateChange(); - + #enter() { + this.#notifyStateChange(_ui_utils.PresentationModeState.FULLSCREEN); this.container.classList.add(ACTIVE_SELECTOR); setTimeout(() => { - this.pdfViewer.currentPageNumber = this.args.page; + this.pdfViewer.scrollMode = _ui_utils.ScrollMode.PAGE; + + if (this.#args.spreadMode !== null) { + this.pdfViewer.spreadMode = _ui_utils.SpreadMode.NONE; + } + + this.pdfViewer.currentPageNumber = this.#args.pageNumber; this.pdfViewer.currentScaleValue = "page-fit"; + + if (this.#args.annotationEditorMode !== null) { + this.pdfViewer.annotationEditorMode = _pdfjsLib.AnnotationEditorType.NONE; + } }, 0); - - this._addWindowListeners(); - - this._showControls(); - + this.#addWindowListeners(); + this.#showControls(); this.contextMenuOpen = false; - this.container.setAttribute("contextmenu", "viewerContextMenu"); window.getSelection().removeAllRanges(); } - _exit() { - const page = this.pdfViewer.currentPageNumber; + #exit() { + const pageNumber = this.pdfViewer.currentPageNumber; this.container.classList.remove(ACTIVE_SELECTOR); setTimeout(() => { - this.active = false; + this.#removeFullscreenChangeListeners(); + this.#notifyStateChange(_ui_utils.PresentationModeState.NORMAL); + this.pdfViewer.scrollMode = this.#args.scrollMode; - this._removeFullscreenChangeListeners(); + if (this.#args.spreadMode !== null) { + this.pdfViewer.spreadMode = this.#args.spreadMode; + } - this._notifyStateChange(); + this.pdfViewer.currentScaleValue = this.#args.scaleValue; + this.pdfViewer.currentPageNumber = pageNumber; - this.pdfViewer.currentScaleValue = this.args.previousScale; - this.pdfViewer.currentPageNumber = page; - this.args = null; + if (this.#args.annotationEditorMode !== null) { + this.pdfViewer.annotationEditorMode = this.#args.annotationEditorMode; + } + + this.#args = null; }, 0); - - this._removeWindowListeners(); - - this._hideControls(); - - this._resetMouseScrollState(); - - this.container.removeAttribute("contextmenu"); + this.#removeWindowListeners(); + this.#hideControls(); + this.#resetMouseScrollState(); this.contextMenuOpen = false; } - _mouseDown(evt) { + #mouseDown(evt) { if (this.contextMenuOpen) { this.contextMenuOpen = false; evt.preventDefault(); @@ -8244,19 +7976,19 @@ class PDFPresentationMode { evt.preventDefault(); if (evt.shiftKey) { - this._goToPreviousPage(); + this.pdfViewer.previousPage(); } else { - this._goToNextPage(); + this.pdfViewer.nextPage(); } } } } - _contextMenu() { + #contextMenu() { this.contextMenuOpen = true; } - _showControls() { + #showControls() { if (this.controlsTimeout) { clearTimeout(this.controlsTimeout); } else { @@ -8269,7 +8001,7 @@ class PDFPresentationMode { }, DELAY_BEFORE_HIDING_CONTROLS); } - _hideControls() { + #hideControls() { if (!this.controlsTimeout) { return; } @@ -8279,12 +8011,12 @@ class PDFPresentationMode { delete this.controlsTimeout; } - _resetMouseScrollState() { + #resetMouseScrollState() { this.mouseScrollTimeStamp = 0; this.mouseScrollDelta = 0; } - _touchSwipe(evt) { + #touchSwipe(evt) { if (!this.active) { return; } @@ -8331,22 +8063,22 @@ class PDFPresentationMode { } if (delta > 0) { - this._goToPreviousPage(); + this.pdfViewer.previousPage(); } else if (delta < 0) { - this._goToNextPage(); + this.pdfViewer.nextPage(); } break; } } - _addWindowListeners() { - this.showControlsBind = this._showControls.bind(this); - this.mouseDownBind = this._mouseDown.bind(this); - this.mouseWheelBind = this._mouseWheel.bind(this); - this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this); - this.contextMenuBind = this._contextMenu.bind(this); - this.touchSwipeBind = this._touchSwipe.bind(this); + #addWindowListeners() { + this.showControlsBind = this.#showControls.bind(this); + this.mouseDownBind = this.#mouseDown.bind(this); + this.mouseWheelBind = this.#mouseWheel.bind(this); + this.resetMouseScrollStateBind = this.#resetMouseScrollState.bind(this); + this.contextMenuBind = this.#contextMenu.bind(this); + this.touchSwipeBind = this.#touchSwipe.bind(this); window.addEventListener("mousemove", this.showControlsBind); window.addEventListener("mousedown", this.mouseDownBind); window.addEventListener("wheel", this.mouseWheelBind, { @@ -8359,7 +8091,7 @@ class PDFPresentationMode { window.addEventListener("touchend", this.touchSwipeBind); } - _removeWindowListeners() { + #removeWindowListeners() { window.removeEventListener("mousemove", this.showControlsBind); window.removeEventListener("mousedown", this.mouseDownBind); window.removeEventListener("wheel", this.mouseWheelBind, { @@ -8378,27 +8110,21 @@ class PDFPresentationMode { delete this.touchSwipeBind; } - _fullscreenChange() { - if (this.isFullscreen) { - this._enter(); + #fullscreenChange() { + if (document.fullscreenElement) { + this.#enter(); } else { - this._exit(); + this.#exit(); } } - _addFullscreenChangeListeners() { - this.fullscreenChangeBind = this._fullscreenChange.bind(this); + #addFullscreenChangeListeners() { + this.fullscreenChangeBind = this.#fullscreenChange.bind(this); window.addEventListener("fullscreenchange", this.fullscreenChangeBind); - window.addEventListener("mozfullscreenchange", this.fullscreenChangeBind); - window.addEventListener("webkitfullscreenchange", this.fullscreenChangeBind); - window.addEventListener("MSFullscreenChange", this.fullscreenChangeBind); } - _removeFullscreenChangeListeners() { + #removeFullscreenChangeListeners() { window.removeEventListener("fullscreenchange", this.fullscreenChangeBind); - window.removeEventListener("mozfullscreenchange", this.fullscreenChangeBind); - window.removeEventListener("webkitfullscreenchange", this.fullscreenChangeBind); - window.removeEventListener("MSFullscreenChange", this.fullscreenChangeBind); delete this.fullscreenChangeBind; } @@ -8407,45 +8133,1031 @@ class PDFPresentationMode { exports.PDFPresentationMode = PDFPresentationMode; /***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 22 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.PDFRenderingQueue = void 0; + +var _pdfjsLib = __webpack_require__(5); + +var _ui_utils = __webpack_require__(1); + +const CLEANUP_TIMEOUT = 30000; + +class PDFRenderingQueue { + constructor() { + this.pdfViewer = null; + this.pdfThumbnailViewer = null; + this.onIdle = null; + this.highestPriorityPage = null; + this.idleTimeout = null; + this.printing = false; + this.isThumbnailViewEnabled = false; + } + + setViewer(pdfViewer) { + this.pdfViewer = pdfViewer; + } + + setThumbnailViewer(pdfThumbnailViewer) { + this.pdfThumbnailViewer = pdfThumbnailViewer; + } + + isHighestPriority(view) { + return this.highestPriorityPage === view.renderingId; + } + + hasViewer() { + return !!this.pdfViewer; + } + + renderHighestPriority(currentlyVisiblePages) { + if (this.idleTimeout) { + clearTimeout(this.idleTimeout); + this.idleTimeout = null; + } + + if (this.pdfViewer.forceRendering(currentlyVisiblePages)) { + return; + } + + if (this.isThumbnailViewEnabled && this.pdfThumbnailViewer?.forceRendering()) { + return; + } + + if (this.printing) { + return; + } + + if (this.onIdle) { + this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT); + } + } + + getHighestPriority(visible, views, scrolledDown, preRenderExtra = false) { + const visibleViews = visible.views, + numVisible = visibleViews.length; + + if (numVisible === 0) { + return null; + } + + for (let i = 0; i < numVisible; i++) { + const view = visibleViews[i].view; + + if (!this.isViewFinished(view)) { + return view; + } + } + + const firstId = visible.first.id, + lastId = visible.last.id; + + if (lastId - firstId + 1 > numVisible) { + const visibleIds = visible.ids; + + for (let i = 1, ii = lastId - firstId; i < ii; i++) { + const holeId = scrolledDown ? firstId + i : lastId - i; + + if (visibleIds.has(holeId)) { + continue; + } + + const holeView = views[holeId - 1]; + + if (!this.isViewFinished(holeView)) { + return holeView; + } + } + } + + let preRenderIndex = scrolledDown ? lastId : firstId - 2; + let preRenderView = views[preRenderIndex]; + + if (preRenderView && !this.isViewFinished(preRenderView)) { + return preRenderView; + } + + if (preRenderExtra) { + preRenderIndex += scrolledDown ? 1 : -1; + preRenderView = views[preRenderIndex]; + + if (preRenderView && !this.isViewFinished(preRenderView)) { + return preRenderView; + } + } + + return null; + } + + isViewFinished(view) { + return view.renderingState === _ui_utils.RenderingStates.FINISHED; + } + + renderView(view) { + switch (view.renderingState) { + case _ui_utils.RenderingStates.FINISHED: + return false; + + case _ui_utils.RenderingStates.PAUSED: + this.highestPriorityPage = view.renderingId; + view.resume(); + break; + + case _ui_utils.RenderingStates.RUNNING: + this.highestPriorityPage = view.renderingId; + break; + + case _ui_utils.RenderingStates.INITIAL: + this.highestPriorityPage = view.renderingId; + view.draw().finally(() => { + this.renderHighestPriority(); + }).catch(reason => { + if (reason instanceof _pdfjsLib.RenderingCancelledException) { + return; + } + + console.error(`renderView: "${reason}"`); + }); + break; + } + + return true; + } + +} + +exports.PDFRenderingQueue = PDFRenderingQueue; + +/***/ }), +/* 23 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFScriptingManager = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdfjsLib = __webpack_require__(5); + +class PDFScriptingManager { + constructor({ + eventBus, + sandboxBundleSrc = null, + scriptingFactory = null, + docPropertiesLookup = null + }) { + this._pdfDocument = null; + this._pdfViewer = null; + this._closeCapability = null; + this._destroyCapability = null; + this._scripting = null; + this._mouseState = Object.create(null); + this._ready = false; + this._eventBus = eventBus; + this._sandboxBundleSrc = sandboxBundleSrc; + this._scriptingFactory = scriptingFactory; + this._docPropertiesLookup = docPropertiesLookup; + } + + setViewer(pdfViewer) { + this._pdfViewer = pdfViewer; + } + + async setDocument(pdfDocument) { + if (this._pdfDocument) { + await this._destroyScripting(); + } + + this._pdfDocument = pdfDocument; + + if (!pdfDocument) { + return; + } + + const [objects, calculationOrder, docActions] = await Promise.all([pdfDocument.getFieldObjects(), pdfDocument.getCalculationOrderIds(), pdfDocument.getJSActions()]); + + if (!objects && !docActions) { + await this._destroyScripting(); + return; + } + + if (pdfDocument !== this._pdfDocument) { + return; + } + + try { + this._scripting = this._createScripting(); + } catch (error) { + console.error(`PDFScriptingManager.setDocument: "${error?.message}".`); + await this._destroyScripting(); + return; + } + + this._internalEvents.set("updatefromsandbox", event => { + if (event?.source !== window) { + return; + } + + this._updateFromSandbox(event.detail); + }); + + this._internalEvents.set("dispatcheventinsandbox", event => { + this._scripting?.dispatchEventInSandbox(event.detail); + }); + + this._internalEvents.set("pagechanging", ({ + pageNumber, + previous + }) => { + if (pageNumber === previous) { + return; + } + + this._dispatchPageClose(previous); + + this._dispatchPageOpen(pageNumber); + }); + + this._internalEvents.set("pagerendered", ({ + pageNumber + }) => { + if (!this._pageOpenPending.has(pageNumber)) { + return; + } + + if (pageNumber !== this._pdfViewer.currentPageNumber) { + return; + } + + this._dispatchPageOpen(pageNumber); + }); + + this._internalEvents.set("pagesdestroy", async event => { + await this._dispatchPageClose(this._pdfViewer.currentPageNumber); + await this._scripting?.dispatchEventInSandbox({ + id: "doc", + name: "WillClose" + }); + this._closeCapability?.resolve(); + }); + + this._domEvents.set("mousedown", event => { + this._mouseState.isDown = true; + }); + + this._domEvents.set("mouseup", event => { + this._mouseState.isDown = false; + }); + + for (const [name, listener] of this._internalEvents) { + this._eventBus._on(name, listener); + } + + for (const [name, listener] of this._domEvents) { + window.addEventListener(name, listener, true); + } + + try { + const docProperties = await this._getDocProperties(); + + if (pdfDocument !== this._pdfDocument) { + return; + } + + await this._scripting.createSandbox({ + objects, + calculationOrder, + appInfo: { + platform: navigator.platform, + language: navigator.language + }, + docInfo: { ...docProperties, + actions: docActions + } + }); + + this._eventBus.dispatch("sandboxcreated", { + source: this + }); + } catch (error) { + console.error(`PDFScriptingManager.setDocument: "${error?.message}".`); + await this._destroyScripting(); + return; + } + + await this._scripting?.dispatchEventInSandbox({ + id: "doc", + name: "Open" + }); + await this._dispatchPageOpen(this._pdfViewer.currentPageNumber, true); + Promise.resolve().then(() => { + if (pdfDocument === this._pdfDocument) { + this._ready = true; + } + }); + } + + async dispatchWillSave(detail) { + return this._scripting?.dispatchEventInSandbox({ + id: "doc", + name: "WillSave" + }); + } + + async dispatchDidSave(detail) { + return this._scripting?.dispatchEventInSandbox({ + id: "doc", + name: "DidSave" + }); + } + + async dispatchWillPrint(detail) { + return this._scripting?.dispatchEventInSandbox({ + id: "doc", + name: "WillPrint" + }); + } + + async dispatchDidPrint(detail) { + return this._scripting?.dispatchEventInSandbox({ + id: "doc", + name: "DidPrint" + }); + } + + get mouseState() { + return this._mouseState; + } + + get destroyPromise() { + return this._destroyCapability?.promise || null; + } + + get ready() { + return this._ready; + } + + get _internalEvents() { + return (0, _pdfjsLib.shadow)(this, "_internalEvents", new Map()); + } + + get _domEvents() { + return (0, _pdfjsLib.shadow)(this, "_domEvents", new Map()); + } + + get _pageOpenPending() { + return (0, _pdfjsLib.shadow)(this, "_pageOpenPending", new Set()); + } + + get _visitedPages() { + return (0, _pdfjsLib.shadow)(this, "_visitedPages", new Map()); + } + + async _updateFromSandbox(detail) { + const isInPresentationMode = this._pdfViewer.isInPresentationMode || this._pdfViewer.isChangingPresentationMode; + const { + id, + siblings, + command, + value + } = detail; + + if (!id) { + switch (command) { + case "clear": + console.clear(); + break; + + case "error": + console.error(value); + break; + + case "layout": + if (isInPresentationMode) { + return; + } + + const modes = (0, _ui_utils.apiPageLayoutToViewerModes)(value); + this._pdfViewer.spreadMode = modes.spreadMode; + break; + + case "page-num": + this._pdfViewer.currentPageNumber = value + 1; + break; + + case "print": + await this._pdfViewer.pagesPromise; + + this._eventBus.dispatch("print", { + source: this + }); + + break; + + case "println": + console.log(value); + break; + + case "zoom": + if (isInPresentationMode) { + return; + } + + this._pdfViewer.currentScaleValue = value; + break; + + case "SaveAs": + this._eventBus.dispatch("download", { + source: this + }); + + break; + + case "FirstPage": + this._pdfViewer.currentPageNumber = 1; + break; + + case "LastPage": + this._pdfViewer.currentPageNumber = this._pdfViewer.pagesCount; + break; + + case "NextPage": + this._pdfViewer.nextPage(); + + break; + + case "PrevPage": + this._pdfViewer.previousPage(); + + break; + + case "ZoomViewIn": + if (isInPresentationMode) { + return; + } + + this._pdfViewer.increaseScale(); + + break; + + case "ZoomViewOut": + if (isInPresentationMode) { + return; + } + + this._pdfViewer.decreaseScale(); + + break; + } + + return; + } + + if (isInPresentationMode) { + if (detail.focus) { + return; + } + } + + delete detail.id; + delete detail.siblings; + const ids = siblings ? [id, ...siblings] : [id]; + + for (const elementId of ids) { + const element = document.querySelector(`[data-element-id="${elementId}"]`); + + if (element) { + element.dispatchEvent(new CustomEvent("updatefromsandbox", { + detail + })); + } else { + this._pdfDocument?.annotationStorage.setValue(elementId, detail); + } + } + } + + async _dispatchPageOpen(pageNumber, initialize = false) { + const pdfDocument = this._pdfDocument, + visitedPages = this._visitedPages; + + if (initialize) { + this._closeCapability = (0, _pdfjsLib.createPromiseCapability)(); + } + + if (!this._closeCapability) { + return; + } + + const pageView = this._pdfViewer.getPageView(pageNumber - 1); + + if (pageView?.renderingState !== _ui_utils.RenderingStates.FINISHED) { + this._pageOpenPending.add(pageNumber); + + return; + } + + this._pageOpenPending.delete(pageNumber); + + const actionsPromise = (async () => { + const actions = await (!visitedPages.has(pageNumber) ? pageView.pdfPage?.getJSActions() : null); + + if (pdfDocument !== this._pdfDocument) { + return; + } + + await this._scripting?.dispatchEventInSandbox({ + id: "page", + name: "PageOpen", + pageNumber, + actions + }); + })(); + + visitedPages.set(pageNumber, actionsPromise); + } + + async _dispatchPageClose(pageNumber) { + const pdfDocument = this._pdfDocument, + visitedPages = this._visitedPages; + + if (!this._closeCapability) { + return; + } + + if (this._pageOpenPending.has(pageNumber)) { + return; + } + + const actionsPromise = visitedPages.get(pageNumber); + + if (!actionsPromise) { + return; + } + + visitedPages.set(pageNumber, null); + await actionsPromise; + + if (pdfDocument !== this._pdfDocument) { + return; + } + + await this._scripting?.dispatchEventInSandbox({ + id: "page", + name: "PageClose", + pageNumber + }); + } + + async _getDocProperties() { + if (this._docPropertiesLookup) { + return this._docPropertiesLookup(this._pdfDocument); + } + + throw new Error("_getDocProperties: Unable to lookup properties."); + } + + _createScripting() { + this._destroyCapability = (0, _pdfjsLib.createPromiseCapability)(); + + if (this._scripting) { + throw new Error("_createScripting: Scripting already exists."); + } + + if (this._scriptingFactory) { + return this._scriptingFactory.createScripting({ + sandboxBundleSrc: this._sandboxBundleSrc + }); + } + + throw new Error("_createScripting: Cannot create scripting."); + } + + async _destroyScripting() { + if (!this._scripting) { + this._pdfDocument = null; + this._destroyCapability?.resolve(); + return; + } + + if (this._closeCapability) { + await Promise.race([this._closeCapability.promise, new Promise(resolve => { + setTimeout(resolve, 1000); + })]).catch(reason => {}); + this._closeCapability = null; + } + + this._pdfDocument = null; + + try { + await this._scripting.destroySandbox(); + } catch (ex) {} + + for (const [name, listener] of this._internalEvents) { + this._eventBus._off(name, listener); + } + + this._internalEvents.clear(); + + for (const [name, listener] of this._domEvents) { + window.removeEventListener(name, listener, true); + } + + this._domEvents.clear(); + + this._pageOpenPending.clear(); + + this._visitedPages.clear(); + + this._scripting = null; + delete this._mouseState.isDown; + this._ready = false; + this._destroyCapability?.resolve(); + } + +} + +exports.PDFScriptingManager = PDFScriptingManager; + +/***/ }), +/* 24 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFSidebar = void 0; + +var _ui_utils = __webpack_require__(1); + +const UI_NOTIFICATION_CLASS = "pdfSidebarNotification"; + +class PDFSidebar { + constructor({ + elements, + pdfViewer, + pdfThumbnailViewer, + eventBus, + l10n + }) { + this.isOpen = false; + this.active = _ui_utils.SidebarView.THUMBS; + this.isInitialViewSet = false; + this.isInitialEventDispatched = false; + this.onToggled = null; + this.pdfViewer = pdfViewer; + this.pdfThumbnailViewer = pdfThumbnailViewer; + this.outerContainer = elements.outerContainer; + this.sidebarContainer = elements.sidebarContainer; + this.toggleButton = elements.toggleButton; + this.thumbnailButton = elements.thumbnailButton; + this.outlineButton = elements.outlineButton; + this.attachmentsButton = elements.attachmentsButton; + this.layersButton = elements.layersButton; + this.thumbnailView = elements.thumbnailView; + this.outlineView = elements.outlineView; + this.attachmentsView = elements.attachmentsView; + this.layersView = elements.layersView; + this._outlineOptionsContainer = elements.outlineOptionsContainer; + this._currentOutlineItemButton = elements.currentOutlineItemButton; + this.eventBus = eventBus; + this.l10n = l10n; + this.#addEventListeners(); + } + + reset() { + this.isInitialViewSet = false; + this.isInitialEventDispatched = false; + this.#hideUINotification(true); + this.switchView(_ui_utils.SidebarView.THUMBS); + this.outlineButton.disabled = false; + this.attachmentsButton.disabled = false; + this.layersButton.disabled = false; + this._currentOutlineItemButton.disabled = true; + } + + get visibleView() { + return this.isOpen ? this.active : _ui_utils.SidebarView.NONE; + } + + setInitialView(view = _ui_utils.SidebarView.NONE) { + if (this.isInitialViewSet) { + return; + } + + this.isInitialViewSet = true; + + if (view === _ui_utils.SidebarView.NONE || view === _ui_utils.SidebarView.UNKNOWN) { + this.#dispatchEvent(); + return; + } + + this.switchView(view, true); + + if (!this.isInitialEventDispatched) { + this.#dispatchEvent(); + } + } + + switchView(view, forceOpen = false) { + const isViewChanged = view !== this.active; + let shouldForceRendering = false; + + switch (view) { + case _ui_utils.SidebarView.NONE: + if (this.isOpen) { + this.close(); + } + + return; + + case _ui_utils.SidebarView.THUMBS: + if (this.isOpen && isViewChanged) { + shouldForceRendering = true; + } + + break; + + case _ui_utils.SidebarView.OUTLINE: + if (this.outlineButton.disabled) { + return; + } + + break; + + case _ui_utils.SidebarView.ATTACHMENTS: + if (this.attachmentsButton.disabled) { + return; + } + + break; + + case _ui_utils.SidebarView.LAYERS: + if (this.layersButton.disabled) { + return; + } + + break; + + default: + console.error(`PDFSidebar.switchView: "${view}" is not a valid view.`); + return; + } + + this.active = view; + const isThumbs = view === _ui_utils.SidebarView.THUMBS, + isOutline = view === _ui_utils.SidebarView.OUTLINE, + isAttachments = view === _ui_utils.SidebarView.ATTACHMENTS, + isLayers = view === _ui_utils.SidebarView.LAYERS; + this.thumbnailButton.classList.toggle("toggled", isThumbs); + this.outlineButton.classList.toggle("toggled", isOutline); + this.attachmentsButton.classList.toggle("toggled", isAttachments); + this.layersButton.classList.toggle("toggled", isLayers); + this.thumbnailButton.setAttribute("aria-checked", isThumbs); + this.outlineButton.setAttribute("aria-checked", isOutline); + this.attachmentsButton.setAttribute("aria-checked", isAttachments); + this.layersButton.setAttribute("aria-checked", isLayers); + this.thumbnailView.classList.toggle("hidden", !isThumbs); + this.outlineView.classList.toggle("hidden", !isOutline); + this.attachmentsView.classList.toggle("hidden", !isAttachments); + this.layersView.classList.toggle("hidden", !isLayers); + + this._outlineOptionsContainer.classList.toggle("hidden", !isOutline); + + if (forceOpen && !this.isOpen) { + this.open(); + return; + } + + if (shouldForceRendering) { + this.#updateThumbnailViewer(); + this.#forceRendering(); + } + + if (isViewChanged) { + this.#dispatchEvent(); + } + } + + open() { + if (this.isOpen) { + return; + } + + this.isOpen = true; + this.toggleButton.classList.add("toggled"); + this.toggleButton.setAttribute("aria-expanded", "true"); + this.outerContainer.classList.add("sidebarMoving", "sidebarOpen"); + + if (this.active === _ui_utils.SidebarView.THUMBS) { + this.#updateThumbnailViewer(); + } + + this.#forceRendering(); + this.#dispatchEvent(); + this.#hideUINotification(); + } + + close() { + if (!this.isOpen) { + return; + } + + this.isOpen = false; + this.toggleButton.classList.remove("toggled"); + this.toggleButton.setAttribute("aria-expanded", "false"); + this.outerContainer.classList.add("sidebarMoving"); + this.outerContainer.classList.remove("sidebarOpen"); + this.#forceRendering(); + this.#dispatchEvent(); + } + + toggle() { + if (this.isOpen) { + this.close(); + } else { + this.open(); + } + } + + #dispatchEvent() { + if (this.isInitialViewSet && !this.isInitialEventDispatched) { + this.isInitialEventDispatched = true; + } + + this.eventBus.dispatch("sidebarviewchanged", { + source: this, + view: this.visibleView + }); + } + + #forceRendering() { + if (this.onToggled) { + this.onToggled(); + } else { + this.pdfViewer.forceRendering(); + this.pdfThumbnailViewer.forceRendering(); + } + } + + #updateThumbnailViewer() { + const { + pdfViewer, + pdfThumbnailViewer + } = this; + const pagesCount = pdfViewer.pagesCount; + + for (let pageIndex = 0; pageIndex < pagesCount; pageIndex++) { + const pageView = pdfViewer.getPageView(pageIndex); + + if (pageView?.renderingState === _ui_utils.RenderingStates.FINISHED) { + const thumbnailView = pdfThumbnailViewer.getThumbnail(pageIndex); + thumbnailView.setImage(pageView); + } + } + + pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); + } + + #showUINotification() { + this.l10n.get("toggle_sidebar_notification2.title").then(msg => { + this.toggleButton.title = msg; + }); + + if (!this.isOpen) { + this.toggleButton.classList.add(UI_NOTIFICATION_CLASS); + } + } + + #hideUINotification(reset = false) { + if (this.isOpen || reset) { + this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS); + } + + if (reset) { + this.l10n.get("toggle_sidebar.title").then(msg => { + this.toggleButton.title = msg; + }); + } + } + + #addEventListeners() { + this.sidebarContainer.addEventListener("transitionend", evt => { + if (evt.target === this.sidebarContainer) { + this.outerContainer.classList.remove("sidebarMoving"); + } + }); + this.toggleButton.addEventListener("click", () => { + this.toggle(); + }); + this.thumbnailButton.addEventListener("click", () => { + this.switchView(_ui_utils.SidebarView.THUMBS); + }); + this.outlineButton.addEventListener("click", () => { + this.switchView(_ui_utils.SidebarView.OUTLINE); + }); + this.outlineButton.addEventListener("dblclick", () => { + this.eventBus.dispatch("toggleoutlinetree", { + source: this + }); + }); + this.attachmentsButton.addEventListener("click", () => { + this.switchView(_ui_utils.SidebarView.ATTACHMENTS); + }); + this.layersButton.addEventListener("click", () => { + this.switchView(_ui_utils.SidebarView.LAYERS); + }); + this.layersButton.addEventListener("dblclick", () => { + this.eventBus.dispatch("resetlayers", { + source: this + }); + }); + + this._currentOutlineItemButton.addEventListener("click", () => { + this.eventBus.dispatch("currentoutlineitem", { + source: this + }); + }); + + const onTreeLoaded = (count, button, view) => { + button.disabled = !count; + + if (count) { + this.#showUINotification(); + } else if (this.active === view) { + this.switchView(_ui_utils.SidebarView.THUMBS); + } + }; + + this.eventBus._on("outlineloaded", evt => { + onTreeLoaded(evt.outlineCount, this.outlineButton, _ui_utils.SidebarView.OUTLINE); + evt.currentOutlineItemPromise.then(enabled => { + if (!this.isInitialViewSet) { + return; + } + + this._currentOutlineItemButton.disabled = !enabled; + }); + }); + + this.eventBus._on("attachmentsloaded", evt => { + onTreeLoaded(evt.attachmentsCount, this.attachmentsButton, _ui_utils.SidebarView.ATTACHMENTS); + }); + + this.eventBus._on("layersloaded", evt => { + onTreeLoaded(evt.layersCount, this.layersButton, _ui_utils.SidebarView.LAYERS); + }); + + this.eventBus._on("presentationmodechanged", evt => { + if (evt.state === _ui_utils.PresentationModeState.NORMAL && this.visibleView === _ui_utils.SidebarView.THUMBS) { + this.#updateThumbnailViewer(); + } + }); + } + +} + +exports.PDFSidebar = PDFSidebar; + +/***/ }), +/* 25 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.PDFSidebarResizer = void 0; -var _ui_utils = __webpack_require__(2); +var _ui_utils = __webpack_require__(1); const SIDEBAR_WIDTH_VAR = "--sidebar-width"; const SIDEBAR_MIN_WIDTH = 200; const SIDEBAR_RESIZING_CLASS = "sidebarResizing"; class PDFSidebarResizer { - constructor(options, eventBus, l10n = _ui_utils.NullL10n) { - this.enabled = false; + constructor(options, eventBus, l10n) { this.isRTL = false; this.sidebarOpen = false; - this.doc = document.documentElement; this._width = null; this._outerContainerWidth = null; this._boundEvents = Object.create(null); this.outerContainer = options.outerContainer; this.resizer = options.resizer; this.eventBus = eventBus; - this.l10n = l10n; - - if (typeof CSS === "undefined" || typeof CSS.supports !== "function" || !CSS.supports(SIDEBAR_WIDTH_VAR, `calc(-1 * ${SIDEBAR_MIN_WIDTH}px)`)) { - console.warn("PDFSidebarResizer: " + "The browser does not support resizing of the sidebar."); - return; - } - - this.enabled = true; - this.resizer.classList.remove("hidden"); - this.l10n.getDirection().then(dir => { + l10n.getDirection().then(dir => { this.isRTL = dir === "rtl"; }); @@ -8453,26 +9165,28 @@ class PDFSidebarResizer { } get outerContainerWidth() { - if (!this._outerContainerWidth) { - this._outerContainerWidth = this.outerContainer.clientWidth; - } - - return this._outerContainerWidth; + return this._outerContainerWidth ||= this.outerContainer.clientWidth; } _updateWidth(width = 0) { - if (!this.enabled) { + const maxWidth = Math.floor(this.outerContainerWidth / 2); + + if (width > maxWidth) { + width = maxWidth; + } + + if (width < SIDEBAR_MIN_WIDTH) { + width = SIDEBAR_MIN_WIDTH; + } + + if (width === this._width) { return false; } - const newWidth = (0, _ui_utils.clamp)(width, SIDEBAR_MIN_WIDTH, Math.floor(this.outerContainerWidth / 2)); + this._width = width; - if (newWidth === this._width) { - return false; - } + _ui_utils.docStyle.setProperty(SIDEBAR_WIDTH_VAR, `${width}px`); - this._width = newWidth; - this.doc.style.setProperty(SIDEBAR_WIDTH_VAR, `${newWidth}px`); return true; } @@ -8497,10 +9211,6 @@ class PDFSidebarResizer { } _addEventListeners() { - if (!this.enabled) { - return; - } - const _boundEvents = this._boundEvents; _boundEvents.mouseMove = this._mouseMove.bind(this); _boundEvents.mouseUp = this._mouseUp.bind(this); @@ -8515,11 +9225,11 @@ class PDFSidebarResizer { }); this.eventBus._on("sidebarviewchanged", evt => { - this.sidebarOpen = !!(evt && evt.view); + this.sidebarOpen = !!evt?.view; }); this.eventBus._on("resize", evt => { - if (!evt || evt.source !== window) { + if (evt?.source !== window) { return; } @@ -8556,20 +9266,19 @@ class PDFSidebarResizer { exports.PDFSidebarResizer = PDFSidebarResizer; /***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 26 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFThumbnailViewer = void 0; -var _ui_utils = __webpack_require__(2); +var _ui_utils = __webpack_require__(1); -var _pdf_thumbnail_view = __webpack_require__(25); +var _pdf_thumbnail_view = __webpack_require__(27); const THUMBNAIL_SCROLL_MARGIN = -19; const THUMBNAIL_SELECTED_CLASS = "selected"; @@ -8580,19 +9289,26 @@ class PDFThumbnailViewer { eventBus, linkService, renderingQueue, - l10n = _ui_utils.NullL10n + l10n, + pageColors }) { this.container = container; this.linkService = linkService; this.renderingQueue = renderingQueue; this.l10n = l10n; + this.pageColors = pageColors || null; + + if (this.pageColors && !(CSS.supports("color", this.pageColors.background) && CSS.supports("color", this.pageColors.foreground))) { + if (this.pageColors.background || this.pageColors.foreground) { + console.warn("PDFThumbnailViewer: Ignoring `pageColors`-option, since the browser doesn't support the values used."); + } + + this.pageColors = null; + } + this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdated.bind(this)); this._resetView(); - - eventBus._on("optionalcontentconfigchanged", () => { - this._setImageDisabled = true; - }); } _scrollUpdated() { @@ -8604,7 +9320,10 @@ class PDFThumbnailViewer { } _getVisibleThumbs() { - return (0, _ui_utils.getVisibleElements)(this.container, this._thumbnails); + return (0, _ui_utils.getVisibleElements)({ + scrollEl: this.container, + views: this._thumbnails + }); } scrollThumbnailIntoView(pageNumber) { @@ -8625,26 +9344,29 @@ class PDFThumbnailViewer { thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS); } - const visibleThumbs = this._getVisibleThumbs(); + const { + first, + last, + views + } = this._getVisibleThumbs(); - const numVisibleThumbs = visibleThumbs.views.length; - - if (numVisibleThumbs > 0) { - const first = visibleThumbs.first.id; - const last = numVisibleThumbs > 1 ? visibleThumbs.last.id : first; + if (views.length > 0) { let shouldScroll = false; - if (pageNumber <= first || pageNumber >= last) { + if (pageNumber <= first.id || pageNumber >= last.id) { shouldScroll = true; } else { - visibleThumbs.views.some(function (view) { - if (view.id !== pageNumber) { - return false; + for (const { + id, + percent + } of views) { + if (id !== pageNumber) { + continue; } - shouldScroll = view.percent < 100; - return true; - }); + shouldScroll = percent < 100; + break; + } } if (shouldScroll) { @@ -8675,14 +9397,23 @@ class PDFThumbnailViewer { } this._pagesRotation = rotation; + const updateArgs = { + rotation + }; - for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { - this._thumbnails[i].update(rotation); + for (const thumbnail of this._thumbnails) { + thumbnail.update(updateArgs); } } cleanup() { - _pdf_thumbnail_view.PDFThumbnailView.cleanup(); + for (const thumbnail of this._thumbnails) { + if (thumbnail.renderingState !== _ui_utils.RenderingStates.FINISHED) { + thumbnail.reset(); + } + } + + _pdf_thumbnail_view.TempImageFactory.destroyCanvas(); } _resetView() { @@ -8690,9 +9421,6 @@ class PDFThumbnailViewer { this._currentPageNumber = 1; this._pageLabels = null; this._pagesRotation = 0; - this._optionalContentConfigPromise = null; - this._pagesRequests = new WeakMap(); - this._setImageDisabled = false; this.container.textContent = ""; } @@ -8712,16 +9440,11 @@ class PDFThumbnailViewer { const firstPagePromise = pdfDocument.getPage(1); const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); firstPagePromise.then(firstPdfPage => { - this._optionalContentConfigPromise = optionalContentConfigPromise; const pagesCount = pdfDocument.numPages; const viewport = firstPdfPage.getViewport({ scale: 1 }); - const checkSetImageDisabled = () => { - return this._setImageDisabled; - }; - for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { const thumbnail = new _pdf_thumbnail_view.PDFThumbnailView({ container: this.container, @@ -8730,9 +9453,8 @@ class PDFThumbnailViewer { optionalContentConfigPromise, linkService: this.linkService, renderingQueue: this.renderingQueue, - checkSetImageDisabled, - disableCanvasToImageConversion: false, - l10n: this.l10n + l10n: this.l10n, + pageColors: this.pageColors }); this._thumbnails.push(thumbnail); @@ -8752,10 +9474,8 @@ class PDFThumbnailViewer { } _cancelRendering() { - for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { - if (this._thumbnails[i]) { - this._thumbnails[i].cancelRendering(); - } + for (const thumbnail of this._thumbnails) { + thumbnail.cancelRendering(); } } @@ -8774,50 +9494,49 @@ class PDFThumbnailViewer { } for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { - const label = this._pageLabels && this._pageLabels[i]; - - this._thumbnails[i].setPageLabel(label); + this._thumbnails[i].setPageLabel(this._pageLabels?.[i] ?? null); } } - _ensurePdfPageLoaded(thumbView) { + async #ensurePdfPageLoaded(thumbView) { if (thumbView.pdfPage) { - return Promise.resolve(thumbView.pdfPage); + return thumbView.pdfPage; } - if (this._pagesRequests.has(thumbView)) { - return this._pagesRequests.get(thumbView); - } + try { + const pdfPage = await this.pdfDocument.getPage(thumbView.id); - const promise = this.pdfDocument.getPage(thumbView.id).then(pdfPage => { if (!thumbView.pdfPage) { thumbView.setPdfPage(pdfPage); } - this._pagesRequests.delete(thumbView); - return pdfPage; - }).catch(reason => { + } catch (reason) { console.error("Unable to get page for thumb view", reason); + return null; + } + } - this._pagesRequests.delete(thumbView); - }); + #getScrollAhead(visible) { + if (visible.first?.id === 1) { + return true; + } else if (visible.last?.id === this._thumbnails.length) { + return false; + } - this._pagesRequests.set(thumbView, promise); - - return promise; + return this.scroll.down; } forceRendering() { const visibleThumbs = this._getVisibleThumbs(); - const thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, this.scroll.down); + const scrollAhead = this.#getScrollAhead(visibleThumbs); + const thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, scrollAhead); if (thumbView) { - this._ensurePdfPageLoaded(thumbView).then(() => { + this.#ensurePdfPageLoaded(thumbView).then(() => { this.renderingQueue.renderView(thumbView); }); - return true; } @@ -8829,64 +9548,56 @@ class PDFThumbnailViewer { exports.PDFThumbnailViewer = PDFThumbnailViewer; /***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 27 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.PDFThumbnailView = void 0; +})); +exports.TempImageFactory = exports.PDFThumbnailView = void 0; + +var _ui_utils = __webpack_require__(1); var _pdfjsLib = __webpack_require__(5); -var _ui_utils = __webpack_require__(2); - -var _pdf_rendering_queue = __webpack_require__(8); - +const DRAW_UPSCALE_FACTOR = 2; const MAX_NUM_SCALING_STEPS = 3; const THUMBNAIL_CANVAS_BORDER_WIDTH = 1; const THUMBNAIL_WIDTH = 98; -const TempImageFactory = function TempImageFactoryClosure() { - let tempCanvasCache = null; - return { - getCanvas(width, height) { - let tempCanvas = tempCanvasCache; +class TempImageFactory { + static #tempCanvas = null; - if (!tempCanvas) { - tempCanvas = document.createElement("canvas"); - tempCanvasCache = tempCanvas; - } + static getCanvas(width, height) { + const tempCanvas = this.#tempCanvas ||= document.createElement("canvas"); + tempCanvas.width = width; + tempCanvas.height = height; + const ctx = tempCanvas.getContext("2d", { + alpha: false + }); + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, width, height); + ctx.restore(); + return [tempCanvas, tempCanvas.getContext("2d")]; + } - tempCanvas.width = width; - tempCanvas.height = height; - tempCanvas.mozOpaque = true; - const ctx = tempCanvas.getContext("2d", { - alpha: false - }); - ctx.save(); - ctx.fillStyle = "rgb(255, 255, 255)"; - ctx.fillRect(0, 0, width, height); - ctx.restore(); - return tempCanvas; - }, + static destroyCanvas() { + const tempCanvas = this.#tempCanvas; - destroyCanvas() { - const tempCanvas = tempCanvasCache; - - if (tempCanvas) { - tempCanvas.width = 0; - tempCanvas.height = 0; - } - - tempCanvasCache = null; + if (tempCanvas) { + tempCanvas.width = 0; + tempCanvas.height = 0; } - }; -}(); + this.#tempCanvas = null; + } + +} + +exports.TempImageFactory = TempImageFactory; class PDFThumbnailView { constructor({ @@ -8896,9 +9607,8 @@ class PDFThumbnailView { optionalContentConfigPromise, linkService, renderingQueue, - checkSetImageDisabled, - disableCanvasToImageConversion = false, - l10n = _ui_utils.NullL10n + l10n, + pageColors }) { this.id = id; this.renderingId = "thumbnail" + id; @@ -8908,23 +9618,18 @@ class PDFThumbnailView { this.viewport = defaultViewport; this.pdfPageRotate = defaultViewport.rotation; this._optionalContentConfigPromise = optionalContentConfigPromise || null; + this.pageColors = pageColors || null; this.linkService = linkService; this.renderingQueue = renderingQueue; this.renderTask = null; - this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; + this.renderingState = _ui_utils.RenderingStates.INITIAL; this.resume = null; - - this._checkSetImageDisabled = checkSetImageDisabled || function () { - return false; - }; - - this.disableCanvasToImageConversion = disableCanvasToImageConversion; - this.pageWidth = this.viewport.width; - this.pageHeight = this.viewport.height; - this.pageRatio = this.pageWidth / this.pageHeight; + const pageWidth = this.viewport.width, + pageHeight = this.viewport.height, + pageRatio = pageWidth / pageHeight; this.canvasWidth = THUMBNAIL_WIDTH; - this.canvasHeight = this.canvasWidth / this.pageRatio | 0; - this.scale = this.canvasWidth / this.pageWidth; + this.canvasHeight = this.canvasWidth / pageRatio | 0; + this.scale = this.canvasWidth / pageWidth; this.l10n = l10n; const anchor = document.createElement("a"); anchor.href = linkService.getAnchorUrl("#page=" + id); @@ -8934,7 +9639,7 @@ class PDFThumbnailView { }); anchor.onclick = function () { - linkService.page = id; + linkService.goToPage(id); return false; }; @@ -8949,9 +9654,9 @@ class PDFThumbnailView { ring.style.width = this.canvasWidth + borderAdjustment + "px"; ring.style.height = this.canvasHeight + borderAdjustment + "px"; this.ring = ring; - div.appendChild(ring); - anchor.appendChild(div); - container.appendChild(anchor); + div.append(ring); + anchor.append(div); + container.append(anchor); } setPdfPage(pdfPage) { @@ -8967,20 +9672,15 @@ class PDFThumbnailView { reset() { this.cancelRendering(); - this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; - this.pageWidth = this.viewport.width; - this.pageHeight = this.viewport.height; - this.pageRatio = this.pageWidth / this.pageHeight; - this.canvasHeight = this.canvasWidth / this.pageRatio | 0; - this.scale = this.canvasWidth / this.pageWidth; + this.renderingState = _ui_utils.RenderingStates.INITIAL; + const pageWidth = this.viewport.width, + pageHeight = this.viewport.height, + pageRatio = pageWidth / pageHeight; + this.canvasHeight = this.canvasWidth / pageRatio | 0; + this.scale = this.canvasWidth / pageWidth; this.div.removeAttribute("data-loaded"); const ring = this.ring; - const childNodes = ring.childNodes; - - for (let i = childNodes.length - 1; i >= 0; i--) { - ring.removeChild(childNodes[i]); - } - + ring.textContent = ""; const borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; ring.style.width = this.canvasWidth + borderAdjustment + "px"; ring.style.height = this.canvasHeight + borderAdjustment + "px"; @@ -8997,8 +9697,10 @@ class PDFThumbnailView { } } - update(rotation) { - if (typeof rotation !== "undefined") { + update({ + rotation = null + }) { + if (typeof rotation === "number") { this.rotation = rotation; } @@ -9019,51 +9721,31 @@ class PDFThumbnailView { this.resume = null; } - _getPageDrawContext(noCtxScale = false) { + _getPageDrawContext(upscaleFactor = 1) { const canvas = document.createElement("canvas"); - this.canvas = canvas; - canvas.mozOpaque = true; const ctx = canvas.getContext("2d", { alpha: false }); - const outputScale = (0, _ui_utils.getOutputScale)(ctx); - canvas.width = this.canvasWidth * outputScale.sx | 0; - canvas.height = this.canvasHeight * outputScale.sy | 0; - canvas.style.width = this.canvasWidth + "px"; - canvas.style.height = this.canvasHeight + "px"; - - if (!noCtxScale && outputScale.scaled) { - ctx.scale(outputScale.sx, outputScale.sy); - } - - return ctx; + const outputScale = new _ui_utils.OutputScale(); + canvas.width = upscaleFactor * this.canvasWidth * outputScale.sx | 0; + canvas.height = upscaleFactor * this.canvasHeight * outputScale.sy | 0; + const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null; + return { + ctx, + canvas, + transform + }; } - _convertCanvasToImage() { - if (!this.canvas) { - return; + _convertCanvasToImage(canvas) { + if (this.renderingState !== _ui_utils.RenderingStates.FINISHED) { + throw new Error("_convertCanvasToImage: Rendering has not finished."); } - if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { - return; - } - - const className = "thumbnailImage"; - - if (this.disableCanvasToImageConversion) { - this.canvas.className = className; - - this._thumbPageCanvas.then(msg => { - this.canvas.setAttribute("aria-label", msg); - }); - - this.div.setAttribute("data-loaded", true); - this.ring.appendChild(this.canvas); - return; - } + const reducedCanvas = this._reduceImage(canvas); const image = document.createElement("img"); - image.className = className; + image.className = "thumbnailImage"; this._thumbPageCanvas.then(msg => { image.setAttribute("aria-label", msg); @@ -9071,19 +9753,18 @@ class PDFThumbnailView { image.style.width = this.canvasWidth + "px"; image.style.height = this.canvasHeight + "px"; - image.src = this.canvas.toDataURL(); + image.src = reducedCanvas.toDataURL(); this.image = image; this.div.setAttribute("data-loaded", true); - this.ring.appendChild(image); - this.canvas.width = 0; - this.canvas.height = 0; - delete this.canvas; + this.ring.append(image); + reducedCanvas.width = 0; + reducedCanvas.height = 0; } draw() { - if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { + if (this.renderingState !== _ui_utils.RenderingStates.INITIAL) { console.error("Must be in new state before drawing"); - return Promise.resolve(undefined); + return Promise.resolve(); } const { @@ -9091,46 +9772,46 @@ class PDFThumbnailView { } = this; if (!pdfPage) { - this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + this.renderingState = _ui_utils.RenderingStates.FINISHED; return Promise.reject(new Error("pdfPage is not loaded")); } - this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; - const renderCapability = (0, _pdfjsLib.createPromiseCapability)(); + this.renderingState = _ui_utils.RenderingStates.RUNNING; - const finishRenderTask = error => { + const finishRenderTask = async (error = null) => { if (renderTask === this.renderTask) { this.renderTask = null; } if (error instanceof _pdfjsLib.RenderingCancelledException) { - renderCapability.resolve(undefined); return; } - this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + this.renderingState = _ui_utils.RenderingStates.FINISHED; - this._convertCanvasToImage(); + this._convertCanvasToImage(canvas); - if (!error) { - renderCapability.resolve(undefined); - } else { - renderCapability.reject(error); + if (error) { + throw error; } }; - const ctx = this._getPageDrawContext(); + const { + ctx, + canvas, + transform + } = this._getPageDrawContext(DRAW_UPSCALE_FACTOR); const drawViewport = this.viewport.clone({ - scale: this.scale + scale: DRAW_UPSCALE_FACTOR * this.scale }); const renderContinueCallback = cont => { if (!this.renderingQueue.isHighestPriority(this)) { - this.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED; + this.renderingState = _ui_utils.RenderingStates.PAUSED; this.resume = () => { - this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; + this.renderingState = _ui_utils.RenderingStates.RUNNING; cont(); }; @@ -9142,56 +9823,72 @@ class PDFThumbnailView { const renderContext = { canvasContext: ctx, + transform, viewport: drawViewport, - optionalContentConfigPromise: this._optionalContentConfigPromise + optionalContentConfigPromise: this._optionalContentConfigPromise, + pageColors: this.pageColors }; const renderTask = this.renderTask = pdfPage.render(renderContext); renderTask.onContinue = renderContinueCallback; - renderTask.promise.then(function () { - finishRenderTask(null); + const resultPromise = renderTask.promise.then(function () { + return finishRenderTask(null); }, function (error) { - finishRenderTask(error); + return finishRenderTask(error); }); - return renderCapability.promise; + resultPromise.finally(() => { + canvas.width = 0; + canvas.height = 0; + const pageCached = this.linkService.isPageCached(this.id); + + if (!pageCached) { + this.pdfPage?.cleanup(); + } + }); + return resultPromise; } setImage(pageView) { - if (this._checkSetImageDisabled()) { + if (this.renderingState !== _ui_utils.RenderingStates.INITIAL) { return; } - if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { - return; - } + const { + thumbnailCanvas: canvas, + pdfPage, + scale + } = pageView; - const img = pageView.canvas; - - if (!img) { + if (!canvas) { return; } if (!this.pdfPage) { - this.setPdfPage(pageView.pdfPage); + this.setPdfPage(pdfPage); } - this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + if (scale < this.scale) { + return; + } - const ctx = this._getPageDrawContext(true); + this.renderingState = _ui_utils.RenderingStates.FINISHED; - const canvas = ctx.canvas; + this._convertCanvasToImage(canvas); + } + + _reduceImage(img) { + const { + ctx, + canvas + } = this._getPageDrawContext(); if (img.width <= 2 * canvas.width) { ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height); - - this._convertCanvasToImage(); - - return; + return canvas; } let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS; let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS; - const reducedImage = TempImageFactory.getCanvas(reducedWidth, reducedHeight); - const reducedImageCtx = reducedImage.getContext("2d"); + const [reducedImage, reducedImageCtx] = TempImageFactory.getCanvas(reducedWidth, reducedHeight); while (reducedWidth > img.width || reducedHeight > img.height) { reducedWidth >>= 1; @@ -9207,24 +9904,19 @@ class PDFThumbnailView { } ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height); - - this._convertCanvasToImage(); + return canvas; } get _thumbPageTitle() { - var _this$pageLabel; - return this.l10n.get("thumb_page_title", { - page: (_this$pageLabel = this.pageLabel) != null ? _this$pageLabel : this.id - }, "Page {{page}}"); + page: this.pageLabel ?? this.id + }); } get _thumbPageCanvas() { - var _this$pageLabel2; - return this.l10n.get("thumb_page_canvas", { - page: (_this$pageLabel2 = this.pageLabel) != null ? _this$pageLabel2 : this.id - }, "Thumbnail of Page {{page}}"); + page: this.pageLabel ?? this.id + }); } setPageLabel(label) { @@ -9234,220 +9926,229 @@ class PDFThumbnailView { this.anchor.title = msg; }); - if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { + if (this.renderingState !== _ui_utils.RenderingStates.FINISHED) { return; } this._thumbPageCanvas.then(msg => { - if (this.image) { - this.image.setAttribute("aria-label", msg); - } else if (this.disableCanvasToImageConversion && this.canvas) { - this.canvas.setAttribute("aria-label", msg); - } + this.image?.setAttribute("aria-label", msg); }); } - static cleanup() { - TempImageFactory.destroyCanvas(); - } - } exports.PDFThumbnailView = PDFThumbnailView; /***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 28 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.PDFViewer = void 0; +})); +exports.PDFViewer = exports.PDFSinglePageViewer = void 0; -var _base_viewer = __webpack_require__(27); +var _ui_utils = __webpack_require__(1); -var _pdfjsLib = __webpack_require__(5); +var _base_viewer = __webpack_require__(29); -class PDFViewer extends _base_viewer.BaseViewer { - get _viewerElement() { - return (0, _pdfjsLib.shadow)(this, "_viewerElement", this.viewer); - } - - _scrollIntoView({ - pageDiv, - pageSpot = null, - pageNumber = null - }) { - if (!pageSpot && !this.isInPresentationMode) { - const left = pageDiv.offsetLeft + pageDiv.clientLeft; - const right = left + pageDiv.clientWidth; - const { - scrollLeft, - clientWidth - } = this.container; - - if (this._isScrollModeHorizontal || left < scrollLeft || right > scrollLeft + clientWidth) { - pageSpot = { - left: 0, - top: 0 - }; - } - } - - super._scrollIntoView({ - pageDiv, - pageSpot, - pageNumber - }); - } - - _getVisiblePages() { - if (this.isInPresentationMode) { - return this._getCurrentVisiblePage(); - } - - return super._getVisiblePages(); - } - - _updateHelper(visiblePages) { - if (this.isInPresentationMode) { - return; - } - - let currentId = this._currentPageNumber; - let stillFullyVisible = false; - - for (const page of visiblePages) { - if (page.percent < 100) { - break; - } - - if (page.id === currentId) { - stillFullyVisible = true; - break; - } - } - - if (!stillFullyVisible) { - currentId = visiblePages[0].id; - } - - this._setCurrentPageNumber(currentId); - } - -} +class PDFViewer extends _base_viewer.BaseViewer {} exports.PDFViewer = PDFViewer; +class PDFSinglePageViewer extends _base_viewer.BaseViewer { + _resetView() { + super._resetView(); + + this._scrollMode = _ui_utils.ScrollMode.PAGE; + this._spreadMode = _ui_utils.SpreadMode.NONE; + } + + set scrollMode(mode) {} + + _updateScrollMode() {} + + set spreadMode(mode) {} + + _updateSpreadMode() {} + +} + +exports.PDFSinglePageViewer = PDFSinglePageViewer; + /***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 29 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.BaseViewer = void 0; - -var _ui_utils = __webpack_require__(2); - -var _pdf_rendering_queue = __webpack_require__(8); - -var _annotation_layer_builder = __webpack_require__(28); +})); +exports.PagesCountLimit = exports.PDFPageViewBuffer = exports.BaseViewer = void 0; var _pdfjsLib = __webpack_require__(5); -var _pdf_page_view = __webpack_require__(29); +var _ui_utils = __webpack_require__(1); -var _pdf_link_service = __webpack_require__(20); +var _annotation_editor_layer_builder = __webpack_require__(30); -var _text_layer_builder = __webpack_require__(30); +var _annotation_layer_builder = __webpack_require__(32); + +var _l10n_utils = __webpack_require__(31); + +var _pdf_page_view = __webpack_require__(33); + +var _pdf_rendering_queue = __webpack_require__(22); + +var _pdf_link_service = __webpack_require__(3); + +var _struct_tree_layer_builder = __webpack_require__(35); + +var _text_highlighter = __webpack_require__(36); + +var _text_layer_builder = __webpack_require__(37); + +var _xfa_layer_builder = __webpack_require__(38); const DEFAULT_CACHE_SIZE = 10; +const ENABLE_PERMISSIONS_CLASS = "enablePermissions"; +const PagesCountLimit = { + FORCE_SCROLL_MODE_PAGE: 15000, + FORCE_LAZY_PAGE_INIT: 7500, + PAUSE_EAGER_PAGE_INIT: 250 +}; +exports.PagesCountLimit = PagesCountLimit; -function PDFPageViewBuffer(size) { - const data = []; +function isValidAnnotationEditorMode(mode) { + return Object.values(_pdfjsLib.AnnotationEditorType).includes(mode) && mode !== _pdfjsLib.AnnotationEditorType.DISABLE; +} - this.push = function (view) { - const i = data.indexOf(view); +class PDFPageViewBuffer { + #buf = new Set(); + #size = 0; - if (i >= 0) { - data.splice(i, 1); + constructor(size) { + this.#size = size; + } + + push(view) { + const buf = this.#buf; + + if (buf.has(view)) { + buf.delete(view); } - data.push(view); + buf.add(view); - if (data.length > size) { - data.shift().destroy(); + if (buf.size > this.#size) { + this.#destroyFirstView(); } - }; + } - this.resize = function (newSize, pagesToKeep) { - size = newSize; + resize(newSize, idsToKeep = null) { + this.#size = newSize; + const buf = this.#buf; - if (pagesToKeep) { - const pageIdsToKeep = new Set(); + if (idsToKeep) { + const ii = buf.size; + let i = 1; - for (let i = 0, iMax = pagesToKeep.length; i < iMax; ++i) { - pageIdsToKeep.add(pagesToKeep[i].id); + for (const view of buf) { + if (idsToKeep.has(view.id)) { + buf.delete(view); + buf.add(view); + } + + if (++i > ii) { + break; + } } - - (0, _ui_utils.moveToEndOfArray)(data, function (page) { - return pageIdsToKeep.has(page.id); - }); } - while (data.length > size) { - data.shift().destroy(); + while (buf.size > this.#size) { + this.#destroyFirstView(); } - }; -} - -function isSameScale(oldScale, newScale) { - if (newScale === oldScale) { - return true; } - if (Math.abs(newScale - oldScale) < 1e-15) { - return true; + has(view) { + return this.#buf.has(view); + } + + [Symbol.iterator]() { + return this.#buf.keys(); + } + + #destroyFirstView() { + const firstView = this.#buf.keys().next().value; + firstView?.destroy(); + this.#buf.delete(firstView); } - return false; } +exports.PDFPageViewBuffer = PDFPageViewBuffer; + class BaseViewer { + #buffer = null; + #annotationEditorMode = _pdfjsLib.AnnotationEditorType.DISABLE; + #annotationEditorUIManager = null; + #annotationMode = _pdfjsLib.AnnotationMode.ENABLE_FORMS; + #enablePermissions = false; + #previousContainerHeight = 0; + #scrollModePageState = null; + #onVisibilityChange = null; + constructor(options) { if (this.constructor === BaseViewer) { throw new Error("Cannot initialize BaseViewer."); } - this._name = this.constructor.name; + const viewerVersion = '2.16.105'; + + if (_pdfjsLib.version !== viewerVersion) { + throw new Error(`The API version "${_pdfjsLib.version}" does not match the Viewer version "${viewerVersion}".`); + } + this.container = options.container; this.viewer = options.viewer || options.container.firstElementChild; - if (!(this.container instanceof HTMLDivElement && this.viewer instanceof HTMLDivElement)) { + if (!(this.container?.tagName.toUpperCase() === "DIV" && this.viewer?.tagName.toUpperCase() === "DIV")) { throw new Error("Invalid `container` and/or `viewer` option."); } + if (this.container.offsetParent && getComputedStyle(this.container).position !== "absolute") { + throw new Error("The `container` must be absolutely positioned."); + } + this.eventBus = options.eventBus; this.linkService = options.linkService || new _pdf_link_service.SimpleLinkService(); this.downloadManager = options.downloadManager || null; this.findController = options.findController || null; + this._scriptingManager = options.scriptingManager || null; this.removePageBorders = options.removePageBorders || false; - this.textLayerMode = Number.isInteger(options.textLayerMode) ? options.textLayerMode : _ui_utils.TextLayerMode.ENABLE; + this.textLayerMode = options.textLayerMode ?? _ui_utils.TextLayerMode.ENABLE; + this.#annotationMode = options.annotationMode ?? _pdfjsLib.AnnotationMode.ENABLE_FORMS; + this.#annotationEditorMode = options.annotationEditorMode ?? _pdfjsLib.AnnotationEditorType.DISABLE; this.imageResourcesPath = options.imageResourcesPath || ""; - this.renderInteractiveForms = typeof options.renderInteractiveForms === "boolean" ? options.renderInteractiveForms : true; this.enablePrintAutoRotate = options.enablePrintAutoRotate || false; this.renderer = options.renderer || _ui_utils.RendererType.CANVAS; - this.enableWebGL = options.enableWebGL || false; this.useOnlyCssZoom = options.useOnlyCssZoom || false; this.maxCanvasPixels = options.maxCanvasPixels; - this.l10n = options.l10n || _ui_utils.NullL10n; + this.l10n = options.l10n || _l10n_utils.NullL10n; + this.#enablePermissions = options.enablePermissions || false; + this.pageColors = options.pageColors || null; + + if (this.pageColors && !(CSS.supports("color", this.pageColors.background) && CSS.supports("color", this.pageColors.foreground))) { + if (this.pageColors.background || this.pageColors.foreground) { + console.warn("BaseViewer: Ignoring `pageColors`-option, since the browser doesn't support the values used."); + } + + this.pageColors = null; + } + this.defaultRenderingQueue = !options.renderingQueue; if (this.defaultRenderingQueue) { @@ -9467,11 +10168,7 @@ class BaseViewer { this.viewer.classList.add("removePageBorders"); } - Promise.resolve().then(() => { - this.eventBus.dispatch("baseviewerinit", { - source: this - }); - }); + this.updateContainerHeightCss(); } get pagesCount() { @@ -9488,10 +10185,18 @@ class BaseViewer { } return this._pages.every(function (pageView) { - return pageView && pageView.pdfPage; + return pageView?.pdfPage; }); } + get renderForms() { + return this.#annotationMode === _pdfjsLib.AnnotationMode.ENABLE_FORMS; + } + + get enableScripting() { + return !!this._scriptingManager; + } + get currentPageNumber() { return this._currentPageNumber; } @@ -9506,14 +10211,14 @@ class BaseViewer { } if (!this._setCurrentPageNumber(val, true)) { - console.error(`${this._name}.currentPageNumber: "${val}" is not a valid page.`); + console.error(`currentPageNumber: "${val}" is not a valid page.`); } } _setCurrentPageNumber(val, resetCurrentPageView = false) { if (this._currentPageNumber === val) { if (resetCurrentPageView) { - this._resetCurrentPageView(); + this.#resetCurrentPageView(); } return true; @@ -9523,22 +10228,24 @@ class BaseViewer { return false; } + const previous = this._currentPageNumber; this._currentPageNumber = val; this.eventBus.dispatch("pagechanging", { source: this, pageNumber: val, - pageLabel: this._pageLabels && this._pageLabels[val - 1] + pageLabel: this._pageLabels?.[val - 1] ?? null, + previous }); if (resetCurrentPageView) { - this._resetCurrentPageView(); + this.#resetCurrentPageView(); } return true; } get currentPageLabel() { - return this._pageLabels && this._pageLabels[this._currentPageNumber - 1]; + return this._pageLabels?.[this._currentPageNumber - 1] ?? null; } set currentPageLabel(val) { @@ -9557,7 +10264,7 @@ class BaseViewer { } if (!this._setCurrentPageNumber(page, true)) { - console.error(`${this._name}.currentPageLabel: "${val}" is not a valid page.`); + console.error(`currentPageLabel: "${val}" is not a valid page.`); } } @@ -9602,16 +10309,24 @@ class BaseViewer { return; } + rotation %= 360; + + if (rotation < 0) { + rotation += 360; + } + if (this._pagesRotation === rotation) { return; } this._pagesRotation = rotation; const pageNumber = this._currentPageNumber; + const updateArgs = { + rotation + }; - for (let i = 0, ii = this._pages.length; i < ii; i++) { - const pageView = this._pages[i]; - pageView.update(pageView.scale, rotation); + for (const pageView of this._pages) { + pageView.update(updateArgs); } if (this._currentScaleValue) { @@ -9641,20 +10356,59 @@ class BaseViewer { return this.pdfDocument ? this._pagesCapability.promise : null; } - get _viewerElement() { - throw new Error("Not implemented: _viewerElement"); + #initializePermissions(permissions) { + const params = { + annotationEditorMode: this.#annotationEditorMode, + annotationMode: this.#annotationMode, + textLayerMode: this.textLayerMode + }; + + if (!permissions) { + return params; + } + + if (!permissions.includes(_pdfjsLib.PermissionFlag.COPY)) { + this.viewer.classList.add(ENABLE_PERMISSIONS_CLASS); + } + + if (!permissions.includes(_pdfjsLib.PermissionFlag.MODIFY_CONTENTS)) { + params.annotationEditorMode = _pdfjsLib.AnnotationEditorType.DISABLE; + } + + if (!permissions.includes(_pdfjsLib.PermissionFlag.MODIFY_ANNOTATIONS) && !permissions.includes(_pdfjsLib.PermissionFlag.FILL_INTERACTIVE_FORMS) && this.#annotationMode === _pdfjsLib.AnnotationMode.ENABLE_FORMS) { + params.annotationMode = _pdfjsLib.AnnotationMode.ENABLE; + } + + return params; } - _onePageRenderedOrForceFetch() { - if (!this.container.offsetParent || this._getVisiblePages().views.length === 0) { + #onePageRenderedOrForceFetch() { + if (document.visibilityState === "hidden" || !this.container.offsetParent || this._getVisiblePages().views.length === 0) { return Promise.resolve(); } - return this._onePageRenderedCapability.promise; + const visibilityChangePromise = new Promise(resolve => { + this.#onVisibilityChange = () => { + if (document.visibilityState !== "hidden") { + return; + } + + resolve(); + document.removeEventListener("visibilitychange", this.#onVisibilityChange); + this.#onVisibilityChange = null; + }; + + document.addEventListener("visibilitychange", this.#onVisibilityChange); + }); + return Promise.race([this._onePageRenderedCapability.promise, visibilityChangePromise]); } setDocument(pdfDocument) { if (this.pdfDocument) { + this.eventBus.dispatch("pagesdestroy", { + source: this + }); + this._cancelRendering(); this._resetView(); @@ -9662,6 +10416,15 @@ class BaseViewer { if (this.findController) { this.findController.setDocument(null); } + + if (this._scriptingManager) { + this._scriptingManager.setDocument(null); + } + + if (this.#annotationEditorUIManager) { + this.#annotationEditorUIManager.destroy(); + this.#annotationEditorUIManager = null; + } } this.pdfDocument = pdfDocument; @@ -9670,17 +10433,27 @@ class BaseViewer { return; } + const isPureXfa = pdfDocument.isPureXfa; const pagesCount = pdfDocument.numPages; const firstPagePromise = pdfDocument.getPage(1); - const annotationStorage = pdfDocument.annotationStorage; const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); + const permissionsPromise = this.#enablePermissions ? pdfDocument.getPermissions() : Promise.resolve(); + + if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { + console.warn("Forcing PAGE-scrolling for performance reasons, given the length of the document."); + const mode = this._scrollMode = _ui_utils.ScrollMode.PAGE; + this.eventBus.dispatch("scrollmodechanged", { + source: this, + mode + }); + } this._pagesCapability.promise.then(() => { this.eventBus.dispatch("pagesloaded", { source: this, pagesCount }); - }); + }, () => {}); this._onBeforeDraw = evt => { const pageView = this._pages[evt.pageNumber - 1]; @@ -9689,7 +10462,7 @@ class BaseViewer { return; } - this._buffer.push(pageView); + this.#buffer.push(pageView); }; this.eventBus._on("pagerender", this._onBeforeDraw); @@ -9699,44 +10472,84 @@ class BaseViewer { return; } - this._onePageRenderedCapability.resolve(); + this._onePageRenderedCapability.resolve({ + timestamp: evt.timestamp + }); this.eventBus._off("pagerendered", this._onAfterDraw); this._onAfterDraw = null; + + if (this.#onVisibilityChange) { + document.removeEventListener("visibilitychange", this.#onVisibilityChange); + this.#onVisibilityChange = null; + } }; this.eventBus._on("pagerendered", this._onAfterDraw); - firstPagePromise.then(firstPdfPage => { + Promise.all([firstPagePromise, permissionsPromise]).then(([firstPdfPage, permissions]) => { + if (pdfDocument !== this.pdfDocument) { + return; + } + this._firstPageCapability.resolve(firstPdfPage); this._optionalContentConfigPromise = optionalContentConfigPromise; + const { + annotationEditorMode, + annotationMode, + textLayerMode + } = this.#initializePermissions(permissions); + + if (annotationEditorMode !== _pdfjsLib.AnnotationEditorType.DISABLE) { + const mode = annotationEditorMode; + + if (isPureXfa) { + console.warn("Warning: XFA-editing is not implemented."); + } else if (isValidAnnotationEditorMode(mode)) { + this.#annotationEditorUIManager = new _pdfjsLib.AnnotationEditorUIManager(this.container, this.eventBus); + + if (mode !== _pdfjsLib.AnnotationEditorType.NONE) { + this.#annotationEditorUIManager.updateMode(mode); + } + } else { + console.error(`Invalid AnnotationEditor mode: ${mode}`); + } + } + + const viewerElement = this._scrollMode === _ui_utils.ScrollMode.PAGE ? null : this.viewer; const scale = this.currentScale; const viewport = firstPdfPage.getViewport({ - scale: scale * _ui_utils.CSS_UNITS + scale: scale * _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS }); - const textLayerFactory = this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE ? this : null; + const textLayerFactory = textLayerMode !== _ui_utils.TextLayerMode.DISABLE && !isPureXfa ? this : null; + const annotationLayerFactory = annotationMode !== _pdfjsLib.AnnotationMode.DISABLE ? this : null; + const xfaLayerFactory = isPureXfa ? this : null; + const annotationEditorLayerFactory = this.#annotationEditorUIManager ? this : null; for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { const pageView = new _pdf_page_view.PDFPageView({ - container: this._viewerElement, + container: viewerElement, eventBus: this.eventBus, id: pageNum, scale, defaultViewport: viewport.clone(), - annotationStorage, optionalContentConfigPromise, renderingQueue: this.renderingQueue, textLayerFactory, - textLayerMode: this.textLayerMode, - annotationLayerFactory: this, + textLayerMode, + annotationLayerFactory, + annotationMode, + xfaLayerFactory, + annotationEditorLayerFactory, + textHighlighterFactory: this, + structTreeLayerFactory: this, imageResourcesPath: this.imageResourcesPath, - renderInteractiveForms: this.renderInteractiveForms, renderer: this.renderer, - enableWebGL: this.enableWebGL, useOnlyCssZoom: this.useOnlyCssZoom, maxCanvasPixels: this.maxCanvasPixels, + pageColors: this.pageColors, l10n: this.l10n }); @@ -9750,16 +10563,29 @@ class BaseViewer { this.linkService.cachePageRef(1, firstPdfPage.ref); } - if (this._spreadMode !== _ui_utils.SpreadMode.NONE) { + if (this._scrollMode === _ui_utils.ScrollMode.PAGE) { + this.#ensurePageViewVisible(); + } else if (this._spreadMode !== _ui_utils.SpreadMode.NONE) { this._updateSpreadMode(); } - this._onePageRenderedOrForceFetch().then(() => { + this.#onePageRenderedOrForceFetch().then(async () => { if (this.findController) { this.findController.setDocument(pdfDocument); } - if (pdfDocument.loadingParams.disableAutoFetch || pagesCount > 7500) { + if (this._scriptingManager) { + this._scriptingManager.setDocument(pdfDocument); + } + + if (this.#annotationEditorUIManager) { + this.eventBus.dispatch("annotationeditormodechanged", { + source: this, + mode: this.#annotationEditorMode + }); + } + + if (pdfDocument.loadingParams.disableAutoFetch || pagesCount > PagesCountLimit.FORCE_LAZY_PAGE_INIT) { this._pagesCapability.resolve(); return; @@ -9774,7 +10600,7 @@ class BaseViewer { } for (let pageNum = 2; pageNum <= pagesCount; ++pageNum) { - pdfDocument.getPage(pageNum).then(pdfPage => { + const promise = pdfDocument.getPage(pageNum).then(pdfPage => { const pageView = this._pages[pageNum - 1]; if (!pageView.pdfPage) { @@ -9793,18 +10619,34 @@ class BaseViewer { this._pagesCapability.resolve(); } }); + + if (pageNum % PagesCountLimit.PAUSE_EAGER_PAGE_INIT === 0) { + await promise; + } } }); - this.eventBus.dispatch("pagesinit", { source: this }); + pdfDocument.getMetadata().then(({ + info + }) => { + if (pdfDocument !== this.pdfDocument) { + return; + } + + if (info.Language) { + this.viewer.lang = info.Language; + } + }); if (this.defaultRenderingQueue) { this.update(); } }).catch(reason => { console.error("Unable to initialize viewer", reason); + + this._pagesCapability.reject(reason); }); } @@ -9817,15 +10659,13 @@ class BaseViewer { this._pageLabels = null; } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) { this._pageLabels = null; - console.error(`${this._name}.setPageLabels: Invalid page labels.`); + console.error(`setPageLabels: Invalid page labels.`); } else { this._pageLabels = labels; } for (let i = 0, ii = this._pages.length; i < ii; i++) { - const pageView = this._pages[i]; - const label = this._pageLabels && this._pageLabels[i]; - pageView.setPageLabel(label); + this._pages[i].setPageLabel(this._pageLabels?.[i] ?? null); } } @@ -9835,16 +10675,21 @@ class BaseViewer { this._currentScale = _ui_utils.UNKNOWN_SCALE; this._currentScaleValue = null; this._pageLabels = null; - this._buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE); + this.#buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE); this._location = null; this._pagesRotation = 0; this._optionalContentConfigPromise = null; - this._pagesRequests = new WeakMap(); this._firstPageCapability = (0, _pdfjsLib.createPromiseCapability)(); this._onePageRenderedCapability = (0, _pdfjsLib.createPromiseCapability)(); this._pagesCapability = (0, _pdfjsLib.createPromiseCapability)(); this._scrollMode = _ui_utils.ScrollMode.VERTICAL; + this._previousScrollMode = _ui_utils.ScrollMode.UNKNOWN; this._spreadMode = _ui_utils.SpreadMode.NONE; + this.#scrollModePageState = { + previousPageNumber: 1, + scrollDown: true, + pages: [] + }; if (this._onBeforeDraw) { this.eventBus._off("pagerender", this._onBeforeDraw); @@ -9858,9 +10703,73 @@ class BaseViewer { this._onAfterDraw = null; } + if (this.#onVisibilityChange) { + document.removeEventListener("visibilitychange", this.#onVisibilityChange); + this.#onVisibilityChange = null; + } + this.viewer.textContent = ""; this._updateScrollMode(); + + this.viewer.removeAttribute("lang"); + this.viewer.classList.remove(ENABLE_PERMISSIONS_CLASS); + } + + #ensurePageViewVisible() { + if (this._scrollMode !== _ui_utils.ScrollMode.PAGE) { + throw new Error("#ensurePageViewVisible: Invalid scrollMode value."); + } + + const pageNumber = this._currentPageNumber, + state = this.#scrollModePageState, + viewer = this.viewer; + viewer.textContent = ""; + state.pages.length = 0; + + if (this._spreadMode === _ui_utils.SpreadMode.NONE && !this.isInPresentationMode) { + const pageView = this._pages[pageNumber - 1]; + viewer.append(pageView.div); + state.pages.push(pageView); + } else { + const pageIndexSet = new Set(), + parity = this._spreadMode - 1; + + if (parity === -1) { + pageIndexSet.add(pageNumber - 1); + } else if (pageNumber % 2 !== parity) { + pageIndexSet.add(pageNumber - 1); + pageIndexSet.add(pageNumber); + } else { + pageIndexSet.add(pageNumber - 2); + pageIndexSet.add(pageNumber - 1); + } + + const spread = document.createElement("div"); + spread.className = "spread"; + + if (this.isInPresentationMode) { + const dummyPage = document.createElement("div"); + dummyPage.className = "dummyPage"; + spread.append(dummyPage); + } + + for (const i of pageIndexSet) { + const pageView = this._pages[i]; + + if (!pageView) { + continue; + } + + spread.append(pageView.div); + state.pages.push(pageView); + } + + viewer.append(spread); + } + + state.scrollDown = pageNumber >= state.previousPageNumber; + state.previousPageNumber = pageNumber; } _scrollUpdate() { @@ -9871,18 +10780,46 @@ class BaseViewer { this.update(); } - _scrollIntoView({ - pageDiv, - pageSpot = null, - pageNumber = null - }) { - (0, _ui_utils.scrollIntoView)(pageDiv, pageSpot); + #scrollIntoView(pageView, pageSpot = null) { + const { + div, + id + } = pageView; + + if (this._scrollMode === _ui_utils.ScrollMode.PAGE) { + this._setCurrentPageNumber(id); + + this.#ensurePageViewVisible(); + this.update(); + } + + if (!pageSpot && !this.isInPresentationMode) { + const left = div.offsetLeft + div.clientLeft, + right = left + div.clientWidth; + const { + scrollLeft, + clientWidth + } = this.container; + + if (this._scrollMode === _ui_utils.ScrollMode.HORIZONTAL || left < scrollLeft || right > scrollLeft + clientWidth) { + pageSpot = { + left: 0, + top: 0 + }; + } + } + + (0, _ui_utils.scrollIntoView)(div, pageSpot); + } + + #isSameScale(newScale) { + return newScale === this._currentScale || Math.abs(newScale - this._currentScale) < 1e-15; } _setScaleUpdatePages(newScale, newValue, noScroll = false, preset = false) { this._currentScaleValue = newValue.toString(); - if (isSameScale(this._currentScale, newScale)) { + if (this.#isSameScale(newScale)) { if (preset) { this.eventBus.dispatch("scalechanging", { source: this, @@ -9894,8 +10831,14 @@ class BaseViewer { return; } - for (let i = 0, ii = this._pages.length; i < ii; i++) { - this._pages[i].update(newScale); + _ui_utils.docStyle.setProperty("--scale-factor", newScale * _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS); + + const updateArgs = { + scale: newScale + }; + + for (const pageView of this._pages) { + pageView.update(updateArgs); } this._currentScale = newScale; @@ -9927,6 +10870,16 @@ class BaseViewer { if (this.defaultRenderingQueue) { this.update(); } + + this.updateContainerHeightCss(); + } + + get _pageWidthScaleFactor() { + if (this._spreadMode !== _ui_utils.SpreadMode.NONE && this._scrollMode !== _ui_utils.ScrollMode.HORIZONTAL) { + return 2; + } + + return 1; } _setScale(value, noScroll = false) { @@ -9941,15 +10894,18 @@ class BaseViewer { return; } - const noPadding = this.isInPresentationMode || this.removePageBorders; - let hPadding = noPadding ? 0 : _ui_utils.SCROLLBAR_PADDING; - let vPadding = noPadding ? 0 : _ui_utils.VERTICAL_PADDING; + let hPadding = _ui_utils.SCROLLBAR_PADDING, + vPadding = _ui_utils.VERTICAL_PADDING; - if (!noPadding && this._isScrollModeHorizontal) { + if (this.isInPresentationMode) { + hPadding = vPadding = 4; + } else if (this.removePageBorders) { + hPadding = vPadding = 0; + } else if (this._scrollMode === _ui_utils.ScrollMode.HORIZONTAL) { [hPadding, vPadding] = [vPadding, hPadding]; } - const pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale; + const pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale / this._pageWidthScaleFactor; const pageHeightScale = (this.container.clientHeight - vPadding) / currentPage.height * currentPage.scale; switch (value) { @@ -9975,7 +10931,7 @@ class BaseViewer { break; default: - console.error(`${this._name}._setScale: "${value}" is an unknown zoom value.`); + console.error(`_setScale: "${value}" is an unknown zoom value.`); return; } @@ -9983,16 +10939,28 @@ class BaseViewer { } } - _resetCurrentPageView() { + #resetCurrentPageView() { + const pageView = this._pages[this._currentPageNumber - 1]; + if (this.isInPresentationMode) { this._setScale(this._currentScaleValue, true); } - const pageView = this._pages[this._currentPageNumber - 1]; + this.#scrollIntoView(pageView); + } - this._scrollIntoView({ - pageDiv: pageView.div - }); + pageLabelToPageNumber(label) { + if (!this._pageLabels) { + return null; + } + + const i = this._pageLabels.indexOf(label); + + if (i < 0) { + return null; + } + + return i + 1; } scrollPageIntoView({ @@ -10008,7 +10976,7 @@ class BaseViewer { const pageView = Number.isInteger(pageNumber) && this._pages[pageNumber - 1]; if (!pageView) { - console.error(`${this._name}.scrollPageIntoView: ` + `"${pageNumber}" is not a valid pageNumber parameter.`); + console.error(`scrollPageIntoView: "${pageNumber}" is not a valid pageNumber parameter.`); return; } @@ -10025,8 +10993,8 @@ class BaseViewer { widthScale, heightScale; const changeOrientation = pageView.rotation % 180 !== 0; - const pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / _ui_utils.CSS_UNITS; - const pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / _ui_utils.CSS_UNITS; + const pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS; + const pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS; let scale = 0; switch (destArray[1].name) { @@ -10051,6 +11019,8 @@ class BaseViewer { if (y === null && this._location) { x = this._location.left; y = this._location.top; + } else if (typeof y !== "number" || y < 0) { + y = pageHeight; } break; @@ -10070,13 +11040,13 @@ class BaseViewer { height = destArray[5] - y; const hPadding = this.removePageBorders ? 0 : _ui_utils.SCROLLBAR_PADDING; const vPadding = this.removePageBorders ? 0 : _ui_utils.VERTICAL_PADDING; - widthScale = (this.container.clientWidth - hPadding) / width / _ui_utils.CSS_UNITS; - heightScale = (this.container.clientHeight - vPadding) / height / _ui_utils.CSS_UNITS; + widthScale = (this.container.clientWidth - hPadding) / width / _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS; + heightScale = (this.container.clientHeight - vPadding) / height / _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS; scale = Math.min(Math.abs(widthScale), Math.abs(heightScale)); break; default: - console.error(`${this._name}.scrollPageIntoView: ` + `"${destArray[1].name}" is not a valid destination type.`); + console.error(`scrollPageIntoView: "${destArray[1].name}" is not a valid destination type.`); return; } @@ -10089,11 +11059,7 @@ class BaseViewer { } if (scale === "page-fit" && !destArray[4]) { - this._scrollIntoView({ - pageDiv: pageView.div, - pageNumber - }); - + this.#scrollIntoView(pageView); return; } @@ -10106,13 +11072,9 @@ class BaseViewer { top = Math.max(top, 0); } - this._scrollIntoView({ - pageDiv: pageView.div, - pageSpot: { - left, - top - }, - pageNumber + this.#scrollIntoView(pageView, { + left, + top }); } @@ -10121,14 +11083,17 @@ class BaseViewer { const currentScaleValue = this._currentScaleValue; const normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue; const pageNumber = firstPage.id; - let pdfOpenParams = "#page=" + pageNumber; - pdfOpenParams += "&zoom=" + normalizedScaleValue; const currentPageView = this._pages[pageNumber - 1]; const container = this.container; const topLeft = currentPageView.getPagePoint(container.scrollLeft - firstPage.x, container.scrollTop - firstPage.y); const intLeft = Math.round(topLeft[0]); const intTop = Math.round(topLeft[1]); - pdfOpenParams += "," + intLeft + "," + intTop; + let pdfOpenParams = `#page=${pageNumber}`; + + if (!this.isInPresentationMode) { + pdfOpenParams += `&zoom=${normalizedScaleValue},${intLeft},${intTop}`; + } + this._location = { pageNumber, scale: normalizedScaleValue, @@ -10139,10 +11104,6 @@ class BaseViewer { }; } - _updateHelper(visiblePages) { - throw new Error("Not implemented: _updateHelper"); - } - update() { const visible = this._getVisiblePages(); @@ -10154,12 +11115,24 @@ class BaseViewer { } const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1); - - this._buffer.resize(newCacheSize, visiblePages); - + this.#buffer.resize(newCacheSize, visible.ids); this.renderingQueue.renderHighestPriority(visible); + const isSimpleLayout = this._spreadMode === _ui_utils.SpreadMode.NONE && (this._scrollMode === _ui_utils.ScrollMode.PAGE || this._scrollMode === _ui_utils.ScrollMode.VERTICAL); + const currentId = this._currentPageNumber; + let stillFullyVisible = false; - this._updateHelper(visiblePages); + for (const page of visiblePages) { + if (page.percent < 100) { + break; + } + + if (page.id === currentId && isSimpleLayout) { + stillFullyVisible = true; + break; + } + } + + this._setCurrentPageNumber(stillFullyVisible ? currentId : visiblePages[0].id); this._updateLocation(visible.first); @@ -10177,8 +11150,8 @@ class BaseViewer { this.container.focus(); } - get _isScrollModeHorizontal() { - return this.isInPresentationMode ? false : this._scrollMode === _ui_utils.ScrollMode.HORIZONTAL; + get _isContainerRtl() { + return getComputedStyle(this.container).direction === "rtl"; } get isInPresentationMode() { @@ -10197,30 +11170,17 @@ class BaseViewer { return this.isInPresentationMode ? false : this.container.scrollHeight > this.container.clientHeight; } - _getCurrentVisiblePage() { - if (!this.pagesCount) { - return { - views: [] - }; - } - - const pageView = this._pages[this._currentPageNumber - 1]; - const element = pageView.div; - const view = { - id: pageView.id, - x: element.offsetLeft + element.clientLeft, - y: element.offsetTop + element.clientTop, - view: pageView - }; - return { - first: view, - last: view, - views: [view] - }; - } - _getVisiblePages() { - return (0, _ui_utils.getVisibleElements)(this.container, this._pages, true, this._isScrollModeHorizontal); + const views = this._scrollMode === _ui_utils.ScrollMode.PAGE ? this.#scrollModePageState.pages : this._pages, + horizontal = this._scrollMode === _ui_utils.ScrollMode.HORIZONTAL, + rtl = horizontal && this._isContainerRtl; + return (0, _ui_utils.getVisibleElements)({ + scrollEl: this.container, + views, + sortByVisibility: true, + horizontal, + rtl + }); } isPageVisible(pageNumber) { @@ -10228,101 +11188,218 @@ class BaseViewer { return false; } - if (pageNumber < 1 || pageNumber > this.pagesCount) { - console.error(`${this._name}.isPageVisible: "${pageNumber}" is out of bounds.`); + if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { + console.error(`isPageVisible: "${pageNumber}" is not a valid page.`); return false; } - return this._getVisiblePages().views.some(function (view) { - return view.id === pageNumber; - }); + return this._getVisiblePages().ids.has(pageNumber); + } + + isPageCached(pageNumber) { + if (!this.pdfDocument) { + return false; + } + + if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { + console.error(`isPageCached: "${pageNumber}" is not a valid page.`); + return false; + } + + const pageView = this._pages[pageNumber - 1]; + return this.#buffer.has(pageView); } cleanup() { - for (let i = 0, ii = this._pages.length; i < ii; i++) { - if (this._pages[i] && this._pages[i].renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { - this._pages[i].reset(); + for (const pageView of this._pages) { + if (pageView.renderingState !== _ui_utils.RenderingStates.FINISHED) { + pageView.reset(); } } } _cancelRendering() { - for (let i = 0, ii = this._pages.length; i < ii; i++) { - if (this._pages[i]) { - this._pages[i].cancelRendering(); - } + for (const pageView of this._pages) { + pageView.cancelRendering(); } } - _ensurePdfPageLoaded(pageView) { + async #ensurePdfPageLoaded(pageView) { if (pageView.pdfPage) { - return Promise.resolve(pageView.pdfPage); + return pageView.pdfPage; } - if (this._pagesRequests.has(pageView)) { - return this._pagesRequests.get(pageView); - } + try { + const pdfPage = await this.pdfDocument.getPage(pageView.id); - const promise = this.pdfDocument.getPage(pageView.id).then(pdfPage => { if (!pageView.pdfPage) { pageView.setPdfPage(pdfPage); } - this._pagesRequests.delete(pageView); + if (!this.linkService._cachedPageNumber?.(pdfPage.ref)) { + this.linkService.cachePageRef(pageView.id, pdfPage.ref); + } return pdfPage; - }).catch(reason => { + } catch (reason) { console.error("Unable to get page for page view", reason); + return null; + } + } - this._pagesRequests.delete(pageView); - }); + #getScrollAhead(visible) { + if (visible.first?.id === 1) { + return true; + } else if (visible.last?.id === this.pagesCount) { + return false; + } - this._pagesRequests.set(pageView, promise); + switch (this._scrollMode) { + case _ui_utils.ScrollMode.PAGE: + return this.#scrollModePageState.scrollDown; - return promise; + case _ui_utils.ScrollMode.HORIZONTAL: + return this.scroll.right; + } + + return this.scroll.down; + } + + #toggleLoadingIconSpinner(visibleIds) { + for (const id of visibleIds) { + const pageView = this._pages[id - 1]; + pageView?.toggleLoadingIconSpinner(true); + } + + for (const pageView of this.#buffer) { + if (visibleIds.has(pageView.id)) { + continue; + } + + pageView.toggleLoadingIconSpinner(false); + } } forceRendering(currentlyVisiblePages) { const visiblePages = currentlyVisiblePages || this._getVisiblePages(); - const scrollAhead = this._isScrollModeHorizontal ? this.scroll.right : this.scroll.down; - const pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, scrollAhead); + const scrollAhead = this.#getScrollAhead(visiblePages); + const preRenderExtra = this._spreadMode !== _ui_utils.SpreadMode.NONE && this._scrollMode !== _ui_utils.ScrollMode.HORIZONTAL; + const pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, scrollAhead, preRenderExtra); + this.#toggleLoadingIconSpinner(visiblePages.ids); if (pageView) { - this._ensurePdfPageLoaded(pageView).then(() => { + this.#ensurePdfPageLoaded(pageView).then(() => { this.renderingQueue.renderView(pageView); }); - return true; } return false; } - createTextLayerBuilder(textLayerDiv, pageIndex, viewport, enhanceTextSelection = false, eventBus) { + createTextLayerBuilder({ + textLayerDiv, + pageIndex, + viewport, + enhanceTextSelection = false, + eventBus, + highlighter, + accessibilityManager = null + }) { return new _text_layer_builder.TextLayerBuilder({ textLayerDiv, eventBus, pageIndex, viewport, - findController: this.isInPresentationMode ? null : this.findController, - enhanceTextSelection: this.isInPresentationMode ? false : enhanceTextSelection + enhanceTextSelection: this.isInPresentationMode ? false : enhanceTextSelection, + highlighter, + accessibilityManager }); } - createAnnotationLayerBuilder(pageDiv, pdfPage, annotationStorage = null, imageResourcesPath = "", renderInteractiveForms = false, l10n = _ui_utils.NullL10n) { + createTextHighlighter({ + pageIndex, + eventBus + }) { + return new _text_highlighter.TextHighlighter({ + eventBus, + pageIndex, + findController: this.isInPresentationMode ? null : this.findController + }); + } + + createAnnotationLayerBuilder({ + pageDiv, + pdfPage, + annotationStorage = this.pdfDocument?.annotationStorage, + imageResourcesPath = "", + renderForms = true, + l10n = _l10n_utils.NullL10n, + enableScripting = this.enableScripting, + hasJSActionsPromise = this.pdfDocument?.hasJSActions(), + mouseState = this._scriptingManager?.mouseState, + fieldObjectsPromise = this.pdfDocument?.getFieldObjects(), + annotationCanvasMap = null, + accessibilityManager = null + }) { return new _annotation_layer_builder.AnnotationLayerBuilder({ pageDiv, pdfPage, annotationStorage, imageResourcesPath, - renderInteractiveForms, + renderForms, linkService: this.linkService, downloadManager: this.downloadManager, + l10n, + enableScripting, + hasJSActionsPromise, + mouseState, + fieldObjectsPromise, + annotationCanvasMap, + accessibilityManager + }); + } + + createAnnotationEditorLayerBuilder({ + uiManager = this.#annotationEditorUIManager, + pageDiv, + pdfPage, + accessibilityManager = null, + l10n, + annotationStorage = this.pdfDocument?.annotationStorage + }) { + return new _annotation_editor_layer_builder.AnnotationEditorLayerBuilder({ + uiManager, + pageDiv, + pdfPage, + annotationStorage, + accessibilityManager, l10n }); } + createXfaLayerBuilder({ + pageDiv, + pdfPage, + annotationStorage = this.pdfDocument?.annotationStorage + }) { + return new _xfa_layer_builder.XfaLayerBuilder({ + pageDiv, + pdfPage, + annotationStorage, + linkService: this.linkService + }); + } + + createStructTreeLayerBuilder({ + pdfPage + }) { + return new _struct_tree_layer_builder.StructTreeLayerBuilder({ + pdfPage + }); + } + get hasEqualPageSizes() { const firstPageView = this._pages[0]; @@ -10338,30 +11415,23 @@ class BaseViewer { } getPagesOverview() { - const pagesOverview = this._pages.map(function (pageView) { + return this._pages.map(pageView => { const viewport = pageView.pdfPage.getViewport({ scale: 1 }); - return { - width: viewport.width, - height: viewport.height, - rotation: viewport.rotation - }; - }); - if (!this.enablePrintAutoRotate) { - return pagesOverview; - } - - return pagesOverview.map(function (size) { - if ((0, _ui_utils.isPortraitOrientation)(size)) { - return size; + if (!this.enablePrintAutoRotate || (0, _ui_utils.isPortraitOrientation)(viewport)) { + return { + width: viewport.width, + height: viewport.height, + rotation: viewport.rotation + }; } return { - width: size.height, - height: size.width, - rotation: (size.rotation + 90) % 360 + width: viewport.height, + height: viewport.width, + rotation: (viewport.rotation - 90) % 360 }; }); } @@ -10372,6 +11442,7 @@ class BaseViewer { } if (!this._optionalContentConfigPromise) { + console.error("optionalContentConfigPromise: Not initialized yet."); return this.pdfDocument.getOptionalContentConfig(); } @@ -10392,9 +11463,12 @@ class BaseViewer { } this._optionalContentConfigPromise = promise; + const updateArgs = { + optionalContentConfigPromise: promise + }; for (const pageView of this._pages) { - pageView.update(pageView.scale, pageView.rotation, promise); + pageView.update(updateArgs); } this.update(); @@ -10417,6 +11491,11 @@ class BaseViewer { throw new Error(`Invalid scroll mode: ${mode}`); } + if (this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { + return; + } + + this._previousScrollMode = this._scrollMode; this._scrollMode = mode; this.eventBus.dispatch("scrollmodechanged", { source: this, @@ -10436,6 +11515,12 @@ class BaseViewer { return; } + if (scrollMode === _ui_utils.ScrollMode.PAGE) { + this.#ensurePageViewVisible(); + } else if (this._previousScrollMode === _ui_utils.ScrollMode.PAGE) { + this._updateSpreadMode(); + } + if (this._currentScaleValue && isNaN(this._currentScaleValue)) { this._setScale(this._currentScaleValue, true); } @@ -10474,27 +11559,32 @@ class BaseViewer { const viewer = this.viewer, pages = this._pages; - viewer.textContent = ""; - if (this._spreadMode === _ui_utils.SpreadMode.NONE) { - for (let i = 0, iMax = pages.length; i < iMax; ++i) { - viewer.appendChild(pages[i].div); - } + if (this._scrollMode === _ui_utils.ScrollMode.PAGE) { + this.#ensurePageViewVisible(); } else { - const parity = this._spreadMode - 1; - let spread = null; + viewer.textContent = ""; - for (let i = 0, iMax = pages.length; i < iMax; ++i) { - if (spread === null) { - spread = document.createElement("div"); - spread.className = "spread"; - viewer.appendChild(spread); - } else if (i % 2 === parity) { - spread = spread.cloneNode(false); - viewer.appendChild(spread); + if (this._spreadMode === _ui_utils.SpreadMode.NONE) { + for (const pageView of this._pages) { + viewer.append(pageView.div); } + } else { + const parity = this._spreadMode - 1; + let spread = null; - spread.appendChild(pages[i].div); + for (let i = 0, ii = pages.length; i < ii; ++i) { + if (spread === null) { + spread = document.createElement("div"); + spread.className = "spread"; + viewer.append(spread); + } else if (i % 2 === parity) { + spread = spread.cloneNode(false); + viewer.append(spread); + } + + spread.append(pages[i].div); + } } } @@ -10502,32 +11592,515 @@ class BaseViewer { return; } + if (this._currentScaleValue && isNaN(this._currentScaleValue)) { + this._setScale(this._currentScaleValue, true); + } + this._setCurrentPageNumber(pageNumber, true); this.update(); } + _getPageAdvance(currentPageNumber, previous = false) { + switch (this._scrollMode) { + case _ui_utils.ScrollMode.WRAPPED: + { + const { + views + } = this._getVisiblePages(), + pageLayout = new Map(); + + for (const { + id, + y, + percent, + widthPercent + } of views) { + if (percent === 0 || widthPercent < 100) { + continue; + } + + let yArray = pageLayout.get(y); + + if (!yArray) { + pageLayout.set(y, yArray ||= []); + } + + yArray.push(id); + } + + for (const yArray of pageLayout.values()) { + const currentIndex = yArray.indexOf(currentPageNumber); + + if (currentIndex === -1) { + continue; + } + + const numPages = yArray.length; + + if (numPages === 1) { + break; + } + + if (previous) { + for (let i = currentIndex - 1, ii = 0; i >= ii; i--) { + const currentId = yArray[i], + expectedId = yArray[i + 1] - 1; + + if (currentId < expectedId) { + return currentPageNumber - expectedId; + } + } + } else { + for (let i = currentIndex + 1, ii = numPages; i < ii; i++) { + const currentId = yArray[i], + expectedId = yArray[i - 1] + 1; + + if (currentId > expectedId) { + return expectedId - currentPageNumber; + } + } + } + + if (previous) { + const firstId = yArray[0]; + + if (firstId < currentPageNumber) { + return currentPageNumber - firstId + 1; + } + } else { + const lastId = yArray[numPages - 1]; + + if (lastId > currentPageNumber) { + return lastId - currentPageNumber + 1; + } + } + + break; + } + + break; + } + + case _ui_utils.ScrollMode.HORIZONTAL: + { + break; + } + + case _ui_utils.ScrollMode.PAGE: + case _ui_utils.ScrollMode.VERTICAL: + { + if (this._spreadMode === _ui_utils.SpreadMode.NONE) { + break; + } + + const parity = this._spreadMode - 1; + + if (previous && currentPageNumber % 2 !== parity) { + break; + } else if (!previous && currentPageNumber % 2 === parity) { + break; + } + + const { + views + } = this._getVisiblePages(), + expectedId = previous ? currentPageNumber - 1 : currentPageNumber + 1; + + for (const { + id, + percent, + widthPercent + } of views) { + if (id !== expectedId) { + continue; + } + + if (percent > 0 && widthPercent === 100) { + return 2; + } + + break; + } + + break; + } + } + + return 1; + } + + nextPage() { + const currentPageNumber = this._currentPageNumber, + pagesCount = this.pagesCount; + + if (currentPageNumber >= pagesCount) { + return false; + } + + const advance = this._getPageAdvance(currentPageNumber, false) || 1; + this.currentPageNumber = Math.min(currentPageNumber + advance, pagesCount); + return true; + } + + previousPage() { + const currentPageNumber = this._currentPageNumber; + + if (currentPageNumber <= 1) { + return false; + } + + const advance = this._getPageAdvance(currentPageNumber, true) || 1; + this.currentPageNumber = Math.max(currentPageNumber - advance, 1); + return true; + } + + increaseScale(steps = 1) { + let newScale = this._currentScale; + + do { + newScale = (newScale * _ui_utils.DEFAULT_SCALE_DELTA).toFixed(2); + newScale = Math.ceil(newScale * 10) / 10; + newScale = Math.min(_ui_utils.MAX_SCALE, newScale); + } while (--steps > 0 && newScale < _ui_utils.MAX_SCALE); + + this.currentScaleValue = newScale; + } + + decreaseScale(steps = 1) { + let newScale = this._currentScale; + + do { + newScale = (newScale / _ui_utils.DEFAULT_SCALE_DELTA).toFixed(2); + newScale = Math.floor(newScale * 10) / 10; + newScale = Math.max(_ui_utils.MIN_SCALE, newScale); + } while (--steps > 0 && newScale > _ui_utils.MIN_SCALE); + + this.currentScaleValue = newScale; + } + + updateContainerHeightCss() { + const height = this.container.clientHeight; + + if (height !== this.#previousContainerHeight) { + this.#previousContainerHeight = height; + + _ui_utils.docStyle.setProperty("--viewer-container-height", `${height}px`); + } + } + + get annotationEditorMode() { + return this.#annotationEditorUIManager ? this.#annotationEditorMode : _pdfjsLib.AnnotationEditorType.DISABLE; + } + + set annotationEditorMode(mode) { + if (!this.#annotationEditorUIManager) { + throw new Error(`The AnnotationEditor is not enabled.`); + } + + if (this.#annotationEditorMode === mode) { + return; + } + + if (!isValidAnnotationEditorMode(mode)) { + throw new Error(`Invalid AnnotationEditor mode: ${mode}`); + } + + if (!this.pdfDocument) { + return; + } + + this.#annotationEditorMode = mode; + this.eventBus.dispatch("annotationeditormodechanged", { + source: this, + mode + }); + this.#annotationEditorUIManager.updateMode(mode); + } + + set annotationEditorParams({ + type, + value + }) { + if (!this.#annotationEditorUIManager) { + throw new Error(`The AnnotationEditor is not enabled.`); + } + + this.#annotationEditorUIManager.updateParams(type, value); + } + + refresh() { + if (!this.pdfDocument) { + return; + } + + const updateArgs = {}; + + for (const pageView of this._pages) { + pageView.update(updateArgs); + } + + this.update(); + } + } exports.BaseViewer = BaseViewer; /***/ }), -/* 28 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 30 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.DefaultAnnotationLayerFactory = exports.AnnotationLayerBuilder = void 0; +})); +exports.AnnotationEditorLayerBuilder = void 0; var _pdfjsLib = __webpack_require__(5); -var _ui_utils = __webpack_require__(2); +var _l10n_utils = __webpack_require__(31); -var _pdf_link_service = __webpack_require__(20); +class AnnotationEditorLayerBuilder { + #uiManager; + + constructor(options) { + this.pageDiv = options.pageDiv; + this.pdfPage = options.pdfPage; + this.annotationStorage = options.annotationStorage || null; + this.accessibilityManager = options.accessibilityManager; + this.l10n = options.l10n || _l10n_utils.NullL10n; + this.annotationEditorLayer = null; + this.div = null; + this._cancelled = false; + this.#uiManager = options.uiManager; + } + + async render(viewport, intent = "display") { + if (intent !== "display") { + return; + } + + if (this._cancelled) { + return; + } + + const clonedViewport = viewport.clone({ + dontFlip: true + }); + + if (this.div) { + this.annotationEditorLayer.update({ + viewport: clonedViewport + }); + this.show(); + return; + } + + this.div = document.createElement("div"); + this.div.className = "annotationEditorLayer"; + this.div.tabIndex = 0; + this.pageDiv.append(this.div); + this.annotationEditorLayer = new _pdfjsLib.AnnotationEditorLayer({ + uiManager: this.#uiManager, + div: this.div, + annotationStorage: this.annotationStorage, + accessibilityManager: this.accessibilityManager, + pageIndex: this.pdfPage._pageIndex, + l10n: this.l10n, + viewport: clonedViewport + }); + const parameters = { + viewport: clonedViewport, + div: this.div, + annotations: null, + intent + }; + this.annotationEditorLayer.render(parameters); + } + + cancel() { + this._cancelled = true; + this.destroy(); + } + + hide() { + if (!this.div) { + return; + } + + this.div.hidden = true; + } + + show() { + if (!this.div) { + return; + } + + this.div.hidden = false; + } + + destroy() { + if (!this.div) { + return; + } + + this.pageDiv = null; + this.annotationEditorLayer.destroy(); + this.div.remove(); + } + +} + +exports.AnnotationEditorLayerBuilder = AnnotationEditorLayerBuilder; + +/***/ }), +/* 31 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.NullL10n = void 0; +exports.fixupLangCode = fixupLangCode; +exports.getL10nFallback = getL10nFallback; +const DEFAULT_L10N_STRINGS = { + of_pages: "of {{pagesCount}}", + page_of_pages: "({{pageNumber}} of {{pagesCount}})", + document_properties_kb: "{{size_kb}} KB ({{size_b}} bytes)", + document_properties_mb: "{{size_mb}} MB ({{size_b}} bytes)", + document_properties_date_string: "{{date}}, {{time}}", + document_properties_page_size_unit_inches: "in", + document_properties_page_size_unit_millimeters: "mm", + document_properties_page_size_orientation_portrait: "portrait", + document_properties_page_size_orientation_landscape: "landscape", + document_properties_page_size_name_a3: "A3", + document_properties_page_size_name_a4: "A4", + document_properties_page_size_name_letter: "Letter", + document_properties_page_size_name_legal: "Legal", + document_properties_page_size_dimension_string: "{{width}} × {{height}} {{unit}} ({{orientation}})", + document_properties_page_size_dimension_name_string: "{{width}} × {{height}} {{unit}} ({{name}}, {{orientation}})", + document_properties_linearized_yes: "Yes", + document_properties_linearized_no: "No", + print_progress_percent: "{{progress}}%", + "toggle_sidebar.title": "Toggle Sidebar", + "toggle_sidebar_notification2.title": "Toggle Sidebar (document contains outline/attachments/layers)", + additional_layers: "Additional Layers", + page_landmark: "Page {{page}}", + thumb_page_title: "Page {{page}}", + thumb_page_canvas: "Thumbnail of Page {{page}}", + find_reached_top: "Reached top of document, continued from bottom", + find_reached_bottom: "Reached end of document, continued from top", + "find_match_count[one]": "{{current}} of {{total}} match", + "find_match_count[other]": "{{current}} of {{total}} matches", + "find_match_count_limit[one]": "More than {{limit}} match", + "find_match_count_limit[other]": "More than {{limit}} matches", + find_not_found: "Phrase not found", + error_version_info: "PDF.js v{{version}} (build: {{build}})", + error_message: "Message: {{message}}", + error_stack: "Stack: {{stack}}", + error_file: "File: {{file}}", + error_line: "Line: {{line}}", + rendering_error: "An error occurred while rendering the page.", + page_scale_width: "Page Width", + page_scale_fit: "Page Fit", + page_scale_auto: "Automatic Zoom", + page_scale_actual: "Actual Size", + page_scale_percent: "{{scale}}%", + loading: "Loading…", + loading_error: "An error occurred while loading the PDF.", + invalid_file_error: "Invalid or corrupted PDF file.", + missing_file_error: "Missing PDF file.", + unexpected_response_error: "Unexpected server response.", + printing_not_supported: "Warning: Printing is not fully supported by this browser.", + printing_not_ready: "Warning: The PDF is not fully loaded for printing.", + web_fonts_disabled: "Web fonts are disabled: unable to use embedded PDF fonts.", + free_text_default_content: "Enter text…", + editor_free_text_aria_label: "FreeText Editor", + editor_ink_aria_label: "Ink Editor", + editor_ink_canvas_aria_label: "User-created image" +}; + +function getL10nFallback(key, args) { + switch (key) { + case "find_match_count": + key = `find_match_count[${args.total === 1 ? "one" : "other"}]`; + break; + + case "find_match_count_limit": + key = `find_match_count_limit[${args.limit === 1 ? "one" : "other"}]`; + break; + } + + return DEFAULT_L10N_STRINGS[key] || ""; +} + +const PARTIAL_LANG_CODES = { + en: "en-US", + es: "es-ES", + fy: "fy-NL", + ga: "ga-IE", + gu: "gu-IN", + hi: "hi-IN", + hy: "hy-AM", + nb: "nb-NO", + ne: "ne-NP", + nn: "nn-NO", + pa: "pa-IN", + pt: "pt-PT", + sv: "sv-SE", + zh: "zh-CN" +}; + +function fixupLangCode(langCode) { + return PARTIAL_LANG_CODES[langCode?.toLowerCase()] || langCode; +} + +function formatL10nValue(text, args) { + if (!args) { + return text; + } + + return text.replace(/\{\{\s*(\w+)\s*\}\}/g, (all, name) => { + return name in args ? args[name] : "{{" + name + "}}"; + }); +} + +const NullL10n = { + async getLanguage() { + return "en-us"; + }, + + async getDirection() { + return "ltr"; + }, + + async get(key, args = null, fallback = getL10nFallback(key, args)) { + return formatL10nValue(fallback, args); + }, + + async translate(element) {} + +}; +exports.NullL10n = NullL10n; + +/***/ }), +/* 32 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.AnnotationLayerBuilder = void 0; + +var _pdfjsLib = __webpack_require__(5); + +var _l10n_utils = __webpack_require__(31); class AnnotationLayerBuilder { constructor({ @@ -10537,60 +12110,74 @@ class AnnotationLayerBuilder { downloadManager, annotationStorage = null, imageResourcesPath = "", - renderInteractiveForms = true, - l10n = _ui_utils.NullL10n + renderForms = true, + l10n = _l10n_utils.NullL10n, + enableScripting = false, + hasJSActionsPromise = null, + fieldObjectsPromise = null, + mouseState = null, + annotationCanvasMap = null, + accessibilityManager = null }) { this.pageDiv = pageDiv; this.pdfPage = pdfPage; this.linkService = linkService; this.downloadManager = downloadManager; this.imageResourcesPath = imageResourcesPath; - this.renderInteractiveForms = renderInteractiveForms; + this.renderForms = renderForms; this.l10n = l10n; this.annotationStorage = annotationStorage; + this.enableScripting = enableScripting; + this._hasJSActionsPromise = hasJSActionsPromise; + this._fieldObjectsPromise = fieldObjectsPromise; + this._mouseState = mouseState; + this._annotationCanvasMap = annotationCanvasMap; + this._accessibilityManager = accessibilityManager; this.div = null; this._cancelled = false; } - render(viewport, intent = "display") { - return this.pdfPage.getAnnotations({ + async render(viewport, intent = "display") { + const [annotations, hasJSActions = false, fieldObjects = null] = await Promise.all([this.pdfPage.getAnnotations({ intent - }).then(annotations => { - if (this._cancelled) { - return; - } + }), this._hasJSActionsPromise, this._fieldObjectsPromise]); - if (annotations.length === 0) { - return; - } + if (this._cancelled || annotations.length === 0) { + return; + } - const parameters = { - viewport: viewport.clone({ - dontFlip: true - }), - div: this.div, - annotations, - page: this.pdfPage, - imageResourcesPath: this.imageResourcesPath, - renderInteractiveForms: this.renderInteractiveForms, - linkService: this.linkService, - downloadManager: this.downloadManager, - annotationStorage: this.annotationStorage - }; + const parameters = { + viewport: viewport.clone({ + dontFlip: true + }), + div: this.div, + annotations, + page: this.pdfPage, + imageResourcesPath: this.imageResourcesPath, + renderForms: this.renderForms, + linkService: this.linkService, + downloadManager: this.downloadManager, + annotationStorage: this.annotationStorage, + enableScripting: this.enableScripting, + hasJSActions, + fieldObjects, + mouseState: this._mouseState, + annotationCanvasMap: this._annotationCanvasMap, + accessibilityManager: this._accessibilityManager + }; - if (this.div) { - _pdfjsLib.AnnotationLayer.update(parameters); - } else { - this.div = document.createElement("div"); - this.div.className = "annotationLayer"; - this.pageDiv.appendChild(this.div); - parameters.div = this.div; + if (this.div) { + _pdfjsLib.AnnotationLayer.update(parameters); + } else { + this.div = document.createElement("div"); + this.div.className = "annotationLayer"; + this.pageDiv.append(this.div); + parameters.div = this.div; - _pdfjsLib.AnnotationLayer.render(parameters); + _pdfjsLib.AnnotationLayer.render(parameters); - this.l10n.translate(this.div); - } - }); + this.l10n.translate(this.div); + } } cancel() { @@ -10602,53 +12189,43 @@ class AnnotationLayerBuilder { return; } - this.div.setAttribute("hidden", "true"); + this.div.hidden = true; } } exports.AnnotationLayerBuilder = AnnotationLayerBuilder; -class DefaultAnnotationLayerFactory { - createAnnotationLayerBuilder(pageDiv, pdfPage, annotationStorage = null, imageResourcesPath = "", renderInteractiveForms = true, l10n = _ui_utils.NullL10n) { - return new AnnotationLayerBuilder({ - pageDiv, - pdfPage, - imageResourcesPath, - renderInteractiveForms, - linkService: new _pdf_link_service.SimpleLinkService(), - l10n, - annotationStorage - }); - } - -} - -exports.DefaultAnnotationLayerFactory = DefaultAnnotationLayerFactory; - /***/ }), -/* 29 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 33 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.PDFPageView = void 0; -var _ui_utils = __webpack_require__(2); - var _pdfjsLib = __webpack_require__(5); -var _pdf_rendering_queue = __webpack_require__(8); +var _ui_utils = __webpack_require__(1); -var _viewer_compatibility = __webpack_require__(4); +var _app_options = __webpack_require__(2); -const MAX_CANVAS_PIXELS = _viewer_compatibility.viewerCompatibilityParams.maxCanvasPixels || 16777216; +var _l10n_utils = __webpack_require__(31); + +var _text_accessibility = __webpack_require__(34); + +const MAX_CANVAS_PIXELS = _app_options.compatibilityParams.maxCanvasPixels || 16777216; class PDFPageView { + #annotationMode = _pdfjsLib.AnnotationMode.ENABLE_FORMS; + #useThumbnailCanvas = { + initialOptionalContent: true, + regularAnnotations: true + }; + constructor(options) { const container = options.container; const defaultViewport = options.defaultViewport; @@ -10660,36 +12237,69 @@ class PDFPageView { this.scale = options.scale || _ui_utils.DEFAULT_SCALE; this.viewport = defaultViewport; this.pdfPageRotate = defaultViewport.rotation; - this._annotationStorage = options.annotationStorage || null; this._optionalContentConfigPromise = options.optionalContentConfigPromise || null; this.hasRestrictedScaling = false; - this.textLayerMode = Number.isInteger(options.textLayerMode) ? options.textLayerMode : _ui_utils.TextLayerMode.ENABLE; + this.textLayerMode = options.textLayerMode ?? _ui_utils.TextLayerMode.ENABLE; + this.#annotationMode = options.annotationMode ?? _pdfjsLib.AnnotationMode.ENABLE_FORMS; this.imageResourcesPath = options.imageResourcesPath || ""; - this.renderInteractiveForms = typeof options.renderInteractiveForms === "boolean" ? options.renderInteractiveForms : true; this.useOnlyCssZoom = options.useOnlyCssZoom || false; this.maxCanvasPixels = options.maxCanvasPixels || MAX_CANVAS_PIXELS; + this.pageColors = options.pageColors || null; this.eventBus = options.eventBus; this.renderingQueue = options.renderingQueue; this.textLayerFactory = options.textLayerFactory; this.annotationLayerFactory = options.annotationLayerFactory; + this.annotationEditorLayerFactory = options.annotationEditorLayerFactory; + this.xfaLayerFactory = options.xfaLayerFactory; + this.textHighlighter = options.textHighlighterFactory?.createTextHighlighter({ + pageIndex: this.id - 1, + eventBus: this.eventBus + }); + this.structTreeLayerFactory = options.structTreeLayerFactory; this.renderer = options.renderer || _ui_utils.RendererType.CANVAS; - this.enableWebGL = options.enableWebGL || false; - this.l10n = options.l10n || _ui_utils.NullL10n; + this.l10n = options.l10n || _l10n_utils.NullL10n; this.paintTask = null; this.paintedViewportMap = new WeakMap(); - this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; + this.renderingState = _ui_utils.RenderingStates.INITIAL; this.resume = null; - this.error = null; + this._renderError = null; + this._isStandalone = !this.renderingQueue?.hasViewer(); + this._annotationCanvasMap = null; this.annotationLayer = null; + this.annotationEditorLayer = null; this.textLayer = null; this.zoomLayer = null; + this.xfaLayer = null; + this.structTreeLayer = null; const div = document.createElement("div"); div.className = "page"; div.style.width = Math.floor(this.viewport.width) + "px"; div.style.height = Math.floor(this.viewport.height) + "px"; div.setAttribute("data-page-number", this.id); + div.setAttribute("role", "region"); + this.l10n.get("page_landmark", { + page: this.id + }).then(msg => { + div.setAttribute("aria-label", msg); + }); this.div = div; - container.appendChild(div); + container?.append(div); + + if (this._isStandalone) { + const { + optionalContentConfigPromise + } = options; + + if (optionalContentConfigPromise) { + optionalContentConfigPromise.then(optionalContentConfig => { + if (optionalContentConfigPromise !== this._optionalContentConfigPromise) { + return; + } + + this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility; + }); + } + } } setPdfPage(pdfPage) { @@ -10697,10 +12307,9 @@ class PDFPageView { this.pdfPageRotate = pdfPage.rotate; const totalRotation = (this.rotation + this.pdfPageRotate) % 360; this.viewport = pdfPage.getViewport({ - scale: this.scale * _ui_utils.CSS_UNITS, + scale: this.scale * _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS, rotation: totalRotation }); - this.stats = pdfPage.stats; this.reset(); } @@ -10718,6 +12327,7 @@ class PDFPageView { try { await this.annotationLayer.render(this.viewport, "display"); } catch (ex) { + console.error(`_renderAnnotationLayer: "${ex}".`); error = ex; } finally { this.eventBus.dispatch("annotationlayerrendered", { @@ -10728,6 +12338,56 @@ class PDFPageView { } } + async _renderAnnotationEditorLayer() { + let error = null; + + try { + await this.annotationEditorLayer.render(this.viewport, "display"); + } catch (ex) { + console.error(`_renderAnnotationEditorLayer: "${ex}".`); + error = ex; + } finally { + this.eventBus.dispatch("annotationeditorlayerrendered", { + source: this, + pageNumber: this.id, + error + }); + } + } + + async _renderXfaLayer() { + let error = null; + + try { + const result = await this.xfaLayer.render(this.viewport, "display"); + + if (this.textHighlighter) { + this._buildXfaTextContentItems(result.textDivs); + } + } catch (ex) { + console.error(`_renderXfaLayer: "${ex}".`); + error = ex; + } finally { + this.eventBus.dispatch("xfalayerrendered", { + source: this, + pageNumber: this.id, + error + }); + } + } + + async _buildXfaTextContentItems(textDivs) { + const text = await this.pdfPage.getTextContent(); + const items = []; + + for (const item of text.items) { + items.push(item.str); + } + + this.textHighlighter.setTextMapping(textDivs, items); + this.textHighlighter.enable(); + } + _resetZoomLayer(removeFromDOM = false) { if (!this.zoomLayer) { return; @@ -10745,36 +12405,58 @@ class PDFPageView { this.zoomLayer = null; } - reset(keepZoomLayer = false, keepAnnotations = false) { - this.cancelRendering(keepAnnotations); - this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; + reset({ + keepZoomLayer = false, + keepAnnotationLayer = false, + keepAnnotationEditorLayer = false, + keepXfaLayer = false + } = {}) { + this.cancelRendering({ + keepAnnotationLayer, + keepAnnotationEditorLayer, + keepXfaLayer + }); + this.renderingState = _ui_utils.RenderingStates.INITIAL; const div = this.div; div.style.width = Math.floor(this.viewport.width) + "px"; div.style.height = Math.floor(this.viewport.height) + "px"; - const childNodes = div.childNodes; - const currentZoomLayerNode = keepZoomLayer && this.zoomLayer || null; - const currentAnnotationNode = keepAnnotations && this.annotationLayer && this.annotationLayer.div || null; + const childNodes = div.childNodes, + zoomLayerNode = keepZoomLayer && this.zoomLayer || null, + annotationLayerNode = keepAnnotationLayer && this.annotationLayer?.div || null, + annotationEditorLayerNode = keepAnnotationEditorLayer && this.annotationEditorLayer?.div || null, + xfaLayerNode = keepXfaLayer && this.xfaLayer?.div || null; for (let i = childNodes.length - 1; i >= 0; i--) { const node = childNodes[i]; - if (currentZoomLayerNode === node || currentAnnotationNode === node) { - continue; + switch (node) { + case zoomLayerNode: + case annotationLayerNode: + case annotationEditorLayerNode: + case xfaLayerNode: + continue; } - div.removeChild(node); + node.remove(); } div.removeAttribute("data-loaded"); - if (currentAnnotationNode) { + if (annotationLayerNode) { this.annotationLayer.hide(); - } else if (this.annotationLayer) { - this.annotationLayer.cancel(); - this.annotationLayer = null; } - if (!currentZoomLayerNode) { + if (annotationEditorLayerNode) { + this.annotationEditorLayer.hide(); + } else { + this.annotationEditorLayer?.destroy(); + } + + if (xfaLayerNode) { + this.xfaLayer.hide(); + } + + if (!zoomLayerNode) { if (this.canvas) { this.paintedViewportMap.delete(this.canvas); this.canvas.width = 0; @@ -10791,34 +12473,64 @@ class PDFPageView { } this.loadingIconDiv = document.createElement("div"); - this.loadingIconDiv.className = "loadingIcon"; - div.appendChild(this.loadingIconDiv); + this.loadingIconDiv.className = "loadingIcon notVisible"; + + if (this._isStandalone) { + this.toggleLoadingIconSpinner(true); + } + + this.loadingIconDiv.setAttribute("role", "img"); + this.l10n.get("loading").then(msg => { + this.loadingIconDiv?.setAttribute("aria-label", msg); + }); + div.append(this.loadingIconDiv); } - update(scale, rotation, optionalContentConfigPromise = null) { + update({ + scale = 0, + rotation = null, + optionalContentConfigPromise = null + }) { this.scale = scale || this.scale; - if (typeof rotation !== "undefined") { + if (typeof rotation === "number") { this.rotation = rotation; } if (optionalContentConfigPromise instanceof Promise) { this._optionalContentConfigPromise = optionalContentConfigPromise; + optionalContentConfigPromise.then(optionalContentConfig => { + if (optionalContentConfigPromise !== this._optionalContentConfigPromise) { + return; + } + + this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility; + }); } const totalRotation = (this.rotation + this.pdfPageRotate) % 360; this.viewport = this.viewport.clone({ - scale: this.scale * _ui_utils.CSS_UNITS, + scale: this.scale * _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS, rotation: totalRotation }); + if (this._isStandalone) { + _ui_utils.docStyle.setProperty("--scale-factor", this.viewport.scale); + } + if (this.svg) { - this.cssTransform(this.svg, true); + this.cssTransform({ + target: this.svg, + redrawAnnotationLayer: true, + redrawAnnotationEditorLayer: true, + redrawXfaLayer: true + }); this.eventBus.dispatch("pagerendered", { source: this, pageNumber: this.id, cssTransform: true, - timestamp: performance.now() + timestamp: performance.now(), + error: this._renderError }); return; } @@ -10835,30 +12547,47 @@ class PDFPageView { if (this.canvas) { if (this.useOnlyCssZoom || this.hasRestrictedScaling && isScalingRestricted) { - this.cssTransform(this.canvas, true); + this.cssTransform({ + target: this.canvas, + redrawAnnotationLayer: true, + redrawAnnotationEditorLayer: true, + redrawXfaLayer: true + }); this.eventBus.dispatch("pagerendered", { source: this, pageNumber: this.id, cssTransform: true, - timestamp: performance.now() + timestamp: performance.now(), + error: this._renderError }); return; } - if (!this.zoomLayer && !this.canvas.hasAttribute("hidden")) { + if (!this.zoomLayer && !this.canvas.hidden) { this.zoomLayer = this.canvas.parentNode; this.zoomLayer.style.position = "absolute"; } } if (this.zoomLayer) { - this.cssTransform(this.zoomLayer.firstChild); + this.cssTransform({ + target: this.zoomLayer.firstChild + }); } - this.reset(true, true); + this.reset({ + keepZoomLayer: true, + keepAnnotationLayer: true, + keepAnnotationEditorLayer: true, + keepXfaLayer: true + }); } - cancelRendering(keepAnnotations = false) { + cancelRendering({ + keepAnnotationLayer = false, + keepAnnotationEditorLayer = false, + keepXfaLayer = false + } = {}) { if (this.paintTask) { this.paintTask.cancel(); this.paintTask = null; @@ -10871,13 +12600,36 @@ class PDFPageView { this.textLayer = null; } - if (!keepAnnotations && this.annotationLayer) { + if (this.annotationLayer && (!keepAnnotationLayer || !this.annotationLayer.div)) { this.annotationLayer.cancel(); this.annotationLayer = null; + this._annotationCanvasMap = null; + } + + if (this.annotationEditorLayer && (!keepAnnotationEditorLayer || !this.annotationEditorLayer.div)) { + this.annotationEditorLayer.cancel(); + this.annotationEditorLayer = null; + } + + if (this.xfaLayer && (!keepXfaLayer || !this.xfaLayer.div)) { + this.xfaLayer.cancel(); + this.xfaLayer = null; + this.textHighlighter?.disable(); + } + + if (this._onTextLayerRendered) { + this.eventBus._off("textlayerrendered", this._onTextLayerRendered); + + this._onTextLayerRendered = null; } } - cssTransform(target, redrawAnnotations = false) { + cssTransform({ + target, + redrawAnnotationLayer = false, + redrawAnnotationEditorLayer = false, + redrawXfaLayer = false + }) { const width = this.viewport.width; const height = this.viewport.height; const div = this.div; @@ -10893,8 +12645,7 @@ class PDFPageView { scaleY = width / height; } - const cssTransform = "rotate(" + relativeRotation + "deg) " + "scale(" + scaleX + "," + scaleY + ")"; - target.style.transform = cssTransform; + target.style.transform = `rotate(${relativeRotation}deg) scale(${scaleX}, ${scaleY})`; if (this.textLayer) { const textLayerViewport = this.textLayer.viewport; @@ -10934,13 +12685,21 @@ class PDFPageView { break; } - textLayerDiv.style.transform = "rotate(" + textAbsRotation + "deg) " + "scale(" + scale + ", " + scale + ") " + "translate(" + transX + ", " + transY + ")"; + textLayerDiv.style.transform = `rotate(${textAbsRotation}deg) ` + `scale(${scale}) ` + `translate(${transX}, ${transY})`; textLayerDiv.style.transformOrigin = "0% 0%"; } - if (redrawAnnotations && this.annotationLayer) { + if (redrawAnnotationLayer && this.annotationLayer) { this._renderAnnotationLayer(); } + + if (redrawAnnotationEditorLayer && this.annotationEditorLayer) { + this._renderAnnotationEditorLayer(); + } + + if (redrawXfaLayer && this.xfaLayer) { + this._renderXfaLayer(); + } } get width() { @@ -10955,8 +12714,12 @@ class PDFPageView { return this.viewport.convertToPdfPoint(x, y); } + toggleLoadingIconSpinner(viewVisible = false) { + this.loadingIconDiv?.classList.toggle("notVisible", !viewVisible); + } + draw() { - if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { + if (this.renderingState !== _ui_utils.RenderingStates.INITIAL) { console.error("Must be in new state before drawing"); this.reset(); } @@ -10967,55 +12730,83 @@ class PDFPageView { } = this; if (!pdfPage) { - this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + this.renderingState = _ui_utils.RenderingStates.FINISHED; if (this.loadingIconDiv) { - div.removeChild(this.loadingIconDiv); + this.loadingIconDiv.remove(); delete this.loadingIconDiv; } return Promise.reject(new Error("pdfPage is not loaded")); } - this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; + this.renderingState = _ui_utils.RenderingStates.RUNNING; const canvasWrapper = document.createElement("div"); canvasWrapper.style.width = div.style.width; canvasWrapper.style.height = div.style.height; canvasWrapper.classList.add("canvasWrapper"); + const lastDivBeforeTextDiv = this.annotationLayer?.div || this.annotationEditorLayer?.div; - if (this.annotationLayer && this.annotationLayer.div) { - div.insertBefore(canvasWrapper, this.annotationLayer.div); + if (lastDivBeforeTextDiv) { + lastDivBeforeTextDiv.before(canvasWrapper); } else { - div.appendChild(canvasWrapper); + div.append(canvasWrapper); } let textLayer = null; if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) { + this._accessibilityManager ||= new _text_accessibility.TextAccessibilityManager(); const textLayerDiv = document.createElement("div"); textLayerDiv.className = "textLayer"; textLayerDiv.style.width = canvasWrapper.style.width; textLayerDiv.style.height = canvasWrapper.style.height; - if (this.annotationLayer && this.annotationLayer.div) { - div.insertBefore(textLayerDiv, this.annotationLayer.div); + if (lastDivBeforeTextDiv) { + lastDivBeforeTextDiv.before(textLayerDiv); } else { - div.appendChild(textLayerDiv); + div.append(textLayerDiv); } - textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE, this.eventBus); + textLayer = this.textLayerFactory.createTextLayerBuilder({ + textLayerDiv, + pageIndex: this.id - 1, + viewport: this.viewport, + enhanceTextSelection: this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE, + eventBus: this.eventBus, + highlighter: this.textHighlighter, + accessibilityManager: this._accessibilityManager + }); } this.textLayer = textLayer; + + if (this.#annotationMode !== _pdfjsLib.AnnotationMode.DISABLE && this.annotationLayerFactory) { + this._annotationCanvasMap ||= new Map(); + this.annotationLayer ||= this.annotationLayerFactory.createAnnotationLayerBuilder({ + pageDiv: div, + pdfPage, + imageResourcesPath: this.imageResourcesPath, + renderForms: this.#annotationMode === _pdfjsLib.AnnotationMode.ENABLE_FORMS, + l10n: this.l10n, + annotationCanvasMap: this._annotationCanvasMap, + accessibilityManager: this._accessibilityManager + }); + } + + if (this.xfaLayer?.div) { + div.append(this.xfaLayer.div); + } + let renderContinueCallback = null; if (this.renderingQueue) { renderContinueCallback = cont => { if (!this.renderingQueue.isHighestPriority(this)) { - this.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED; + this.renderingState = _ui_utils.RenderingStates.PAUSED; this.resume = () => { - this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; + this.renderingState = _ui_utils.RenderingStates.RUNNING; cont(); }; @@ -11026,32 +12817,33 @@ class PDFPageView { }; } - const finishPaintTask = async error => { + const finishPaintTask = async (error = null) => { if (paintTask === this.paintTask) { this.paintTask = null; } if (error instanceof _pdfjsLib.RenderingCancelledException) { - this.error = null; + this._renderError = null; return; } - this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + this._renderError = error; + this.renderingState = _ui_utils.RenderingStates.FINISHED; if (this.loadingIconDiv) { - div.removeChild(this.loadingIconDiv); + this.loadingIconDiv.remove(); delete this.loadingIconDiv; } this._resetZoomLayer(true); - this.error = error; - this.stats = pdfPage.stats; + this.#useThumbnailCanvas.regularAnnotations = !paintTask.separateAnnots; this.eventBus.dispatch("pagerendered", { source: this, pageNumber: this.id, cssTransform: false, - timestamp: performance.now() + timestamp: performance.now(), + error: this._renderError }); if (error) { @@ -11062,26 +12854,78 @@ class PDFPageView { const paintTask = this.renderer === _ui_utils.RendererType.SVG ? this.paintOnSvg(canvasWrapper) : this.paintOnCanvas(canvasWrapper); paintTask.onRenderContinue = renderContinueCallback; this.paintTask = paintTask; - const resultPromise = paintTask.promise.then(function () { - return finishPaintTask(null).then(function () { + const resultPromise = paintTask.promise.then(() => { + return finishPaintTask(null).then(() => { if (textLayer) { const readableStream = pdfPage.streamTextContent({ - normalizeWhitespace: true + includeMarkedContent: true }); textLayer.setTextContentStream(readableStream); textLayer.render(); } + + if (this.annotationLayer) { + this._renderAnnotationLayer().then(() => { + if (this.annotationEditorLayerFactory) { + this.annotationEditorLayer ||= this.annotationEditorLayerFactory.createAnnotationEditorLayerBuilder({ + pageDiv: div, + pdfPage, + l10n: this.l10n, + accessibilityManager: this._accessibilityManager + }); + + this._renderAnnotationEditorLayer(); + } + }); + } }); }, function (reason) { return finishPaintTask(reason); }); - if (this.annotationLayerFactory) { - if (!this.annotationLayer) { - this.annotationLayer = this.annotationLayerFactory.createAnnotationLayerBuilder(div, pdfPage, this._annotationStorage, this.imageResourcesPath, this.renderInteractiveForms, this.l10n); - } + if (this.xfaLayerFactory) { + this.xfaLayer ||= this.xfaLayerFactory.createXfaLayerBuilder({ + pageDiv: div, + pdfPage + }); - this._renderAnnotationLayer(); + this._renderXfaLayer(); + } + + if (this.structTreeLayerFactory && this.textLayer && this.canvas) { + this._onTextLayerRendered = event => { + if (event.pageNumber !== this.id) { + return; + } + + this.eventBus._off("textlayerrendered", this._onTextLayerRendered); + + this._onTextLayerRendered = null; + + if (!this.canvas) { + return; + } + + this.pdfPage.getStructTree().then(tree => { + if (!tree) { + return; + } + + if (!this.canvas) { + return; + } + + const treeDom = this.structTreeLayer.render(tree); + treeDom.classList.add("structTree"); + this.canvas.append(treeDom); + }); + }; + + this.eventBus._on("textlayerrendered", this._onTextLayerRendered); + + this.structTreeLayer = this.structTreeLayerFactory.createStructTreeLayerBuilder({ + pdfPage + }); } div.setAttribute("data-loaded", true); @@ -11103,42 +12947,39 @@ class PDFPageView { cancel() { renderTask.cancel(); + }, + + get separateAnnots() { + return renderTask.separateAnnots; } }; const viewport = this.viewport; const canvas = document.createElement("canvas"); - this.l10n.get("page_canvas", { - page: this.id - }, "Page {{page}}").then(msg => { - canvas.setAttribute("aria-label", msg); - }); - canvas.setAttribute("hidden", "hidden"); + canvas.setAttribute("role", "presentation"); + canvas.hidden = true; let isCanvasHidden = true; const showCanvas = function () { if (isCanvasHidden) { - canvas.removeAttribute("hidden"); + canvas.hidden = false; isCanvasHidden = false; } }; - canvasWrapper.appendChild(canvas); + canvasWrapper.append(canvas); this.canvas = canvas; - canvas.mozOpaque = true; const ctx = canvas.getContext("2d", { alpha: false }); - const outputScale = (0, _ui_utils.getOutputScale)(ctx); - this.outputScale = outputScale; + const outputScale = this.outputScale = new _ui_utils.OutputScale(); if (this.useOnlyCssZoom) { const actualSizeViewport = viewport.clone({ - scale: _ui_utils.CSS_UNITS + scale: _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS }); outputScale.sx *= actualSizeViewport.width / viewport.width; outputScale.sy *= actualSizeViewport.height / viewport.height; - outputScale.scaled = true; } if (this.maxCanvasPixels > 0) { @@ -11148,7 +12989,6 @@ class PDFPageView { if (outputScale.sx > maxScale || outputScale.sy > maxScale) { outputScale.sx = maxScale; outputScale.sy = maxScale; - outputScale.scaled = true; this.hasRestrictedScaling = true; } else { this.hasRestrictedScaling = false; @@ -11162,14 +13002,15 @@ class PDFPageView { canvas.style.width = (0, _ui_utils.roundToDivide)(viewport.width, sfx[1]) + "px"; canvas.style.height = (0, _ui_utils.roundToDivide)(viewport.height, sfy[1]) + "px"; this.paintedViewportMap.set(canvas, viewport); - const transform = !outputScale.scaled ? null : [outputScale.sx, 0, 0, outputScale.sy, 0, 0]; + const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null; const renderContext = { canvasContext: ctx, transform, viewport: this.viewport, - enableWebGL: this.enableWebGL, - renderInteractiveForms: this.renderInteractiveForms, - optionalContentConfigPromise: this._optionalContentConfigPromise + annotationMode: this.#annotationMode, + optionalContentConfigPromise: this._optionalContentConfigPromise, + annotationCanvasMap: this._annotationCanvasMap, + pageColors: this.pageColors }; const renderTask = this.pdfPage.render(renderContext); @@ -11185,7 +13026,7 @@ class PDFPageView { renderTask.promise.then(function () { showCanvas(); - renderCapability.resolve(undefined); + renderCapability.resolve(); }, function (error) { showCanvas(); renderCapability.reject(error); @@ -11204,9 +13045,11 @@ class PDFPageView { const pdfPage = this.pdfPage; const actualSizeViewport = this.viewport.clone({ - scale: _ui_utils.CSS_UNITS + scale: _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS }); - const promise = pdfPage.getOperatorList().then(opList => { + const promise = pdfPage.getOperatorList({ + annotationMode: this.#annotationMode + }).then(opList => { ensureNotCancelled(); const svgGfx = new _pdfjsLib.SVGGraphics(pdfPage.commonObjs, pdfPage.objs); return svgGfx.getSVG(opList, actualSizeViewport).then(svg => { @@ -11215,8 +13058,8 @@ class PDFPageView { this.paintedViewportMap.set(svg, actualSizeViewport); svg.style.width = wrapper.style.width; svg.style.height = wrapper.style.height; - this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; - wrapper.appendChild(svg); + this.renderingState = _ui_utils.RenderingStates.FINISHED; + wrapper.append(svg); }); }); return { @@ -11228,6 +13071,10 @@ class PDFPageView { cancel() { cancelled = true; + }, + + get separateAnnots() { + return false; } }; @@ -11243,95 +13090,384 @@ class PDFPageView { } } + get thumbnailCanvas() { + const { + initialOptionalContent, + regularAnnotations + } = this.#useThumbnailCanvas; + return initialOptionalContent && regularAnnotations ? this.canvas : null; + } + } exports.PDFPageView = PDFPageView; /***/ }), -/* 30 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 34 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.DefaultTextLayerFactory = exports.TextLayerBuilder = void 0; +})); +exports.TextAccessibilityManager = void 0; -var _pdfjsLib = __webpack_require__(5); +var _ui_utils = __webpack_require__(1); -const EXPAND_DIVS_TIMEOUT = 300; +class TextAccessibilityManager { + #enabled = false; + #textChildren = null; + #textNodes = new Map(); + #waitingElements = new Map(); -class TextLayerBuilder { - constructor({ - textLayerDiv, - eventBus, - pageIndex, - viewport, - findController = null, - enhanceTextSelection = false - }) { - this.textLayerDiv = textLayerDiv; - this.eventBus = eventBus; - this.textContent = null; - this.textContentItemsStr = []; - this.textContentStream = null; - this.renderingDone = false; - this.pageIdx = pageIndex; - this.pageNumber = this.pageIdx + 1; - this.matches = []; - this.viewport = viewport; - this.textDivs = []; - this.findController = findController; - this.textLayerRenderTask = null; - this.enhanceTextSelection = enhanceTextSelection; - this._onUpdateTextLayerMatches = null; - - this._bindMouse(); + setTextMapping(textDivs) { + this.#textChildren = textDivs; } - _finishRendering() { - this.renderingDone = true; + static #compareElementPositions(e1, e2) { + const rect1 = e1.getBoundingClientRect(); + const rect2 = e2.getBoundingClientRect(); - if (!this.enhanceTextSelection) { - const endOfContent = document.createElement("div"); - endOfContent.className = "endOfContent"; - this.textLayerDiv.appendChild(endOfContent); + if (rect1.width === 0 && rect1.height === 0) { + return +1; } - this.eventBus.dispatch("textlayerrendered", { - source: this, - pageNumber: this.pageNumber, - numTextDivs: this.textDivs.length - }); + if (rect2.width === 0 && rect2.height === 0) { + return -1; + } + + const top1 = rect1.y; + const bot1 = rect1.y + rect1.height; + const mid1 = rect1.y + rect1.height / 2; + const top2 = rect2.y; + const bot2 = rect2.y + rect2.height; + const mid2 = rect2.y + rect2.height / 2; + + if (mid1 <= top2 && mid2 >= bot1) { + return -1; + } + + if (mid2 <= top1 && mid1 >= bot2) { + return +1; + } + + const centerX1 = rect1.x + rect1.width / 2; + const centerX2 = rect2.x + rect2.width / 2; + return centerX1 - centerX2; } - render(timeout = 0) { - if (!(this.textContent || this.textContentStream) || this.renderingDone) { + enable() { + if (this.#enabled) { + throw new Error("TextAccessibilityManager is already enabled."); + } + + if (!this.#textChildren) { + throw new Error("Text divs and strings have not been set."); + } + + this.#enabled = true; + this.#textChildren = this.#textChildren.slice(); + this.#textChildren.sort(TextAccessibilityManager.#compareElementPositions); + + if (this.#textNodes.size > 0) { + const textChildren = this.#textChildren; + + for (const [id, nodeIndex] of this.#textNodes) { + const element = document.getElementById(id); + + if (!element) { + this.#textNodes.delete(id); + continue; + } + + this.#addIdToAriaOwns(id, textChildren[nodeIndex]); + } + } + + for (const [element, isRemovable] of this.#waitingElements) { + this.addPointerInTextLayer(element, isRemovable); + } + + this.#waitingElements.clear(); + } + + disable() { + if (!this.#enabled) { return; } - this.cancel(); - this.textDivs = []; - const textLayerFrag = document.createDocumentFragment(); - this.textLayerRenderTask = (0, _pdfjsLib.renderTextLayer)({ - textContent: this.textContent, - textContentStream: this.textContentStream, - container: textLayerFrag, - viewport: this.viewport, - textDivs: this.textDivs, - textContentItemsStr: this.textContentItemsStr, - timeout, - enhanceTextSelection: this.enhanceTextSelection - }); - this.textLayerRenderTask.promise.then(() => { - this.textLayerDiv.appendChild(textLayerFrag); + this.#waitingElements.clear(); + this.#textChildren = null; + this.#enabled = false; + } - this._finishRendering(); + removePointerInTextLayer(element) { + if (!this.#enabled) { + this.#waitingElements.delete(element); + return; + } - this._updateMatches(); - }, function (reason) {}); + const children = this.#textChildren; + + if (!children || children.length === 0) { + return; + } + + const { + id + } = element; + const nodeIndex = this.#textNodes.get(id); + + if (nodeIndex === undefined) { + return; + } + + const node = children[nodeIndex]; + this.#textNodes.delete(id); + let owns = node.getAttribute("aria-owns"); + + if (owns?.includes(id)) { + owns = owns.split(" ").filter(x => x !== id).join(" "); + + if (owns) { + node.setAttribute("aria-owns", owns); + } else { + node.removeAttribute("aria-owns"); + node.setAttribute("role", "presentation"); + } + } + } + + #addIdToAriaOwns(id, node) { + const owns = node.getAttribute("aria-owns"); + + if (!owns?.includes(id)) { + node.setAttribute("aria-owns", owns ? `${owns} ${id}` : id); + } + + node.removeAttribute("role"); + } + + addPointerInTextLayer(element, isRemovable) { + const { + id + } = element; + + if (!id) { + return; + } + + if (!this.#enabled) { + this.#waitingElements.set(element, isRemovable); + return; + } + + if (isRemovable) { + this.removePointerInTextLayer(element); + } + + const children = this.#textChildren; + + if (!children || children.length === 0) { + return; + } + + const index = (0, _ui_utils.binarySearchFirstItem)(children, node => TextAccessibilityManager.#compareElementPositions(element, node) < 0); + const nodeIndex = Math.max(0, index - 1); + this.#addIdToAriaOwns(id, children[nodeIndex]); + this.#textNodes.set(id, nodeIndex); + } + + moveElementInDOM(container, element, contentElement, isRemovable) { + this.addPointerInTextLayer(contentElement, isRemovable); + + if (!container.hasChildNodes()) { + container.append(element); + return; + } + + const children = Array.from(container.childNodes).filter(node => node !== element); + + if (children.length === 0) { + return; + } + + const elementToCompare = contentElement || element; + const index = (0, _ui_utils.binarySearchFirstItem)(children, node => TextAccessibilityManager.#compareElementPositions(elementToCompare, node) < 0); + + if (index === 0) { + children[0].before(element); + } else { + children[index - 1].after(element); + } + } + +} + +exports.TextAccessibilityManager = TextAccessibilityManager; + +/***/ }), +/* 35 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.StructTreeLayerBuilder = void 0; +const PDF_ROLE_TO_HTML_ROLE = { + Document: null, + DocumentFragment: null, + Part: "group", + Sect: "group", + Div: "group", + Aside: "note", + NonStruct: "none", + P: null, + H: "heading", + Title: null, + FENote: "note", + Sub: "group", + Lbl: null, + Span: null, + Em: null, + Strong: null, + Link: "link", + Annot: "note", + Form: "form", + Ruby: null, + RB: null, + RT: null, + RP: null, + Warichu: null, + WT: null, + WP: null, + L: "list", + LI: "listitem", + LBody: null, + Table: "table", + TR: "row", + TH: "columnheader", + TD: "cell", + THead: "columnheader", + TBody: null, + TFoot: null, + Caption: null, + Figure: "figure", + Formula: null, + Artifact: null +}; +const HEADING_PATTERN = /^H(\d+)$/; + +class StructTreeLayerBuilder { + constructor({ + pdfPage + }) { + this.pdfPage = pdfPage; + } + + render(structTree) { + return this._walk(structTree); + } + + _setAttributes(structElement, htmlElement) { + if (structElement.alt !== undefined) { + htmlElement.setAttribute("aria-label", structElement.alt); + } + + if (structElement.id !== undefined) { + htmlElement.setAttribute("aria-owns", structElement.id); + } + + if (structElement.lang !== undefined) { + htmlElement.setAttribute("lang", structElement.lang); + } + } + + _walk(node) { + if (!node) { + return null; + } + + const element = document.createElement("span"); + + if ("role" in node) { + const { + role + } = node; + const match = role.match(HEADING_PATTERN); + + if (match) { + element.setAttribute("role", "heading"); + element.setAttribute("aria-level", match[1]); + } else if (PDF_ROLE_TO_HTML_ROLE[role]) { + element.setAttribute("role", PDF_ROLE_TO_HTML_ROLE[role]); + } + } + + this._setAttributes(node, element); + + if (node.children) { + if (node.children.length === 1 && "id" in node.children[0]) { + this._setAttributes(node.children[0], element); + } else { + for (const kid of node.children) { + element.append(this._walk(kid)); + } + } + } + + return element; + } + +} + +exports.StructTreeLayerBuilder = StructTreeLayerBuilder; + +/***/ }), +/* 36 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TextHighlighter = void 0; + +class TextHighlighter { + constructor({ + findController, + eventBus, + pageIndex + }) { + this.findController = findController; + this.matches = []; + this.eventBus = eventBus; + this.pageIdx = pageIndex; + this._onUpdateTextLayerMatches = null; + this.textDivs = null; + this.textContentItemsStr = null; + this.enabled = false; + } + + setTextMapping(divs, texts) { + this.textDivs = divs; + this.textContentItemsStr = texts; + } + + enable() { + if (!this.textDivs || !this.textContentItemsStr) { + throw new Error("Text divs and strings have not been set."); + } + + if (this.enabled) { + throw new Error("TextHighlighter is already enabled."); + } + + this.enabled = true; if (!this._onUpdateTextLayerMatches) { this._onUpdateTextLayerMatches = evt => { @@ -11342,14 +13478,17 @@ class TextLayerBuilder { this.eventBus._on("updatetextlayermatches", this._onUpdateTextLayerMatches); } + + this._updateMatches(); } - cancel() { - if (this.textLayerRenderTask) { - this.textLayerRenderTask.cancel(); - this.textLayerRenderTask = null; + disable() { + if (!this.enabled) { + return; } + this.enabled = false; + if (this._onUpdateTextLayerMatches) { this.eventBus._off("updatetextlayermatches", this._onUpdateTextLayerMatches); @@ -11357,29 +13496,17 @@ class TextLayerBuilder { } } - setTextContentStream(readableStream) { - this.cancel(); - this.textContentStream = readableStream; - } - - setTextContent(textContent) { - this.cancel(); - this.textContent = textContent; - } - _convertMatches(matches, matchesLength) { if (!matches) { return []; } const { - findController, textContentItemsStr } = this; let i = 0, iIndex = 0; const end = textContentItemsStr.length - 1; - const queryLen = findController.state.query.length; const result = []; for (let m = 0, mm = matches.length; m < mm; m++) { @@ -11400,12 +13527,7 @@ class TextLayerBuilder { offset: matchIdx - iIndex } }; - - if (matchesLength) { - matchIdx += matchesLength[m]; - } else { - matchIdx += queryLen; - } + matchIdx += matchesLength[m]; while (i !== end && matchIdx > iIndex + textContentItemsStr[i].length) { iIndex += textContentItemsStr[i].length; @@ -11429,7 +13551,9 @@ class TextLayerBuilder { const { findController, - pageIdx, + pageIdx + } = this; + const { textContentItemsStr, textDivs } = this; @@ -11445,23 +13569,33 @@ class TextLayerBuilder { function beginText(begin, className) { const divIdx = begin.divIdx; textDivs[divIdx].textContent = ""; - appendTextToDiv(divIdx, 0, begin.offset, className); + return appendTextToDiv(divIdx, 0, begin.offset, className); } function appendTextToDiv(divIdx, fromOffset, toOffset, className) { - const div = textDivs[divIdx]; + let div = textDivs[divIdx]; + + if (div.nodeType === Node.TEXT_NODE) { + const span = document.createElement("span"); + div.before(span); + span.append(div); + textDivs[divIdx] = span; + div = span; + } + const content = textContentItemsStr[divIdx].substring(fromOffset, toOffset); const node = document.createTextNode(content); if (className) { const span = document.createElement("span"); - span.className = className; - span.appendChild(node); - div.appendChild(span); - return; + span.className = `${className} appended`; + span.append(node); + div.append(span); + return className.includes("selected") ? span.offsetLeft : 0; } - div.appendChild(node); + div.append(node); + return 0; } let i0 = selectedMatchIdx, @@ -11480,14 +13614,7 @@ class TextLayerBuilder { const end = match.end; const isSelected = isSelectedPage && i === selectedMatchIdx; const highlightSuffix = isSelected ? " selected" : ""; - - if (isSelected) { - findController.scrollMatchIntoView({ - element: textDivs[begin.divIdx], - pageIndex: pageIdx, - matchIndex: selectedMatchIdx - }); - } + let selectedLeft = 0; if (!prevEnd || begin.divIdx !== prevEnd.divIdx) { if (prevEnd !== null) { @@ -11500,9 +13627,9 @@ class TextLayerBuilder { } if (begin.divIdx === end.divIdx) { - appendTextToDiv(begin.divIdx, begin.offset, end.offset, "highlight" + highlightSuffix); + selectedLeft = appendTextToDiv(begin.divIdx, begin.offset, end.offset, "highlight" + highlightSuffix); } else { - appendTextToDiv(begin.divIdx, begin.offset, infinity.offset, "highlight begin" + highlightSuffix); + selectedLeft = appendTextToDiv(begin.divIdx, begin.offset, infinity.offset, "highlight begin" + highlightSuffix); for (let n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) { textDivs[n0].className = "highlight middle" + highlightSuffix; @@ -11512,6 +13639,15 @@ class TextLayerBuilder { } prevEnd = end; + + if (isSelected) { + findController.scrollMatchIntoView({ + element: textDivs[begin.divIdx], + selectedLeft, + pageIndex: pageIdx, + matchIndex: selectedMatchIdx + }); + } } if (prevEnd) { @@ -11520,14 +13656,16 @@ class TextLayerBuilder { } _updateMatches() { - if (!this.renderingDone) { + if (!this.enabled) { return; } const { findController, matches, - pageIdx, + pageIdx + } = this; + const { textContentItemsStr, textDivs } = this; @@ -11546,7 +13684,7 @@ class TextLayerBuilder { clearedUntilDivIdx = match.end.divIdx + 1; } - if (!findController || !findController.highlightMatches) { + if (!findController?.highlightMatches) { return; } @@ -11557,6 +13695,118 @@ class TextLayerBuilder { this._renderMatches(this.matches); } +} + +exports.TextHighlighter = TextHighlighter; + +/***/ }), +/* 37 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TextLayerBuilder = void 0; + +var _pdfjsLib = __webpack_require__(5); + +const EXPAND_DIVS_TIMEOUT = 300; + +class TextLayerBuilder { + constructor({ + textLayerDiv, + eventBus, + pageIndex, + viewport, + highlighter = null, + enhanceTextSelection = false, + accessibilityManager = null + }) { + this.textLayerDiv = textLayerDiv; + this.eventBus = eventBus; + this.textContent = null; + this.textContentItemsStr = []; + this.textContentStream = null; + this.renderingDone = false; + this.pageNumber = pageIndex + 1; + this.viewport = viewport; + this.textDivs = []; + this.textLayerRenderTask = null; + this.highlighter = highlighter; + this.enhanceTextSelection = enhanceTextSelection; + this.accessibilityManager = accessibilityManager; + + this._bindMouse(); + } + + _finishRendering() { + this.renderingDone = true; + + if (!this.enhanceTextSelection) { + const endOfContent = document.createElement("div"); + endOfContent.className = "endOfContent"; + this.textLayerDiv.append(endOfContent); + } + + this.eventBus.dispatch("textlayerrendered", { + source: this, + pageNumber: this.pageNumber, + numTextDivs: this.textDivs.length + }); + } + + render(timeout = 0) { + if (!(this.textContent || this.textContentStream) || this.renderingDone) { + return; + } + + this.cancel(); + this.textDivs.length = 0; + this.highlighter?.setTextMapping(this.textDivs, this.textContentItemsStr); + this.accessibilityManager?.setTextMapping(this.textDivs); + const textLayerFrag = document.createDocumentFragment(); + this.textLayerRenderTask = (0, _pdfjsLib.renderTextLayer)({ + textContent: this.textContent, + textContentStream: this.textContentStream, + container: textLayerFrag, + viewport: this.viewport, + textDivs: this.textDivs, + textContentItemsStr: this.textContentItemsStr, + timeout, + enhanceTextSelection: this.enhanceTextSelection + }); + this.textLayerRenderTask.promise.then(() => { + this.textLayerDiv.append(textLayerFrag); + + this._finishRendering(); + + this.highlighter?.enable(); + this.accessibilityManager?.enable(); + }, function (reason) {}); + } + + cancel() { + if (this.textLayerRenderTask) { + this.textLayerRenderTask.cancel(); + this.textLayerRenderTask = null; + } + + this.highlighter?.disable(); + this.accessibilityManager?.disable(); + } + + setTextContentStream(readableStream) { + this.cancel(); + this.textContentStream = readableStream; + } + + setTextContent(textContent) { + this.cancel(); + this.textContent = textContent; + } + _bindMouse() { const div = this.textLayerDiv; let expandDivsTimer = null; @@ -11616,52 +13866,129 @@ class TextLayerBuilder { exports.TextLayerBuilder = TextLayerBuilder; -class DefaultTextLayerFactory { - createTextLayerBuilder(textLayerDiv, pageIndex, viewport, enhanceTextSelection = false, eventBus) { - return new TextLayerBuilder({ - textLayerDiv, - pageIndex, - viewport, - enhanceTextSelection, - eventBus +/***/ }), +/* 38 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XfaLayerBuilder = void 0; + +var _pdfjsLib = __webpack_require__(5); + +class XfaLayerBuilder { + constructor({ + pageDiv, + pdfPage, + annotationStorage = null, + linkService, + xfaHtml = null + }) { + this.pageDiv = pageDiv; + this.pdfPage = pdfPage; + this.annotationStorage = annotationStorage; + this.linkService = linkService; + this.xfaHtml = xfaHtml; + this.div = null; + this._cancelled = false; + } + + render(viewport, intent = "display") { + if (intent === "print") { + const parameters = { + viewport: viewport.clone({ + dontFlip: true + }), + div: this.div, + xfaHtml: this.xfaHtml, + annotationStorage: this.annotationStorage, + linkService: this.linkService, + intent + }; + const div = document.createElement("div"); + this.pageDiv.append(div); + parameters.div = div; + + const result = _pdfjsLib.XfaLayer.render(parameters); + + return Promise.resolve(result); + } + + return this.pdfPage.getXfa().then(xfaHtml => { + if (this._cancelled || !xfaHtml) { + return { + textDivs: [] + }; + } + + const parameters = { + viewport: viewport.clone({ + dontFlip: true + }), + div: this.div, + xfaHtml, + annotationStorage: this.annotationStorage, + linkService: this.linkService, + intent + }; + + if (this.div) { + return _pdfjsLib.XfaLayer.update(parameters); + } + + this.div = document.createElement("div"); + this.pageDiv.append(this.div); + parameters.div = this.div; + return _pdfjsLib.XfaLayer.render(parameters); + }).catch(error => { + console.error(error); }); } + cancel() { + this._cancelled = true; + } + + hide() { + if (!this.div) { + return; + } + + this.div.hidden = true; + } + } -exports.DefaultTextLayerFactory = DefaultTextLayerFactory; +exports.XfaLayerBuilder = XfaLayerBuilder; /***/ }), -/* 31 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 39 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.SecondaryToolbar = void 0; -var _ui_utils = __webpack_require__(2); +var _ui_utils = __webpack_require__(1); -var _pdf_cursor_tools = __webpack_require__(6); +var _pdf_cursor_tools = __webpack_require__(7); -var _pdf_single_page_viewer = __webpack_require__(32); +var _base_viewer = __webpack_require__(29); class SecondaryToolbar { - constructor(options, mainContainer, eventBus) { + constructor(options, eventBus) { this.toolbar = options.toolbar; this.toggleButton = options.toggleButton; - this.toolbarButtonContainer = options.toolbarButtonContainer; this.buttons = [{ element: options.presentationModeButton, eventName: "presentationmode", close: true - }, { - element: options.openFileButton, - eventName: "openfile", - close: true }, { element: options.printButton, eventName: "print", @@ -11704,6 +14031,13 @@ class SecondaryToolbar { tool: _pdf_cursor_tools.CursorTool.HAND }, close: true + }, { + element: options.scrollPageButton, + eventName: "switchscrollmode", + eventDetails: { + mode: _ui_utils.ScrollMode.PAGE + }, + close: true }, { element: options.scrollVerticalButton, eventName: "switchscrollmode", @@ -11751,36 +14085,24 @@ class SecondaryToolbar { eventName: "documentproperties", close: true }]; + this.buttons.push({ + element: options.openFileButton, + eventName: "openfile", + close: true + }); this.items = { firstPage: options.firstPageButton, lastPage: options.lastPageButton, pageRotateCw: options.pageRotateCwButton, pageRotateCcw: options.pageRotateCcwButton }; - this.mainContainer = mainContainer; this.eventBus = eventBus; this.opened = false; - this.containerHeight = null; - this.previousContainerHeight = null; + this.#bindClickListeners(); + this.#bindCursorToolsListener(options); + this.#bindScrollModeListener(options); + this.#bindSpreadModeListener(options); this.reset(); - - this._bindClickListeners(); - - this._bindCursorToolsListener(options); - - this._bindScrollModeListener(options); - - this._bindSpreadModeListener(options); - - this.eventBus._on("resize", this._setMaxHeight.bind(this)); - - this.eventBus._on("baseviewerinit", evt => { - if (evt.source instanceof _pdf_single_page_viewer.PDFSinglePageViewer) { - this.toolbarButtonContainer.classList.add("hiddenScrollModeButtons", "hiddenSpreadModeButtons"); - } else { - this.toolbarButtonContainer.classList.remove("hiddenScrollModeButtons", "hiddenSpreadModeButtons"); - } - }); } get isOpen() { @@ -11789,35 +14111,31 @@ class SecondaryToolbar { setPageNumber(pageNumber) { this.pageNumber = pageNumber; - - this._updateUIState(); + this.#updateUIState(); } setPagesCount(pagesCount) { this.pagesCount = pagesCount; - - this._updateUIState(); + this.#updateUIState(); } reset() { this.pageNumber = 0; this.pagesCount = 0; - - this._updateUIState(); - + this.#updateUIState(); this.eventBus.dispatch("secondarytoolbarreset", { source: this }); } - _updateUIState() { + #updateUIState() { this.items.firstPage.disabled = this.pageNumber <= 1; this.items.lastPage.disabled = this.pageNumber >= this.pagesCount; this.items.pageRotateCw.disabled = this.pagesCount === 0; this.items.pageRotateCcw.disabled = this.pagesCount === 0; } - _bindClickListeners() { + #bindClickListeners() { this.toggleButton.addEventListener("click", this.toggle.bind(this)); for (const { @@ -11826,49 +14144,77 @@ class SecondaryToolbar { close, eventDetails } of this.buttons) { - if (element) { - element.addEventListener("click", evt => { - if (eventName !== null) { - const details = { - source: this - }; + if ( element !== null ) { + element.addEventListener("click", evt => { + if (eventName !== null) { + const details = { + source: this + }; - for (const property in eventDetails) { - details[property] = eventDetails[property]; - } + for (const property in eventDetails) { + details[property] = eventDetails[property]; + } - this.eventBus.dispatch(eventName, details); - } + this.eventBus.dispatch(eventName, details); + } - if (close) { - this.close(); - } - }); - } + if (close) { + this.close(); + } + }); + } } } - _bindCursorToolsListener(buttons) { + #bindCursorToolsListener({ + cursorSelectToolButton, + cursorHandToolButton + }) { this.eventBus._on("cursortoolchanged", function ({ tool }) { - buttons.cursorSelectToolButton.classList.toggle("toggled", tool === _pdf_cursor_tools.CursorTool.SELECT); - buttons.cursorHandToolButton.classList.toggle("toggled", tool === _pdf_cursor_tools.CursorTool.HAND); + const isSelect = tool === _pdf_cursor_tools.CursorTool.SELECT, + isHand = tool === _pdf_cursor_tools.CursorTool.HAND; + cursorSelectToolButton.classList.toggle("toggled", isSelect); + cursorHandToolButton.classList.toggle("toggled", isHand); + cursorSelectToolButton.setAttribute("aria-checked", isSelect); + cursorHandToolButton.setAttribute("aria-checked", isHand); }); } - _bindScrollModeListener(buttons) { - function scrollModeChanged({ + #bindScrollModeListener({ + scrollPageButton, + scrollVerticalButton, + scrollHorizontalButton, + scrollWrappedButton, + spreadNoneButton, + spreadOddButton, + spreadEvenButton + }) { + const scrollModeChanged = ({ mode - }) { - buttons.scrollVerticalButton.classList.toggle("toggled", mode === _ui_utils.ScrollMode.VERTICAL); - buttons.scrollHorizontalButton.classList.toggle("toggled", mode === _ui_utils.ScrollMode.HORIZONTAL); - buttons.scrollWrappedButton.classList.toggle("toggled", mode === _ui_utils.ScrollMode.WRAPPED); - const isScrollModeHorizontal = mode === _ui_utils.ScrollMode.HORIZONTAL; - buttons.spreadNoneButton.disabled = isScrollModeHorizontal; - buttons.spreadOddButton.disabled = isScrollModeHorizontal; - buttons.spreadEvenButton.disabled = isScrollModeHorizontal; - } + }) => { + const isPage = mode === _ui_utils.ScrollMode.PAGE, + isVertical = mode === _ui_utils.ScrollMode.VERTICAL, + isHorizontal = mode === _ui_utils.ScrollMode.HORIZONTAL, + isWrapped = mode === _ui_utils.ScrollMode.WRAPPED; + scrollPageButton.classList.toggle("toggled", isPage); + scrollVerticalButton.classList.toggle("toggled", isVertical); + scrollHorizontalButton.classList.toggle("toggled", isHorizontal); + scrollWrappedButton.classList.toggle("toggled", isWrapped); + scrollPageButton.setAttribute("aria-checked", isPage); + scrollVerticalButton.setAttribute("aria-checked", isVertical); + scrollHorizontalButton.setAttribute("aria-checked", isHorizontal); + scrollWrappedButton.setAttribute("aria-checked", isWrapped); + const forceScrollModePage = this.pagesCount > _base_viewer.PagesCountLimit.FORCE_SCROLL_MODE_PAGE; + scrollPageButton.disabled = forceScrollModePage; + scrollVerticalButton.disabled = forceScrollModePage; + scrollHorizontalButton.disabled = forceScrollModePage; + scrollWrappedButton.disabled = forceScrollModePage; + spreadNoneButton.disabled = isHorizontal; + spreadOddButton.disabled = isHorizontal; + spreadEvenButton.disabled = isHorizontal; + }; this.eventBus._on("scrollmodechanged", scrollModeChanged); @@ -11881,13 +14227,23 @@ class SecondaryToolbar { }); } - _bindSpreadModeListener(buttons) { + #bindSpreadModeListener({ + spreadNoneButton, + spreadOddButton, + spreadEvenButton + }) { function spreadModeChanged({ mode }) { - buttons.spreadNoneButton.classList.toggle("toggled", mode === _ui_utils.SpreadMode.NONE); - buttons.spreadOddButton.classList.toggle("toggled", mode === _ui_utils.SpreadMode.ODD); - buttons.spreadEvenButton.classList.toggle("toggled", mode === _ui_utils.SpreadMode.EVEN); + const isNone = mode === _ui_utils.SpreadMode.NONE, + isOdd = mode === _ui_utils.SpreadMode.ODD, + isEven = mode === _ui_utils.SpreadMode.EVEN; + spreadNoneButton.classList.toggle("toggled", isNone); + spreadOddButton.classList.toggle("toggled", isOdd); + spreadEvenButton.classList.toggle("toggled", isEven); + spreadNoneButton.setAttribute("aria-checked", isNone); + spreadOddButton.setAttribute("aria-checked", isOdd); + spreadEvenButton.setAttribute("aria-checked", isEven); } this.eventBus._on("spreadmodechanged", spreadModeChanged); @@ -11907,10 +14263,8 @@ class SecondaryToolbar { } this.opened = true; - - this._setMaxHeight(); - this.toggleButton.classList.add("toggled"); + this.toggleButton.setAttribute("aria-expanded", "true"); this.toolbar.classList.remove("hidden"); } @@ -11922,6 +14276,7 @@ class SecondaryToolbar { this.opened = false; this.toolbar.classList.add("hidden"); this.toggleButton.classList.remove("toggled"); + this.toggleButton.setAttribute("aria-expanded", "false"); } toggle() { @@ -11932,167 +14287,31 @@ class SecondaryToolbar { } } - _setMaxHeight() { - if (!this.opened) { - return; - } - - this.containerHeight = this.mainContainer.clientHeight; - - if (this.containerHeight === this.previousContainerHeight) { - return; - } - - this.toolbarButtonContainer.style.maxHeight = `${this.containerHeight - _ui_utils.SCROLLBAR_PADDING}px`; - this.previousContainerHeight = this.containerHeight; - } - } exports.SecondaryToolbar = SecondaryToolbar; /***/ }), -/* 32 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 40 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); -exports.PDFSinglePageViewer = void 0; +})); +exports.Toolbar = void 0; -var _base_viewer = __webpack_require__(27); +var _ui_utils = __webpack_require__(1); var _pdfjsLib = __webpack_require__(5); -class PDFSinglePageViewer extends _base_viewer.BaseViewer { - constructor(options) { - super(options); - - this.eventBus._on("pagesinit", evt => { - this._ensurePageViewVisible(); - }); - } - - get _viewerElement() { - return (0, _pdfjsLib.shadow)(this, "_viewerElement", this._shadowViewer); - } - - _resetView() { - super._resetView(); - - this._previousPageNumber = 1; - this._shadowViewer = document.createDocumentFragment(); - this._updateScrollDown = null; - } - - _ensurePageViewVisible() { - const pageView = this._pages[this._currentPageNumber - 1]; - const previousPageView = this._pages[this._previousPageNumber - 1]; - const viewerNodes = this.viewer.childNodes; - - switch (viewerNodes.length) { - case 0: - this.viewer.appendChild(pageView.div); - break; - - case 1: - if (viewerNodes[0] !== previousPageView.div) { - throw new Error("_ensurePageViewVisible: Unexpected previously visible page."); - } - - if (pageView === previousPageView) { - break; - } - - this._shadowViewer.appendChild(previousPageView.div); - - this.viewer.appendChild(pageView.div); - this.container.scrollTop = 0; - break; - - default: - throw new Error("_ensurePageViewVisible: Only one page should be visible at a time."); - } - - this._previousPageNumber = this._currentPageNumber; - } - - _scrollUpdate() { - if (this._updateScrollDown) { - this._updateScrollDown(); - } - - super._scrollUpdate(); - } - - _scrollIntoView({ - pageDiv, - pageSpot = null, - pageNumber = null - }) { - if (pageNumber) { - this._setCurrentPageNumber(pageNumber); - } - - const scrolledDown = this._currentPageNumber >= this._previousPageNumber; - - this._ensurePageViewVisible(); - - this.update(); - - super._scrollIntoView({ - pageDiv, - pageSpot, - pageNumber - }); - - this._updateScrollDown = () => { - this.scroll.down = scrolledDown; - this._updateScrollDown = null; - }; - } - - _getVisiblePages() { - return this._getCurrentVisiblePage(); - } - - _updateHelper(visiblePages) {} - - get _isScrollModeHorizontal() { - return (0, _pdfjsLib.shadow)(this, "_isScrollModeHorizontal", false); - } - - _updateScrollMode() {} - - _updateSpreadMode() {} - -} - -exports.PDFSinglePageViewer = PDFSinglePageViewer; - -/***/ }), -/* 33 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.Toolbar = void 0; - -var _ui_utils = __webpack_require__(2); - const PAGE_NUMBER_LOADING_INDICATOR = "visiblePageIsLoading"; -const SCALE_SELECT_CONTAINER_WIDTH = 140; -const SCALE_SELECT_WIDTH = 162; class Toolbar { - constructor(options, eventBus, l10n = _ui_utils.NullL10n) { + #wasLocalized = false; + + constructor(options, eventBus, l10n) { this.toolbar = options.container; this.eventBus = eventBus; this.l10n = l10n; @@ -12108,9 +14327,6 @@ class Toolbar { }, { element: options.zoomOut, eventName: "zoomout" - }, { - element: options.openFile, - eventName: "openfile" }, { element: options.print, eventName: "print" @@ -12123,11 +14339,38 @@ class Toolbar { }, { element: options.viewBookmark, eventName: null + }, { + element: options.editorFreeTextButton, + eventName: "switchannotationeditormode", + eventDetails: { + get mode() { + const { + classList + } = options.editorFreeTextButton; + return classList.contains("toggled") ? _pdfjsLib.AnnotationEditorType.NONE : _pdfjsLib.AnnotationEditorType.FREETEXT; + } + + } + }, { + element: options.editorInkButton, + eventName: "switchannotationeditormode", + eventDetails: { + get mode() { + const { + classList + } = options.editorInkButton; + return classList.contains("toggled") ? _pdfjsLib.AnnotationEditorType.NONE : _pdfjsLib.AnnotationEditorType.INK; + } + + } }]; + this.buttons.push({ + element: options.openFile, + eventName: "openfile" + }); this.items = { numPages: options.numPages, pageNumber: options.pageNumber, - scaleSelectContainer: options.scaleSelectContainer, scaleSelect: options.scaleSelect, customScaleOption: options.customScaleOption, previous: options.previous, @@ -12135,31 +14378,26 @@ class Toolbar { zoomIn: options.zoomIn, zoomOut: options.zoomOut }; - this._wasLocalized = false; + this.#bindListeners(options); this.reset(); - - this._bindListeners(); } setPageNumber(pageNumber, pageLabel) { this.pageNumber = pageNumber; this.pageLabel = pageLabel; - - this._updateUIState(false); + this.#updateUIState(false); } setPagesCount(pagesCount, hasPageLabels) { this.pagesCount = pagesCount; this.hasPageLabels = hasPageLabels; - - this._updateUIState(true); + this.#updateUIState(true); } setPageScale(pageScaleValue, pageScale) { this.pageScaleValue = (pageScaleValue || pageScale).toString(); this.pageScale = pageScale; - - this._updateUIState(false); + this.#updateUIState(false); } reset() { @@ -12169,13 +14407,14 @@ class Toolbar { this.pagesCount = 0; this.pageScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; this.pageScale = _ui_utils.DEFAULT_SCALE; - - this._updateUIState(true); - + this.#updateUIState(true); this.updateLoadingIndicatorState(); + this.eventBus.dispatch("toolbarreset", { + source: this + }); } - _bindListeners() { + #bindListeners(options) { const { pageNumber, scaleSelect @@ -12184,14 +14423,23 @@ class Toolbar { for (const { element, - eventName + eventName, + eventDetails } of this.buttons) { - if (element) { + if ( element !== null ) { element.addEventListener("click", evt => { if (eventName !== null) { - this.eventBus.dispatch(eventName, { + const details = { source: this - }); + }; + + if (eventDetails) { + for (const property in eventDetails) { + details[property] = eventDetails[property]; + } + } + + this.eventBus.dispatch(eventName, details); } }); } @@ -12216,19 +14464,67 @@ class Toolbar { value: this.value }); }); + scaleSelect.addEventListener("click", function (evt) { + const target = evt.target; + + if (this.value === self.pageScaleValue && target.tagName.toUpperCase() === "OPTION") { + this.blur(); + } + }); scaleSelect.oncontextmenu = _ui_utils.noContextMenuHandler; this.eventBus._on("localized", () => { - this._wasLocalized = true; + this.#wasLocalized = true; + this.#adjustScaleWidth(); + this.#updateUIState(true); + }); - this._adjustScaleWidth(); + this.#bindEditorToolsListener(options); + } - this._updateUIState(true); + #bindEditorToolsListener({ + editorFreeTextButton, + editorFreeTextParamsToolbar, + editorInkButton, + editorInkParamsToolbar + }) { + const editorModeChanged = (evt, disableButtons = false) => { + const editorButtons = [{ + mode: _pdfjsLib.AnnotationEditorType.FREETEXT, + button: editorFreeTextButton, + toolbar: editorFreeTextParamsToolbar + }, { + mode: _pdfjsLib.AnnotationEditorType.INK, + button: editorInkButton, + toolbar: editorInkParamsToolbar + }]; + + for (const { + mode, + button, + toolbar + } of editorButtons) { + const checked = mode === evt.mode; + button.classList.toggle("toggled", checked); + button.setAttribute("aria-checked", checked); + button.disabled = disableButtons; + toolbar?.classList.toggle("hidden", !checked); + } + }; + + this.eventBus._on("annotationeditormodechanged", editorModeChanged); + + this.eventBus._on("toolbarreset", evt => { + if (evt.source === this) { + editorModeChanged({ + mode: _pdfjsLib.AnnotationEditorType.NONE + }, true); + } }); } - _updateUIState(resetNumPages = false) { - if (!this._wasLocalized) { + #updateUIState(resetNumPages = false) { + if (!this.#wasLocalized) { return; } @@ -12247,7 +14543,7 @@ class Toolbar { items.pageNumber.type = "number"; this.l10n.get("of_pages", { pagesCount - }, "of {{pagesCount}}").then(msg => { + }).then(msg => { items.numPages.textContent = msg; }); } @@ -12260,7 +14556,7 @@ class Toolbar { this.l10n.get("page_of_pages", { pageNumber, pagesCount - }, "({{pageNumber}} of {{pagesCount}})").then(msg => { + }).then(msg => { items.numPages.textContent = msg; }); } else { @@ -12271,10 +14567,9 @@ class Toolbar { items.next.disabled = pageNumber >= pagesCount; items.zoomOut.disabled = pageScale <= _ui_utils.MIN_SCALE; items.zoomIn.disabled = pageScale >= _ui_utils.MAX_SCALE; - const customScale = Math.round(pageScale * 10000) / 100; this.l10n.get("page_scale_percent", { - scale: customScale - }, "{{scale}}%").then(msg => { + scale: Math.round(pageScale * 10000) / 100 + }).then(msg => { let predefinedValueFound = false; for (const option of items.scaleSelect.options) { @@ -12295,27 +14590,27 @@ class Toolbar { } updateLoadingIndicatorState(loading = false) { - const pageNumberInput = this.items.pageNumber; - pageNumberInput.classList.toggle(PAGE_NUMBER_LOADING_INDICATOR, loading); + const { + pageNumber + } = this.items; + pageNumber.classList.toggle(PAGE_NUMBER_LOADING_INDICATOR, loading); } - async _adjustScaleWidth() { + async #adjustScaleWidth() { const { items, l10n } = this; - const predefinedValuesPromise = Promise.all([l10n.get("page_scale_auto", null, "Automatic Zoom"), l10n.get("page_scale_actual", null, "Actual Size"), l10n.get("page_scale_fit", null, "Page Fit"), l10n.get("page_scale_width", null, "Page Width")]); - let canvas = document.createElement("canvas"); - canvas.mozOpaque = true; - let ctx = canvas.getContext("2d", { + const predefinedValuesPromise = Promise.all([l10n.get("page_scale_auto"), l10n.get("page_scale_actual"), l10n.get("page_scale_fit"), l10n.get("page_scale_width")]); + await _ui_utils.animationStarted; + const style = getComputedStyle(items.scaleSelect), + scaleSelectContainerWidth = parseInt(style.getPropertyValue("--scale-select-container-width"), 10), + scaleSelectOverflow = parseInt(style.getPropertyValue("--scale-select-overflow"), 10); + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d", { alpha: false }); - await _ui_utils.animationStarted; - const { - fontSize, - fontFamily - } = getComputedStyle(items.scaleSelect); - ctx.font = `${fontSize} ${fontFamily}`; + ctx.font = `${style.fontSize} ${style.fontFamily}`; let maxWidth = 0; for (const predefinedValue of await predefinedValuesPromise) { @@ -12328,17 +14623,14 @@ class Toolbar { } } - const overflow = SCALE_SELECT_WIDTH - SCALE_SELECT_CONTAINER_WIDTH; - maxWidth += 2 * overflow; + maxWidth += 2 * scaleSelectOverflow; - if (maxWidth > SCALE_SELECT_CONTAINER_WIDTH) { - items.scaleSelect.style.width = `${maxWidth + overflow}px`; - items.scaleSelectContainer.style.width = `${maxWidth}px`; + if (maxWidth > scaleSelectContainerWidth) { + _ui_utils.docStyle.setProperty("--scale-select-container-width", `${maxWidth}px`); } canvas.width = 0; canvas.height = 0; - canvas = ctx = null; } } @@ -12346,15 +14638,14 @@ class Toolbar { exports.Toolbar = Toolbar; /***/ }), -/* 34 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 41 */ +/***/ ((__unused_webpack_module, exports) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.ViewHistory = void 0; const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20; @@ -12442,24 +14733,25 @@ class ViewHistory { exports.ViewHistory = ViewHistory; /***/ }), -/* 35 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 42 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.GenericCom = void 0; -var _app = __webpack_require__(1); +var _app = __webpack_require__(4); -var _preferences = __webpack_require__(36); +var _preferences = __webpack_require__(43); -var _download_manager = __webpack_require__(37); +var _download_manager = __webpack_require__(44); -var _genericl10n = __webpack_require__(38); +var _genericl10n = __webpack_require__(45); + +var _generic_scripting = __webpack_require__(47); ; const GenericCom = {}; @@ -12478,7 +14770,7 @@ class GenericPreferences extends _preferences.BasePreferences { class GenericExternalServices extends _app.DefaultExternalServices { static createDownloadManager(options) { - return new _download_manager.DownloadManager(options); + return new _download_manager.DownloadManager(); } static createPreferences() { @@ -12491,87 +14783,75 @@ class GenericExternalServices extends _app.DefaultExternalServices { return new _genericl10n.GenericL10n(locale); } + static createScripting({ + sandboxBundleSrc + }) { + return new _generic_scripting.GenericScripting(sandboxBundleSrc); + } + } _app.PDFViewerApplication.externalServices = GenericExternalServices; /***/ }), -/* 36 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 43 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.BasePreferences = void 0; -var _app_options = __webpack_require__(3); - -let defaultPreferences = null; - -function getDefaultPreferences() { - if (!defaultPreferences) { - defaultPreferences = Promise.resolve({ - "cursorToolOnLoad": 0, - "defaultZoomValue": "", - "disablePageLabels": false, - "enablePermissions": false, - "enablePrintAutoRotate": false, - "enableWebGL": false, - "externalLinkTarget": 0, - "historyUpdateUrl": false, - "ignoreDestinationZoom": false, - "pdfBugEnabled": false, - "renderer": "canvas", - "renderInteractiveForms": true, - "sidebarViewOnLoad": -1, - "scrollModeOnLoad": -1, - "spreadModeOnLoad": -1, - "textLayerMode": 1, - "useOnlyCssZoom": false, - "viewOnLoad": 0, - "disableAutoFetch": false, - "disableFontFace": false, - "disableRange": false, - "disableStream": false - }); - } - - return defaultPreferences; -} +var _app_options = __webpack_require__(2); class BasePreferences { + #defaults = Object.freeze({ + "annotationEditorMode": -1, + "annotationMode": 2, + "cursorToolOnLoad": 0, + "defaultZoomValue": "", + "disablePageLabels": false, + "enablePermissions": false, + "enablePrintAutoRotate": true, + "enableScripting": true, + "externalLinkTarget": 0, + "historyUpdateUrl": false, + "ignoreDestinationZoom": false, + "forcePageColors": false, + "pageColorsBackground": "Canvas", + "pageColorsForeground": "CanvasText", + "pdfBugEnabled": false, + "sidebarViewOnLoad": -1, + "scrollModeOnLoad": -1, + "spreadModeOnLoad": -1, + "textLayerMode": 1, + "useOnlyCssZoom": false, + "viewerCssTheme": 0, + "viewOnLoad": 0, + "disableAutoFetch": false, + "disableFontFace": false, + "disableRange": false, + "disableStream": false, + "enableXfa": true, + "renderer": "canvas" + }); + #prefs = Object.create(null); + #initializedPromise = null; + constructor() { if (this.constructor === BasePreferences) { throw new Error("Cannot initialize BasePreferences."); } - this.prefs = null; - this._initializedPromise = getDefaultPreferences().then(defaults => { - Object.defineProperty(this, "defaults", { - value: Object.freeze(defaults), - writable: false, - enumerable: true, - configurable: false - }); - this.prefs = Object.assign(Object.create(null), defaults); - return this._readFromStorage(defaults); - }).then(prefs => { - if (!prefs) { - return; - } + this.#initializedPromise = this._readFromStorage(this.#defaults).then(prefs => { + for (const name in this.#defaults) { + const prefValue = prefs?.[name]; - for (const name in prefs) { - const defaultValue = this.defaults[name], - prefValue = prefs[name]; - - if (defaultValue === undefined || typeof prefValue !== typeof defaultValue) { - continue; + if (typeof prefValue === typeof this.#defaults[name]) { + this.#prefs[name] = prefValue; } - - this.prefs[name] = prefValue; } }); } @@ -12585,14 +14865,19 @@ class BasePreferences { } async reset() { - await this._initializedPromise; - this.prefs = Object.assign(Object.create(null), this.defaults); - return this._writeToStorage(this.defaults); + await this.#initializedPromise; + const prefs = this.#prefs; + this.#prefs = Object.create(null); + return this._writeToStorage(this.#defaults).catch(reason => { + this.#prefs = prefs; + throw reason; + }); } async set(name, value) { - await this._initializedPromise; - const defaultValue = this.defaults[name]; + await this.#initializedPromise; + const defaultValue = this.#defaults[name], + prefs = this.#prefs; if (defaultValue === undefined) { throw new Error(`Set preference: "${name}" is undefined.`); @@ -12600,14 +14885,14 @@ class BasePreferences { throw new Error("Set preference: no value is specified."); } - const valueType = typeof value; - const defaultType = typeof defaultValue; + const valueType = typeof value, + defaultType = typeof defaultValue; if (valueType !== defaultType) { if (valueType === "number" && defaultType === "string") { value = value.toString(); } else { - throw new Error(`Set preference: "${value}" is a ${valueType}, ` + `expected a ${defaultType}.`); + throw new Error(`Set preference: "${value}" is a ${valueType}, expected a ${defaultType}.`); } } else { if (valueType === "number" && !Number.isInteger(value)) { @@ -12615,30 +14900,33 @@ class BasePreferences { } } - this.prefs[name] = value; - return this._writeToStorage(this.prefs); + this.#prefs[name] = value; + return this._writeToStorage(this.#prefs).catch(reason => { + this.#prefs = prefs; + throw reason; + }); } async get(name) { - await this._initializedPromise; - const defaultValue = this.defaults[name]; + await this.#initializedPromise; + const defaultValue = this.#defaults[name]; if (defaultValue === undefined) { throw new Error(`Get preference: "${name}" is undefined.`); - } else { - const prefValue = this.prefs[name]; - - if (prefValue !== undefined) { - return prefValue; - } } - return defaultValue; + return this.#prefs[name] ?? defaultValue; } async getAll() { - await this._initializedPromise; - return Object.assign(Object.create(null), this.defaults, this.prefs); + await this.#initializedPromise; + const obj = Object.create(null); + + for (const name in this.#defaults) { + obj[name] = this.#prefs[name] ?? this.#defaults[name]; + } + + return obj; } } @@ -12646,21 +14934,18 @@ class BasePreferences { exports.BasePreferences = BasePreferences; /***/ }), -/* 37 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 44 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.DownloadManager = void 0; var _pdfjsLib = __webpack_require__(5); -var _viewer_compatibility = __webpack_require__(4); - ; function download(blobUrl, filename) { @@ -12677,14 +14962,19 @@ function download(blobUrl, filename) { a.download = filename; } - (document.body || document.documentElement).appendChild(a); + (document.body || document.documentElement).append(a); a.click(); a.remove(); } class DownloadManager { + constructor() { + this._openBlobUrls = new WeakMap(); + } + downloadUrl(url, filename) { if (!(0, _pdfjsLib.createValidAbsoluteUrl)(url, "http://example.com")) { + console.error(`downloadUrl - not a valid URL: ${url}`); return; } @@ -12692,31 +14982,46 @@ class DownloadManager { } downloadData(data, filename, contentType) { - if (navigator.msSaveBlob) { - navigator.msSaveBlob(new Blob([data], { - type: contentType - }), filename); - return; - } - - const blobUrl = (0, _pdfjsLib.createObjectURL)(data, contentType, _viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL); + const blobUrl = URL.createObjectURL(new Blob([data], { + type: contentType + })); download(blobUrl, filename); } - download(blob, url, filename, sourceEventType = "download") { - if (navigator.msSaveBlob) { - if (!navigator.msSaveBlob(blob, filename)) { - this.downloadUrl(url, filename); + openOrDownloadData(element, data, filename) { + const isPdfData = (0, _pdfjsLib.isPdfFile)(filename); + const contentType = isPdfData ? "application/pdf" : ""; + + if (isPdfData) { + let blobUrl = this._openBlobUrls.get(element); + + if (!blobUrl) { + blobUrl = URL.createObjectURL(new Blob([data], { + type: contentType + })); + + this._openBlobUrls.set(element, blobUrl); } - return; + let viewerUrl; + viewerUrl = "?file=" + encodeURIComponent(blobUrl + "#" + filename); + + try { + window.open(viewerUrl); + return true; + } catch (ex) { + console.error(`openOrDownloadData: ${ex}`); + URL.revokeObjectURL(blobUrl); + + this._openBlobUrls.delete(element); + } } - if (_viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL) { - this.downloadUrl(url, filename); - return; - } + this.downloadData(data, filename, contentType); + return false; + } + download(blob, url, filename) { const blobUrl = URL.createObjectURL(blob); download(blobUrl, filename); } @@ -12726,18 +15031,19 @@ class DownloadManager { exports.DownloadManager = DownloadManager; /***/ }), -/* 38 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 45 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); exports.GenericL10n = void 0; -__webpack_require__(39); +__webpack_require__(46); + +var _l10n_utils = __webpack_require__(31); const webL10n = document.webL10n; @@ -12745,7 +15051,7 @@ class GenericL10n { constructor(lang) { this._lang = lang; this._ready = new Promise((resolve, reject) => { - webL10n.setLanguage(lang, () => { + webL10n.setLanguage((0, _l10n_utils.fixupLangCode)(lang), () => { resolve(webL10n); }); }); @@ -12761,9 +15067,9 @@ class GenericL10n { return l10n.getDirection(); } - async get(property, args, fallback) { + async get(key, args = null, fallback = (0, _l10n_utils.getL10nFallback)(key, args)) { const l10n = await this._ready; - return l10n.get(property, args, fallback); + return l10n.get(key, args, fallback); } async translate(element) { @@ -12776,10 +15082,9 @@ class GenericL10n { exports.GenericL10n = GenericL10n; /***/ }), -/* 39 */ -/***/ (function(module, exports, __webpack_require__) { +/* 46 */ +/***/ (() => { -"use strict"; document.webL10n = function (window, document, undefined) { @@ -13491,7 +15796,7 @@ document.webL10n = function (window, document, undefined) { if (!found) { var textNode = document.createTextNode(data[gTextProp]); - element.insertBefore(textNode, element.firstChild); + element.prepend(textNode); } } @@ -13599,39 +15904,105 @@ document.webL10n = function (window, document, undefined) { }(window, document); /***/ }), -/* 40 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +/* 47 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { -Object.defineProperty(exports, "__esModule", { + +Object.defineProperty(exports, "__esModule", ({ value: true -}); +})); +exports.GenericScripting = void 0; +exports.docPropertiesLookup = docPropertiesLookup; + +var _pdfjsLib = __webpack_require__(5); + +async function docPropertiesLookup(pdfDocument) { + const url = "", + baseUrl = url.split("#")[0]; + let { + info, + metadata, + contentDispositionFilename, + contentLength + } = await pdfDocument.getMetadata(); + + if (!contentLength) { + const { + length + } = await pdfDocument.getDownloadInfo(); + contentLength = length; + } + + return { ...info, + baseURL: baseUrl, + filesize: contentLength, + filename: contentDispositionFilename || (0, _pdfjsLib.getPdfFilenameFromUrl)(url), + metadata: metadata?.getRaw(), + authors: metadata?.get("dc:creator"), + numPages: pdfDocument.numPages, + URL: url + }; +} + +class GenericScripting { + constructor(sandboxBundleSrc) { + this._ready = (0, _pdfjsLib.loadScript)(sandboxBundleSrc, true).then(() => { + return window.pdfjsSandbox.QuickJSSandbox(); + }); + } + + async createSandbox(data) { + const sandbox = await this._ready; + sandbox.create(data); + } + + async dispatchEventInSandbox(event) { + const sandbox = await this._ready; + setTimeout(() => sandbox.dispatchEvent(event), 0); + } + + async destroySandbox() { + const sandbox = await this._ready; + sandbox.nukeSandbox(); + } + +} + +exports.GenericScripting = GenericScripting; + +/***/ }), +/* 48 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); exports.PDFPrintService = PDFPrintService; -var _ui_utils = __webpack_require__(2); +var _pdfjsLib = __webpack_require__(5); -var _app = __webpack_require__(1); +var _app = __webpack_require__(4); -var _viewer_compatibility = __webpack_require__(4); +var _print_utils = __webpack_require__(49); let activeService = null; +let dialog = null; let overlayManager = null; -function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printResolution, optionalContentConfigPromise) { +function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise) { const scratchCanvas = activeService.scratchCanvas; - const PRINT_UNITS = printResolution / 72.0; + const PRINT_UNITS = printResolution / _pdfjsLib.PixelsPerInch.PDF; scratchCanvas.width = Math.floor(size.width * PRINT_UNITS); scratchCanvas.height = Math.floor(size.height * PRINT_UNITS); - const width = Math.floor(size.width * _ui_utils.CSS_UNITS) + "px"; - const height = Math.floor(size.height * _ui_utils.CSS_UNITS) + "px"; const ctx = scratchCanvas.getContext("2d"); ctx.save(); ctx.fillStyle = "rgb(255, 255, 255)"; ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height); ctx.restore(); - return pdfDocument.getPage(pageNumber).then(function (pdfPage) { + return Promise.all([pdfDocument.getPage(pageNumber), printAnnotationStoragePromise]).then(function ([pdfPage, printAnnotationStorage]) { const renderContext = { canvasContext: ctx, transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0], @@ -13640,25 +16011,22 @@ function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printRe rotation: size.rotation }), intent: "print", - annotationStorage: pdfDocument.annotationStorage, - optionalContentConfigPromise + annotationMode: _pdfjsLib.AnnotationMode.ENABLE_STORAGE, + optionalContentConfigPromise, + printAnnotationStorage }; return pdfPage.render(renderContext).promise; - }).then(function () { - return { - width, - height - }; }); } -function PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise = null, l10n) { +function PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise = null, printAnnotationStoragePromise = null, l10n) { this.pdfDocument = pdfDocument; this.pagesOverview = pagesOverview; this.printContainer = printContainer; this._printResolution = printResolution || 150; this._optionalContentConfigPromise = optionalContentConfigPromise || pdfDocument.getOptionalContentConfig(); - this.l10n = l10n || _ui_utils.NullL10n; + this._printAnnotationStoragePromise = printAnnotationStoragePromise || Promise.resolve(); + this.l10n = l10n; this.currentPage = -1; this.scratchCanvas = document.createElement("canvas"); } @@ -13678,8 +16046,8 @@ PDFPrintService.prototype = { this.pageStyleSheet = document.createElement("style"); const pageSize = this.pagesOverview[0]; - this.pageStyleSheet.textContent = "@supports ((size:A4) and (size:1pt 1pt)) {" + "@page { size: " + pageSize.width + "pt " + pageSize.height + "pt;}" + "}"; - body.appendChild(this.pageStyleSheet); + this.pageStyleSheet.textContent = "@page { size: " + pageSize.width + "pt " + pageSize.height + "pt;}"; + body.append(this.pageStyleSheet); }, destroy() { @@ -13700,15 +16068,18 @@ PDFPrintService.prototype = { this.scratchCanvas = null; activeService = null; ensureOverlay().then(function () { - if (overlayManager.active !== "printServiceOverlay") { - return; + if (overlayManager.active === dialog) { + overlayManager.close(dialog); } - - overlayManager.close("printServiceOverlay"); }); }, renderPages() { + if (this.pdfDocument.isPureXfa) { + (0, _print_utils.getXfaHtmlForPrinting)(this.printContainer, this.pdfDocument); + return Promise.resolve(); + } + const pageCount = this.pagesOverview.length; const renderNextPage = (resolve, reject) => { @@ -13722,7 +16093,7 @@ PDFPrintService.prototype = { const index = this.currentPage; renderProgress(index, pageCount, this.l10n); - renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index], this._printResolution, this._optionalContentConfigPromise).then(this.useRenderedPage.bind(this)).then(function () { + renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index], this._printResolution, this._optionalContentConfigPromise, this._printAnnotationStoragePromise).then(this.useRenderedPage.bind(this)).then(function () { renderNextPage(resolve, reject); }, reject); }; @@ -13730,14 +16101,12 @@ PDFPrintService.prototype = { return new Promise(renderNextPage); }, - useRenderedPage(printItem) { + useRenderedPage() { this.throwIfInactive(); const img = document.createElement("img"); - img.style.width = printItem.width; - img.style.height = printItem.height; const scratchCanvas = this.scratchCanvas; - if ("toBlob" in scratchCanvas && !_viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL) { + if ("toBlob" in scratchCanvas) { scratchCanvas.toBlob(function (blob) { img.src = URL.createObjectURL(blob); }); @@ -13746,8 +16115,9 @@ PDFPrintService.prototype = { } const wrapper = document.createElement("div"); - wrapper.appendChild(img); - this.printContainer.appendChild(wrapper); + wrapper.className = "printedPage"; + wrapper.append(img); + this.printContainer.append(wrapper); return new Promise(function (resolve, reject) { img.onload = resolve; img.onerror = reject; @@ -13790,7 +16160,7 @@ window.print = function () { ensureOverlay().then(function () { if (activeService) { - overlayManager.open("printServiceOverlay"); + overlayManager.open(dialog); } }); @@ -13800,8 +16170,8 @@ window.print = function () { if (!activeService) { console.error("Expected print service to be initialized."); ensureOverlay().then(function () { - if (overlayManager.active === "printServiceOverlay") { - overlayManager.close("printServiceOverlay"); + if (overlayManager.active === dialog) { + overlayManager.close(dialog); } }); return; @@ -13832,14 +16202,14 @@ function abort() { } function renderProgress(index, total, l10n) { - const progressContainer = document.getElementById("printServiceOverlay"); + dialog ||= document.getElementById("printServiceDialog"); const progress = Math.round(100 * index / total); - const progressBar = progressContainer.querySelector("progress"); - const progressPerc = progressContainer.querySelector(".relative-progress"); + const progressBar = dialog.querySelector("progress"); + const progressPerc = dialog.querySelector(".relative-progress"); progressBar.value = progress; l10n.get("print_progress_percent", { progress - }, progress + "%").then(msg => { + }).then(msg => { progressPerc.textContent = msg; }); } @@ -13878,8 +16248,10 @@ function ensureOverlay() { throw new Error("The overlay manager has not yet been initialized."); } - overlayPromise = overlayManager.register("printServiceOverlay", document.getElementById("printServiceOverlay"), abort, true); + dialog ||= document.getElementById("printServiceDialog"); + overlayPromise = overlayManager.register(dialog, true); document.getElementById("printCancel").onclick = abort; + dialog.addEventListener("close", abort); } return overlayPromise; @@ -13888,17 +16260,295 @@ function ensureOverlay() { _app.PDFPrintServiceFactory.instance = { supportsPrinting: true, - createPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, l10n) { + createPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise, l10n) { if (activeService) { throw new Error("The print service is created and active."); } - activeService = new PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, l10n); + activeService = new PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise, l10n); return activeService; } }; +/***/ }), +/* 49 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.getXfaHtmlForPrinting = getXfaHtmlForPrinting; + +var _pdfjsLib = __webpack_require__(5); + +var _pdf_link_service = __webpack_require__(3); + +var _xfa_layer_builder = __webpack_require__(38); + +function getXfaHtmlForPrinting(printContainer, pdfDocument) { + const xfaHtml = pdfDocument.allXfaHtml; + const linkService = new _pdf_link_service.SimpleLinkService(); + const scale = Math.round(_pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS * 100) / 100; + + for (const xfaPage of xfaHtml.children) { + const page = document.createElement("div"); + page.className = "xfaPrintedPage"; + printContainer.append(page); + const builder = new _xfa_layer_builder.XfaLayerBuilder({ + pageDiv: page, + pdfPage: null, + annotationStorage: pdfDocument.annotationStorage, + linkService, + xfaHtml: xfaPage + }); + const viewport = (0, _pdfjsLib.getXfaPageViewport)(xfaPage, { + scale + }); + builder.render(viewport, "print"); + } +} + /***/ }) -/******/ ]); +/******/ ]); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +var exports = __webpack_exports__; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +Object.defineProperty(exports, "PDFViewerApplication", ({ + enumerable: true, + get: function () { + return _app.PDFViewerApplication; + } +})); +exports.PDFViewerApplicationConstants = void 0; +Object.defineProperty(exports, "PDFViewerApplicationOptions", ({ + enumerable: true, + get: function () { + return _app_options.AppOptions; + } +})); + +var _ui_utils = __webpack_require__(1); + +var _app_options = __webpack_require__(2); + +var _pdf_link_service = __webpack_require__(3); + +var _app = __webpack_require__(4); + +const pdfjsVersion = '2.16.105'; +const pdfjsBuild = '172ccdbe5'; +const AppConstants = { + LinkTarget: _pdf_link_service.LinkTarget, + RenderingStates: _ui_utils.RenderingStates, + ScrollMode: _ui_utils.ScrollMode, + SpreadMode: _ui_utils.SpreadMode +}; +exports.PDFViewerApplicationConstants = AppConstants; +window.PDFViewerApplication = _app.PDFViewerApplication; +window.PDFViewerApplicationConstants = AppConstants; +window.PDFViewerApplicationOptions = _app_options.AppOptions; +; +; +{ + __webpack_require__(42); +} +; +{ + __webpack_require__(48); +} + +function getViewerConfiguration() { + let errorWrapper = null; + errorWrapper = { + container: document.getElementById("errorWrapper"), + errorMessage: document.getElementById("errorMessage"), + closeButton: document.getElementById("errorClose"), + errorMoreInfo: document.getElementById("errorMoreInfo"), + moreInfoButton: document.getElementById("errorShowMore"), + lessInfoButton: document.getElementById("errorShowLess") + }; + return { + appContainer: document.body, + mainContainer: document.getElementById("viewerContainer"), + viewerContainer: document.getElementById("viewer"), + toolbar: { + container: document.getElementById("toolbarViewer"), + numPages: document.getElementById("numPages"), + pageNumber: document.getElementById("pageNumber"), + scaleSelect: document.getElementById("scaleSelect"), + customScaleOption: document.getElementById("customScaleOption"), + previous: document.getElementById("previous"), + next: document.getElementById("next"), + zoomIn: document.getElementById("zoomIn"), + zoomOut: document.getElementById("zoomOut"), + viewFind: document.getElementById("viewFind"), + openFile: document.getElementById("openFile"), + print: document.getElementById("print"), + editorFreeTextButton: document.getElementById("editorFreeText"), + editorFreeTextParamsToolbar: document.getElementById("editorFreeTextParamsToolbar"), + editorInkButton: document.getElementById("editorInk"), + editorInkParamsToolbar: document.getElementById("editorInkParamsToolbar"), + presentationModeButton: document.getElementById("presentationMode"), + download: document.getElementById("download"), + viewBookmark: document.getElementById("viewBookmark") + }, + secondaryToolbar: { + toolbar: document.getElementById("secondaryToolbar"), + toggleButton: document.getElementById("secondaryToolbarToggle"), + presentationModeButton: document.getElementById("secondaryPresentationMode"), + openFileButton: document.getElementById("secondaryOpenFile"), + printButton: document.getElementById("secondaryPrint"), + downloadButton: document.getElementById("secondaryDownload"), + viewBookmarkButton: document.getElementById("secondaryViewBookmark"), + firstPageButton: document.getElementById("firstPage"), + lastPageButton: document.getElementById("lastPage"), + pageRotateCwButton: document.getElementById("pageRotateCw"), + pageRotateCcwButton: document.getElementById("pageRotateCcw"), + cursorSelectToolButton: document.getElementById("cursorSelectTool"), + cursorHandToolButton: document.getElementById("cursorHandTool"), + scrollPageButton: document.getElementById("scrollPage"), + scrollVerticalButton: document.getElementById("scrollVertical"), + scrollHorizontalButton: document.getElementById("scrollHorizontal"), + scrollWrappedButton: document.getElementById("scrollWrapped"), + spreadNoneButton: document.getElementById("spreadNone"), + spreadOddButton: document.getElementById("spreadOdd"), + spreadEvenButton: document.getElementById("spreadEven"), + documentPropertiesButton: document.getElementById("documentProperties") + }, + sidebar: { + outerContainer: document.getElementById("outerContainer"), + sidebarContainer: document.getElementById("sidebarContainer"), + toggleButton: document.getElementById("sidebarToggle"), + thumbnailButton: document.getElementById("viewThumbnail"), + outlineButton: document.getElementById("viewOutline"), + attachmentsButton: document.getElementById("viewAttachments"), + layersButton: document.getElementById("viewLayers"), + thumbnailView: document.getElementById("thumbnailView"), + outlineView: document.getElementById("outlineView"), + attachmentsView: document.getElementById("attachmentsView"), + layersView: document.getElementById("layersView"), + outlineOptionsContainer: document.getElementById("outlineOptionsContainer"), + currentOutlineItemButton: document.getElementById("currentOutlineItem") + }, + sidebarResizer: { + outerContainer: document.getElementById("outerContainer"), + resizer: document.getElementById("sidebarResizer") + }, + findBar: { + bar: document.getElementById("findbar"), + toggleButton: document.getElementById("viewFind"), + findField: document.getElementById("findInput"), + highlightAllCheckbox: document.getElementById("findHighlightAll"), + caseSensitiveCheckbox: document.getElementById("findMatchCase"), + matchDiacriticsCheckbox: document.getElementById("findMatchDiacritics"), + entireWordCheckbox: document.getElementById("findEntireWord"), + findMsg: document.getElementById("findMsg"), + findResultsCount: document.getElementById("findResultsCount"), + findPreviousButton: document.getElementById("findPrevious"), + findNextButton: document.getElementById("findNext") + }, + passwordOverlay: { + dialog: document.getElementById("passwordDialog"), + label: document.getElementById("passwordText"), + input: document.getElementById("password"), + submitButton: document.getElementById("passwordSubmit"), + cancelButton: document.getElementById("passwordCancel") + }, + documentProperties: { + dialog: document.getElementById("documentPropertiesDialog"), + closeButton: document.getElementById("documentPropertiesClose"), + fields: { + fileName: document.getElementById("fileNameField"), + fileSize: document.getElementById("fileSizeField"), + title: document.getElementById("titleField"), + author: document.getElementById("authorField"), + subject: document.getElementById("subjectField"), + keywords: document.getElementById("keywordsField"), + creationDate: document.getElementById("creationDateField"), + modificationDate: document.getElementById("modificationDateField"), + creator: document.getElementById("creatorField"), + producer: document.getElementById("producerField"), + version: document.getElementById("versionField"), + pageCount: document.getElementById("pageCountField"), + pageSize: document.getElementById("pageSizeField"), + linearized: document.getElementById("linearizedField") + } + }, + annotationEditorParams: { + editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"), + editorFreeTextColor: document.getElementById("editorFreeTextColor"), + editorInkColor: document.getElementById("editorInkColor"), + editorInkThickness: document.getElementById("editorInkThickness"), + editorInkOpacity: document.getElementById("editorInkOpacity") + }, + errorWrapper, + printContainer: document.getElementById("printContainer"), + openFileInput: document.getElementById("fileInput"), + debuggerScriptPath: "./debugger.js" + }; +} + +function webViewerLoad() { + const config = getViewerConfiguration(); + const event = document.createEvent("CustomEvent"); + event.initCustomEvent("webviewerloaded", true, true, { + source: window + }); + + try { + parent.document.dispatchEvent(event); + } catch (ex) { + console.error(`webviewerloaded: ${ex}`); + document.dispatchEvent(event); + } + + _app.PDFViewerApplication.run(config); +} + +document.blockUnblockOnload?.(true); + +if (document.readyState === "interactive" || document.readyState === "complete") { + webViewerLoad(); +} else { + document.addEventListener("DOMContentLoaded", webViewerLoad, true); +} +})(); + +/******/ })() +; //# sourceMappingURL=viewer.js.map diff --git a/cps/static/js/main.js b/cps/static/js/main.js index 7a59b172c..4ff73d721 100644 --- a/cps/static/js/main.js +++ b/cps/static/js/main.js @@ -20,6 +20,20 @@ function getPath() { return jsFileLocation.substr(0, jsFileLocation.search("/static/js/libs/jquery.min.js")); // the js folder path } +function postButton(event, action){ + event.preventDefault(); + var newForm = jQuery('
      ', { + "action": action, + 'target': "_top", + 'method': "post" + }).append(jQuery('', { + 'name': 'csrf_token', + 'value': $("input[name=\'csrf_token\']").val(), + 'type': 'hidden' + })).appendTo('body'); + newForm.submit(); +} + function elementSorter(a, b) { a = +a.slice(0, -2); b = +b.slice(0, -2); @@ -71,6 +85,22 @@ $(document).on("change", "select[data-controlall]", function() { } }); +/*$(document).on("click", "#sendbtn", function (event) { + postButton(event, $(this).data('action')); +}); + +$(document).on("click", ".sendbutton", function (event) { + // $(".sendbutton").on("click", "body", function(event) { + postButton(event, $(this).data('action')); +});*/ + +$(document).on("click", ".postAction", function (event) { + // $(".sendbutton").on("click", "body", function(event) { + postButton(event, $(this).data('action')); +}); + + + // Syntax has to be bind not on, otherwise problems with firefox $(".container-fluid").bind("dragenter dragover", function () { if($("#btn-upload").length && !$('body').hasClass('shelforder')) { @@ -168,18 +198,18 @@ function confirmDialog(id, dialogid, dataValue, yesFn, noFn) { $confirm.modal('show'); } -$("#delete_confirm").click(function() { +$("#delete_confirm").click(function(event) { //get data-id attribute of the clicked element var deleteId = $(this).data("delete-id"); var bookFormat = $(this).data("delete-format"); var ajaxResponse = $(this).data("ajax"); if (bookFormat) { - window.location.href = getPath() + "/delete/" + deleteId + "/" + bookFormat; + postButton(event, getPath() + "/delete/" + deleteId + "/" + bookFormat); } else { if (ajaxResponse) { path = getPath() + "/ajax/delete/" + deleteId; $.ajax({ - method:"get", + method:"post", url: path, timeout: 900, success:function(data) { @@ -198,8 +228,7 @@ $("#delete_confirm").click(function() { } }); } else { - window.location.href = getPath() + "/delete/" + deleteId; - + postButton(event, getPath() + "/delete/" + deleteId); } } @@ -284,11 +313,7 @@ $(function() { } function fillFileTable(path, type, folder, filt) { - if (window.location.pathname.endsWith("/basicconfig")) { - var request_path = "/../basicconfig/pathchooser/"; - } else { - var request_path = "/../../ajax/pathchooser/"; - } + var request_path = "/../../ajax/pathchooser/"; $.ajax({ dataType: "json", data: { @@ -339,12 +364,6 @@ $(function() { layoutMode : "fitRows" }); - $(".grid").isotope({ - // options - itemSelector : ".grid-item", - layoutMode : "fitColumns" - }); - if ($(".load-more").length && $(".next").length) { var $loadMore = $(".load-more .row").infiniteScroll({ debug: false, @@ -356,8 +375,8 @@ $(function() { //extraScrollPx: 300 }); $loadMore.on( "append.infiniteScroll", function( event, response, path, data ) { + $(".pagination").addClass("hidden").html(() => $(response).find(".pagination").html()); if ($("body").hasClass("blur")) { - $(".pagination").addClass("hidden").html(() => $(response).find(".pagination").html()); $(" a:not(.dropdown-toggle) ") .removeAttr("data-toggle"); } @@ -380,9 +399,11 @@ $(function() { $("#restart").click(function() { $.ajax({ + method:"post", + contentType: "application/json; charset=utf-8", dataType: "json", - url: window.location.pathname + "/../../shutdown", - data: {"parameter":0}, + url: getPath() + "/shutdown", + data: JSON.stringify({"parameter":0}), success: function success() { $("#spinner").show(); setTimeout(restartTimer, 3000); @@ -391,9 +412,11 @@ $(function() { }); $("#shutdown").click(function() { $.ajax({ + method:"post", + contentType: "application/json; charset=utf-8", dataType: "json", - url: window.location.pathname + "/../../shutdown", - data: {"parameter":1}, + url: getPath() + "/shutdown", + data: JSON.stringify({"parameter":1}), success: function success(data) { return alert(data.text); } @@ -445,15 +468,45 @@ $(function() { } }); }); + $("#admin_refresh_cover_cache").click(function() { + confirmDialog("admin_refresh_cover_cache", "GeneralChangeModal", 0, function () { + $.ajax({ + method:"post", + contentType: "application/json; charset=utf-8", + dataType: "json", + url: getPath() + "/ajax/updateThumbnails", + }); + }); + }); + $("#restart_database").click(function() { $("#DialogHeader").addClass("hidden"); $("#DialogFinished").addClass("hidden"); $("#DialogContent").html(""); $("#spinner2").show(); $.ajax({ + method:"post", + contentType: "application/json; charset=utf-8", dataType: "json", url: getPath() + "/shutdown", - data: {"parameter":2}, + data: JSON.stringify({"parameter":2}), + success: function success(data) { + $("#spinner2").hide(); + $("#DialogContent").html(data.text); + $("#DialogFinished").removeClass("hidden"); + } + }); + }); + $("#metadata_backup").click(function() { + $("#DialogHeader").addClass("hidden"); + $("#DialogFinished").addClass("hidden"); + $("#DialogContent").html(""); + $("#spinner2").show(); + $.ajax({ + method: "post", + contentType: "application/json; charset=utf-8", + dataType: "json", + url: getPath() + "/metadata_backup", success: function success(data) { $("#spinner2").hide(); $("#DialogContent").html(data.text); @@ -484,6 +537,7 @@ $(function() { $("#bookDetailsModal") .on("show.bs.modal", function(e) { + $("#flash_danger").remove(); var $modalBody = $(this).find(".modal-body"); // Prevent static assets from loading multiple times @@ -504,6 +558,7 @@ $(function() { $("#modal_kobo_token") .on("show.bs.modal", function(e) { + $(e.relatedTarget).one('focus', function(e){$(this).blur();}); var $modalBody = $(this).find(".modal-body"); // Prevent static assets from loading multiple times @@ -521,6 +576,7 @@ $(function() { .on("hidden.bs.modal", function() { $(this).find(".modal-body").html("..."); $("#config_delete_kobo_token").show(); + $("#kobo_full_sync").show(); }); $("#config_delete_kobo_token").click(function() { @@ -530,10 +586,11 @@ $(function() { $(this).data('value'), function (value) { $.ajax({ - method: "get", + method: "post", url: getPath() + "/kobo_auth/deleteauthtoken/" + value, }); $("#config_delete_kobo_token").hide(); + $("#kobo_full_sync").hide(); } ); }); @@ -567,6 +624,33 @@ $(function() { } ); }); + + $("#kobo_full_sync").click(function() { + confirmDialog( + "btnfullsync", + "GeneralDeleteModal", + $(this).data('value'), + function(value){ + path = getPath() + "/ajax/fullsync" + $.ajax({ + method:"post", + url: path, + timeout: 900, + success:function(data) { + data.forEach(function(item) { + if (!jQuery.isEmptyObject(item)) { + $( ".navbar" ).after( '
      ' + + '
      '+item.message+'
      ' + + '
      '); + } + }); + } + }); + } + ); + }); + + $("#user_submit").click(function() { this.closest("form").submit(); }); @@ -604,8 +688,8 @@ $(function() { if ( data.change ) { if ( data.valid ) { confirmDialog( - "db_submit", - "GeneralChangeModal", + "db_submit", + "GeneralChangeModal", 0, changeDbSettings ); @@ -613,7 +697,7 @@ $(function() { else { $("#InvalidDialog").modal('show'); } - } else { + } else { changeDbSettings(); } } @@ -654,13 +738,14 @@ $(function() { }); }); - $("#delete_shelf").click(function() { + $("#delete_shelf").click(function(event) { confirmDialog( $(this).attr('id'), "GeneralDeleteModal", $(this).data('value'), function(value){ - window.location.href = window.location.pathname + "/../../shelf/delete/" + value + postButton(event, $("#delete_shelf").data("action")); + // $("#delete_shelf").closest("form").submit() } ); @@ -709,7 +794,8 @@ $(function() { $("#DialogContent").html(""); $("#spinner2").show(); $.ajax({ - method:"get", + method:"post", + contentType: "application/json; charset=utf-8", dataType: "json", url: getPath() + "/import_ldap_users", success: function success(data) { @@ -743,4 +829,3 @@ $(function() { }); }); }); - diff --git a/cps/static/js/reading/epub.js b/cps/static/js/reading/epub.js index edafa82c0..cfc12bad3 100644 --- a/cps/static/js/reading/epub.js +++ b/cps/static/js/reading/epub.js @@ -13,6 +13,11 @@ var reader; bookmarks: calibre.bookmark ? [calibre.bookmark] : [] }); + reader.rendition.themes.register("lightTheme", "/static/css/epub_themes.css"); + reader.rendition.themes.register("darkTheme", "/static/css/epub_themes.css"); + reader.rendition.themes.register("sepiaTheme", "/static/css/epub_themes.css"); + reader.rendition.themes.register("blackTheme", "/static/css/epub_themes.css"); + if (calibre.useBookmarks) { reader.on("reader:bookmarked", updateBookmark.bind(reader, "add")); reader.on("reader:unbookmarked", updateBookmark.bind(reader, "remove")); @@ -61,11 +66,14 @@ var reader; this.removeBookmark(bookmark); }.bind(this)); } + + var csrftoken = $("input[name='csrf_token']").val(); // Save to database $.ajax(calibre.bookmarkUrl, { method: "post", - data: { bookmark: location || "" } + data: { bookmark: location || "" }, + headers: { "X-CSRFToken": csrftoken } }).fail(function (xhr, status, error) { alert(error); }); diff --git a/cps/static/js/table.js b/cps/static/js/table.js index 0600f0b33..33c22a887 100644 --- a/cps/static/js/table.js +++ b/cps/static/js/table.js @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -/* exported TableActions, RestrictionActions, EbookActions, responseHandler */ +/* exported TableActions, RestrictionActions, EbookActions, TaskActions, responseHandler */ /* global getPath, confirmDialog */ var selections = []; @@ -42,20 +42,38 @@ $(function() { }, 1000); } + $("#cancel_task_confirm").click(function() { + //get data-id attribute of the clicked element + var taskId = $(this).data("task-id"); + $.ajax({ + method: "post", + contentType: "application/json; charset=utf-8", + dataType: "json", + url: window.location.pathname + "/../ajax/canceltask", + data: JSON.stringify({"task_id": taskId}), + }); + }); + //triggered when modal is about to be shown + $("#cancelTaskModal").on("show.bs.modal", function(e) { + //get data-id attribute of the clicked element and store in button + var taskId = $(e.relatedTarget).data("task-id"); + $(e.currentTarget).find("#cancel_task_confirm").data("task-id", taskId); + }); + $("#books-table").on("check.bs.table check-all.bs.table uncheck.bs.table uncheck-all.bs.table", function (e, rowsAfter, rowsBefore) { var rows = rowsAfter; if (e.type === "uncheck-all") { - rows = rowsBefore; + selections = []; + } else { + var ids = $.map(!$.isArray(rows) ? [rows] : rows, function (row) { + return row.id; + }); + + var func = $.inArray(e.type, ["check", "check-all"]) > -1 ? "union" : "difference"; + selections = window._[func](selections, ids); } - - var ids = $.map(!$.isArray(rows) ? [rows] : rows, function (row) { - return row.id; - }); - - var func = $.inArray(e.type, ["check", "check-all"]) > -1 ? "union" : "difference"; - selections = window._[func](selections, ids); if (selections.length >= 2) { $("#merge_books").removeClass("disabled"); $("#merge_books").attr("aria-disabled", false); @@ -107,8 +125,9 @@ $(function() { url: window.location.pathname + "/../ajax/simulatemerge", data: JSON.stringify({"Merge_books":selections}), success: function success(booTitles) { + $('#merge_from').empty(); $.each(booTitles.from, function(i, item) { - $("- " + item + "").appendTo("#merge_from"); + $("- " + item + "

      ").appendTo("#merge_from"); }); $("#merge_to").text("- " + booTitles.to); @@ -529,25 +548,19 @@ $(function() { }, }); - $("#user-table").on("click-cell.bs.table", function (field, value, row, $element) { - if (value === "denied_column_value") { - ConfirmDialog("btndeluser", "GeneralDeleteModal", $element.id, user_handle); - } - }); - $("#user-table").on("check.bs.table check-all.bs.table uncheck.bs.table uncheck-all.bs.table", function (e, rowsAfter, rowsBefore) { var rows = rowsAfter; if (e.type === "uncheck-all") { - rows = rowsBefore; + selections = []; + } else { + var ids = $.map(!$.isArray(rows) ? [rows] : rows, function (row) { + return row.id; + }); + var func = $.inArray(e.type, ["check", "check-all"]) > -1 ? "union" : "difference"; + selections = window._[func](selections, ids); } - - var ids = $.map(!$.isArray(rows) ? [rows] : rows, function (row) { - return row.id; - }); - var func = $.inArray(e.type, ["check", "check-all"]) > -1 ? "union" : "difference"; - selections = window._[func](selections, ids); handle_header_buttons(); }); }); @@ -581,6 +594,7 @@ function handle_header_buttons () { $(".header_select").removeAttr("disabled"); } } + /* Function for deleting domain restrictions */ function TableActions (value, row) { return [ @@ -618,6 +632,19 @@ function UserActions (value, row) { ].join(""); } +/* Function for cancelling tasks */ +function TaskActions (value, row) { + var cancellableStats = [0, 1, 2]; + if (row.task_id && row.is_cancellable && cancellableStats.includes(row.stat)) { + return [ + "
      ", + "", + "
      " + ].join(""); + } + return ''; +} + /* Function for keeping checked rows */ function responseHandler(res) { $.each(res.rows, function (i, row) { @@ -631,14 +658,21 @@ function singleUserFormatter(value, row) { } function checkboxFormatter(value, row){ - if(value & this.column) + if (value & this.column) return ''; else return ''; } +function bookCheckboxFormatter(value, row){ + if (value) + return ''; + else + return ''; +} + function singlecheckboxFormatter(value, row){ - if(value) + if (value) return ''; else return ''; @@ -793,7 +827,7 @@ function handleListServerResponse (data) { function checkboxChange(checkbox, userId, field, field_index) { $.ajax({ method: "post", - url: window.location.pathname + "/../../ajax/editlistusers/" + field, + url: getPath() + "/ajax/editlistusers/" + field, data: {"pk": userId, "field_index": field_index, "value": checkbox.checked}, error: function(data) { handleListServerResponse([{type:"danger", message:data.responseText}]) @@ -802,6 +836,22 @@ function checkboxChange(checkbox, userId, field, field_index) { }); } +function BookCheckboxChange(checkbox, userId, field) { + var value = checkbox.checked ? "True" : "False"; + var element = checkbox; + $.ajax({ + method: "post", + url: getPath() + "/ajax/editbooks/" + field, + data: {"pk": userId, "value": value}, + error: function(data) { + element.checked = !element.checked; + handleListServerResponse([{type:"danger", message:data.responseText}]) + }, + success: handleListServerResponse + }); +} + + function selectHeader(element, field) { if (element.value !== "None") { confirmDialog(element.id, "GeneralChangeModal", 0, function () { diff --git a/cps/static/locale/ach/viewer.properties b/cps/static/locale/ach/viewer.properties index 46e36fb7e..3a74d767b 100644 --- a/cps/static/locale/ach/viewer.properties +++ b/cps/static/locale/ach/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Neno ma kombedi tools.title=Gintic tools_label=Gintic first_page.title=Cit i pot buk mukwongo -first_page.label=Cit i pot buk mukwongo first_page_label=Cit i pot buk mukwongo last_page.title=Cit i pot buk magiko -last_page.label=Cit i pot buk magiko last_page_label=Cit i pot buk magiko page_rotate_cw.title=Wire i tung lacuc -page_rotate_cw.label=Wire i tung lacuc page_rotate_cw_label=Wire i tung lacuc page_rotate_ccw.title=Wire i tung lacam -page_rotate_ccw.label=Wire i tung lacam page_rotate_ccw_label=Wire i tung lacam cursor_text_select_tool.title=Cak gitic me yero coc @@ -124,7 +120,6 @@ print_progress_close=Juki # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Lok gintic ma inget -toggle_sidebar_notification.title=Lok lanyut me nget (wiyewiye tye i gin acoya/attachments) toggle_sidebar_label=Lok gintic ma inget document_outline.title=Nyut Wiyewiye me Gin acoya (dii-kiryo me yaro/kano jami weng) document_outline_label=Pek pa gin acoya @@ -184,8 +179,6 @@ page_scale_actual=Dite kikome # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Bal loading_error=Bal otime kun cano PDF. invalid_file_error=Pwail me PDF ma pe atir onyo obale woko. missing_file_error=Pwail me PDF tye ka rem. diff --git a/cps/static/locale/af/viewer.properties b/cps/static/locale/af/viewer.properties index c7d6c42b4..9bd5476da 100644 --- a/cps/static/locale/af/viewer.properties +++ b/cps/static/locale/af/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Huidige aansig tools.title=Nutsgoed tools_label=Nutsgoed first_page.title=Gaan na eerste bladsy -first_page.label=Gaan na eerste bladsy first_page_label=Gaan na eerste bladsy last_page.title=Gaan na laaste bladsy -last_page.label=Gaan na laaste bladsy last_page_label=Gaan na laaste bladsy page_rotate_cw.title=Roteer kloksgewys -page_rotate_cw.label=Roteer kloksgewys page_rotate_cw_label=Roteer kloksgewys page_rotate_ccw.title=Roteer anti-kloksgewys -page_rotate_ccw.label=Roteer anti-kloksgewys page_rotate_ccw_label=Roteer anti-kloksgewys cursor_text_select_tool.title=Aktiveer gereedskap om teks te merk @@ -101,7 +97,6 @@ print_progress_close=Kanselleer # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Sypaneel aan/af -toggle_sidebar_notification.title=Sypaneel aan/af (dokument bevat skema/aanhegsels) toggle_sidebar_label=Sypaneel aan/af document_outline.title=Wys dokumentskema (dubbelklik om alle items oop/toe te vou) document_outline_label=Dokumentoorsig @@ -161,8 +156,6 @@ page_scale_actual=Werklike grootte # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Fout loading_error='n Fout het voorgekom met die laai van die PDF. invalid_file_error=Ongeldige of korrupte PDF-lêer. missing_file_error=PDF-lêer is weg. diff --git a/cps/static/locale/an/viewer.properties b/cps/static/locale/an/viewer.properties index 7e3504c77..16028f372 100644 --- a/cps/static/locale/an/viewer.properties +++ b/cps/static/locale/an/viewer.properties @@ -42,22 +42,18 @@ print_label=Imprentar download.title=Descargar download_label=Descargar bookmark.title=Vista actual (copiar u ubrir en una nueva finestra) -bookmark_label=Anvista actual +bookmark_label=Vista actual # Secondary toolbar and context menu tools.title=Ferramientas tools_label=Ferramientas first_page.title=Ir ta la primer pachina -first_page.label=Ir ta la primer pachina first_page_label=Ir ta la primer pachina last_page.title=Ir ta la zaguer pachina -last_page.label=Ir ta la zaguera pachina last_page_label=Ir ta la zaguer pachina page_rotate_cw.title=Chirar enta la dreita -page_rotate_cw.label=Chirar enta la dreita page_rotate_cw_label=Chira enta la dreita page_rotate_ccw.title=Chirar enta la zurda -page_rotate_ccw.label=Chirar en sentiu antihorario page_rotate_ccw_label=Chirar enta la zurda cursor_text_select_tool.title=Activar la ferramienta de selección de texto @@ -65,6 +61,20 @@ cursor_text_select_tool_label=Ferramienta de selección de texto cursor_hand_tool.title=Activar la ferramienta man cursor_hand_tool_label=Ferramienta man +scroll_vertical.title=Usar lo desplazamiento vertical +scroll_vertical_label=Desplazamiento vertical +scroll_horizontal.title=Usar lo desplazamiento horizontal +scroll_horizontal_label=Desplazamiento horizontal +scroll_wrapped.title=Activaar lo desplazamiento contino +scroll_wrapped_label=Desplazamiento contino + +spread_none.title=No unir vistas de pachinas +spread_none_label=Una pachina nomás +spread_odd.title=Mostrar vista de pachinas, con as impars a la zurda +spread_odd_label=Doble pachina, impar a la zurda +spread_even.title=Amostrar vista de pachinas, con as pars a la zurda +spread_even_label=Doble pachina, para a la zurda + # Document properties dialog box document_properties.title=Propiedatz d'o documento... document_properties_label=Propiedatz d'o documento... @@ -89,6 +99,28 @@ document_properties_creator=Creyador: document_properties_producer=Creyador de PDF: document_properties_version=Versión de PDF: document_properties_page_count=Numero de pachinas: +document_properties_page_size=Mida de pachina: +document_properties_page_size_unit_inches=pulgadas +document_properties_page_size_unit_millimeters=mm +document_properties_page_size_orientation_portrait=vertical +document_properties_page_size_orientation_landscape=horizontal +document_properties_page_size_name_a3=A3 +document_properties_page_size_name_a4=A4 +document_properties_page_size_name_letter=Carta +document_properties_page_size_name_legal=Legal +# LOCALIZATION NOTE (document_properties_page_size_dimension_string): +# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement and orientation, of the (current) page. +document_properties_page_size_dimension_string={{width}} x {{height}} {{unit}} {{orientation}} +# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): +# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement, name, and orientation, of the (current) page. +document_properties_page_size_dimension_name_string={{width}} x {{height}} {{unit}} {{name}}, {{orientation}} +# LOCALIZATION NOTE (document_properties_linearized): The linearization status of +# the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized=Vista web rapida: +document_properties_linearized_yes=Sí +document_properties_linearized_no=No document_properties_close=Zarrar print_progress_message=Se ye preparando la documentación pa imprentar… @@ -101,17 +133,20 @@ print_progress_close=Cancelar # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Amostrar u amagar a barra lateral -toggle_sidebar_notification.title=Cambiar barra lateral (lo documento contiene esquema/adchuntos) +toggle_sidebar_notification2.title=Cambiar barra lateral (lo documento contiene esquema/adchuntos/capas) toggle_sidebar_label=Amostrar a barra lateral document_outline.title=Amostrar esquema d'o documento (fer doble clic pa expandir/compactar totz los items) document_outline_label=Esquema d'o documento attachments.title=Amostrar os adchuntos attachments_label=Adchuntos +layers.title=Amostrar capas (doble clic para reiniciar totas las capas a lo estau per defecto) +layers_label=Capas thumbs.title=Amostrar as miniaturas thumbs_label=Miniaturas findbar.title=Trobar en o documento findbar_label=Trobar +additional_layers=Capas adicionals # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -129,8 +164,30 @@ find_next.title=Trobar a siguient coincidencia d'a frase find_next_label=Siguient find_highlight=Resaltar-lo tot find_match_case_label=Coincidencia de mayusclas/minusclas +find_entire_word_label=Parolas completas find_reached_top=S'ha plegau a l'inicio d'o documento, se contina dende baixo find_reached_bottom=S'ha plegau a la fin d'o documento, se contina dende alto +# LOCALIZATION NOTE (find_match_count): The supported plural forms are +# [one|two|few|many|other], with [other] as the default value. +# "{{current}}" and "{{total}}" will be replaced by a number representing the +# index of the currently active find result, respectively a number representing +# the total number of matches in the document. +find_match_count={[ plural(total) ]} +find_match_count[one]={{current}} de {{total}} coincidencia +find_match_count[two]={{current}} de {{total}} coincidencias +find_match_count[few]={{current}} de {{total}} coincidencias +find_match_count[many]={{current}} de {{total}} coincidencias +find_match_count[other]={{current}} de {{total}} coincidencias +# LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are +# [zero|one|two|few|many|other], with [other] as the default value. +# "{{limit}}" will be replaced by a numerical value. +find_match_count_limit={[ plural(limit) ]} +find_match_count_limit[zero]=Mas de {{limit}} coincidencias +find_match_count_limit[one]=Mas de {{limit}} coincidencias +find_match_count_limit[two]=Mas que {{limit}} coincidencias +find_match_count_limit[few]=Mas que {{limit}} coincidencias +find_match_count_limit[many]=Mas que {{limit}} coincidencias +find_match_count_limit[other]=Mas que {{limit}} coincidencias find_not_found=No s'ha trobau a frase # Error panel labels @@ -161,13 +218,15 @@ page_scale_actual=Grandaria actual # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Error loading_error=S'ha produciu una error en cargar o PDF. invalid_file_error=O PDF no ye valido u ye estorbau. missing_file_error=No i ha fichero PDF. unexpected_response_error=Respuesta a lo servicio inasperada. +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. +annotation_date_string={{date}}, {{time}} + # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). diff --git a/cps/static/locale/ar/viewer.properties b/cps/static/locale/ar/viewer.properties index cffa8bec5..082816fb6 100644 --- a/cps/static/locale/ar/viewer.properties +++ b/cps/static/locale/ar/viewer.properties @@ -47,17 +47,13 @@ bookmark_label=المنظور الحالي # Secondary toolbar and context menu tools.title=الأدوات tools_label=الأدوات -first_page.title=اذهب إلى الصفحة الأولى -first_page.label=اذهب إلى الصفحة الأولى -first_page_label=اذهب إلى الصفحة الأولى -last_page.title=اذهب إلى الصفحة الأخيرة -last_page.label=اذهب إلى الصفحة الأخيرة -last_page_label=اذهب إلى الصفحة الأخيرة +first_page.title=انتقل إلى الصفحة الأولى +first_page_label=انتقل إلى الصفحة الأولى +last_page.title=انتقل إلى الصفحة الأخيرة +last_page_label=انتقل إلى الصفحة الأخيرة page_rotate_cw.title=أدر باتجاه عقارب الساعة -page_rotate_cw.label=أدر باتجاه عقارب الساعة page_rotate_cw_label=أدر باتجاه عقارب الساعة page_rotate_ccw.title=أدر بعكس اتجاه عقارب الساعة -page_rotate_ccw.label=أدر بعكس اتجاه عقارب الساعة page_rotate_ccw_label=أدر بعكس اتجاه عقارب الساعة cursor_text_select_tool.title=فعّل أداة اختيار النص @@ -137,17 +133,22 @@ print_progress_close=ألغِ # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=بدّل ظهور الشريط الجانبي -toggle_sidebar_notification.title=بدّل ظهور الشريط الجانبي (يحتوي المستند على مخطط أو مرفقات) +toggle_sidebar_notification2.title=بدّل ظهور الشريط الجانبي (يحتوي المستند على مخطط أو مرفقات أو طبقات) toggle_sidebar_label=بدّل ظهور الشريط الجانبي document_outline.title=اعرض فهرس المستند (نقر مزدوج لتمديد أو تقليص كل العناصر) document_outline_label=مخطط المستند attachments.title=اعرض المرفقات attachments_label=المُرفقات +layers.title=اعرض الطبقات (انقر مرتين لتصفير كل الطبقات إلى الحالة المبدئية) +layers_label=‏‏الطبقات thumbs.title=اعرض مُصغرات thumbs_label=مُصغّرات findbar.title=ابحث في المستند findbar_label=ابحث +additional_layers=الطبقات الإضافية +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=صفحة {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -220,7 +221,7 @@ page_scale_actual=الحجم الفعلي page_scale_percent={{scale}}٪ # Loading indicator messages -loading_error_indicator=عطل +loading=يحمّل… loading_error=حدث عطل أثناء تحميل ملف PDF. invalid_file_error=ملف PDF تالف أو غير صحيح. missing_file_error=ملف PDF غير موجود. diff --git a/cps/static/locale/ast/viewer.properties b/cps/static/locale/ast/viewer.properties index 5f6d5e7c0..1f8bb2e57 100644 --- a/cps/static/locale/ast/viewer.properties +++ b/cps/static/locale/ast/viewer.properties @@ -28,44 +28,51 @@ of_pages=de {{pagesCount}} # respectively a number representing the total number of pages in the document. page_of_pages=({{pageNumber}} de {{pagesCount}}) -zoom_out.title=Reducir -zoom_out_label=Reducir -zoom_in.title=Aumentar -zoom_in_label=Aumentar -zoom.title=Tamañu -open_file.title=Abrir ficheru +zoom_out.title=Alloñar +zoom_out_label=Alloña +zoom_in.title=Averar +zoom_in_label=Avera +zoom.title=Zoom +presentation_mode.title=Cambiar al mou de presentación +presentation_mode_label=Mou de presentación open_file_label=Abrir print.title=Imprentar print_label=Imprentar -download.title=Descargar -download_label=Descargar -bookmark.title=Vista actual (copiar o abrir nuna nueva ventana) +download.title=Baxar +download_label=Baxar bookmark_label=Vista actual # Secondary toolbar and context menu tools.title=Ferramientes tools_label=Ferramientes -first_page.title=Dir a la primer páxina -first_page.label=Dir a la primer páxina first_page_label=Dir a la primer páxina -last_page.title=Dir a la postrer páxina -last_page.label=Dir a la cabera páxina -last_page_label=Dir a la postrer páxina -page_rotate_cw.title=Xirar en sen horariu -page_rotate_cw_label=Xirar en sen horariu -page_rotate_ccw.title=Xirar en sen antihorariu -page_rotate_ccw_label=Xirar en sen antihorariu +last_page_label=Dir a la última páxina +page_rotate_cw.title=Voltia a la derecha +page_rotate_cw_label=Voltiar a la derecha +page_rotate_ccw.title=Voltia a la esquierda +page_rotate_ccw_label=Voltiar a la esquierda +cursor_text_select_tool.title=Activa la ferramienta d'esbilla de testu +cursor_text_select_tool_label=Ferramienta d'esbilla de testu +cursor_hand_tool.title=Activa la ferramienta de mano +cursor_hand_tool_label=Ferramienta de mano +scroll_vertical.title=Usa'l desplazamientu vertical scroll_vertical_label=Desplazamientu vertical +scroll_horizontal.title=Usa'l desplazamientu horizontal scroll_horizontal_label=Desplazamientu horizontal +scroll_wrapped.title=Usa'l desplazamientu continuu +scroll_wrapped_label=Desplazamientu continuu +spread_none_label=Fueyes individuales +spread_odd_label=Fueyes pares +spread_even_label=Fueyes impares # Document properties dialog box document_properties.title=Propiedaes del documentu… document_properties_label=Propiedaes del documentu… -document_properties_file_name=Nome de ficheru: -document_properties_file_size=Tamañu de ficheru: +document_properties_file_name=Nome del ficheru: +document_properties_file_size=Tamañu del ficheru: # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" # will be replaced by the PDF file size in kilobytes, respectively in bytes. document_properties_kb={{size_kb}} KB ({{size_b}} bytes) @@ -73,20 +80,20 @@ document_properties_kb={{size_kb}} KB ({{size_b}} bytes) # will be replaced by the PDF file size in megabytes, respectively in bytes. document_properties_mb={{size_mb}} MB ({{size_b}} bytes) document_properties_title=Títulu: -document_properties_author=Autor: -document_properties_subject=Asuntu: document_properties_keywords=Pallabres clave: document_properties_creation_date=Data de creación: document_properties_modification_date=Data de modificación: # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" # will be replaced by the creation/modification date, and time, of the PDF file. document_properties_date_string={{date}}, {{time}} -document_properties_creator=Creador: -document_properties_producer=Productor PDF: -document_properties_version=Versión PDF: +document_properties_producer=Productor del PDF: +document_properties_version=Versión del PDF: document_properties_page_count=Númberu de páxines: +document_properties_page_size=Tamañu de páxina: document_properties_page_size_unit_inches=in document_properties_page_size_unit_millimeters=mm +document_properties_page_size_orientation_portrait=vertical +document_properties_page_size_orientation_landscape=horizontal document_properties_page_size_name_a3=A3 document_properties_page_size_name_a4=A4 # LOCALIZATION NOTE (document_properties_page_size_dimension_string): @@ -99,11 +106,11 @@ document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) # LOCALIZATION NOTE (document_properties_linearized): The linearization status of # the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized=Vista web rápida: document_properties_linearized_yes=Sí document_properties_linearized_no=Non document_properties_close=Zarrar -print_progress_message=Tresnando documentu pa imprentar… # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by # a numerical per cent value. print_progress_percent={{progress}}% @@ -112,54 +119,56 @@ print_progress_close=Encaboxar # Tooltips and alt text for side panel toolbar buttons # (the _label strings are alt text for the buttons, the .title strings are # tooltips) -toggle_sidebar.title=Camudar barra llateral -toggle_sidebar_label=Camudar barra llateral -document_outline.title=Amosar esquema del documentu (duble clic pa espander/contrayer tolos elementos) -document_outline_label=Esquema del documentu -attachments.title=Amosar axuntos +toggle_sidebar.title=Alternar la barra llateral +attachments.title=Amosar los axuntos attachments_label=Axuntos -thumbs.title=Amosar miniatures +layers_label=Capes +thumbs.title=Amosar les miniatures thumbs_label=Miniatures -findbar.title=Guetar nel documentu -findbar_label=Guetar +findbar_label=Atopar +additional_layers=Capes adicionales +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Páxina {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. thumb_page_title=Páxina {{page}} # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page # number. -thumb_page_canvas=Miniatura de la páxina {{page}} # Find panel button title and messages -find_input.title=Guetar -find_input.placeholder=Guetar nel documentu… -find_previous.title=Alcontrar l'anterior apaición de la fras find_previous_label=Anterior -find_next.title=Alcontrar la siguiente apaición d'esta fras find_next_label=Siguiente -find_highlight=Remarcar toos -find_match_case_label=Coincidencia de mayús./minús. -find_entire_word_label=Pallabres enteres -find_reached_top=Algamóse'l principiu del documentu, siguir dende'l final -find_reached_bottom=Algamóse'l final del documentu, siguir dende'l principiu +find_entire_word_label=Pallabres completes +find_reached_top=Algamóse'l comienzu de la páxina, síguese dende abaxo +find_reached_bottom=Algamóse la fin del documentu, síguese dende arriba # LOCALIZATION NOTE (find_match_count): The supported plural forms are # [one|two|few|many|other], with [other] as the default value. # "{{current}}" and "{{total}}" will be replaced by a number representing the # index of the currently active find result, respectively a number representing # the total number of matches in the document. +find_match_count[one]={{current}} de {{total}} coincidencia +find_match_count[two]={{current}} de {{total}} coincidencies +find_match_count[few]={{current}} de {{total}} coincidencies +find_match_count[many]={{current}} de {{total}} coincidencies +find_match_count[other]={{current}} de {{total}} coincidencies # LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are # [zero|one|two|few|many|other], with [other] as the default value. # "{{limit}}" will be replaced by a numerical value. -find_not_found=Frase non atopada +find_match_count_limit[zero]=Más de {{limit}} coincidencies +find_match_count_limit[one]=Más de {{limit}} coincidencia +find_match_count_limit[two]=Más de {{limit}} coincidencies +find_match_count_limit[few]=Más de {{limit}} coincidencies +find_match_count_limit[many]=Más de {{limit}} coincidencies +find_match_count_limit[other]=Más de {{limit}} coincidencies # Error panel labels error_more_info=Más información error_less_info=Menos información -error_close=Zarrar # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be # replaced by the PDF.JS version and build ID. -error_version_info=PDF.js v{{version}} (build: {{build}}) +error_version_info=PDF.js v{{version}} (compilación: {{build}}) # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an # english string describing the error. error_message=Mensaxe: {{message}} @@ -170,37 +179,29 @@ error_stack=Pila: {{stack}} error_file=Ficheru: {{file}} # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number error_line=Llinia: {{line}} -rendering_error=Hebo un fallu al renderizar la páxina. # Predefined zoom values -page_scale_width=Anchor de la páxina -page_scale_fit=Axuste de la páxina -page_scale_auto=Tamañu automáticu -page_scale_actual=Tamañu actual +page_scale_auto=Zoom automáticu +page_scale_actual=Tamañu real # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a # numerical scale value. page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Fallu -loading_error=Hebo un fallu al cargar el PDF. -invalid_file_error=Ficheru PDF inválidu o corruptu. -missing_file_error=Nun hai ficheru PDF. -unexpected_response_error=Rempuesta inesperada del sirvidor. +loading=Cargando… +loading_error=Asocedió un fallu mentanto se cargaba'l PDF. # LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be # replaced by the modification date, and time, of the annotation. +annotation_date_string={{date}}, {{time}} # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). # Some common types are e.g.: "Check", "Text", "Comment", "Note" -text_annotation_type.alt=[Anotación {{type}}] -password_label=Introduz la contraseña p'abrir esti ficheru PDF -password_invalid=Contraseña non válida. Vuelvi a intentalo. -password_ok=Aceutar +password_ok=Aceptar password_cancel=Encaboxar -printing_not_supported=Alvertencia: La imprentación entá nun ta sofitada dafechu nesti restolador. -printing_not_ready=Avisu: Esti PDF nun se cargó completamente pa poder imprentase. -web_fonts_disabled=Les fontes web tán desactivaes: ye imposible usar les fontes PDF embebíes. +# LOCALIZATION NOTE (unsupported_feature_signatures): Should contain the same +# exact string as in the `chrome.properties` file. + diff --git a/cps/static/locale/az/viewer.properties b/cps/static/locale/az/viewer.properties index 8f61d9641..bdc0ce615 100644 --- a/cps/static/locale/az/viewer.properties +++ b/cps/static/locale/az/viewer.properties @@ -39,8 +39,8 @@ open_file.title=Fayl Aç open_file_label=Aç print.title=Yazdır print_label=Yazdır -download.title=Yüklə -download_label=Yüklə +download.title=Endir +download_label=Endir bookmark.title=Hazırkı görünüş (köçür və ya yeni pəncərədə aç) bookmark_label=Hazırkı görünüş @@ -48,16 +48,12 @@ bookmark_label=Hazırkı görünüş tools.title=Alətlər tools_label=Alətlər first_page.title=İlk Səhifəyə get -first_page.label=İlk Səhifəyə get first_page_label=İlk Səhifəyə get last_page.title=Son Səhifəyə get -last_page.label=Son Səhifəyə get last_page_label=Son Səhifəyə get page_rotate_cw.title=Saat İstiqamətində Fırlat -page_rotate_cw.label=Saat İstiqamətində Fırlat page_rotate_cw_label=Saat İstiqamətində Fırlat page_rotate_ccw.title=Saat İstiqamətinin Əksinə Fırlat -page_rotate_ccw.label=Saat İstiqamətinin Əksinə Fırlat page_rotate_ccw_label=Saat İstiqamətinin Əksinə Fırlat cursor_text_select_tool.title=Yazı seçmə alətini aktivləşdir @@ -137,19 +133,20 @@ print_progress_close=Ləğv et # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Yan Paneli Aç/Bağla -toggle_sidebar_notification.title=Yan paneli çevir (sənəddə icmal/bağlama var) +toggle_sidebar_notification2.title=Yan paneli çevir (sənəddə icmal/bağlamalar/laylar mövcuddur) toggle_sidebar_label=Yan Paneli Aç/Bağla document_outline.title=Sənədin eskizini göstər (bütün bəndləri açmaq/yığmaq üçün iki dəfə klikləyin) document_outline_label=Sənəd strukturu attachments.title=Bağlamaları göstər attachments_label=Bağlamalar +layers.title=Layları göstər (bütün layları ilkin halına sıfırlamaq üçün iki dəfə klikləyin) +layers_label=Laylar thumbs.title=Kiçik şəkilləri göstər thumbs_label=Kiçik şəkillər findbar.title=Sənəddə Tap findbar_label=Tap -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Səhifə {{page}} +additional_layers=Əlavə laylar # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -221,8 +218,6 @@ page_scale_actual=Hazırkı Həcm # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Səhv loading_error=PDF yüklenərkən bir səhv yarandı. invalid_file_error=Səhv və ya zədələnmiş olmuş PDF fayl. missing_file_error=PDF fayl yoxdur. diff --git a/cps/static/locale/be/viewer.properties b/cps/static/locale/be/viewer.properties index 6ac719288..5c006b96c 100644 --- a/cps/static/locale/be/viewer.properties +++ b/cps/static/locale/be/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Цяперашняя праява tools.title=Прылады tools_label=Прылады first_page.title=Перайсці на першую старонку -first_page.label=Перайсці на першую старонку first_page_label=Перайсці на першую старонку last_page.title=Перайсці на апошнюю старонку -last_page.label=Перайсці на апошнюю старонку last_page_label=Перайсці на апошнюю старонку page_rotate_cw.title=Павярнуць па сонцу -page_rotate_cw.label=Павярнуць па сонцу page_rotate_cw_label=Павярнуць па сонцу page_rotate_ccw.title=Павярнуць супраць сонца -page_rotate_ccw.label=Павярнуць супраць сонца page_rotate_ccw_label=Павярнуць супраць сонца cursor_text_select_tool.title=Уключыць прыладу выбару тэксту @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Прылада выбару тэксту cursor_hand_tool.title=Уключыць ручную прыладу cursor_hand_tool_label=Ручная прылада +scroll_page.title=Выкарыстоўваць пракрутку старонкi +scroll_page_label=Пракрутка старонкi scroll_vertical.title=Ужываць вертыкальную пракрутку scroll_vertical_label=Вертыкальная пракрутка scroll_horizontal.title=Ужываць гарызантальную пракрутку @@ -137,19 +135,24 @@ print_progress_close=Скасаваць # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Паказаць/схаваць бакавую панэль -toggle_sidebar_notification.title=Паказаць/схаваць бакавую панэль (дакумент мае змест/укладанні) +toggle_sidebar_notification2.title=Паказаць/схаваць бакавую панэль (дакумент мае змест/укладанні/пласты) toggle_sidebar_label=Паказаць/схаваць бакавую панэль document_outline.title=Паказаць структуру дакумента (двайная пстрычка, каб разгарнуць /згарнуць усе элементы) document_outline_label=Структура дакумента attachments.title=Паказаць далучэнні attachments_label=Далучэнні +layers.title=Паказаць пласты (двойчы пстрыкніце, каб скінуць усе пласты да прадвызначанага стану) +layers_label=Пласты thumbs.title=Паказ мініяцюр thumbs_label=Мініяцюры +current_outline_item.title=Знайсці бягучы элемент структуры +current_outline_item_label=Бягучы элемент структуры findbar.title=Пошук у дакуменце findbar_label=Знайсці -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Старонка {{page}} +additional_layers=Дадатковыя пласты +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Старонка {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Знайсці наступны выпадак выразу find_next_label=Наступны find_highlight=Падфарбаваць усе find_match_case_label=Адрозніваць вялікія/малыя літары +find_match_diacritics_label=З улікам дыякрытык find_entire_word_label=Словы цалкам find_reached_top=Дасягнуты пачатак дакумента, працяг з канца find_reached_bottom=Дасягнуты канец дакумента, працяг з пачатку @@ -222,8 +226,8 @@ page_scale_actual=Сапраўдны памер page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Памылка -loading_error=Здарылася памылка падчас загрузкі PDF. +loading=Чытаецца… +loading_error=Здарылася памылка ў часе загрузкі PDF. invalid_file_error=Няспраўны або пашкоджаны файл PDF. missing_file_error=Адсутны файл PDF. unexpected_response_error=Нечаканы адказ сервера. @@ -245,3 +249,33 @@ password_cancel=Скасаваць printing_not_supported=Папярэджанне: друк не падтрымліваецца цалкам гэтым браўзерам. printing_not_ready=Увага: PDF не сцягнуты цалкам для друкавання. web_fonts_disabled=Шрыфты Сеціва забаронены: немагчыма ўжываць укладзеныя шрыфты PDF. + +# Editor +editor_none.title=Адключыць рэдагаванне анатацый +editor_none_label=Адключыць рэдагаванне +editor_free_text.title=Дадаць анатацыю FreeText +editor_free_text_label=Анатацыя FreeText +editor_ink.title=Дадаць анатацыю чарнілам +editor_ink_label=Анатацыя чарнілам + +freetext_default_content=Увядзіце тэкст… + +free_text_default_content=Увядзіце тэкст… + +# Editor Parameters +editor_free_text_font_color=Колер шрыфту +editor_free_text_font_size=Памер шрыфту +editor_ink_line_color=Колер лініі +editor_ink_line_thickness=Таўшчыня лініі + +# Editor Parameters +editor_free_text_color=Колер +editor_free_text_size=Памер +editor_ink_color=Колер +editor_ink_thickness=Таўшчыня +editor_ink_opacity=Непразрыстасць + +# Editor aria +editor_free_text_aria_label=Рэдактар FreeText +editor_ink_aria_label=Рэдактар чарнілаў +editor_ink_canvas_aria_label=Відарыс, створаны карыстальнікам diff --git a/cps/static/locale/bg/viewer.properties b/cps/static/locale/bg/viewer.properties index b93e3d1e4..0ec7649c6 100644 --- a/cps/static/locale/bg/viewer.properties +++ b/cps/static/locale/bg/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Текущ изглед tools.title=Инструменти tools_label=Инструменти first_page.title=Към първата страница -first_page.label=Към първата страница first_page_label=Към първата страница last_page.title=Към последната страница -last_page.label=Към последната страница last_page_label=Към последната страница page_rotate_cw.title=Завъртане по час. стрелка -page_rotate_cw.label=Завъртане по часовниковата стрелка page_rotate_cw_label=Завъртане по часовниковата стрелка page_rotate_ccw.title=Завъртане обратно на час. стрелка -page_rotate_ccw.label=Завъртане обратно на часовниковата стрелка page_rotate_ccw_label=Завъртане обратно на часовниковата стрелка cursor_text_select_tool.title=Включване на инструмента за избор на текст @@ -137,7 +133,6 @@ print_progress_close=Отказ # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Превключване на страничната лента -toggle_sidebar_notification.title=Превключване на страничната лента (документи със структура/прикачени файлове) toggle_sidebar_label=Превключване на страничната лента document_outline.title=Показване на структурата на документа (двукратно щракване за свиване/разгъване на всичко) document_outline_label=Структура на документа @@ -219,8 +214,6 @@ page_scale_actual=Действителен размер # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Грешка loading_error=Получи се грешка при зареждане на PDF-а. invalid_file_error=Невалиден или повреден PDF файл. missing_file_error=Липсващ PDF файл. diff --git a/cps/static/locale/bn/viewer.properties b/cps/static/locale/bn/viewer.properties index c106df10c..e31c135fd 100644 --- a/cps/static/locale/bn/viewer.properties +++ b/cps/static/locale/bn/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=বর্তমান অবস্থা tools.title=টুল tools_label=টুল first_page.title=প্রথম পাতায় যাও -first_page.label=প্রথম পাতায় যাও first_page_label=প্রথম পাতায় যাও last_page.title=শেষ পাতায় যাও -last_page.label=শেষ পাতায় যাও last_page_label=শেষ পাতায় যাও page_rotate_cw.title=ঘড়ির কাঁটার দিকে ঘোরাও -page_rotate_cw.label=ঘড়ির কাঁটার দিকে ঘোরাও page_rotate_cw_label=ঘড়ির কাঁটার দিকে ঘোরাও page_rotate_ccw.title=ঘড়ির কাঁটার বিপরীতে ঘোরাও -page_rotate_ccw.label=ঘড়ির কাঁটার বিপরীতে ঘোরাও page_rotate_ccw_label=ঘড়ির কাঁটার বিপরীতে ঘোরাও cursor_text_select_tool.title=লেখা নির্বাচক টুল সক্রিয় করুন @@ -135,7 +131,6 @@ print_progress_close=বাতিল # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=সাইডবার টগল করুন -toggle_sidebar_notification.title=সাইডবার টগল (নথিতে আউটলাইন/এটাচমেন্ট রয়েছে) toggle_sidebar_label=সাইডবার টগল করুন document_outline.title=নথির আউটলাইন দেখাও (সব আইটেম প্রসারিত/সঙ্কুচিত করতে ডবল ক্লিক করুন) document_outline_label=নথির রূপরেখা @@ -146,8 +141,7 @@ thumbs_label=থাম্বনেইল সমূহ findbar.title=নথির মধ্যে খুঁজুন findbar_label=খুঁজুন -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=পাতা {{page}} +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -163,7 +157,7 @@ find_previous.title=বাক্যাংশের পূর্ববর্ত find_previous_label=পূর্ববর্তী find_next.title=বাক্যাংশের পরবর্তী উপস্থিতি অনুসন্ধান find_next_label=পরবর্তী -find_highlight=সব হাইলাইট করা হবে +find_highlight=সব হাইলাইট করুন find_match_case_label=অক্ষরের ছাঁদ মেলানো find_entire_word_label=সম্পূর্ণ শব্দ find_reached_top=পাতার শুরুতে পৌছে গেছে, নীচ থেকে আরম্ভ করা হয়েছে @@ -220,7 +214,6 @@ page_scale_actual=প্রকৃত আকার page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=ত্রুটি loading_error=পিডিএফ লোড করার সময় ত্রুটি দেখা দিয়েছে। invalid_file_error=অকার্যকর অথবা ক্ষতিগ্রস্ত পিডিএফ ফাইল। missing_file_error=নিখোঁজ PDF ফাইল। diff --git a/cps/static/locale/bo/viewer.properties b/cps/static/locale/bo/viewer.properties index 3ffa84819..bba049082 100644 --- a/cps/static/locale/bo/viewer.properties +++ b/cps/static/locale/bo/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Current View tools.title=Tools tools_label=Tools first_page.title=Go to First Page -first_page.label=Go to First Page first_page_label=Go to First Page last_page.title=Go to Last Page -last_page.label=Go to Last Page last_page_label=Go to Last Page page_rotate_cw.title=Rotate Clockwise -page_rotate_cw.label=Rotate Clockwise page_rotate_cw_label=Rotate Clockwise page_rotate_ccw.title=Rotate Counterclockwise -page_rotate_ccw.label=Rotate Counterclockwise page_rotate_ccw_label=Rotate Counterclockwise cursor_text_select_tool.title=Enable Text Selection Tool @@ -137,7 +133,6 @@ print_progress_close=Cancel # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Toggle Sidebar -toggle_sidebar_notification.title=Toggle Sidebar (document contains outline/attachments) toggle_sidebar_label=Toggle Sidebar document_outline.title=Show Document Outline (double-click to expand/collapse all items) document_outline_label=Document Outline @@ -219,8 +214,6 @@ page_scale_actual=Actual Size # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Error loading_error=An error occurred while loading the PDF. invalid_file_error=Invalid or corrupted PDF file. missing_file_error=Missing PDF file. diff --git a/cps/static/locale/br/viewer.properties b/cps/static/locale/br/viewer.properties index 9add9a432..c26ca6810 100644 --- a/cps/static/locale/br/viewer.properties +++ b/cps/static/locale/br/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Gwel bremanel tools.title=Ostilhoù tools_label=Ostilhoù first_page.title=Mont d'ar bajenn gentañ -first_page.label=Mont d'ar bajenn gentañ first_page_label=Mont d'ar bajenn gentañ last_page.title=Mont d'ar bajenn diwezhañ -last_page.label=Mont d'ar bajenn diwezhañ last_page_label=Mont d'ar bajenn diwezhañ page_rotate_cw.title=C'hwelañ gant roud ar bizied -page_rotate_cw.label=C'hwelañ gant roud ar bizied page_rotate_cw_label=C'hwelañ gant roud ar bizied page_rotate_ccw.title=C'hwelañ gant roud gin ar bizied -page_rotate_ccw.label=C'hwelañ gant roud gin ar bizied page_rotate_ccw_label=C'hwelañ gant roud gin ar bizied cursor_text_select_tool.title=Gweredekaat an ostilh diuzañ testenn @@ -82,27 +78,27 @@ spread_even_label=Pajennoù par # Document properties dialog box document_properties.title=Perzhioù an teul… document_properties_label=Perzhioù an teul… -document_properties_file_name=Anv restr : -document_properties_file_size=Ment ar restr : +document_properties_file_name=Anv restr: +document_properties_file_size=Ment ar restr: # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" # will be replaced by the PDF file size in kilobytes, respectively in bytes. document_properties_kb={{size_kb}} Ke ({{size_b}} eizhbit) # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" # will be replaced by the PDF file size in megabytes, respectively in bytes. document_properties_mb={{size_mb}} Me ({{size_b}} eizhbit) -document_properties_title=Titl : -document_properties_author=Aozer : -document_properties_subject=Danvez : -document_properties_keywords=Gerioù-alc'hwez : -document_properties_creation_date=Deiziad krouiñ : -document_properties_modification_date=Deiziad kemmañ : +document_properties_title=Titl: +document_properties_author=Aozer: +document_properties_subject=Danvez: +document_properties_keywords=Gerioù-alc'hwez: +document_properties_creation_date=Deiziad krouiñ: +document_properties_modification_date=Deiziad kemmañ: # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" # will be replaced by the creation/modification date, and time, of the PDF file. document_properties_date_string={{date}}, {{time}} -document_properties_creator=Krouer : -document_properties_producer=Kenderc'her PDF : -document_properties_version=Handelv PDF : -document_properties_page_count=Niver a bajennoù : +document_properties_creator=Krouer: +document_properties_producer=Kenderc'her PDF: +document_properties_version=Handelv PDF: +document_properties_page_count=Niver a bajennoù: document_properties_page_size=Ment ar bajenn: document_properties_page_size_unit_inches=in document_properties_page_size_unit_millimeters=mm @@ -137,19 +133,22 @@ print_progress_close=Nullañ # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Diskouez/kuzhat ar varrenn gostez -toggle_sidebar_notification.title=Trec'haoliñ ar verrenn-gostez (ur steuñv pe stagadennoù a zo en teul) +toggle_sidebar_notification2.title=Trec'haoliñ ar varrenn-gostez (ur steuñv pe stagadennoù a zo en teul) toggle_sidebar_label=Diskouez/kuzhat ar varrenn gostez document_outline.title=Diskouez steuñv an teul (daouglikit evit brasaat/bihanaat an holl elfennoù) document_outline_label=Sinedoù an teuliad attachments.title=Diskouez ar c'henstagadurioù attachments_label=Kenstagadurioù +layers.title=Diskouez ar gwiskadoù (daou-glikañ evit adderaouekaat an holl gwiskadoù d'o stad dre ziouer) +layers_label=Gwiskadoù thumbs.title=Diskouez ar melvennoù thumbs_label=Melvennoù findbar.title=Klask e-barzh an teuliad findbar_label=Klask -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Pajenn {{page}} +additional_layers=Gwiskadoù ouzhpenn +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Pajenn {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -199,17 +198,17 @@ error_less_info=Nebeutoc'h a ditouroù error_close=Serriñ # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be # replaced by the PDF.JS version and build ID. -error_version_info=PDF.js handelv {{version}} (kempunadur : {{build}}) +error_version_info=PDF.js handelv {{version}} (kempunadur: {{build}}) # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an # english string describing the error. -error_message=Kemennadenn : {{message}} +error_message=Kemennadenn: {{message}} # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack # trace. -error_stack=Torn : {{stack}} +error_stack=Torn: {{stack}} # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename -error_file=Restr : {{file}} +error_file=Restr: {{file}} # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number -error_line=Linenn : {{line}} +error_line=Linenn: {{line}} rendering_error=Degouezhet ez eus bet ur fazi e-pad skrammañ ar bajennad. # Predefined zoom values @@ -222,7 +221,7 @@ page_scale_actual=Ment wir page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Fazi +loading=O kargañ… loading_error=Degouezhet ez eus bet ur fazi e-pad kargañ ar PDF. invalid_file_error=Restr PDF didalvoudek pe kontronet. missing_file_error=Restr PDF o vankout. @@ -242,6 +241,6 @@ password_invalid=Ger-tremen didalvoudek. Klaskit en-dro mar plij. password_ok=Mat eo password_cancel=Nullañ -printing_not_supported=Kemenn : N'eo ket skoret penn-da-benn ar moullañ gant ar merdeer-mañ. -printing_not_ready=Kemenn : N'hall ket bezañ moullet ar restr PDF rak n'eo ket karget penn-da-benn. -web_fonts_disabled=Diweredekaet eo an nodrezhoù web : n'haller ket arverañ an nodrezhoù PDF enframmet. +printing_not_supported=Kemenn: N'eo ket skoret penn-da-benn ar moullañ gant ar merdeer-mañ. +printing_not_ready=Kemenn: N'hall ket bezañ moullet ar restr PDF rak n'eo ket karget penn-da-benn. +web_fonts_disabled=Diweredekaet eo an nodrezhoù web: n'haller ket arverañ an nodrezhoù PDF enframmet. diff --git a/cps/static/locale/brx/viewer.properties b/cps/static/locale/brx/viewer.properties index cd3656380..3d1c92ddd 100644 --- a/cps/static/locale/brx/viewer.properties +++ b/cps/static/locale/brx/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=दानि नुथाय tools.title=टुल tools_label=टुल first_page.title=गिबि बिलाइआव थां -first_page.label=गिबि बिलाइआव थां first_page_label=गिबि बिलाइआव थां last_page.title=जोबथा बिलाइआव थां -last_page.label=जोबथा बिलाइआव थां last_page_label=जोबथा बिलाइआव थां page_rotate_cw.title=घरि गिदिंनाय फार्से फिदिं -page_rotate_cw.label=घरि गिदिंनाय फार्से फिदिं page_rotate_cw_label=घरि गिदिंनाय फार्से फिदिं page_rotate_ccw.title=घरि गिदिंनाय उल्था फार्से फिदिं -page_rotate_ccw.label=घरि गिदिंनाय उल्था फार्से फिदिं page_rotate_ccw_label=घरि गिदिंनाय उल्था फार्से फिदिं @@ -184,8 +180,6 @@ page_scale_actual=थार महर # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=गोरोन्थि loading_error=PDF ल'ड खालामनाय समाव मोनसे गोरोन्थि जाबाय। invalid_file_error=बाहायजायै एबा गाज्रि जानाय PDF फाइल missing_file_error=गोमानाय PDF फाइल diff --git a/cps/static/locale/bs/viewer.properties b/cps/static/locale/bs/viewer.properties index e5346cb0c..ec115d03c 100644 --- a/cps/static/locale/bs/viewer.properties +++ b/cps/static/locale/bs/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Trenutni prikaz tools.title=Alati tools_label=Alati first_page.title=Idi na prvu stranu -first_page.label=Idi na prvu stranu first_page_label=Idi na prvu stranu last_page.title=Idi na zadnju stranu -last_page.label=Idi na zadnju stranu last_page_label=Idi na zadnju stranu page_rotate_cw.title=Rotiraj u smjeru kazaljke na satu -page_rotate_cw.label=Rotiraj u smjeru kazaljke na satu page_rotate_cw_label=Rotiraj u smjeru kazaljke na satu page_rotate_ccw.title=Rotiraj suprotno smjeru kazaljke na satu -page_rotate_ccw.label=Rotiraj suprotno smjeru kazaljke na satu page_rotate_ccw_label=Rotiraj suprotno smjeru kazaljke na satu cursor_text_select_tool.title=Omogući alat za označavanje teksta @@ -118,7 +114,6 @@ print_progress_close=Otkaži # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Uključi/isključi bočnu traku -toggle_sidebar_notification.title=Uključi/isključi sidebar (dokument sadrži outline/priloge) toggle_sidebar_label=Uključi/isključi bočnu traku document_outline.title=Prikaži outline dokumenta (dvoklik za skupljanje/širenje svih stavki) document_outline_label=Konture dokumenta @@ -178,8 +173,6 @@ page_scale_actual=Stvarna veličina # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Greška loading_error=Došlo je do greške prilikom učitavanja PDF-a. invalid_file_error=Neispravan ili oštećen PDF fajl. missing_file_error=Nedostaje PDF fajl. diff --git a/cps/static/locale/ca/viewer.properties b/cps/static/locale/ca/viewer.properties index ac6fb779f..21e7dff92 100644 --- a/cps/static/locale/ca/viewer.properties +++ b/cps/static/locale/ca/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vista actual tools.title=Eines tools_label=Eines first_page.title=Vés a la primera pàgina -first_page.label=Vés a la primera pàgina first_page_label=Vés a la primera pàgina last_page.title=Vés a l'última pàgina -last_page.label=Vés a l'última pàgina last_page_label=Vés a l'última pàgina page_rotate_cw.title=Gira cap a la dreta -page_rotate_cw.label=Gira cap a la dreta page_rotate_cw_label=Gira cap a la dreta page_rotate_ccw.title=Gira cap a l'esquerra -page_rotate_ccw.label=Gira cap a l'esquerra page_rotate_ccw_label=Gira cap a l'esquerra cursor_text_select_tool.title=Habilita l'eina de selecció de text @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Eina de selecció de text cursor_hand_tool.title=Habilita l'eina de mà cursor_hand_tool_label=Eina de mà +scroll_page.title=Usa el desplaçament de pàgina +scroll_page_label=Desplaçament de pàgina scroll_vertical.title=Utilitza el desplaçament vertical scroll_vertical_label=Desplaçament vertical scroll_horizontal.title=Utilitza el desplaçament horitzontal @@ -137,19 +135,24 @@ print_progress_close=Cancel·la # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Mostra/amaga la barra lateral -toggle_sidebar_notification.title=Mostra/amaga la barra lateral (el document conté un esquema o adjuncions) +toggle_sidebar_notification2.title=Mostra/amaga la barra lateral (el document conté un esquema, adjuncions o capes) toggle_sidebar_label=Mostra/amaga la barra lateral document_outline.title=Mostra l'esquema del document (doble clic per ampliar/reduir tots els elements) -document_outline_label=Contorn del document +document_outline_label=Esquema del document attachments.title=Mostra les adjuncions attachments_label=Adjuncions +layers.title=Mostra les capes (doble clic per restablir totes les capes al seu estat per defecte) +layers_label=Capes thumbs.title=Mostra les miniatures thumbs_label=Miniatures +current_outline_item.title=Cerca l'element d'esquema actual +current_outline_item_label=Element d'esquema actual findbar.title=Cerca al document findbar_label=Cerca -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Pàgina {{page}} +additional_layers=Capes addicionals +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Pàgina {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -213,7 +216,7 @@ error_line=Línia: {{line}} rendering_error=S'ha produït un error mentre es renderitzava la pàgina. # Predefined zoom values -page_scale_width=Amplària de la pàgina +page_scale_width=Amplada de la pàgina page_scale_fit=Ajusta la pàgina page_scale_auto=Zoom automàtic page_scale_actual=Mida real @@ -222,7 +225,7 @@ page_scale_actual=Mida real page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=S'està carregant… loading_error=S'ha produït un error en carregar el PDF. invalid_file_error=El fitxer PDF no és vàlid o està malmès. missing_file_error=Falta el fitxer PDF. diff --git a/cps/static/locale/cak/viewer.properties b/cps/static/locale/cak/viewer.properties index d4eae51a8..1828641ea 100644 --- a/cps/static/locale/cak/viewer.properties +++ b/cps/static/locale/cak/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Rutzub'al wakami tools.title=Samajib'äl tools_label=Samajib'äl first_page.title=Tib'e pa nab'ey ruxaq -first_page.label=Tib'e pa nab'ey ruxaq first_page_label=Tib'e pa nab'ey ruxaq last_page.title=Tib'e pa ruk'isib'äl ruxaq -last_page.label=Tib'e pa ruk'isib'äl ruxaq last_page_label=Tib'e pa ruk'isib'äl ruxaq page_rotate_cw.title=Tisutïx pan ajkiq'a' -page_rotate_cw.label=Tisutïx pan ajkiq'a' page_rotate_cw_label=Tisutïx pan ajkiq'a' page_rotate_ccw.title=Tisutïx pan ajxokon -page_rotate_ccw.label=Tisutïx pan ajxokon page_rotate_ccw_label=Tisutïx pan ajxokon cursor_text_select_tool.title=Titzij ri rusamajib'al Rucha'ik Rucholajem Tzij @@ -137,19 +133,24 @@ print_progress_close=Tiq'at # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Tijal ri ajxikin kajtz'ik -toggle_sidebar_notification.title=Tik'ex ri ajxikin yuqkajtz'ik (ri wuj eruk'wan taq ruchi'/taqoj taq yakb'äl) +toggle_sidebar_notification2.title=Tik'ex ri ajxikin yuqkajtz'ik (ri wuj eruk'wan taq ruchi'/taqo/kuchuj) toggle_sidebar_label=Tijal ri ajxikin kajtz'ik document_outline.title=Tik'ut pe ruch'akulal wuj (kamul-pitz'oj richin nirik'/nich'utinirisäx ronojel ruch'akulal) document_outline_label=Ruch'akulal wuj attachments.title=Kek'ut pe ri taq taqoj attachments_label=Taq taqoj +layers.title=Kek'ut taq Kuchuj (ka'i'-pitz' richin yetzolïx ronojel ri taq kuchuj e k'o wi) +layers_label=Taq kuchuj thumbs.title=Kek'ut pe taq ch'utiq thumbs_label=Koköj +current_outline_item.title=Kekanöx Taq Ch'akulal Kik'wan Chib'äl +current_outline_item_label=Taq Ch'akulal Kik'wan Chib'äl findbar.title=Tikanöx chupam ri wuj findbar_label=Tikanöx -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Ruxaq {{page}} +additional_layers=Tz'aqat ta Kuchuj +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Ruxaq {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -222,7 +223,7 @@ page_scale_actual=Runimilem Wakami page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Sachoj +loading=Nisamäj… loading_error=\u0020Xk'ulwachitäj jun sach'oj toq xnuk'ux ri PDF . invalid_file_error=Man oke ta o yujtajinäq ri PDF yakb'äl. missing_file_error=Man xilitäj ta ri PDF yakb'äl. diff --git a/cps/static/locale/ckb/viewer.properties b/cps/static/locale/ckb/viewer.properties index d1bed431b..b30cb7672 100644 --- a/cps/static/locale/ckb/viewer.properties +++ b/cps/static/locale/ckb/viewer.properties @@ -13,6 +13,8 @@ # limitations under the License. # Main toolbar buttons (tooltips and alt text for images) +previous.title=پەڕەی پێشوو +previous_label=پێشوو next.title=پەڕەی دوواتر next_label=دوواتر @@ -20,92 +22,212 @@ next_label=دوواتر page.title=پەرە # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number # representing the total number of pages in the document. +of_pages=لە {{pagesCount}} # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" # will be replaced by a number representing the currently visible page, # respectively a number representing the total number of pages in the document. +page_of_pages=({{pageNumber}} لە {{pagesCount}}) +zoom_out.title=ڕۆچوونی +zoom_out_label=ڕۆچوونی +zoom_in.title=هێنانەپێش +zoom_in_label=هێنانەپێش +zoom.title=زووم +presentation_mode.title=گۆڕین بۆ دۆخی پێشکەشکردن +presentation_mode_label=دۆخی پێشکەشکردن open_file.title=پەڕگە بکەرەوە open_file_label=کردنەوە print.title=چاپکردن +print_label=چاپکردن download.title=داگرتن +download_label=داگرتن +bookmark.title=پێشبینینی ئێستا(لەبەریبگرەوە یان پەنجەرەیەکی نوێ بکەرەوە) +bookmark_label=پیشبینینی ئێستا # Secondary toolbar and context menu tools.title=ئامرازەکان +tools_label=ئامرازەکان first_page.title=برۆ بۆ یەکەم پەڕە +first_page_label=بڕۆ بۆ یەکەم پەڕە +last_page.title=بڕۆ بۆ کۆتا پەڕە +last_page_label=بڕۆ بۆ کۆتا پەڕە +page_rotate_cw.title=ئاڕاستەی میلی کاتژمێر +page_rotate_cw_label=ئاڕاستەی میلی کاتژمێر +page_rotate_ccw.title=پێچەوانەی میلی کاتژمێر +page_rotate_ccw_label=پێچەوانەی میلی کاتژمێر +cursor_text_select_tool.title=توڵامرازی نیشانکەری دەق چالاک بکە +cursor_text_select_tool_label=توڵامرازی نیشانکەری دەق +cursor_hand_tool.title=توڵامرازی دەستی چالاک بکە +cursor_hand_tool_label=توڵامرازی دەستی +scroll_vertical.title=ناردنی ئەستوونی بەکاربێنە +scroll_vertical_label=ناردنی ئەستوونی +scroll_horizontal.title=ناردنی ئاسۆیی بەکاربێنە +scroll_horizontal_label=ناردنی ئاسۆیی +scroll_wrapped.title=ناردنی لوولکراو بەکاربێنە +scroll_wrapped_label=ناردنی لوولکراو # Document properties dialog box +document_properties.title=تایبەتمەندییەکانی بەڵگەنامە... +document_properties_label=تایبەتمەندییەکانی بەڵگەنامە... document_properties_file_name=ناوی پەڕگە: document_properties_file_size=قەبارەی پەڕگە: # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" # will be replaced by the PDF file size in kilobytes, respectively in bytes. +document_properties_kb={{size_kb}} کب ({{size_b}} بایت) # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" # will be replaced by the PDF file size in megabytes, respectively in bytes. +document_properties_mb={{size_mb}} مب ({{size_b}} بایت) document_properties_title=سەردێڕ: document_properties_author=نووسەر +document_properties_subject=بابەت: document_properties_keywords=کلیلەوشە: +document_properties_creation_date=بەرواری درووستکردن: +document_properties_modification_date=بەرواری دەستکاریکردن: # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" # will be replaced by the creation/modification date, and time, of the PDF file. +document_properties_date_string={{date}}, {{time}} +document_properties_creator=درووستکەر: +document_properties_producer=بەرهەمهێنەری PDF: +document_properties_version=وەشانی PDF: +document_properties_page_count=ژمارەی پەرەکان: +document_properties_page_size=قەبارەی پەڕە: +document_properties_page_size_unit_inches=ئینچ +document_properties_page_size_unit_millimeters=ملم +document_properties_page_size_orientation_portrait=پۆرترەیت(درێژ) +document_properties_page_size_orientation_landscape=پانیی +document_properties_page_size_name_a3=A3 +document_properties_page_size_name_a4=A4 +document_properties_page_size_name_letter=نامە +document_properties_page_size_name_legal=یاسایی # LOCALIZATION NOTE (document_properties_page_size_dimension_string): # "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by # the size, respectively their unit of measurement and orientation, of the (current) page. +document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} ({{orientation}}) # LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): # "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by # the size, respectively their unit of measurement, name, and orientation, of the (current) page. +document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) # LOCALIZATION NOTE (document_properties_linearized): The linearization status of # the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized=پیشاندانی وێبی خێرا: +document_properties_linearized_yes=بەڵێ +document_properties_linearized_no=نەخێر document_properties_close=داخستن +print_progress_message=بەڵگەنامە ئامادەدەکرێت بۆ چاپکردن... # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by # a numerical per cent value. +print_progress_percent={{progress}}% print_progress_close=پاشگەزبوونەوە # Tooltips and alt text for side panel toolbar buttons # (the _label strings are alt text for the buttons, the .title strings are # tooltips) +toggle_sidebar.title=لاتەنیشت پیشاندان/شاردنەوە +toggle_sidebar_label=لاتەنیشت پیشاندان/شاردنەوە +document_outline_label=سنووری چوارچێوە +attachments.title=پاشکۆکان پیشان بدە +attachments_label=پاشکۆکان +layers_label=چینەکان +thumbs.title=وێنۆچکە پیشان بدە +thumbs_label=وێنۆچکە +findbar.title=لە بەڵگەنامە بگەرێ findbar_label=دۆزینەوە -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. +additional_layers=چینی زیاتر # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. +thumb_page_title=پەڕەی {{page}} # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page # number. +thumb_page_canvas=وێنۆچکەی پەڕەی {{page}} # Find panel button title and messages find_input.title=دۆزینەوە +find_input.placeholder=لە بەڵگەنامە بگەرێ... +find_previous.title=هەبوونی پێشوو بدۆزرەوە لە ڕستەکەدا +find_previous_label=پێشوو +find_next.title=هەبوونی داهاتوو بدۆزەرەوە لە ڕستەکەدا +find_next_label=دوواتر +find_highlight=هەمووی نیشانە بکە +find_match_case_label=دۆخی لەیەکچوون +find_entire_word_label=هەموو وشەکان +find_reached_top=گەشتیتە سەرەوەی بەڵگەنامە، لە خوارەوە دەستت پێکرد +find_reached_bottom=گەشتیتە کۆتایی بەڵگەنامە. لەسەرەوە دەستت پێکرد # LOCALIZATION NOTE (find_match_count): The supported plural forms are # [one|two|few|many|other], with [other] as the default value. # "{{current}}" and "{{total}}" will be replaced by a number representing the # index of the currently active find result, respectively a number representing # the total number of matches in the document. +find_match_count={[ plural(total) ]} +find_match_count[one]={{current}} لە کۆی {{total}} لەیەکچوو +find_match_count[two]={{current}} لە کۆی {{total}} لەیەکچوو +find_match_count[few]={{current}} لە کۆی {{total}} لەیەکچوو +find_match_count[many]={{current}} لە کۆی {{total}} لەیەکچوو +find_match_count[other]={{current}} لە کۆی {{total}} لەیەکچوو # LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are # [zero|one|two|few|many|other], with [other] as the default value. # "{{limit}}" will be replaced by a numerical value. +find_match_count_limit={[ plural(limit) ]} +find_match_count_limit[zero]=زیاتر لە {{limit}} لەیەکچوو +find_match_count_limit[one]=زیاتر لە {{limit}} لەیەکچوو +find_match_count_limit[two]=زیاتر لە {{limit}} لەیەکچوو +find_match_count_limit[few]=زیاتر لە {{limit}} لەیەکچوو +find_match_count_limit[many]=زیاتر لە {{limit}} لەیەکچوو +find_match_count_limit[other]=زیاتر لە {{limit}} لەیەکچوو +find_not_found=نووسین نەدۆزرایەوە # Error panel labels +error_more_info=زانیاری زیاتر +error_less_info=زانیاری کەمتر +error_close=داخستن # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be # replaced by the PDF.JS version and build ID. +error_version_info=PDF.js v{{version}} (build: {{build}}) # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an # english string describing the error. +error_message=پەیام: {{message}} # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack # trace. +error_stack=لەسەریەک: {{stack}} # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=پەڕگە: {{file}} # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=هێڵ: {{line}} +rendering_error=هەڵەیەک ڕوویدا لە کاتی پوختەکردنی (ڕێندەر) پەڕە. # Predefined zoom values +page_scale_width=پانی پەڕە +page_scale_fit=پڕبوونی پەڕە +page_scale_auto=زوومی خۆکار +page_scale_actual=قەبارەی ڕاستی # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a # numerical scale value. +page_scale_percent={{scale}}% -# Loading indicator messages +loading_error=هەڵەیەک ڕوویدا لە کاتی بارکردنی PDF. +invalid_file_error=پەڕگەی pdf تێکچووە یان نەگونجاوە. +missing_file_error=پەڕگەی pdf بوونی نیە. +unexpected_response_error=وەڵامی ڕاژەخوازی نەخوازراو. # LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be # replaced by the modification date, and time, of the annotation. +annotation_date_string={{date}}, {{time}} # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). # Some common types are e.g.: "Check", "Text", "Comment", "Note" +text_annotation_type.alt=[{{type}} سەرنج] +password_label=وشەی تێپەڕ بنووسە بۆ کردنەوەی پەڕگەی pdf. +password_invalid=وشەی تێپەڕ هەڵەیە. تکایە دووبارە هەوڵ بدەرەوە. +password_ok=باشە +password_cancel=پاشگەزبوونەوە +printing_not_supported=ئاگاداربە: چاپکردن بە تەواوی پشتگیر ناکرێت لەم وێبگەڕە. +printing_not_ready=ئاگاداربە: PDF بە تەواوی بارنەبووە بۆ چاپکردن. +web_fonts_disabled=جۆرەپیتی وێب ناچالاکە: نەتوانی جۆرەپیتی تێخراوی ناو pdfـەکە بەکاربێت. diff --git a/cps/static/locale/cs/viewer.properties b/cps/static/locale/cs/viewer.properties index 646f410bb..1bf8f00b3 100644 --- a/cps/static/locale/cs/viewer.properties +++ b/cps/static/locale/cs/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Současný pohled tools.title=Nástroje tools_label=Nástroje first_page.title=Přejde na první stránku -first_page.label=Přejít na první stránku first_page_label=Přejít na první stránku last_page.title=Přejde na poslední stránku -last_page.label=Přejít na poslední stránku last_page_label=Přejít na poslední stránku page_rotate_cw.title=Otočí po směru hodin -page_rotate_cw.label=Otočit po směru hodin page_rotate_cw_label=Otočit po směru hodin page_rotate_ccw.title=Otočí proti směru hodin -page_rotate_ccw.label=Otočit proti směru hodin page_rotate_ccw_label=Otočit proti směru hodin cursor_text_select_tool.title=Povolí výběr textu @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Výběr textu cursor_hand_tool.title=Povolí nástroj ručička cursor_hand_tool_label=Nástroj ručička +scroll_page.title=Posouvat po stránkách +scroll_page_label=Posouvání po stránkách scroll_vertical.title=Použít svislé posouvání scroll_vertical_label=Svislé posouvání scroll_horizontal.title=Použít vodorovné posouvání @@ -137,19 +135,24 @@ print_progress_close=Zrušit # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Postranní lišta -toggle_sidebar_notification.title=Přepne postranní lištu (dokument obsahuje osnovu/přílohy) +toggle_sidebar_notification2.title=Přepnout postranní lištu (dokument obsahuje osnovu/přílohy/vrstvy) toggle_sidebar_label=Postranní lišta -document_outline.title=Zobrazí osnovu dokumentu (dvojité klepnutí rozbalí/sbalí všechny položky) +document_outline.title=Zobrazí osnovu dokumentu (poklepání přepne zobrazení všech položek) document_outline_label=Osnova dokumentu attachments.title=Zobrazí přílohy attachments_label=Přílohy +layers.title=Zobrazit vrstvy (poklepáním obnovíte všechny vrstvy do výchozího stavu) +layers_label=Vrstvy thumbs.title=Zobrazí náhledy thumbs_label=Náhledy +current_outline_item.title=Najít aktuální položku v osnově +current_outline_item_label=Aktuální položka v osnově findbar.title=Najde v dokumentu findbar_label=Najít -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Strana {{page}} +additional_layers=Další vrstvy +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Strana {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Najde další výskyt hledaného textu find_next_label=Další find_highlight=Zvýraznit find_match_case_label=Rozlišovat velikost +find_match_diacritics_label=Rozlišovat diakritiku find_entire_word_label=Celá slova find_reached_top=Dosažen začátek dokumentu, pokračuje se od konce find_reached_bottom=Dosažen konec dokumentu, pokračuje se od začátku @@ -222,7 +226,7 @@ page_scale_actual=Skutečná velikost page_scale_percent={{scale}} % # Loading indicator messages -loading_error_indicator=Chyba +loading=Načítání… loading_error=Při nahrávání PDF nastala chyba. invalid_file_error=Neplatný nebo chybný soubor PDF. missing_file_error=Chybí soubor PDF. @@ -245,3 +249,31 @@ password_cancel=Zrušit printing_not_supported=Upozornění: Tisk není v tomto prohlížeči plně podporován. printing_not_ready=Upozornění: Dokument PDF není kompletně načten. web_fonts_disabled=Webová písma jsou zakázána, proto není možné použít vložená písma PDF. + +# Editor +editor_none.title=Zakázat úpravy anotací +editor_none_label=Zakázat úpravy +editor_free_text.title=Přidat textovou anotaci +editor_free_text_label=Textová anotace +editor_ink.title=Přidat psanou anotaci +editor_ink_label=Psaná anotace + +free_text_default_content=Zadejte text… + +# Editor Parameters +editor_free_text_font_color=Barva písma +editor_free_text_font_size=Velikost písma +editor_ink_line_color=Barva čáry +editor_ink_line_thickness=Tloušťka čáry + +# Editor Parameters +editor_free_text_color=Barva +editor_free_text_size=Velikost +editor_ink_color=Barva +editor_ink_thickness=Tloušťka +editor_ink_opacity=Průhlednost + +# Editor aria +editor_free_text_aria_label=Editor textu +editor_ink_aria_label=Editor psaní rukou +editor_ink_canvas_aria_label=Uživatelem vytvořený obrázek diff --git a/cps/static/locale/cy/viewer.properties b/cps/static/locale/cy/viewer.properties index 16cda5fd7..b5d064709 100644 --- a/cps/static/locale/cy/viewer.properties +++ b/cps/static/locale/cy/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Golwg Gyfredol tools.title=Offer tools_label=Offer first_page.title=Mynd i'r Dudalen Gyntaf -first_page.label=Mynd i'r Dudalen Gyntaf first_page_label=Mynd i'r Dudalen Gyntaf last_page.title=Mynd i'r Dudalen Olaf -last_page.label=Mynd i'r Dudalen Olaf last_page_label=Mynd i'r Dudalen Olaf page_rotate_cw.title=Cylchdroi Clocwedd -page_rotate_cw.label=Cylchdroi Clocwedd page_rotate_cw_label=Cylchdroi Clocwedd page_rotate_ccw.title=Cylchdroi Gwrthglocwedd -page_rotate_ccw.label=Cylchdroi Gwrthglocwedd page_rotate_ccw_label=Cylchdroi Gwrthglocwedd cursor_text_select_tool.title=Galluogi Dewis Offeryn Testun @@ -65,19 +61,21 @@ cursor_text_select_tool_label=Offeryn Dewis Testun cursor_hand_tool.title=Galluogi Offeryn Llaw cursor_hand_tool_label=Offeryn Llaw +scroll_page.title=Defnyddio Sgrolio Tudalen +scroll_page_label=Sgrolio Tudalen scroll_vertical.title=Defnyddio Sgrolio Fertigol scroll_vertical_label=Sgrolio Fertigol -scroll_horizontal.title=Defnyddio Sgrolio Fertigol -scroll_horizontal_label=Sgrolio Fertigol +scroll_horizontal.title=Defnyddio Sgrolio Llorweddol +scroll_horizontal_label=Sgrolio Llorweddol scroll_wrapped.title=Defnyddio Sgrolio Amlapio scroll_wrapped_label=Sgrolio Amlapio -spread_none.title=Peidio uno taeniadau canol -spread_none_label=Dim Taeniadau -spread_odd.title=Uno taeniadau tudalen yn cychwyn gyda thudalennau odrif -spread_odd_label=Taeniadau Odrifau -spread_even.title=Uno taeniadau tudalen yn cychwyn gyda thudalennau eilrif -spread_even_label=Taeniadau Eilrif +spread_none.title=Peidio uno trawsdaleniadau +spread_none_label=Dim Trawsdaleniadau +spread_odd.title=Uno trawsdaleniadau gan gychwyn gyda thudalennau odrif +spread_odd_label=Trawsdaleniadau Odrif +spread_even.title=Uno trawsdaleniadau gan gychwyn gyda thudalennau eilrif +spread_even_label=Trawsdaleniadau Eilrif # Document properties dialog box document_properties.title=Priodweddau Dogfen… @@ -137,19 +135,24 @@ print_progress_close=Diddymu # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Toglo'r Bar Ochr -toggle_sidebar_notification.title=Toglo'r Bar Ochr (mae'r ddogfen yn cynnwys outline/attachments) +toggle_sidebar_notification2.title=Toglo'r Bar Ochr (mae'r ddogfen yn cynnwys amlinelliadau/atodiadau/haenau) toggle_sidebar_label=Toglo'r Bar Ochr document_outline.title=Dangos Amlinell Dogfen (clic dwbl i ymestyn/cau pob eitem) document_outline_label=Amlinelliad Dogfen attachments.title=Dangos Atodiadau attachments_label=Atodiadau +layers.title=Dangos Haenau (cliciwch ddwywaith i ailosod yr holl haenau i'r cyflwr rhagosodedig) +layers_label=Haenau thumbs.title=Dangos Lluniau Bach thumbs_label=Lluniau Bach +current_outline_item.title=Canfod yr Eitem Amlinellol Gyfredol +current_outline_item_label=Yr Eitem Amlinellol Gyfredol findbar.title=Canfod yn y Ddogfen findbar_label=Canfod -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Tudalen {{page}} +additional_layers=Haenau Ychwanegol +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Tudalen {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Canfod enghraifft nesaf yr ymadrodd find_next_label=Nesaf find_highlight=Amlygu popeth find_match_case_label=Cydweddu maint +find_match_diacritics_label=Diacritigau Cyfatebol find_entire_word_label=Geiriau cyfan find_reached_top=Wedi cyrraedd brig y dudalen, parhau o'r gwaelod find_reached_bottom=Wedi cyrraedd diwedd y dudalen, parhau o'r brig @@ -222,7 +226,7 @@ page_scale_actual=Maint Gwirioneddol page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Gwall +loading=Yn llwytho… loading_error=Digwyddodd gwall wrth lwytho'r PDF. invalid_file_error=Ffeil PDF annilys neu llwgr. missing_file_error=Ffeil PDF coll. @@ -245,3 +249,33 @@ password_cancel=Diddymu printing_not_supported=Rhybudd: Nid yw argraffu yn cael ei gynnal yn llawn gan y porwr. printing_not_ready=Rhybudd: Nid yw'r PDF wedi ei lwytho'n llawn ar gyfer argraffu. web_fonts_disabled=Ffontiau gwe wedi eu hanalluogi: methu defnyddio ffontiau PDF mewnblanedig. + +# Editor +editor_none.title=Analluogi Golygu Anodi +editor_none_label=Analluogi Golygu +editor_free_text.title=Ychwanegu Anodiad Testun Rhydd +editor_free_text_label=Anodi Testun Rhydd +editor_ink.title=Ychwanegu Anodiad Inc +editor_ink_label=Ychwanegu Anodiad Inc + +freetext_default_content=Rhowch ychydig o destun… + +free_text_default_content=Rhowch destun… + +# Editor Parameters +editor_free_text_font_color=Lliw Ffont +editor_free_text_font_size=Maint Ffont +editor_ink_line_color=Lliw Llinell +editor_ink_line_thickness=Trwch Llinell + +# Editor Parameters +editor_free_text_color=Lliw +editor_free_text_size=Maint +editor_ink_color=Lliw +editor_ink_thickness=Trwch +editor_ink_opacity=Didreiddedd + +# Editor aria +editor_free_text_aria_label=Golygydd FreeText +editor_ink_aria_label=Golygydd Inc +editor_ink_canvas_aria_label=Delwedd wedi'i chreu gan ddefnyddwyr diff --git a/cps/static/locale/da/viewer.properties b/cps/static/locale/da/viewer.properties index 38ed99d0b..213f4314f 100644 --- a/cps/static/locale/da/viewer.properties +++ b/cps/static/locale/da/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Aktuel visning tools.title=Funktioner tools_label=Funktioner first_page.title=Gå til første side -first_page.label=Gå til første side first_page_label=Gå til første side last_page.title=Gå til sidste side -last_page.label=Gå til sidste side last_page_label=Gå til sidste side page_rotate_cw.title=Roter med uret -page_rotate_cw.label=Roter med uret page_rotate_cw_label=Roter med uret page_rotate_ccw.title=Roter mod uret -page_rotate_ccw.label=Roter mod uret page_rotate_ccw_label=Roter mod uret cursor_text_select_tool.title=Aktiver markeringsværktøj @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Markeringsværktøj cursor_hand_tool.title=Aktiver håndværktøj cursor_hand_tool_label=Håndværktøj +scroll_page.title=Brug sidescrolling +scroll_page_label=Sidescrolling scroll_vertical.title=Brug vertikal scrolling scroll_vertical_label=Vertikal scrolling scroll_horizontal.title=Brug horisontal scrolling @@ -137,19 +135,24 @@ print_progress_close=Annuller # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Slå sidepanel til eller fra -toggle_sidebar_notification.title=Slå sidepanel til eller fra (dokumentet indeholder disposition/vedhæftede filer) +toggle_sidebar_notification2.title=Slå sidepanel til eller fra (dokumentet indeholder disposition/vedhæftede filer/lag) toggle_sidebar_label=Slå sidepanel til eller fra document_outline.title=Vis dokumentets disposition (dobbeltklik for at vise/skjule alle elementer) document_outline_label=Dokument-disposition attachments.title=Vis vedhæftede filer attachments_label=Vedhæftede filer +layers.title=Vis lag (dobbeltklik for at nulstille alle lag til standard-tilstanden) +layers_label=Lag thumbs.title=Vis miniaturer thumbs_label=Miniaturer +current_outline_item.title=Find det aktuelle dispositions-element +current_outline_item_label=Aktuelt dispositions-element findbar.title=Find i dokument findbar_label=Find -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Side {{page}} +additional_layers=Yderligere lag +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Side {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Find den næste forekomst find_next_label=Næste find_highlight=Fremhæv alle find_match_case_label=Forskel på store og små bogstaver +find_match_diacritics_label=Diakritiske tegn find_entire_word_label=Hele ord find_reached_top=Toppen af siden blev nået, fortsatte fra bunden find_reached_bottom=Bunden af siden blev nået, fortsatte fra toppen @@ -222,7 +226,7 @@ page_scale_actual=Faktisk størrelse page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Fejl +loading=Indlæser… loading_error=Der opstod en fejl ved indlæsning af PDF-filen. invalid_file_error=PDF-filen er ugyldig eller ødelagt. missing_file_error=Manglende PDF-fil. @@ -245,3 +249,19 @@ password_cancel=Fortryd printing_not_supported=Advarsel: Udskrivning er ikke fuldt understøttet af browseren. printing_not_ready=Advarsel: PDF-filen er ikke fuldt indlæst til udskrivning. web_fonts_disabled=Webskrifttyper er deaktiverede. De indlejrede skrifttyper i PDF-filen kan ikke anvendes. + +# Editor +editor_none.title=Deaktiver redigering af anmærkninger +editor_none_label=Deaktiver redigering +editor_ink.title=Tilføj håndskreven anmærkning +editor_ink_label=Håndskreven anmærkning + +freetext_default_content=Indtast noget tekst… + +free_text_default_content=Indtast tekst… + +# Editor Parameters +editor_free_text_font_color=Skriftfarve +editor_free_text_font_size=Skriftstørrelse +editor_ink_line_color=Linjefarve +editor_ink_line_thickness=Linjetykkelse diff --git a/cps/static/locale/de/viewer.properties b/cps/static/locale/de/viewer.properties index 26b682ebe..5afa6db26 100644 --- a/cps/static/locale/de/viewer.properties +++ b/cps/static/locale/de/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Aktuelle Ansicht tools.title=Werkzeuge tools_label=Werkzeuge first_page.title=Erste Seite anzeigen -first_page.label=Erste Seite anzeigen first_page_label=Erste Seite anzeigen last_page.title=Letzte Seite anzeigen -last_page.label=Letzte Seite anzeigen last_page_label=Letzte Seite anzeigen page_rotate_cw.title=Im Uhrzeigersinn drehen -page_rotate_cw.label=Im Uhrzeigersinn drehen page_rotate_cw_label=Im Uhrzeigersinn drehen page_rotate_ccw.title=Gegen Uhrzeigersinn drehen -page_rotate_ccw.label=Gegen Uhrzeigersinn drehen page_rotate_ccw_label=Gegen Uhrzeigersinn drehen cursor_text_select_tool.title=Textauswahl-Werkzeug aktivieren @@ -65,11 +61,13 @@ cursor_text_select_tool_label=Textauswahl-Werkzeug cursor_hand_tool.title=Hand-Werkzeug aktivieren cursor_hand_tool_label=Hand-Werkzeug +scroll_page.title=Seiten einzeln anordnen +scroll_page_label=Einzelseitenanordnung scroll_vertical.title=Seiten übereinander anordnen scroll_vertical_label=Vertikale Seitenanordnung scroll_horizontal.title=Seiten nebeneinander anordnen scroll_horizontal_label=Horizontale Seitenanordnung -scroll_wrapped.title=Seiten neben- und übereinander anordnen, anhängig vom Platz +scroll_wrapped.title=Seiten neben- und übereinander anordnen, abhängig vom Platz scroll_wrapped_label=Kombinierte Seitenanordnung spread_none.title=Seiten nicht nebeneinander anzeigen @@ -137,19 +135,24 @@ print_progress_close=Abbrechen # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Sidebar umschalten -toggle_sidebar_notification.title=Sidebar umschalten (Dokument enthält Dokumentstruktur/Anhänge) +toggle_sidebar_notification2.title=Sidebar umschalten (Dokument enthält Dokumentstruktur/Anhänge/Ebenen) toggle_sidebar_label=Sidebar umschalten document_outline.title=Dokumentstruktur anzeigen (Doppelklicken, um alle Einträge aus- bzw. einzuklappen) document_outline_label=Dokumentstruktur attachments.title=Anhänge anzeigen attachments_label=Anhänge +layers.title=Ebenen anzeigen (Doppelklicken, um alle Ebenen auf den Standardzustand zurückzusetzen) +layers_label=Ebenen thumbs.title=Miniaturansichten anzeigen thumbs_label=Miniaturansichten +current_outline_item.title=Aktuelles Struktur-Element finden +current_outline_item_label=Aktuelles Struktur-Element findbar.title=Dokument durchsuchen findbar_label=Suchen -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Seite {{page}} +additional_layers=Zusätzliche Ebenen +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Seite {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Nächstes Vorkommen des Suchbegriffs finden find_next_label=Weiter find_highlight=Alle hervorheben find_match_case_label=Groß-/Kleinschreibung beachten +find_match_diacritics_label=Akzente find_entire_word_label=Ganze Wörter find_reached_top=Anfang des Dokuments erreicht, fahre am Ende fort find_reached_bottom=Ende des Dokuments erreicht, fahre am Anfang fort @@ -222,7 +226,7 @@ page_scale_actual=Originalgröße page_scale_percent={{scale}} % # Loading indicator messages -loading_error_indicator=Fehler +loading=Wird geladen… loading_error=Beim Laden der PDF-Datei trat ein Fehler auf. invalid_file_error=Ungültige oder beschädigte PDF-Datei missing_file_error=Fehlende PDF-Datei @@ -245,3 +249,33 @@ password_cancel=Abbrechen printing_not_supported=Warnung: Die Drucken-Funktion wird durch diesen Browser nicht vollständig unterstützt. printing_not_ready=Warnung: Die PDF-Datei ist nicht vollständig geladen, dies ist für das Drucken aber empfohlen. web_fonts_disabled=Web-Schriftarten sind deaktiviert: Eingebettete PDF-Schriftarten konnten nicht geladen werden. + +# Editor +editor_none.title=Bearbeiten von Annotationen deaktivieren +editor_none_label=Bearbeiten deaktivieren +editor_free_text.title=FreeText-Annotation hinzufügen +editor_free_text_label=FreeText-Annotation +editor_ink.title=Ink-Annotation hinzufügen +editor_ink_label=Ink-Annotation + +freetext_default_content=Text eingeben… + +free_text_default_content=Text eingeben… + +# Editor Parameters +editor_free_text_font_color=Schriftfarbe +editor_free_text_font_size=Schriftgröße +editor_ink_line_color=Linienfarbe +editor_ink_line_thickness=Liniendicke + +# Editor Parameters +editor_free_text_color=Farbe +editor_free_text_size=Größe +editor_ink_color=Farbe +editor_ink_thickness=Dicke +editor_ink_opacity=Deckkraft + +# Editor aria +editor_free_text_aria_label=FreeText-Editor +editor_ink_aria_label=Ink-Editor +editor_ink_canvas_aria_label=Vom Benutzer erstelltes Bild diff --git a/cps/static/locale/dsb/viewer.properties b/cps/static/locale/dsb/viewer.properties index 468ccd745..d7e5f1a4f 100644 --- a/cps/static/locale/dsb/viewer.properties +++ b/cps/static/locale/dsb/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Aktualny naglěd tools.title=Rědy tools_label=Rědy first_page.title=K prědnemu bokoju -first_page.label=K prědnemu bokoju first_page_label=K prědnemu bokoju last_page.title=K slědnemu bokoju -last_page.label=K slědnemu bokoju last_page_label=K slědnemu bokoju page_rotate_cw.title=Wobwjertnuś ako špěra źo -page_rotate_cw.label=Wobwjertnuś ako špěra źo page_rotate_cw_label=Wobwjertnuś ako špěra źo page_rotate_ccw.title=Wobwjertnuś nawopaki ako špěra źo -page_rotate_ccw.label=Wobwjertnuś nawopaki ako špěra źo page_rotate_ccw_label=Wobwjertnuś nawopaki ako špěra źo cursor_text_select_tool.title=Rěd za wuběranje teksta zmóžniś @@ -65,8 +61,10 @@ cursor_text_select_tool_label=Rěd za wuběranje teksta cursor_hand_tool.title=Rucny rěd zmóžniś cursor_hand_tool_label=Rucny rěd +scroll_page.title=Kulanje boka wužywaś +scroll_page_label=Kulanje boka scroll_vertical.title=Wertikalne suwanje wužywaś -scroll_vertical_label=Wertikalnje suwanje +scroll_vertical_label=Wertikalne suwanje scroll_horizontal.title=Horicontalne suwanje wužywaś scroll_horizontal_label=Horicontalne suwanje scroll_wrapped.title=Pózlažke suwanje wužywaś @@ -137,19 +135,24 @@ print_progress_close=Pśetergnuś # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Bócnicu pokazaś/schowaś -toggle_sidebar_notification.title=Bocnicu pśešaltowaś (dokument wopśimujo pśeglěd/pśipiski) +toggle_sidebar_notification2.title=Bocnicu pśešaltowaś (dokument rozrědowanje/pśipiski/warstwy wopśimujo) toggle_sidebar_label=Bócnicu pokazaś/schowaś document_outline.title=Dokumentowe naraźenje pokazaś (dwójne kliknjenje, aby se wšykne zapiski pokazali/schowali) document_outline_label=Dokumentowa struktura attachments.title=Pśidanki pokazaś attachments_label=Pśidanki +layers.title=Warstwy pokazaś (klikniśo dwójcy, aby wšykne warstwy na standardny staw slědk stajił) +layers_label=Warstwy thumbs.title=Miniatury pokazaś thumbs_label=Miniatury +current_outline_item.title=Aktualny rozrědowański zapisk pytaś +current_outline_item_label=Aktualny rozrědowański zapisk findbar.title=W dokumenśe pytaś findbar_label=Pytaś -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Bok {{page}} +additional_layers=Dalšne warstwy +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Bok {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Pśidujuce wustupowanje pytańskego wuraza pytaś find_next_label=Dalej find_highlight=Wšykne wuzwignuś find_match_case_label=Na wjelikopisanje źiwaś +find_match_diacritics_label=Diakritiske znamuška wužywaś find_entire_word_label=Cełe słowa find_reached_top=Zachopjeńk dokumenta dostany, pókšacujo se z kóńcom find_reached_bottom=Kóńc dokumenta dostany, pókšacujo se ze zachopjeńkom @@ -222,7 +226,7 @@ page_scale_actual=Aktualna wjelikosć page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Zmólka +loading=Zacytujo se… loading_error=Pśi zacytowanju PDF jo zmólka nastała. invalid_file_error=Njepłaśiwa abo wobškóźona PDF-dataja. missing_file_error=Felujuca PDF-dataja. @@ -245,3 +249,33 @@ password_cancel=Pśetergnuś printing_not_supported=Warnowanje: Śišćanje njepódpěra se połnje pśez toś ten wobglědowak. printing_not_ready=Warnowanje: PDF njejo se za śišćanje dopołnje zacytał. web_fonts_disabled=Webpisma su znjemóžnjone: njejo móžno, zasajźone PDF-pisma wužywaś. + +# Editor +editor_none.title=Wobźěłowanje anotacijow znjemóžniś +editor_none_label=Wobźěłowanje znjemóžniś +editor_free_text.title=Anotaciju FreeText pśidaś +editor_free_text_label=Anotacija FreeText +editor_ink.title=Tintowu anotaciju pśidaś +editor_ink_label=Tintowa anotacija + +freetext_default_content=Zapódajśo pitśku teksta… + +free_text_default_content=Tekst zapódaś… + +# Editor Parameters +editor_free_text_font_color=Pismowa barwa +editor_free_text_font_size=Pismowe wjelikosć +editor_ink_line_color=Linijowa barwa +editor_ink_line_thickness=Linijowa tłustosć + +# Editor Parameters +editor_free_text_color=Barwa +editor_free_text_size=Wjelikosć +editor_ink_color=Barwa +editor_ink_thickness=Tłustosć +editor_ink_opacity=Opacita + +# Editor aria +editor_free_text_aria_label=Dermotny tekstowy editor +editor_ink_aria_label=Tintowy editor +editor_ink_canvas_aria_label=Wobraz napórany wót wužywarja diff --git a/cps/static/locale/el/viewer.properties b/cps/static/locale/el/viewer.properties index 896bbeefc..cf60407f6 100644 --- a/cps/static/locale/el/viewer.properties +++ b/cps/static/locale/el/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Τρέχουσα προβολή tools.title=Εργαλεία tools_label=Εργαλεία first_page.title=Μετάβαση στην πρώτη σελίδα -first_page.label=Μετάβαση στην πρώτη σελίδα first_page_label=Μετάβαση στην πρώτη σελίδα last_page.title=Μετάβαση στην τελευταία σελίδα -last_page.label=Μετάβαση στην τελευταία σελίδα last_page_label=Μετάβαση στην τελευταία σελίδα page_rotate_cw.title=Δεξιόστροφη περιστροφή -page_rotate_cw.label=Δεξιόστροφη περιστροφή page_rotate_cw_label=Δεξιόστροφη περιστροφή page_rotate_ccw.title=Αριστερόστροφη περιστροφή -page_rotate_ccw.label=Αριστερόστροφη περιστροφή page_rotate_ccw_label=Αριστερόστροφη περιστροφή cursor_text_select_tool.title=Ενεργοποίηση εργαλείου επιλογής κειμένου @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Εργαλείο επιλογής κειμένου cursor_hand_tool.title=Ενεργοποίηση εργαλείου χεριού cursor_hand_tool_label=Εργαλείο χεριού +scroll_page.title=Χρήση κύλισης σελίδας +scroll_page_label=Κύλιση σελίδας scroll_vertical.title=Χρήση κάθετης κύλισης scroll_vertical_label=Κάθετη κύλιση scroll_horizontal.title=Χρήση οριζόντιας κύλισης @@ -93,7 +91,7 @@ document_properties_mb={{size_mb}} MB ({{size_b}} bytes) document_properties_title=Τίτλος: document_properties_author=Συγγραφέας: document_properties_subject=Θέμα: -document_properties_keywords=Λέξεις κλειδιά: +document_properties_keywords=Λέξεις-κλειδιά: document_properties_creation_date=Ημερομηνία δημιουργίας: document_properties_modification_date=Ημερομηνία τροποποίησης: # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" @@ -105,7 +103,7 @@ document_properties_version=Έκδοση PDF: document_properties_page_count=Αριθμός σελίδων: document_properties_page_size=Μέγεθος σελίδας: document_properties_page_size_unit_inches=ίντσες -document_properties_page_size_unit_millimeters=χιλιοστά +document_properties_page_size_unit_millimeters=mm document_properties_page_size_orientation_portrait=κατακόρυφα document_properties_page_size_orientation_landscape=οριζόντια document_properties_page_size_name_a3=A3 @@ -131,32 +129,37 @@ print_progress_message=Προετοιμασία του εγγράφου για # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by # a numerical per cent value. print_progress_percent={{progress}}% -print_progress_close=Άκυρο +print_progress_close=Ακύρωση # Tooltips and alt text for side panel toolbar buttons # (the _label strings are alt text for the buttons, the .title strings are # tooltips) -toggle_sidebar.title=(Απ)ενεργοποίηση πλευρικής στήλης -toggle_sidebar_notification.title=(Απ)ενεργοποίηση πλευρικής στήλης (το έγγραφο περιέχει περίγραμμα/συνημμένα) -toggle_sidebar_label=(Απ)ενεργοποίηση πλευρικής στήλης +toggle_sidebar.title=(Απ)ενεργοποίηση πλαϊνής γραμμής +toggle_sidebar_notification2.title=(Απ)ενεργοποίηση πλαϊνής γραμμής (το έγγραφο περιέχει περίγραμμα/συνημμένα/επίπεδα) +toggle_sidebar_label=(Απ)ενεργοποίηση πλαϊνής γραμμής document_outline.title=Εμφάνιση διάρθρωσης εγγράφου (διπλό κλικ για ανάπτυξη/σύμπτυξη όλων των στοιχείων) document_outline_label=Διάρθρωση εγγράφου -attachments.title=Προβολή συνημμένων +attachments.title=Εμφάνιση συνημμένων attachments_label=Συνημμένα -thumbs.title=Προβολή μικρογραφιών +layers.title=Εμφάνιση επιπέδων (διπλό κλικ για επαναφορά όλων των επιπέδων στην προεπιλεγμένη κατάσταση) +layers_label=Επίπεδα +thumbs.title=Εμφάνιση μικρογραφιών thumbs_label=Μικρογραφίες +current_outline_item.title=Εύρεση τρέχοντος στοιχείου διάρθρωσης +current_outline_item_label=Τρέχον στοιχείο διάρθρωσης findbar.title=Εύρεση στο έγγραφο findbar_label=Εύρεση -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Σελίδα {{page}} +additional_layers=Επιπρόσθετα επίπεδα +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Σελίδα {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. thumb_page_title=Σελίδα {{page}} # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page # number. -thumb_page_canvas=Μικρογραφία της σελίδας {{page}} +thumb_page_canvas=Μικρογραφία σελίδας {{page}} # Find panel button title and messages find_input.title=Εύρεση @@ -166,10 +169,11 @@ find_previous_label=Προηγούμενο find_next.title=Εύρεση της επόμενης εμφάνισης της φράσης find_next_label=Επόμενο find_highlight=Επισήμανση όλων -find_match_case_label=Ταίριασμα χαρακτήρα +find_match_case_label=Συμφωνία πεζών/κεφαλαίων +find_match_diacritics_label=Αντιστοίχιση διακριτικών find_entire_word_label=Ολόκληρες λέξεις -find_reached_top=Έλευση στην αρχή του εγγράφου, συνέχεια από το τέλος -find_reached_bottom=Έλευση στο τέλος του εγγράφου, συνέχεια από την αρχή +find_reached_top=Φτάσατε στην αρχή του εγγράφου, συνέχεια από το τέλος +find_reached_bottom=Φτάσατε στο τέλος του εγγράφου, συνέχεια από την αρχή # LOCALIZATION NOTE (find_match_count): The supported plural forms are # [one|two|few|many|other], with [other] as the default value. # "{{current}}" and "{{total}}" will be replaced by a number representing the @@ -199,7 +203,7 @@ error_less_info=Λιγότερες πληροφορίες error_close=Κλείσιμο # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be # replaced by the PDF.JS version and build ID. -error_version_info=PDF.js v{{version}} (build: {{build}}) +error_version_info=PDF.js v{{version}} (έκδοση: {{build}}) # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an # english string describing the error. error_message=Μήνυμα: {{message}} @@ -210,7 +214,7 @@ error_stack=Στοίβα: {{stack}} error_file=Αρχείο: {{file}} # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number error_line=Γραμμή: {{line}} -rendering_error=Προέκυψε σφάλμα κατά την ανάλυση της σελίδας. +rendering_error=Προέκυψε σφάλμα κατά την εμφάνιση της σελίδας. # Predefined zoom values page_scale_width=Πλάτος σελίδας @@ -222,8 +226,8 @@ page_scale_actual=Πραγματικό μέγεθος page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Σφάλμα -loading_error=Προέκυψε ένα σφάλμα κατά τη φόρτωση του PDF. +loading=Φόρτωση… +loading_error=Προέκυψε σφάλμα κατά τη φόρτωση του PDF. invalid_file_error=Μη έγκυρο ή κατεστραμμένο αρχείο PDF. missing_file_error=Λείπει αρχείο PDF. unexpected_response_error=Μη αναμενόμενη απόκριση από το διακομιστή. @@ -236,12 +240,42 @@ annotation_date_string={{date}}, {{time}} # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). # Some common types are e.g.: "Check", "Text", "Comment", "Note" -text_annotation_type.alt=[{{type}} Σχόλιο] -password_label=Εισαγωγή κωδικού για το άνοιγμα του PDF αρχείου. -password_invalid=Μη έγκυρος κωδικός. Προσπαθείστε ξανά. -password_ok=ΟΚ +text_annotation_type.alt=[Σχόλιο «{{type}}»] +password_label=Εισαγάγετε τον κωδικό πρόσβασης για να ανοίξετε αυτό το αρχείο PDF. +password_invalid=Μη έγκυρος κωδικός πρόσβασης. Παρακαλώ δοκιμάστε ξανά. +password_ok=OK password_cancel=Ακύρωση -printing_not_supported=Προειδοποίηση: Η εκτύπωση δεν υποστηρίζεται πλήρως από αυτόν τον περιηγητή. +printing_not_supported=Προειδοποίηση: Η εκτύπωση δεν υποστηρίζεται πλήρως από το πρόγραμμα περιήγησης. printing_not_ready=Προειδοποίηση: Το PDF δεν φορτώθηκε πλήρως για εκτύπωση. -web_fonts_disabled=Οι γραμματοσειρές Web απενεργοποιημένες: αδυναμία χρήσης των ενσωματωμένων γραμματοσειρών PDF. +web_fonts_disabled=Οι γραμματοσειρές ιστού είναι ανενεργές: δεν είναι δυνατή η χρήση των ενσωματωμένων γραμματοσειρών PDF. + +# Editor +editor_none.title=Απενεργοποίηση επεξεργασίας σχολίων +editor_none_label=Απενεργοποίηση επεξεργασίας +editor_free_text.title=Προσθήκη σχολίου ελεύθερου κειμένου +editor_free_text_label=Σχόλιο ελεύθερου κειμένου +editor_ink.title=Προσθήκη σχολίου με μελάνι +editor_ink_label=Σχόλιο με μελάνι + +freetext_default_content=Εισαγάγετε κάποιο κείμενο… + +free_text_default_content=Εισαγάγετε κείμενο… + +# Editor Parameters +editor_free_text_font_color=Χρώμα γραμματοσειράς +editor_free_text_font_size=Μέγεθος γραμματοσειράς +editor_ink_line_color=Χρώμα γραμμής +editor_ink_line_thickness=Πάχος γραμμής + +# Editor Parameters +editor_free_text_color=Χρώμα +editor_free_text_size=Μέγεθος +editor_ink_color=Χρώμα +editor_ink_thickness=Πάχος +editor_ink_opacity=Αδιαφάνεια + +# Editor aria +editor_free_text_aria_label=Επεξεργασία ελεύθερου κειμένου +editor_ink_aria_label=Επεξεργασία γραφής μελανιού +editor_ink_canvas_aria_label=Εικόνα από τον χρήστη diff --git a/cps/static/locale/en-CA/viewer.properties b/cps/static/locale/en-CA/viewer.properties index 554a0e176..786ad3a4b 100644 --- a/cps/static/locale/en-CA/viewer.properties +++ b/cps/static/locale/en-CA/viewer.properties @@ -48,23 +48,21 @@ bookmark_label=Current View tools.title=Tools tools_label=Tools first_page.title=Go to First Page -first_page.label=Go to First Page first_page_label=Go to First Page last_page.title=Go to Last Page -last_page.label=Go to Last Page last_page_label=Go to Last Page page_rotate_cw.title=Rotate Clockwise -page_rotate_cw.label=Rotate Clockwise page_rotate_cw_label=Rotate Clockwise -page_rotate_ccw.title=Rotate Anti-Clockwise -page_rotate_ccw.label=Rotate Anti-Clockwise -page_rotate_ccw_label=Rotate Anti-Clockwise +page_rotate_ccw.title=Rotate Counterclockwise +page_rotate_ccw_label=Rotate Counterclockwise cursor_text_select_tool.title=Enable Text Selection Tool cursor_text_select_tool_label=Text Selection Tool cursor_hand_tool.title=Enable Hand Tool cursor_hand_tool_label=Hand Tool +scroll_page.title=Use Page Scrolling +scroll_page_label=Page Scrolling scroll_vertical.title=Use Vertical Scrolling scroll_vertical_label=Vertical Scrolling scroll_horizontal.title=Use Horizontal Scrolling @@ -137,19 +135,24 @@ print_progress_close=Cancel # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Toggle Sidebar -toggle_sidebar_notification.title=Toggle Sidebar (document contains outline/attachments) +toggle_sidebar_notification2.title=Toggle Sidebar (document contains outline/attachments/layers) toggle_sidebar_label=Toggle Sidebar document_outline.title=Show Document Outline (double-click to expand/collapse all items) document_outline_label=Document Outline attachments.title=Show Attachments attachments_label=Attachments +layers.title=Show Layers (double-click to reset all layers to the default state) +layers_label=Layers thumbs.title=Show Thumbnails thumbs_label=Thumbnails +current_outline_item.title=Find Current Outline Item +current_outline_item_label=Current Outline Item findbar.title=Find in Document findbar_label=Find -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Page {{page}} +additional_layers=Additional Layers +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Page {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -165,9 +168,10 @@ find_previous.title=Find the previous occurrence of the phrase find_previous_label=Previous find_next.title=Find the next occurrence of the phrase find_next_label=Next -find_highlight=Highlight all -find_match_case_label=Match case -find_entire_word_label=Whole words +find_highlight=Highlight All +find_match_case_label=Match Case +find_match_diacritics_label=Match Diacritics +find_entire_word_label=Whole Words find_reached_top=Reached top of document, continued from bottom find_reached_bottom=Reached end of document, continued from top # LOCALIZATION NOTE (find_match_count): The supported plural forms are @@ -222,7 +226,7 @@ page_scale_actual=Actual Size page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=Loading… loading_error=An error occurred while loading the PDF. invalid_file_error=Invalid or corrupted PDF file. missing_file_error=Missing PDF file. @@ -245,3 +249,21 @@ password_cancel=Cancel printing_not_supported=Warning: Printing is not fully supported by this browser. printing_not_ready=Warning: The PDF is not fully loaded for printing. web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts. + +# Editor +editor_none.title=Disable Annotation Editing +editor_none_label=Disable Editing +editor_free_text.title=Add FreeText Annotation +editor_free_text_label=FreeText Annotation +editor_ink.title=Add Ink Annotation +editor_ink_label=Ink Annotation + +freetext_default_content=Enter some text… + +free_text_default_content=Enter text… + +# Editor Parameters +editor_free_text_font_color=Font Colour +editor_free_text_font_size=Font Size +editor_ink_line_color=Line Colour +editor_ink_line_thickness=Line Thickness diff --git a/cps/static/locale/en-GB/viewer.properties b/cps/static/locale/en-GB/viewer.properties index 554a0e176..c8cdaeeee 100644 --- a/cps/static/locale/en-GB/viewer.properties +++ b/cps/static/locale/en-GB/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Current View tools.title=Tools tools_label=Tools first_page.title=Go to First Page -first_page.label=Go to First Page first_page_label=Go to First Page last_page.title=Go to Last Page -last_page.label=Go to Last Page last_page_label=Go to Last Page page_rotate_cw.title=Rotate Clockwise -page_rotate_cw.label=Rotate Clockwise page_rotate_cw_label=Rotate Clockwise page_rotate_ccw.title=Rotate Anti-Clockwise -page_rotate_ccw.label=Rotate Anti-Clockwise page_rotate_ccw_label=Rotate Anti-Clockwise cursor_text_select_tool.title=Enable Text Selection Tool @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Text Selection Tool cursor_hand_tool.title=Enable Hand Tool cursor_hand_tool_label=Hand Tool +scroll_page.title=Use Page Scrolling +scroll_page_label=Page Scrolling scroll_vertical.title=Use Vertical Scrolling scroll_vertical_label=Vertical Scrolling scroll_horizontal.title=Use Horizontal Scrolling @@ -137,19 +135,24 @@ print_progress_close=Cancel # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Toggle Sidebar -toggle_sidebar_notification.title=Toggle Sidebar (document contains outline/attachments) +toggle_sidebar_notification2.title=Toggle Sidebar (document contains outline/attachments/layers) toggle_sidebar_label=Toggle Sidebar document_outline.title=Show Document Outline (double-click to expand/collapse all items) document_outline_label=Document Outline attachments.title=Show Attachments attachments_label=Attachments +layers.title=Show Layers (double-click to reset all layers to the default state) +layers_label=Layers thumbs.title=Show Thumbnails thumbs_label=Thumbnails +current_outline_item.title=Find Current Outline Item +current_outline_item_label=Current Outline Item findbar.title=Find in Document findbar_label=Find -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Page {{page}} +additional_layers=Additional Layers +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Page {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -165,9 +168,10 @@ find_previous.title=Find the previous occurrence of the phrase find_previous_label=Previous find_next.title=Find the next occurrence of the phrase find_next_label=Next -find_highlight=Highlight all -find_match_case_label=Match case -find_entire_word_label=Whole words +find_highlight=Highlight All +find_match_case_label=Match Case +find_match_diacritics_label=Match Diacritics +find_entire_word_label=Whole Words find_reached_top=Reached top of document, continued from bottom find_reached_bottom=Reached end of document, continued from top # LOCALIZATION NOTE (find_match_count): The supported plural forms are @@ -222,7 +226,7 @@ page_scale_actual=Actual Size page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=Loading… loading_error=An error occurred while loading the PDF. invalid_file_error=Invalid or corrupted PDF file. missing_file_error=Missing PDF file. @@ -245,3 +249,33 @@ password_cancel=Cancel printing_not_supported=Warning: Printing is not fully supported by this browser. printing_not_ready=Warning: The PDF is not fully loaded for printing. web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts. + +# Editor +editor_none.title=Disable Annotation Editing +editor_none_label=Disable Editing +editor_free_text.title=Add FreeText Annotation +editor_free_text_label=FreeText Annotation +editor_ink.title=Add Ink Annotation +editor_ink_label=Ink Annotation + +freetext_default_content=Enter some text… + +free_text_default_content=Enter text… + +# Editor Parameters +editor_free_text_font_color=Font Colour +editor_free_text_font_size=Font Size +editor_ink_line_color=Line Colour +editor_ink_line_thickness=Line Thickness + +# Editor Parameters +editor_free_text_color=Colour +editor_free_text_size=Size +editor_ink_color=Colour +editor_ink_thickness=Thickness +editor_ink_opacity=Opacity + +# Editor aria +editor_free_text_aria_label=FreeText Editor +editor_ink_aria_label=Ink Editor +editor_ink_canvas_aria_label=User-created image diff --git a/cps/static/locale/en-US/viewer.properties b/cps/static/locale/en-US/viewer.properties index d31103c00..4a95b937d 100644 --- a/cps/static/locale/en-US/viewer.properties +++ b/cps/static/locale/en-US/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Current View tools.title=Tools tools_label=Tools first_page.title=Go to First Page -first_page.label=Go to First Page first_page_label=Go to First Page last_page.title=Go to Last Page -last_page.label=Go to Last Page last_page_label=Go to Last Page page_rotate_cw.title=Rotate Clockwise -page_rotate_cw.label=Rotate Clockwise page_rotate_cw_label=Rotate Clockwise page_rotate_ccw.title=Rotate Counterclockwise -page_rotate_ccw.label=Rotate Counterclockwise page_rotate_ccw_label=Rotate Counterclockwise cursor_text_select_tool.title=Enable Text Selection Tool @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Text Selection Tool cursor_hand_tool.title=Enable Hand Tool cursor_hand_tool_label=Hand Tool +scroll_page.title=Use Page Scrolling +scroll_page_label=Page Scrolling scroll_vertical.title=Use Vertical Scrolling scroll_vertical_label=Vertical Scrolling scroll_horizontal.title=Use Horizontal Scrolling @@ -147,12 +145,14 @@ layers.title=Show Layers (double-click to reset all layers to the default state) layers_label=Layers thumbs.title=Show Thumbnails thumbs_label=Thumbnails +current_outline_item.title=Find Current Outline Item +current_outline_item_label=Current Outline Item findbar.title=Find in Document findbar_label=Find additional_layers=Additional Layers -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Page {{page}} +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Page {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -168,9 +168,10 @@ find_previous.title=Find the previous occurrence of the phrase find_previous_label=Previous find_next.title=Find the next occurrence of the phrase find_next_label=Next -find_highlight=Highlight all -find_match_case_label=Match case -find_entire_word_label=Whole words +find_highlight=Highlight All +find_match_case_label=Match Case +find_match_diacritics_label=Match Diacritics +find_entire_word_label=Whole Words find_reached_top=Reached top of document, continued from bottom find_reached_bottom=Reached end of document, continued from top # LOCALIZATION NOTE (find_match_count): The supported plural forms are @@ -225,7 +226,7 @@ page_scale_actual=Actual Size page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=Loading… loading_error=An error occurred while loading the PDF. invalid_file_error=Invalid or corrupted PDF file. missing_file_error=Missing PDF file. @@ -248,3 +249,23 @@ password_cancel=Cancel printing_not_supported=Warning: Printing is not fully supported by this browser. printing_not_ready=Warning: The PDF is not fully loaded for printing. web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts. + +# Editor +editor_free_text.title=Add FreeText Annotation +editor_free_text_label=FreeText Annotation +editor_ink.title=Add Ink Annotation +editor_ink_label=Ink Annotation + +free_text_default_content=Enter text… + +# Editor Parameters +editor_free_text_color=Color +editor_free_text_size=Size +editor_ink_color=Color +editor_ink_thickness=Thickness +editor_ink_opacity=Opacity + +# Editor aria +editor_free_text_aria_label=FreeText Editor +editor_ink_aria_label=Ink Editor +editor_ink_canvas_aria_label=User-created image diff --git a/cps/static/locale/eo/viewer.properties b/cps/static/locale/eo/viewer.properties index 804bd9842..77f8b9af7 100644 --- a/cps/static/locale/eo/viewer.properties +++ b/cps/static/locale/eo/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Nuna vido tools.title=Iloj tools_label=Iloj first_page.title=Iri al la unua paĝo -first_page.label=Iri al la unua paĝo first_page_label=Iri al la unua paĝo last_page.title=Iri al la lasta paĝo -last_page.label=Iri al la lasta paĝo last_page_label=Iri al la lasta paĝo page_rotate_cw.title=Rotaciigi dekstrume -page_rotate_cw.label=Rotaciigi dekstrume page_rotate_cw_label=Rotaciigi dekstrume page_rotate_ccw.title=Rotaciigi maldekstrume -page_rotate_ccw.label=Rotaciigi maldekstrume page_rotate_ccw_label=Rotaciigi maldekstrume cursor_text_select_tool.title=Aktivigi tekstan elektilon @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Teksta elektilo cursor_hand_tool.title=Aktivigi ilon de mano cursor_hand_tool_label=Ilo de mano +scroll_page.title=Uzi ŝovadon de paĝo +scroll_page_label=Ŝovado de paĝo scroll_vertical.title=Uzi vertikalan ŝovadon scroll_vertical_label=Vertikala ŝovado scroll_horizontal.title=Uzi horizontalan ŝovadon @@ -137,19 +135,24 @@ print_progress_close=Nuligi # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Montri/kaŝi flankan strion -toggle_sidebar_notification.title=Montri/kaŝi flankan strion (la dokumento enhavas konturon/aneksaĵojn) +toggle_sidebar_notification2.title=Montri/kaŝi flankan strion (la dokumento enhavas konturon/kunsendaĵojn/tavolojn) toggle_sidebar_label=Montri/kaŝi flankan strion document_outline.title=Montri la konturon de dokumento (alklaku duoble por faldi/malfaldi ĉiujn elementojn) document_outline_label=Konturo de dokumento attachments.title=Montri kunsendaĵojn attachments_label=Kunsendaĵojn +layers.title=Montri tavolojn (duoble alklaku por remeti ĉiujn tavolojn en la norman staton) +layers_label=Tavoloj thumbs.title=Montri miniaturojn thumbs_label=Miniaturoj +current_outline_item.title=Trovi nunan konturan elementon +current_outline_item_label=Nuna kontura elemento findbar.title=Serĉi en dokumento findbar_label=Serĉi -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Paĝo {{page}} +additional_layers=Aldonaj tavoloj +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Paĝo {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Serĉi la venontan aperon de la frazo find_next_label=Antaŭen find_highlight=Elstarigi ĉiujn find_match_case_label=Distingi inter majuskloj kaj minuskloj +find_match_diacritics_label=Respekti supersignojn find_entire_word_label=Tutaj vortoj find_reached_top=Komenco de la dokumento atingita, daŭrigado ekde la fino find_reached_bottom=Fino de la dokumento atingita, daŭrigado ekde la komenco @@ -222,7 +226,7 @@ page_scale_actual=Reala grando page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Eraro +loading=Ŝargado… loading_error=Okazis eraro dum la ŝargado de la PDF dosiero. invalid_file_error=Nevalida aŭ difektita PDF dosiero. missing_file_error=Mankas dosiero PDF. @@ -245,3 +249,33 @@ password_cancel=Nuligi printing_not_supported=Averto: tiu ĉi retumilo ne plene subtenas presadon. printing_not_ready=Averto: la PDF dosiero ne estas plene ŝargita por presado. web_fonts_disabled=Neaktivaj teksaĵaj tiparoj: ne elbas uzi enmetitajn tiparojn de PDF. + +# Editor +editor_none.title=Malaktivigi modifon de notoj +editor_none_label=Malaktivigi modifon +editor_free_text.title=Aldoni tekstan noton +editor_free_text_label=Teksta noto +editor_ink.title=Aldoni desegnan noton +editor_ink_label=Desegna noto + +freetext_default_content=Tajpu tekston… + +free_text_default_content=Tajpu tekston… + +# Editor Parameters +editor_free_text_font_color=Tipara koloro +editor_free_text_font_size=Tipara grando +editor_ink_line_color=Linia koloro +editor_ink_line_thickness=Linia larĝo + +# Editor Parameters +editor_free_text_color=Koloro +editor_free_text_size=Grando +editor_ink_color=Koloro +editor_ink_thickness=Dikeco +editor_ink_opacity=Maldiafaneco + +# Editor aria +editor_free_text_aria_label=Teksta redaktilo +editor_ink_aria_label=Inka redaktilo +editor_ink_canvas_aria_label=Bildo kreita de uzanto diff --git a/cps/static/locale/es-AR/viewer.properties b/cps/static/locale/es-AR/viewer.properties index ca2c87ba6..6782eb869 100644 --- a/cps/static/locale/es-AR/viewer.properties +++ b/cps/static/locale/es-AR/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vista actual tools.title=Herramientas tools_label=Herramientas first_page.title=Ir a primera página -first_page.label=Ir a primera página first_page_label=Ir a primera página last_page.title=Ir a última página -last_page.label=Ir a última página last_page_label=Ir a última página page_rotate_cw.title=Rotar horario -page_rotate_cw.label=Rotar horario page_rotate_cw_label=Rotar horario page_rotate_ccw.title=Rotar antihorario -page_rotate_ccw.label=Rotar antihorario page_rotate_ccw_label=Rotar antihorario cursor_text_select_tool.title=Habilitar herramienta de selección de texto @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Herramienta de selección de texto cursor_hand_tool.title=Habilitar herramienta mano cursor_hand_tool_label=Herramienta mano +scroll_page.title=Usar desplazamiento de página +scroll_page_label=Desplazamiento de página scroll_vertical.title=Usar desplazamiento vertical scroll_vertical_label=Desplazamiento vertical scroll_horizontal.title=Usar desplazamiento vertical @@ -137,19 +135,24 @@ print_progress_close=Cancelar # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Alternar barra lateral -toggle_sidebar_notification.title=Intercambiar barra lateral (el documento contiene esquema/adjuntos) +toggle_sidebar_notification2.title=Alternar barra lateral (el documento contiene esquemas/adjuntos/capas) toggle_sidebar_label=Alternar barra lateral document_outline.title=Mostrar esquema del documento (doble clic para expandir/colapsar todos los ítems) document_outline_label=Esquema del documento attachments.title=Mostrar adjuntos attachments_label=Adjuntos +layers.title=Mostrar capas (doble clic para restablecer todas las capas al estado predeterminado) +layers_label=Capas thumbs.title=Mostrar miniaturas thumbs_label=Miniaturas +current_outline_item.title=Buscar elemento de esquema actual +current_outline_item_label=Elemento de esquema actual findbar.title=Buscar en documento findbar_label=Buscar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Página {{page}} +additional_layers=Capas adicionales +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Página {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Buscar la siguiente aparición de la frase find_next_label=Siguiente find_highlight=Resaltar todo find_match_case_label=Coincidir mayúsculas +find_match_diacritics_label=Coincidir diacríticos find_entire_word_label=Palabras completas find_reached_top=Inicio de documento alcanzado, continuando desde abajo find_reached_bottom=Fin de documento alcanzando, continuando desde arriba @@ -222,7 +226,7 @@ page_scale_actual=Tamaño real page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=Cargando… loading_error=Ocurrió un error al cargar el PDF. invalid_file_error=Archivo PDF no válido o cocrrupto. missing_file_error=Archivo PDF faltante. @@ -245,3 +249,33 @@ password_cancel=Cancelar printing_not_supported=Advertencia: La impresión no está totalmente soportada por este navegador. printing_not_ready=Advertencia: El PDF no está completamente cargado para impresión. web_fonts_disabled=Tipografía web deshabilitada: no se pueden usar tipos incrustados en PDF. + +# Editor +editor_none.title=Deshabilitar la edición de anotaciones +editor_none_label=Deshabilitar edición +editor_free_text.title=Agregar anotación FreeText +editor_free_text_label=Anotación FreeText +editor_ink.title=Agregar anotación de tinta +editor_ink_label=Anotación de tinta + +freetext_default_content=Ingresar algún texto… + +free_text_default_content=Ingresar texto… + +# Editor Parameters +editor_free_text_font_color=Color de letra +editor_free_text_font_size=Tamaño de letra +editor_ink_line_color=Color de linea +editor_ink_line_thickness=Grosor de línea + +# Editor Parameters +editor_free_text_color=Color +editor_free_text_size=Tamaño +editor_ink_color=Color +editor_ink_thickness=Espesor +editor_ink_opacity=Opacidad + +# Editor aria +editor_free_text_aria_label=Editor de FreeText +editor_ink_aria_label=Editor de tinta +editor_ink_canvas_aria_label=Imagen creada por el usuario diff --git a/cps/static/locale/es-CL/viewer.properties b/cps/static/locale/es-CL/viewer.properties index b6ac40939..7f375f4d2 100644 --- a/cps/static/locale/es-CL/viewer.properties +++ b/cps/static/locale/es-CL/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vista actual tools.title=Herramientas tools_label=Herramientas first_page.title=Ir a la primera página -first_page.label=Ir a la primera página first_page_label=Ir a la primera página last_page.title=Ir a la última página -last_page.label=Ir a la última página last_page_label=Ir a la última página page_rotate_cw.title=Girar a la derecha -page_rotate_cw.label=Girar a la derecha page_rotate_cw_label=Girar a la derecha page_rotate_ccw.title=Girar a la izquierda -page_rotate_ccw.label=Girar a la izquierda page_rotate_ccw_label=Girar a la izquierda cursor_text_select_tool.title=Activar la herramienta de selección de texto @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Herramienta de selección de texto cursor_hand_tool.title=Activar la herramienta de mano cursor_hand_tool_label=Herramienta de mano +scroll_page.title=Usar desplazamiento de página +scroll_page_label=Desplazamiento de página scroll_vertical.title=Usar desplazamiento vertical scroll_vertical_label=Desplazamiento vertical scroll_horizontal.title=Usar desplazamiento horizontal @@ -137,19 +135,24 @@ print_progress_close=Cancelar # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Barra lateral -toggle_sidebar_notification.title=Cambiar barra lateral (índice de contenidos del documento/adjuntos) +toggle_sidebar_notification2.title=Cambiar barra lateral (índice de contenidos del documento/adjuntos/capas) toggle_sidebar_label=Mostrar u ocultar la barra lateral document_outline.title=Mostrar esquema del documento (doble clic para expandir/contraer todos los elementos) document_outline_label=Esquema del documento attachments.title=Mostrar adjuntos attachments_label=Adjuntos +layers.title=Mostrar capas (doble clic para restablecer todas las capas al estado predeterminado) +layers_label=Capas thumbs.title=Mostrar miniaturas thumbs_label=Miniaturas +current_outline_item.title=Buscar elemento de esquema actual +current_outline_item_label=Elemento de esquema actual findbar.title=Buscar en el documento findbar_label=Buscar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Página {{page}} +additional_layers=Capas adicionales +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Página {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Buscar la siguiente aparición de la frase find_next_label=Siguiente find_highlight=Destacar todos find_match_case_label=Coincidir mayús./minús. +find_match_diacritics_label=Coincidir diacríticos find_entire_word_label=Palabras completas find_reached_top=Se alcanzó el inicio del documento, continuando desde el final find_reached_bottom=Se alcanzó el final del documento, continuando desde el inicio @@ -176,11 +180,11 @@ find_reached_bottom=Se alcanzó el final del documento, continuando desde el ini # index of the currently active find result, respectively a number representing # the total number of matches in the document. find_match_count={[ plural(total) ]} -find_match_count[one]={{current}} de {{total}} coincidencia -find_match_count[two]={{current}} de {{total}} coincidencias -find_match_count[few]={{current}} de {{total}} coincidencias -find_match_count[many]={{current}} de {{total}} coincidencias -find_match_count[other]={{current}} de {{total}} coincidencias +find_match_count[one]=Coincidencia {{current}} de {{total}} +find_match_count[two]=Coincidencia {{current}} de {{total}} +find_match_count[few]=Coincidencia {{current}} de {{total}} +find_match_count[many]=Coincidencia {{current}} de {{total}} +find_match_count[other]=Coincidencia {{current}} de {{total}} # LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are # [zero|one|two|few|many|other], with [other] as the default value. # "{{limit}}" will be replaced by a numerical value. @@ -222,7 +226,7 @@ page_scale_actual=Tamaño actual page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=Cargando… loading_error=Ocurrió un error al cargar el PDF. invalid_file_error=Archivo PDF inválido o corrupto. missing_file_error=Falta el archivo PDF. @@ -245,3 +249,33 @@ password_cancel=Cancelar printing_not_supported=Advertencia: Imprimir no está soportado completamente por este navegador. printing_not_ready=Advertencia: El PDF no está completamente cargado para ser impreso. web_fonts_disabled=Las tipografías web están desactivadas: imposible usar las fuentes PDF embebidas. + +# Editor +editor_none.title=Deshabilitar la edición de anotaciones +editor_none_label=Deshabilitar edición +editor_free_text.title=Agregar anotación FreeText +editor_free_text_label=Anotación FreeText +editor_ink.title=Agregar anotación de tinta +editor_ink_label=Anotación de tinta + +freetext_default_content=Ingresar algún texto… + +free_text_default_content=Ingresar texto… + +# Editor Parameters +editor_free_text_font_color=Color de la fuente +editor_free_text_font_size=Tamaño de la fuente +editor_ink_line_color=Color de la línea +editor_ink_line_thickness=Grosor de la línea + +# Editor Parameters +editor_free_text_color=Color +editor_free_text_size=Tamaño +editor_ink_color=Color +editor_ink_thickness=Grosor +editor_ink_opacity=Opacidad + +# Editor aria +editor_free_text_aria_label=Editor FreeText +editor_ink_aria_label=Editor de tinta +editor_ink_canvas_aria_label=Imagen creada por el usuario diff --git a/cps/static/locale/es-ES/viewer.properties b/cps/static/locale/es-ES/viewer.properties index 75e5f0ad4..9bc7d607b 100644 --- a/cps/static/locale/es-ES/viewer.properties +++ b/cps/static/locale/es-ES/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vista actual tools.title=Herramientas tools_label=Herramientas first_page.title=Ir a la primera página -first_page.label=Ir a la primera página first_page_label=Ir a la primera página last_page.title=Ir a la última página -last_page.label=Ir a la última página last_page_label=Ir a la última página page_rotate_cw.title=Rotar en sentido horario -page_rotate_cw.label=Rotar en sentido horario page_rotate_cw_label=Rotar en sentido horario page_rotate_ccw.title=Rotar en sentido antihorario -page_rotate_ccw.label=Rotar en sentido antihorario page_rotate_ccw_label=Rotar en sentido antihorario cursor_text_select_tool.title=Activar herramienta de selección de texto @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Herramienta de selección de texto cursor_hand_tool.title=Activar herramienta de mano cursor_hand_tool_label=Herramienta de mano +scroll_page.title=Usar desplazamiento de página +scroll_page_label=Desplazamiento de página scroll_vertical.title=Usar desplazamiento vertical scroll_vertical_label=Desplazamiento vertical scroll_horizontal.title=Usar desplazamiento horizontal @@ -137,19 +135,24 @@ print_progress_close=Cancelar # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Cambiar barra lateral -toggle_sidebar_notification.title=Alternar panel lateral (el documento contiene un esquema o adjuntos) +toggle_sidebar_notification2.title=Alternar barra lateral (el documento contiene esquemas/adjuntos/capas) toggle_sidebar_label=Cambiar barra lateral document_outline.title=Mostrar resumen del documento (doble clic para expandir/contraer todos los elementos) document_outline_label=Resumen de documento attachments.title=Mostrar adjuntos attachments_label=Adjuntos +layers.title=Mostrar capas (doble clic para restablecer todas las capas al estado predeterminado) +layers_label=Capas thumbs.title=Mostrar miniaturas thumbs_label=Miniaturas +current_outline_item.title=Encontrar elemento de esquema actual +current_outline_item_label=Elemento de esquema actual findbar.title=Buscar en el documento findbar_label=Buscar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Página {{page}} +additional_layers=Capas adicionales +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Página {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Encontrar la siguiente aparición de esta frase find_next_label=Siguiente find_highlight=Resaltar todos find_match_case_label=Coincidencia de mayús./minús. +find_match_diacritics_label=Coincidir diacríticos find_entire_word_label=Palabras completas find_reached_top=Se alcanzó el inicio del documento, se continúa desde el final find_reached_bottom=Se alcanzó el final del documento, se continúa desde el inicio @@ -222,7 +226,7 @@ page_scale_actual=Tamaño real page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=Cargando… loading_error=Ocurrió un error al cargar el PDF. invalid_file_error=Fichero PDF no válido o corrupto. missing_file_error=No hay fichero PDF. @@ -245,3 +249,21 @@ password_cancel=Cancelar printing_not_supported=Advertencia: Imprimir no está totalmente soportado por este navegador. printing_not_ready=Advertencia: Este PDF no se ha cargado completamente para poder imprimirse. web_fonts_disabled=Las tipografías web están desactivadas: es imposible usar las tipografías PDF embebidas. + +# Editor +editor_none.title=Desactivar la edición de anotaciones +editor_none_label=Desactivar edición +editor_free_text.title=Añadir anotación FreeText +editor_free_text_label=Anotación FreeText +editor_ink.title=Añadir anotación de tinta +editor_ink_label=Anotación de tinta + +freetext_default_content=Introduzca algún texto… + +free_text_default_content=Introducir texto… + +# Editor Parameters +editor_free_text_font_color=Color de la fuente +editor_free_text_font_size=Tamaño de la fuente +editor_ink_line_color=Color de la línea +editor_ink_line_thickness=Grosor de la línea diff --git a/cps/static/locale/es-MX/viewer.properties b/cps/static/locale/es-MX/viewer.properties index 5098ad195..03dfaa114 100644 --- a/cps/static/locale/es-MX/viewer.properties +++ b/cps/static/locale/es-MX/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vista actual tools.title=Herramientas tools_label=Herramientas first_page.title=Ir a la primera página -first_page.label=Ir a la primera página first_page_label=Ir a la primera página last_page.title=Ir a la última página -last_page.label=Ir a la última página last_page_label=Ir a la última página page_rotate_cw.title=Girar a la derecha -page_rotate_cw.label=Girar a la derecha page_rotate_cw_label=Girar a la derecha page_rotate_ccw.title=Girar a la izquierda -page_rotate_ccw.label=Girar a la izquierda page_rotate_ccw_label=Girar a la izquierda cursor_text_select_tool.title=Activar la herramienta de selección de texto @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Herramienta de selección de texto cursor_hand_tool.title=Activar la herramienta de mano cursor_hand_tool_label=Herramienta de mano +scroll_page.title=Usar desplazamiento de página +scroll_page_label=Desplazamiento de página scroll_vertical.title=Usar desplazamiento vertical scroll_vertical_label=Desplazamiento vertical scroll_horizontal.title=Usar desplazamiento horizontal @@ -137,19 +135,24 @@ print_progress_close=Cancelar # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Cambiar barra lateral -toggle_sidebar_notification.title=Cambiar barra lateral (índice de contenidos del documento/adjuntos) +toggle_sidebar_notification2.title=Alternar barra lateral (el documento contiene esquemas/adjuntos/capas) toggle_sidebar_label=Cambiar barra lateral document_outline.title=Mostrar esquema del documento (doble clic para expandir/contraer todos los elementos) document_outline_label=Esquema del documento attachments.title=Mostrar adjuntos attachments_label=Adjuntos +layers.title=Mostrar capas (doble clic para restablecer todas las capas al estado predeterminado) +layers_label=Capas thumbs.title=Mostrar miniaturas thumbs_label=Miniaturas +current_outline_item.title=Buscar elemento de esquema actual +current_outline_item_label=Elemento de esquema actual findbar.title=Buscar en el documento findbar_label=Buscar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Página {{page}} +additional_layers=Capas adicionales +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Página {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Ir a la siguiente frase encontrada find_next_label=Siguiente find_highlight=Resaltar todo find_match_case_label=Coincidir con mayúsculas y minúsculas +find_match_diacritics_label=Coincidir diacríticos find_entire_word_label=Palabras completas find_reached_top=Se alcanzó el inicio del documento, se buscará al final find_reached_bottom=Se alcanzó el final del documento, se buscará al inicio @@ -222,7 +226,7 @@ page_scale_actual=Tamaño real page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=Cargando… loading_error=Un error ocurrió al cargar el PDF. invalid_file_error=Archivo PDF invalido o dañado. missing_file_error=Archivo PDF no encontrado. @@ -245,3 +249,33 @@ password_cancel=Cancelar printing_not_supported=Advertencia: La impresión no esta completamente soportada por este navegador. printing_not_ready=Advertencia: El PDF no cargo completamente para impresión. web_fonts_disabled=Las fuentes web están desactivadas: es imposible usar las fuentes PDF embebidas. + +# Editor +editor_none.title=Deshabilitar la edición de anotaciones +editor_none_label=Deshabilitar edición +editor_free_text.title=Agregar anotación FreeText +editor_free_text_label=Anotación FreeText +editor_ink.title=Agregar anotación de tinta +editor_ink_label=Anotación de tinta + +freetext_default_content=Ingresar algún texto… + +free_text_default_content=Ingresar texto… + +# Editor Parameters +editor_free_text_font_color=Color de fuente +editor_free_text_font_size=Tamaño de la fuente +editor_ink_line_color=Color de línea +editor_ink_line_thickness=Grosor de la línea + +# Editor Parameters +editor_free_text_color=Color +editor_free_text_size=Tamaño +editor_ink_color=Color +editor_ink_thickness=Grossor +editor_ink_opacity=Opacidad + +# Editor aria +editor_free_text_aria_label=Editor de FreeText +editor_ink_aria_label=Editor de tinta +editor_ink_canvas_aria_label=Imagen creada por el usuario diff --git a/cps/static/locale/et/viewer.properties b/cps/static/locale/et/viewer.properties index 97f2c9bd7..2d2f7da5c 100644 --- a/cps/static/locale/et/viewer.properties +++ b/cps/static/locale/et/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Praegune vaade tools.title=Tööriistad tools_label=Tööriistad first_page.title=Mine esimesele leheküljele -first_page.label=Mine esimesele leheküljele first_page_label=Mine esimesele leheküljele last_page.title=Mine viimasele leheküljele -last_page.label=Mine viimasele leheküljele last_page_label=Mine viimasele leheküljele page_rotate_cw.title=Pööra päripäeva -page_rotate_cw.label=Pööra päripäeva page_rotate_cw_label=Pööra päripäeva page_rotate_ccw.title=Pööra vastupäeva -page_rotate_ccw.label=Pööra vastupäeva page_rotate_ccw_label=Pööra vastupäeva cursor_text_select_tool.title=Luba teksti valimise tööriist @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Teksti valimise tööriist cursor_hand_tool.title=Luba sirvimistööriist cursor_hand_tool_label=Sirvimistööriist +scroll_page.title=Kasutatakse lehe kaupa kerimist +scroll_page_label=Lehe kaupa kerimine scroll_vertical.title=Kasuta vertikaalset kerimist scroll_vertical_label=Vertikaalne kerimine scroll_horizontal.title=Kasuta horisontaalset kerimist @@ -137,17 +135,24 @@ print_progress_close=Loobu # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Näita külgriba -toggle_sidebar_notification.title=Näita külgriba (dokument sisaldab sisukorda/manuseid) +toggle_sidebar_notification2.title=Näita külgriba (dokument sisaldab sisukorda/manuseid/kihte) toggle_sidebar_label=Näita külgriba document_outline.title=Näita sisukorda (kõigi punktide laiendamiseks/ahendamiseks topeltklõpsa) document_outline_label=Näita sisukorda attachments.title=Näita manuseid attachments_label=Manused +layers.title=Näita kihte (kõikide kihtide vaikeolekusse lähtestamiseks topeltklõpsa) +layers_label=Kihid thumbs.title=Näita pisipilte thumbs_label=Pisipildid +current_outline_item.title=Otsi üles praegune kontuuriüksus +current_outline_item_label=Praegune kontuuriüksus findbar.title=Otsi dokumendist findbar_label=Otsi +additional_layers=Täiendavad kihid +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Lehekülg {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -165,6 +170,7 @@ find_next.title=Otsi fraasi järgmine esinemiskoht find_next_label=Järgmine find_highlight=Too kõik esile find_match_case_label=Tõstutundlik +find_match_diacritics_label=Otsitakse diakriitiliselt find_entire_word_label=Täissõnad find_reached_top=Jõuti dokumendi algusesse, jätkati lõpust find_reached_bottom=Jõuti dokumendi lõppu, jätkati algusest @@ -220,7 +226,7 @@ page_scale_actual=Tegelik suurus page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Viga +loading=Laadimine… loading_error=PDFi laadimisel esines viga. invalid_file_error=Vigane või rikutud PDF-fail. missing_file_error=PDF-fail puudub. @@ -243,3 +249,21 @@ password_cancel=Loobu printing_not_supported=Hoiatus: printimine pole selle brauseri poolt täielikult toetatud. printing_not_ready=Hoiatus: PDF pole printimiseks täielikult laaditud. web_fonts_disabled=Veebifondid on keelatud: PDFiga kaasatud fonte pole võimalik kasutada. + +# Editor +editor_none.title=Keela annotatsioonide muutmine +editor_none_label=Keela muutmine +editor_free_text.title=Lisa vabateksti annotatsioon +editor_free_text_label=Vabateksti annotatsioon +editor_ink.title=Lisa tindiannotatsioon +editor_ink_label=Tindiannotatsioon + +freetext_default_content=Sisesta mingi tekst… + +free_text_default_content=Sisesta tekst… + +# Editor Parameters +editor_free_text_font_color=Fondi värv +editor_free_text_font_size=Fondi suurus +editor_ink_line_color=Joone värv +editor_ink_line_thickness=Joone paksus diff --git a/cps/static/locale/eu/viewer.properties b/cps/static/locale/eu/viewer.properties index 5700d6019..664445935 100644 --- a/cps/static/locale/eu/viewer.properties +++ b/cps/static/locale/eu/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Uneko ikuspegia tools.title=Tresnak tools_label=Tresnak first_page.title=Joan lehen orrira -first_page.label=Joan lehen orrira first_page_label=Joan lehen orrira last_page.title=Joan azken orrira -last_page.label=Joan azken orrira last_page_label=Joan azken orrira page_rotate_cw.title=Biratu erlojuaren norantzan -page_rotate_cw.label=Biratu erlojuaren norantzan page_rotate_cw_label=Biratu erlojuaren norantzan page_rotate_ccw.title=Biratu erlojuaren aurkako norantzan -page_rotate_ccw.label=Biratu erlojuaren aurkako norantzan page_rotate_ccw_label=Biratu erlojuaren aurkako norantzan cursor_text_select_tool.title=Gaitu testuaren hautapen tresna @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Testuaren hautapen tresna cursor_hand_tool.title=Gaitu eskuaren tresna cursor_hand_tool_label=Eskuaren tresna +scroll_page.title=Erabili orriaren korritzea +scroll_page_label=Orriaren korritzea scroll_vertical.title=Erabili korritze bertikala scroll_vertical_label=Korritze bertikala scroll_horizontal.title=Erabili korritze horizontala @@ -137,19 +135,24 @@ print_progress_close=Utzi # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Txandakatu alboko barra -toggle_sidebar_notification.title=Txandakatu alboko barra (dokumentuak eskema/eranskinak ditu) +toggle_sidebar_notification2.title=Txandakatu alboko barra (dokumentuak eskema/eranskinak/geruzak ditu) toggle_sidebar_label=Txandakatu alboko barra document_outline.title=Erakutsi dokumentuaren eskema (klik bikoitza elementu guztiak zabaltzeko/tolesteko) document_outline_label=Dokumentuaren eskema attachments.title=Erakutsi eranskinak attachments_label=Eranskinak +layers.title=Erakutsi geruzak (klik bikoitza geruza guztiak egoera lehenetsira berrezartzeko) +layers_label=Geruzak thumbs.title=Erakutsi koadro txikiak thumbs_label=Koadro txikiak +current_outline_item.title=Bilatu uneko eskemaren elementua +current_outline_item_label=Uneko eskemaren elementua findbar.title=Bilatu dokumentuan findbar_label=Bilatu -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas={{page}}. orria +additional_layers=Geruza gehigarriak +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark={{page}}. orria # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Bilatu esaldiaren hurrengo parekatzea find_next_label=Hurrengoa find_highlight=Nabarmendu guztia find_match_case_label=Bat etorri maiuskulekin/minuskulekin +find_match_diacritics_label=Bereizi diakritikoak find_entire_word_label=Hitz osoak find_reached_top=Dokumentuaren hasierara heldu da, bukaeratik jarraitzen find_reached_bottom=Dokumentuaren bukaerara heldu da, hasieratik jarraitzen @@ -222,7 +226,7 @@ page_scale_actual=Benetako tamaina page_scale_percent=%{{scale}} # Loading indicator messages -loading_error_indicator=Errorea +loading=Kargatzen… loading_error=Errorea gertatu da PDFa kargatzean. invalid_file_error=PDF fitxategi baliogabe edo hondatua. missing_file_error=PDF fitxategia falta da. @@ -245,3 +249,21 @@ password_cancel=Utzi printing_not_supported=Abisua: inprimatzeko euskarria ez da erabatekoa nabigatzaile honetan. printing_not_ready=Abisua: PDFa ez dago erabat kargatuta inprimatzeko. web_fonts_disabled=Webeko letra-tipoak desgaituta daude: ezin dira kapsulatutako PDF letra-tipoak erabili. + +# Editor +editor_none.title=Desgaitu oharren edizioa +editor_none_label=Desgaitu edizioa +editor_free_text.title=Gehitu testu-oharra +editor_free_text_label=Testu-oharra +editor_ink.title=Gehitu esku-oharra +editor_ink_label=Esku-oharra + +freetext_default_content=Idatzi testua… + +free_text_default_content=Idatzi testua… + +# Editor Parameters +editor_free_text_font_color=Letra-kolorea +editor_free_text_font_size=Letra-tamaina +editor_ink_line_color=Lerroaren kolorea +editor_ink_line_thickness=Lerroaren lodiera diff --git a/cps/static/locale/fa/viewer.properties b/cps/static/locale/fa/viewer.properties index 9886b39d2..2c28f01b5 100644 --- a/cps/static/locale/fa/viewer.properties +++ b/cps/static/locale/fa/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=نمای فعلی tools.title=ابزارها tools_label=ابزارها first_page.title=برو به اولین صفحه -first_page.label=برو یه اولین صفحه first_page_label=برو به اولین صفحه last_page.title=برو به آخرین صفحه -last_page.label=برو به آخرین صفحه last_page_label=برو به آخرین صفحه page_rotate_cw.title=چرخش ساعتگرد -page_rotate_cw.label=چرخش ساعتگرد page_rotate_cw_label=چرخش ساعتگرد page_rotate_ccw.title=چرخش پاد ساعتگرد -page_rotate_ccw.label=چرخش پاد ساعتگرد page_rotate_ccw_label=چرخش پاد ساعتگرد cursor_text_select_tool.title=فعال کردن ابزارِ انتخابِ متن @@ -126,7 +122,6 @@ print_progress_close=لغو # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=باز و بسته کردن نوار کناری -toggle_sidebar_notification.title=تغییر وضعیت نوار کناری (سند حاوی طرح/پیوست است) toggle_sidebar_label=تغییرحالت نوارکناری document_outline.title=نمایش رئوس مطالب مدارک(برای بازشدن/جمع شدن همه موارد دوبار کلیک کنید) document_outline_label=طرح نوشتار @@ -200,8 +195,6 @@ page_scale_actual=اندازه واقعی‌ # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=خطا loading_error=هنگام بارگیری پرونده PDF خطایی رخ داد. invalid_file_error=پرونده PDF نامعتبر یامعیوب می‌باشد. missing_file_error=پرونده PDF یافت نشد. diff --git a/cps/static/locale/ff/viewer.properties b/cps/static/locale/ff/viewer.properties index 0a081021b..bc954578d 100644 --- a/cps/static/locale/ff/viewer.properties +++ b/cps/static/locale/ff/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Jiytol Gonangol tools.title=Kuutorɗe tools_label=Kuutorɗe first_page.title=Yah to hello adanngo -first_page.label=Yah to hello adanngo first_page_label=Yah to hello adanngo last_page.title=Yah to hello wattindiingo -last_page.label=Yah to hello wattindiingo last_page_label=Yah to hello wattindiingo page_rotate_cw.title=Yiiltu Faya Ñaamo -page_rotate_cw.label=Yiiltu Faya Ñaamo page_rotate_cw_label=Yiiltu Faya Ñaamo page_rotate_ccw.title=Yiiltu Faya Nano -page_rotate_ccw.label=Yiiltu Faya Nano page_rotate_ccw_label=Yiiltu Faya Nano cursor_text_select_tool.title=Gollin kaɓirgel cuɓirgel binndi @@ -137,7 +133,6 @@ print_progress_close=Haaytu # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Toggilo Palal Sawndo -toggle_sidebar_notification.title=Palal sawndo (dokimaa oo ina waɗi taarngo/cinnde) toggle_sidebar_label=Toggilo Palal Sawndo document_outline.title=Hollu Ƴiyal Fiilannde (dobdobo ngam wertude/taggude teme fof) document_outline_label=Toɓɓe Fiilannde @@ -219,8 +214,6 @@ page_scale_actual=Ɓetol Jaati # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Juumre loading_error=Juumre waɗii tuma nde loowata PDF oo. invalid_file_error=Fiilde PDF moƴƴaani walla jiibii. missing_file_error=Fiilde PDF ena ŋakki. diff --git a/cps/static/locale/fi/viewer.properties b/cps/static/locale/fi/viewer.properties index 38c40a395..77123edef 100644 --- a/cps/static/locale/fi/viewer.properties +++ b/cps/static/locale/fi/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Avoin ikkuna tools.title=Tools tools_label=Tools first_page.title=Siirry ensimmäiselle sivulle -first_page.label=Siirry ensimmäiselle sivulle first_page_label=Siirry ensimmäiselle sivulle last_page.title=Siirry viimeiselle sivulle -last_page.label=Siirry viimeiselle sivulle last_page_label=Siirry viimeiselle sivulle page_rotate_cw.title=Kierrä oikealle -page_rotate_cw.label=Kierrä oikealle page_rotate_cw_label=Kierrä oikealle page_rotate_ccw.title=Kierrä vasemmalle -page_rotate_ccw.label=Kierrä vasemmalle page_rotate_ccw_label=Kierrä vasemmalle cursor_text_select_tool.title=Käytä tekstinvalintatyökalua @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Tekstinvalintatyökalu cursor_hand_tool.title=Käytä käsityökalua cursor_hand_tool_label=Käsityökalu +scroll_page.title=Käytä sivun vieritystä +scroll_page_label=Sivun vieritys scroll_vertical.title=Käytä pystysuuntaista vieritystä scroll_vertical_label=Pystysuuntainen vieritys scroll_horizontal.title=Käytä vaakasuuntaista vieritystä @@ -137,19 +135,24 @@ print_progress_close=Peruuta # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Näytä/piilota sivupaneeli -toggle_sidebar_notification.title=Näytä/piilota sivupaneeli (dokumentissa on sisällys tai liitteitä) +toggle_sidebar_notification2.title=Näytä/piilota sivupaneeli (dokumentissa on sisällys/liitteitä/tasoja) toggle_sidebar_label=Näytä/piilota sivupaneeli document_outline.title=Näytä dokumentin sisällys (laajenna tai kutista kohdat kaksoisnapsauttamalla) document_outline_label=Dokumentin sisällys attachments.title=Näytä liitteet attachments_label=Liitteet +layers.title=Näytä tasot (kaksoisnapsauta palauttaaksesi kaikki tasot oletustilaan) +layers_label=Tasot thumbs.title=Näytä pienoiskuvat thumbs_label=Pienoiskuvat +current_outline_item.title=Etsi nykyinen sisällyksen kohta +current_outline_item_label=Nykyinen sisällyksen kohta findbar.title=Etsi dokumentista findbar_label=Etsi -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Sivu {{page}} +additional_layers=Lisätasot +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Sivu {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Etsi hakusanan seuraava osuma find_next_label=Seuraava find_highlight=Korosta kaikki find_match_case_label=Huomioi kirjainkoko +find_match_diacritics_label=Erota tarkkeet find_entire_word_label=Kokonaiset sanat find_reached_top=Päästiin dokumentin alkuun, jatketaan lopusta find_reached_bottom=Päästiin dokumentin loppuun, jatketaan alusta @@ -222,7 +226,7 @@ page_scale_actual=Todellinen koko page_scale_percent={{scale}} % # Loading indicator messages -loading_error_indicator=Virhe +loading=Ladataan… loading_error=Tapahtui virhe ladattaessa PDF-tiedostoa. invalid_file_error=Virheellinen tai vioittunut PDF-tiedosto. missing_file_error=Puuttuva PDF-tiedosto. @@ -245,3 +249,19 @@ password_cancel=Peruuta printing_not_supported=Varoitus: Selain ei tue kaikkia tulostustapoja. printing_not_ready=Varoitus: PDF-tiedosto ei ole vielä latautunut kokonaan, eikä sitä voi vielä tulostaa. web_fonts_disabled=Verkkosivujen omat kirjasinlajit on estetty: ei voida käyttää upotettuja PDF-kirjasinlajeja. + +# Editor +editor_none_label=Poista muokkaus käytöstä + + +free_text_default_content=Kirjoita tekstiä… + +# Editor Parameters + +# Editor Parameters +editor_free_text_color=Väri +editor_free_text_size=Koko +editor_ink_color=Väri + +# Editor aria +editor_ink_canvas_aria_label=Käyttäjän luoma kuva diff --git a/cps/static/locale/fr/viewer.properties b/cps/static/locale/fr/viewer.properties index 589a4185c..1d358c2fe 100644 --- a/cps/static/locale/fr/viewer.properties +++ b/cps/static/locale/fr/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Affichage actuel tools.title=Outils tools_label=Outils first_page.title=Aller à la première page -first_page.label=Aller à la première page first_page_label=Aller à la première page last_page.title=Aller à la dernière page -last_page.label=Aller à la dernière page last_page_label=Aller à la dernière page page_rotate_cw.title=Rotation horaire -page_rotate_cw.label=Rotation horaire page_rotate_cw_label=Rotation horaire page_rotate_ccw.title=Rotation antihoraire -page_rotate_ccw.label=Rotation antihoraire page_rotate_ccw_label=Rotation antihoraire cursor_text_select_tool.title=Activer l’outil de sélection de texte @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Outil de sélection de texte cursor_hand_tool.title=Activer l’outil main cursor_hand_tool_label=Outil main +scroll_page.title=Utiliser le défilement par page +scroll_page_label=Défilement par page scroll_vertical.title=Utiliser le défilement vertical scroll_vertical_label=Défilement vertical scroll_horizontal.title=Utiliser le défilement horizontal @@ -137,19 +135,24 @@ print_progress_close=Annuler # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Afficher/Masquer le panneau latéral -toggle_sidebar_notification.title=Afficher/Masquer le panneau latéral (le document contient des signets/pièces jointes) +toggle_sidebar_notification2.title=Afficher/Masquer le panneau latéral (le document contient des signets/pièces jointes/calques) toggle_sidebar_label=Afficher/Masquer le panneau latéral document_outline.title=Afficher les signets du document (double-cliquer pour développer/réduire tous les éléments) document_outline_label=Signets du document attachments.title=Afficher les pièces jointes attachments_label=Pièces jointes +layers.title=Afficher les calques (double-cliquer pour réinitialiser tous les calques à l’état par défaut) +layers_label=Calques thumbs.title=Afficher les vignettes thumbs_label=Vignettes +current_outline_item.title=Trouver l’élément de plan actuel +current_outline_item_label=Élément de plan actuel findbar.title=Rechercher dans le document findbar_label=Rechercher -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Page {{page}} +additional_layers=Calques additionnels +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Page {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Trouver la prochaine occurrence de l’expression find_next_label=Suivant find_highlight=Tout surligner find_match_case_label=Respecter la casse +find_match_diacritics_label=Respecter les accents et diacritiques find_entire_word_label=Mots entiers find_reached_top=Haut de la page atteint, poursuite depuis la fin find_reached_bottom=Bas de la page atteint, poursuite au début @@ -222,7 +226,7 @@ page_scale_actual=Taille réelle page_scale_percent={{scale}} % # Loading indicator messages -loading_error_indicator=Erreur +loading=Chargement… loading_error=Une erreur s’est produite lors du chargement du fichier PDF. invalid_file_error=Fichier PDF invalide ou corrompu. missing_file_error=Fichier PDF manquant. @@ -245,3 +249,31 @@ password_cancel=Annuler printing_not_supported=Attention : l’impression n’est pas totalement prise en charge par ce navigateur. printing_not_ready=Attention : le PDF n’est pas entièrement chargé pour pouvoir l’imprimer. web_fonts_disabled=Les polices web sont désactivées : impossible d’utiliser les polices intégrées au PDF. + +# Editor +editor_none.title=Désactiver l’édition d’annotations +editor_none_label=Désactiver l’édition +editor_free_text.title=Ajouter du texte +editor_free_text_label=Texte +editor_ink.title=Dessiner +editor_ink_label=Dessin + +free_text_default_content=Saisissez du texte… + +# Editor Parameters +editor_free_text_font_color=Couleur de police +editor_free_text_font_size=Taille de police +editor_ink_line_color=Couleur de la ligne +editor_ink_line_thickness=Épaisseur de la ligne + +# Editor Parameters +editor_free_text_color=Couleur +editor_free_text_size=Taille +editor_ink_color=Couleur +editor_ink_thickness=Épaisseur +editor_ink_opacity=Opacité + +# Editor aria +editor_free_text_aria_label=Éditeur de texte +editor_ink_aria_label=Dessin +editor_ink_canvas_aria_label=Image créée par l’utilisateur·trice diff --git a/cps/static/locale/fy-NL/viewer.properties b/cps/static/locale/fy-NL/viewer.properties index 5a506540b..d6ecbb6e9 100644 --- a/cps/static/locale/fy-NL/viewer.properties +++ b/cps/static/locale/fy-NL/viewer.properties @@ -22,7 +22,7 @@ next_label=Folgjende page.title=Side # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number # representing the total number of pages in the document. -of_pages=fa {{pagesCount}} +of_pages=fan {{pagesCount}} # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" # will be replaced by a number representing the currently visible page, # respectively a number representing the total number of pages in the document. @@ -48,16 +48,12 @@ bookmark_label=Aktuele finster tools.title=Ark tools_label=Ark first_page.title=Gean nei earste side -first_page.label=Nei earste side gean first_page_label=Gean nei earste side last_page.title=Gean nei lêste side -last_page.label=Nei lêste side gean last_page_label=Gean nei lêste side page_rotate_cw.title=Rjochtsom draaie -page_rotate_cw.label=Rjochtsom draaie page_rotate_cw_label=Rjochtsom draaie page_rotate_ccw.title=Loftsom draaie -page_rotate_ccw.label=Loftsom draaie page_rotate_ccw_label=Loftsom draaie cursor_text_select_tool.title=Tekstseleksjehelpmiddel ynskeakelje @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Tekstseleksjehelpmiddel cursor_hand_tool.title=Hânhelpmiddel ynskeakelje cursor_hand_tool_label=Hânhelpmiddel +scroll_page.title=Sideskowen brûke +scroll_page_label=Sideskowen scroll_vertical.title=Fertikaal skowe brûke scroll_vertical_label=Fertikaal skowe scroll_horizontal.title=Horizontaal skowe brûke @@ -137,19 +135,24 @@ print_progress_close=Annulearje # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Sidebalke yn-/útskeakelje -toggle_sidebar_notification.title=Sidebalke yn-/útskeakelje (dokumint befettet outline/bylagen) +toggle_sidebar_notification2.title=Sidebalke yn-/útskeakelje (dokumint befettet oersjoch/bylagen/lagen) toggle_sidebar_label=Sidebalke yn-/útskeakelje document_outline.title=Dokumintoersjoch toane (dûbelklik om alle items út/yn te klappen) document_outline_label=Dokumintoersjoch attachments.title=Bylagen toane attachments_label=Bylagen +layers.title=Lagen toane (dûbelklik om alle lagen nei de standertsteat werom te setten) +layers_label=Lagen thumbs.title=Foarbylden toane thumbs_label=Foarbylden +current_outline_item.title=Aktueel item yn ynhâldsopjefte sykje +current_outline_item_label=Aktueel item yn ynhâldsopjefte findbar.title=Sykje yn dokumint findbar_label=Sykje -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Side {{page}} +additional_layers=Oanfoljende lagen +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Side {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=It folgjende foarkommen fan de tekst sykje find_next_label=Folgjende find_highlight=Alles markearje find_match_case_label=Haadlettergefoelich +find_match_diacritics_label=Diakrityske tekens brûke find_entire_word_label=Hiele wurden find_reached_top=Boppekant fan dokumint berikt, trochgien fan ûnder ôf find_reached_bottom=Ein fan dokumint berikt, trochgien fan boppe ôf @@ -222,7 +226,7 @@ page_scale_actual=Werklike grutte page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Flater +loading=Lade… loading_error=Der is in flater bard by it laden fan de PDF. invalid_file_error=Ynfalide of korruptearre PDF-bestân. missing_file_error=PDF-bestân ûntbrekt. @@ -245,3 +249,33 @@ password_cancel=Annulearje printing_not_supported=Warning: Printen is net folslein stipe troch dizze browser. printing_not_ready=Warning: PDF is net folslein laden om ôf te drukken. web_fonts_disabled=Weblettertypen binne útskeakele: gebrûk fan ynsluten PDF-lettertypen is net mooglik. + +# Editor +editor_none.title=Bewurkjen fan annotaasjes útskeakelje +editor_none_label=Bewurkjen útskeakelje +editor_free_text.title=FreeText-annotaasje tafoegje +editor_free_text_label=FreeText-annotaasje +editor_ink.title=Ink-annotaasje tafoegje +editor_ink_label=Ink-annotaasje + +freetext_default_content=Fier wat tekst yn… + +free_text_default_content=Fier tekst yn… + +# Editor Parameters +editor_free_text_font_color=Letterkleur +editor_free_text_font_size=Lettergrutte +editor_ink_line_color=Linekleur +editor_ink_line_thickness=Linedikte + +# Editor Parameters +editor_free_text_color=Kleur +editor_free_text_size=Grutte +editor_ink_color=Kleur +editor_ink_thickness=Tsjokte +editor_ink_opacity=Transparânsje + +# Editor aria +editor_free_text_aria_label=FreeText-bewurker +editor_ink_aria_label=Ink-bewurker +editor_ink_canvas_aria_label=Troch brûker makke ôfbylding diff --git a/cps/static/locale/ga-IE/viewer.properties b/cps/static/locale/ga-IE/viewer.properties index f606e81b0..e82e55b14 100644 --- a/cps/static/locale/ga-IE/viewer.properties +++ b/cps/static/locale/ga-IE/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=An tAmharc Reatha tools.title=Uirlisí tools_label=Uirlisí first_page.title=Go dtí an chéad leathanach -first_page.label=Go dtí an chéad leathanach first_page_label=Go dtí an chéad leathanach last_page.title=Go dtí an leathanach deiridh -last_page.label=Go dtí an leathanach deiridh last_page_label=Go dtí an leathanach deiridh page_rotate_cw.title=Rothlaigh ar deiseal -page_rotate_cw.label=Rothlaigh ar deiseal page_rotate_cw_label=Rothlaigh ar deiseal page_rotate_ccw.title=Rothlaigh ar tuathal -page_rotate_ccw.label=Rothlaigh ar tuathal page_rotate_ccw_label=Rothlaigh ar tuathal cursor_text_select_tool.title=Cumasaigh an Uirlis Roghnaithe Téacs @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Uirlis Roghnaithe Téacs cursor_hand_tool.title=Cumasaigh an Uirlis Láimhe cursor_hand_tool_label=Uirlis Láimhe + + # Document properties dialog box document_properties.title=Airíonna na Cáipéise… document_properties_label=Airíonna na Cáipéise… @@ -89,6 +87,14 @@ document_properties_creator=Cruthaitheoir: document_properties_producer=Cruthaitheoir an PDF: document_properties_version=Leagan PDF: document_properties_page_count=Líon Leathanach: +# LOCALIZATION NOTE (document_properties_page_size_dimension_string): +# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement and orientation, of the (current) page. +# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): +# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement, name, and orientation, of the (current) page. +# LOCALIZATION NOTE (document_properties_linearized): The linearization status of +# the document; usually called "Fast Web View" in English locales of Adobe software. document_properties_close=Dún print_progress_message=Cáipéis á hullmhú le priontáil… @@ -101,7 +107,6 @@ print_progress_close=Cealaigh # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Scoránaigh an Barra Taoibh -toggle_sidebar_notification.title=Scoránaigh an Barra Taoibh (achoimre/iatáin sa cháipéis) toggle_sidebar_label=Scoránaigh an Barra Taoibh document_outline.title=Taispeáin Imlíne na Cáipéise (déchliceáil chun chuile rud a leathnú nó a laghdú) document_outline_label=Creatlach na Cáipéise @@ -112,6 +117,7 @@ thumbs_label=Mionsamhlacha findbar.title=Aimsigh sa Cháipéis findbar_label=Aimsigh +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -129,8 +135,18 @@ find_next.title=Aimsigh an chéad sampla eile den nath sin find_next_label=Ar aghaidh find_highlight=Aibhsigh uile find_match_case_label=Cásíogair +find_entire_word_label=Focail iomlána find_reached_top=Ag barr na cáipéise, ag leanúint ón mbun find_reached_bottom=Ag bun na cáipéise, ag leanúint ón mbarr +# LOCALIZATION NOTE (find_match_count): The supported plural forms are +# [one|two|few|many|other], with [other] as the default value. +# "{{current}}" and "{{total}}" will be replaced by a number representing the +# index of the currently active find result, respectively a number representing +# the total number of matches in the document. +find_match_count={[ plural(total) ]} +# LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are +# [zero|one|two|few|many|other], with [other] as the default value. +# "{{limit}}" will be replaced by a numerical value. find_not_found=Frása gan aimsiú # Error panel labels @@ -162,12 +178,14 @@ page_scale_actual=Fíormhéid page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Earráid loading_error=Tharla earráid agus an cháipéis PDF á lódáil. invalid_file_error=Comhad neamhbhailí nó truaillithe PDF. missing_file_error=Comhad PDF ar iarraidh. unexpected_response_error=Freagra ón bhfreastalaí nach rabhthas ag súil leis. +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. + # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). diff --git a/cps/static/locale/gd/viewer.properties b/cps/static/locale/gd/viewer.properties index af4433e3f..4f056b1e0 100644 --- a/cps/static/locale/gd/viewer.properties +++ b/cps/static/locale/gd/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=An sealladh làithreach tools.title=Innealan tools_label=Innealan first_page.title=Rach gun chiad duilleag -first_page.label=Rach gun chiad duilleag first_page_label=Rach gun chiad duilleag last_page.title=Rach gun duilleag mu dheireadh -last_page.label=Rach gun duilleag mu dheireadh last_page_label=Rach gun duilleag mu dheireadh page_rotate_cw.title=Cuairtich gu deiseil -page_rotate_cw.label=Cuairtich gu deiseil page_rotate_cw_label=Cuairtich gu deiseil page_rotate_ccw.title=Cuairtich gu tuathail -page_rotate_ccw.label=Cuairtich gu tuathail page_rotate_ccw_label=Cuairtich gu tuathail cursor_text_select_tool.title=Cuir an comas inneal taghadh an teacsa @@ -137,17 +133,24 @@ print_progress_close=Sguir dheth # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Toglaich am bàr-taoibh -toggle_sidebar_notification.title=Toglaich am bàr-taoibh (tha oir-loidhne/ceanglachain aig an sgrìobhainn) +toggle_sidebar_notification2.title=Toglaich am bàr-taoibh (tha oir-loidhne/ceanglachain/breathan aig an sgrìobhainn) toggle_sidebar_label=Toglaich am bàr-taoibh document_outline.title=Seall oir-loidhne na sgrìobhainn (dèan briogadh dùbailte airson a h-uile nì a leudachadh/a cho-theannadh) document_outline_label=Oir-loidhne na sgrìobhainne attachments.title=Seall na ceanglachain attachments_label=Ceanglachain +layers.title=Seall na breathan (dèan briogadh dùbailte airson a h-uile breath ath-shuidheachadh dhan staid bhunaiteach) +layers_label=Breathan thumbs.title=Seall na dealbhagan thumbs_label=Dealbhagan +current_outline_item.title=Lorg nì làithreach na h-oir-loidhne +current_outline_item_label=Nì làithreach na h-oir-loidhne findbar.title=Lorg san sgrìobhainn findbar_label=Lorg +additional_layers=Barrachd breathan +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Duilleag {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -220,12 +223,16 @@ page_scale_actual=Am fìor-mheud page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Mearachd +loading=’Ga luchdadh… loading_error=Thachair mearachd rè luchdadh a' PDF. invalid_file_error=Faidhle PDF a tha mì-dhligheach no coirbte. missing_file_error=Faidhle PDF a tha a dhìth. unexpected_response_error=Freagairt on fhrithealaiche ris nach robh dùil. +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. +annotation_date_string={{date}}, {{time}} + # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). @@ -233,7 +240,7 @@ unexpected_response_error=Freagairt on fhrithealaiche ris nach robh dùil. text_annotation_type.alt=[Nòtachadh {{type}}] password_label=Cuir a-steach am facal-faire gus am faidhle PDF seo fhosgladh. password_invalid=Tha am facal-faire cearr. Nach fheuch thu ris a-rithist? -password_ok=Ceart ma-tha +password_ok=Ceart ma-thà password_cancel=Sguir dheth printing_not_supported=Rabhadh: Chan eil am brabhsair seo a' cur làn-taic ri clò-bhualadh. diff --git a/cps/static/locale/gl/viewer.properties b/cps/static/locale/gl/viewer.properties index c3a30fecd..d4ea8174f 100644 --- a/cps/static/locale/gl/viewer.properties +++ b/cps/static/locale/gl/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vista actual tools.title=Ferramentas tools_label=Ferramentas first_page.title=Ir á primeira páxina -first_page.label=Ir á primeira páxina first_page_label=Ir á primeira páxina last_page.title=Ir á última páxina -last_page.label=Ir á última páxina last_page_label=Ir á última páxina page_rotate_cw.title=Rotar no sentido das agullas do reloxo -page_rotate_cw.label=Rotar no sentido das agullas do reloxo page_rotate_cw_label=Rotar no sentido das agullas do reloxo page_rotate_ccw.title=Rotar no sentido contrario ás agullas do reloxo -page_rotate_ccw.label=Rotar no sentido contrario ás agullas do reloxo page_rotate_ccw_label=Rotar no sentido contrario ás agullas do reloxo cursor_text_select_tool.title=Activar a ferramenta de selección de texto @@ -137,19 +133,24 @@ print_progress_close=Cancelar # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Amosar/agochar a barra lateral -toggle_sidebar_notification.title=Amosar/agochar a barra lateral (o documento contén un esquema ou anexos) +toggle_sidebar_notification2.title=Alternar barra lateral (o documento contén esquema/anexos/capas) toggle_sidebar_label=Amosar/agochar a barra lateral document_outline.title=Amosar o esquema do documento (prema dúas veces para expandir/contraer todos os elementos) document_outline_label=Esquema do documento attachments.title=Amosar anexos attachments_label=Anexos +layers.title=Mostrar capas (prema dúas veces para restaurar todas as capas o estado predeterminado) +layers_label=Capas thumbs.title=Amosar miniaturas thumbs_label=Miniaturas +current_outline_item.title=Atopar o elemento delimitado actualmente +current_outline_item_label=Elemento delimitado actualmente findbar.title=Atopar no documento findbar_label=Atopar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Páxina {{page}} +additional_layers=Capas adicionais +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Páxina {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -222,7 +223,7 @@ page_scale_actual=Tamaño actual page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Erro +loading=A cargar… loading_error=Produciuse un erro ao cargar o PDF. invalid_file_error=Ficheiro PDF danado ou non válido. missing_file_error=Falta o ficheiro PDF. diff --git a/cps/static/locale/gn/viewer.properties b/cps/static/locale/gn/viewer.properties index 4b893971d..566e361bb 100644 --- a/cps/static/locale/gn/viewer.properties +++ b/cps/static/locale/gn/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Ag̃agua jehecha tools.title=Tembipuru tools_label=Tembipuru first_page.title=Kuatiarogue ñepyrũme jeho -first_page.label=Kuatiarogue ñepyrũme jeho first_page_label=Kuatiarogue ñepyrũme jeho last_page.title=Kuatiarogue pahápe jeho -last_page.label=Kuatiarogue pahápe jeho last_page_label=Kuatiarogue pahápe jeho page_rotate_cw.title=Aravóicha mbojere -page_rotate_cw.label=Aravóicha mbojere page_rotate_cw_label=Aravóicha mbojere page_rotate_ccw.title=Aravo rapykue gotyo mbojere -page_rotate_ccw.label=Aravo rapykue gotyo mbojere page_rotate_ccw_label=Aravo rapykue gotyo mbojere cursor_text_select_tool.title=Emyandy moñe’ẽrã jeporavo rembipuru @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Moñe’ẽrã jeporavo rembipuru cursor_hand_tool.title=Tembipuru po pegua myandy cursor_hand_tool_label=Tembipuru po pegua +scroll_page.title=Eipuru kuatiarogue jeku’e +scroll_page_label=Kuatiarogue jeku’e scroll_vertical.title=Eipuru jeku’e ykeguáva scroll_vertical_label=Jeku’e ykeguáva scroll_horizontal.title=Eipuru jeku’e yvate gotyo @@ -137,19 +135,24 @@ print_progress_close=Heja # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Tenda yke moambue -toggle_sidebar_notification.title=Embojopyru tenda ykegua (kuatia oguereko kora/marandurenda moirũha) +toggle_sidebar_notification2.title=Embojopyru tenda ykegua (kuatia oguereko kuaakaha/moirũha/ñuãha) toggle_sidebar_label=Tenda yke moambue document_outline.title=Ehechauka kuatia rape (eikutu mokõi jey embotuicha/emomichĩ hag̃ua opavavete mba’epuru) document_outline_label=Kuatia apopyre attachments.title=Moirũha jehechauka attachments_label=Moirũha +layers.title=Ehechauka ñuãha (eikutu jo’a emomba’apo hag̃ua opaite ñuãha tekoypýpe) +layers_label=Ñuãha thumbs.title=Mba’emirĩ jehechauka thumbs_label=Mba’emirĩ +current_outline_item.title=Eheka mba’epuru ag̃aguaitéva +current_outline_item_label=Mba’epuru ag̃aguaitéva findbar.title=Kuatiápe jeheka findbar_label=Juhu -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Kuatiarogue {{page}} +additional_layers=Ñuãha moirũguáva +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Kuatiarogue {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Eho ñe’ẽ juhupyre upeiguávape find_next_label=Upeigua find_highlight=Embojekuaavepa find_match_case_label=Ejesareko taiguasu/taimichĩre +find_match_diacritics_label=Diacrítico moñondive find_entire_word_label=Ñe’ẽ oĩmbáva find_reached_top=Ojehupyty kuatia ñepyrũ, oku’ejeýta kuatia paha guive find_reached_bottom=Ojehupyty kuatia paha, oku’ejeýta kuatia ñepyrũ guive @@ -222,7 +226,7 @@ page_scale_actual=Tuichakue ag̃agua page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Oĩvaíva +loading=Henyhẽhína… loading_error=Oiko jejavy PDF oñemyeñyhẽnguévo. invalid_file_error=PDF marandurenda ndoikóiva térã ivaipyréva. missing_file_error=Ndaipóri PDF marandurenda @@ -245,3 +249,33 @@ password_cancel=Heja printing_not_supported=Kyhyjerã: Ñembokuatia ndojokupytypái ko kundahára ndive. printing_not_ready=Kyhyjerã: Ko PDF nahenyhẽmbái oñembokuatia hag̃uáicha. web_fonts_disabled=Ñanduti taity oñemongéma: ndaikatumo’ãi eipuru PDF jehai’íva taity. + +# Editor +editor_none.title=Eipe’a jehaiha ñembosako’i +editor_none_label=Eipe’a ñembosako’i +editor_free_text.title=Embojuaju FreeText jehaiha +editor_free_text_label=FreeTextjehaiha +editor_ink.title=Embojuaju mbokuatiarã jehaiha +editor_ink_label=Mbokuatiarã jehaiha + +freetext_default_content=Emoinge moñe’ẽrã… + +free_text_default_content=Emoinge moñe’ẽrã… + +# Editor Parameters +editor_free_text_font_color=Teñoiha Sa’y +editor_free_text_font_size=Tai tuichakue +editor_ink_line_color=Tairenda sa’y +editor_ink_line_thickness=Tairenda poguasukue + +# Editor Parameters +editor_free_text_color=Sa’y +editor_free_text_size=Tuichakue +editor_ink_color=Sa’y +editor_ink_thickness=Anambusu +editor_ink_opacity=Pytũngy + +# Editor aria +editor_free_text_aria_label=FreeText Moheñoiha +editor_ink_aria_label=Jehaiha moheñoiha +editor_ink_canvas_aria_label=Ta’ãnga omoheñóiva puruhára diff --git a/cps/static/locale/gu-IN/viewer.properties b/cps/static/locale/gu-IN/viewer.properties index 579c068d9..174d4648c 100644 --- a/cps/static/locale/gu-IN/viewer.properties +++ b/cps/static/locale/gu-IN/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=વર્તમાન દૃશ્ય tools.title=સાધનો tools_label=સાધનો first_page.title=પહેલાં પાનામાં જાવ -first_page.label=પહેલાં પાનામાં જાવ first_page_label=પ્રથમ પાનાં પર જાવ last_page.title=છેલ્લા પાનાં પર જાવ -last_page.label=છેલ્લા પાનામાં જાવ last_page_label=છેલ્લા પાનાં પર જાવ page_rotate_cw.title=ઘડિયાળનાં કાંટા તરફ ફેરવો -page_rotate_cw.label=ઘડિયાળનાં કાંટાની જેમ ફેરવો page_rotate_cw_label=ઘડિયાળનાં કાંટા તરફ ફેરવો page_rotate_ccw.title=ઘડિયાળનાં કાંટાની ઉલટી દિશામાં ફેરવો -page_rotate_ccw.label=ઘડિયાળનાં કાંટાની ઉલટી દિશામાં ફેરવો page_rotate_ccw_label=ઘડિયાળનાં કાંટાની વિરુદ્દ ફેરવો cursor_text_select_tool.title=ટેક્સ્ટ પસંદગી ટૂલ સક્ષમ કરો @@ -137,7 +133,6 @@ print_progress_close=રદ કરો # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=ટૉગલ બાજુપટ્ટી -toggle_sidebar_notification.title=સાઇડબારને ટૉગલ કરો(દસ્તાવેજની રૂપરેખા/જોડાણો શામેલ છે) toggle_sidebar_label=ટૉગલ બાજુપટ્ટી document_outline.title=દસ્તાવેજની રૂપરેખા બતાવો(બધી આઇટમ્સને વિસ્તૃત/સંકુચિત કરવા માટે ડબલ-ક્લિક કરો) document_outline_label=દસ્તાવેજ રૂપરેખા @@ -219,8 +214,6 @@ page_scale_actual=ચોક્કસ માપ # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=ભૂલ loading_error=ભૂલ ઉદ્ભવી જ્યારે PDF ને લાવી રહ્યા હોય. invalid_file_error=અયોગ્ય અથવા ભાંગેલ PDF ફાઇલ. missing_file_error=ગુમ થયેલ PDF ફાઇલ. diff --git a/cps/static/locale/he/viewer.properties b/cps/static/locale/he/viewer.properties index 066478921..65f35edef 100644 --- a/cps/static/locale/he/viewer.properties +++ b/cps/static/locale/he/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=תצוגה נוכחית tools.title=כלים tools_label=כלים first_page.title=מעבר לעמוד הראשון -first_page.label=מעבר לעמוד הראשון first_page_label=מעבר לעמוד הראשון last_page.title=מעבר לעמוד האחרון -last_page.label=מעבר לעמוד האחרון last_page_label=מעבר לעמוד האחרון page_rotate_cw.title=הטיה עם כיוון השעון -page_rotate_cw.label=הטיה עם כיוון השעון page_rotate_cw_label=הטיה עם כיוון השעון page_rotate_ccw.title=הטיה כנגד כיוון השעון -page_rotate_ccw.label=הטיה כנגד כיוון השעון page_rotate_ccw_label=הטיה כנגד כיוון השעון cursor_text_select_tool.title=הפעלת כלי בחירת טקסט @@ -65,6 +61,8 @@ cursor_text_select_tool_label=כלי בחירת טקסט cursor_hand_tool.title=הפעלת כלי היד cursor_hand_tool_label=כלי יד +scroll_page.title=שימוש בגלילת עמוד +scroll_page_label=גלילת עמוד scroll_vertical.title=שימוש בגלילה אנכית scroll_vertical_label=גלילה אנכית scroll_horizontal.title=שימוש בגלילה אופקית @@ -137,19 +135,24 @@ print_progress_close=ביטול # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=הצגה/הסתרה של סרגל הצד -toggle_sidebar_notification.title=החלפת תצוגת סרגל צד (מסמך שמכיל מתאר/צרופות) +toggle_sidebar_notification2.title=החלפת תצוגת סרגל צד (מסמך שמכיל תוכן עניינים/קבצים מצורפים/שכבות) toggle_sidebar_label=הצגה/הסתרה של סרגל הצד -document_outline.title=הצגת מתאר מסמך (לחיצה כפולה כדי להרחיב או לצמצם את כל הפריטים) -document_outline_label=מתאר מסמך +document_outline.title=הצגת תוכן העניינים של המסמך (לחיצה כפולה כדי להרחיב או לצמצם את כל הפריטים) +document_outline_label=תוכן העניינים של המסמך attachments.title=הצגת צרופות attachments_label=צרופות +layers.title=הצגת שכבות (יש ללחוץ לחיצה כפולה כדי לאפס את כל השכבות למצב ברירת המחדל) +layers_label=שכבות thumbs.title=הצגת תצוגה מקדימה thumbs_label=תצוגה מקדימה +current_outline_item.title=מציאת פריט תוכן העניינים הנוכחי +current_outline_item_label=פריט תוכן העניינים הנוכחי findbar.title=חיפוש במסמך findbar_label=חיפוש -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=עמוד {{page}} +additional_layers=שכבות נוספות +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=עמוד {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=מציאת המופע הבא של הביטוי find_next_label=הבא find_highlight=הדגשת הכול find_match_case_label=התאמת אותיות +find_match_diacritics_label=התאמה דיאקריטית find_entire_word_label=מילים שלמות find_reached_top=הגיע לראש הדף, ממשיך מלמטה find_reached_bottom=הגיע לסוף הדף, ממשיך מלמעלה @@ -222,7 +226,7 @@ page_scale_actual=גודל אמיתי page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=שגיאה +loading=בטעינה… loading_error=אירעה שגיאה בעת טעינת ה־PDF. invalid_file_error=קובץ PDF פגום או לא תקין. missing_file_error=קובץ PDF חסר. @@ -243,5 +247,35 @@ password_ok=אישור password_cancel=ביטול printing_not_supported=אזהרה: הדפסה אינה נתמכת במלואה בדפדפן זה. -printing_not_ready=אזהרה: ה־PDF לא ניתן לחלוטין עד מצב שמאפשר הדפסה. +printing_not_ready=אזהרה: מסמך ה־PDF לא נטען לחלוטין עד מצב שמאפשר הדפסה. web_fonts_disabled=גופני רשת מנוטרלים: לא ניתן להשתמש בגופני PDF מוטבעים. + +# Editor +editor_none.title=השבתת עריכת ההערות +editor_none_label=השבתת עריכה +editor_free_text.title=הוספת הערת FreeText +editor_free_text_label=הערת FreeText +editor_ink.title=הוספת הערת דיו +editor_ink_label=הערת דיו + +freetext_default_content=נא להזין טקסט… + +free_text_default_content=נא להקליד טקסט… + +# Editor Parameters +editor_free_text_font_color=צבע גופן +editor_free_text_font_size=גודל גופן +editor_ink_line_color=צבע קו +editor_ink_line_thickness=עובי קו + +# Editor Parameters +editor_free_text_color=צבע +editor_free_text_size=גודל +editor_ink_color=צבע +editor_ink_thickness=עובי +editor_ink_opacity=אטימות + +# Editor aria +editor_free_text_aria_label=עורך FreeText +editor_ink_aria_label=עורך דיו +editor_ink_canvas_aria_label=תמונה שנוצרה על־ידי משתמש diff --git a/cps/static/locale/hi-IN/viewer.properties b/cps/static/locale/hi-IN/viewer.properties index 6a49a9a98..27064ee93 100644 --- a/cps/static/locale/hi-IN/viewer.properties +++ b/cps/static/locale/hi-IN/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=\u0020मौजूदा दृश्य tools.title=औज़ार tools_label=औज़ार first_page.title=प्रथम पृष्ठ पर जाएँ -first_page.label=\u0020प्रथम पृष्ठ पर जाएँ first_page_label=प्रथम पृष्ठ पर जाएँ last_page.title=अंतिम पृष्ठ पर जाएँ -last_page.label=\u0020अंतिम पृष्ठ पर जाएँ last_page_label=\u0020अंतिम पृष्ठ पर जाएँ page_rotate_cw.title=घड़ी की दिशा में घुमाएँ -page_rotate_cw.label=घड़ी की दिशा में घुमाएँ page_rotate_cw_label=घड़ी की दिशा में घुमाएँ page_rotate_ccw.title=घड़ी की दिशा से उल्टा घुमाएँ -page_rotate_ccw.label=घड़ी की दिशा से उल्टा घुमाएँ page_rotate_ccw_label=\u0020घड़ी की दिशा से उल्टा घुमाएँ cursor_text_select_tool.title=पाठ चयन उपकरण सक्षम करें @@ -133,7 +129,6 @@ print_progress_close=रद्द करें # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=\u0020स्लाइडर टॉगल करें -toggle_sidebar_notification.title=साइडबार टॉगल करें (दस्तावेज़ में रूपरेखा शामिल है/attachments) toggle_sidebar_label=स्लाइडर टॉगल करें document_outline.title=दस्तावेज़ की रूपरेखा दिखाइए (सारी वस्तुओं को फलने अथवा समेटने के लिए दो बार क्लिक करें) document_outline_label=दस्तावेज़ आउटलाइन @@ -144,8 +139,6 @@ thumbs_label=लघु छवि findbar.title=\u0020दस्तावेज़ में ढूँढ़ें findbar_label=ढूँढें -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=पृष्ठ {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -217,8 +210,6 @@ page_scale_actual=वास्तविक आकार # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=त्रुटि loading_error=PDF लोड करते समय एक त्रुटि हुई. invalid_file_error=अमान्य या भ्रष्ट PDF फ़ाइल. missing_file_error=\u0020अनुपस्थित PDF फ़ाइल. diff --git a/cps/static/locale/hr/viewer.properties b/cps/static/locale/hr/viewer.properties index bfe10f808..1ccf441cb 100644 --- a/cps/static/locale/hr/viewer.properties +++ b/cps/static/locale/hr/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Trenutačni prikaz tools.title=Alati tools_label=Alati first_page.title=Idi na prvu stranicu -first_page.label=Idi na prvu stranicu first_page_label=Idi na prvu stranicu last_page.title=Idi na posljednju stranicu -last_page.label=Idi na posljednju stranicu last_page_label=Idi na posljednju stranicu page_rotate_cw.title=Rotiraj u smjeru kazaljke na satu -page_rotate_cw.label=Rotiraj u smjeru kazaljke na satu page_rotate_cw_label=Rotiraj u smjeru kazaljke na satu page_rotate_ccw.title=Rotiraj obrnutno od smjera kazaljke na satu -page_rotate_ccw.label=Rotiraj obrnutno od smjera kazaljke na satu page_rotate_ccw_label=Rotiraj obrnutno od smjera kazaljke na satu cursor_text_select_tool.title=Omogući alat za označavanje teksta @@ -80,8 +76,8 @@ spread_even.title=Izradi duplerice koje počinju s parnim stranicama spread_even_label=Parne duplerice # Document properties dialog box -document_properties.title=Svojstva dokumenta... -document_properties_label=Svojstva dokumenta... +document_properties.title=Svojstva dokumenta … +document_properties_label=Svojstva dokumenta … document_properties_file_name=Naziv datoteke: document_properties_file_size=Veličina datoteke: # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" @@ -137,19 +133,24 @@ print_progress_close=Odustani # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Prikaži/sakrij bočnu traku -toggle_sidebar_notification.title=Prikazivanje i sklanjanje bočne trake (dokument sadrži konturu/privitke) +toggle_sidebar_notification2.title=Prikazivanje i sklanjanje bočne trake (dokument sadrži strukturu/privitke/slojeve) toggle_sidebar_label=Prikaži/sakrij bočnu traku document_outline.title=Prikaži strukturu dokumenta (dvostruki klik za rasklapanje/sklapanje svih stavki) document_outline_label=Struktura dokumenta attachments.title=Prikaži privitke attachments_label=Privitci +layers.title=Prikaži slojeve (dvoklik za vraćanje svih slojeva u zadano stanje) +layers_label=Slojevi thumbs.title=Prikaži minijature thumbs_label=Minijature -findbar.title=Traži u dokumentu -findbar_label=Traži +current_outline_item.title=Pronađi trenutačni element strukture +current_outline_item_label=Trenutačni element strukture +findbar.title=Pronađi u dokumentu +findbar_label=Pronađi -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Stranica br. {{page}} +additional_layers=Dodatni slojevi +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Stranica {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -159,8 +160,8 @@ thumb_page_title=Stranica {{page}} thumb_page_canvas=Minijatura stranice {{page}} # Find panel button title and messages -find_input.title=Traži -find_input.placeholder=Traži u dokumentu… +find_input.title=Pronađi +find_input.placeholder=Pronađi u dokumentu … find_previous.title=Pronađi prethodno pojavljivanje ovog izraza find_previous_label=Prethodno find_next.title=Pronađi sljedeće pojavljivanje ovog izraza @@ -222,7 +223,7 @@ page_scale_actual=Stvarna veličina page_scale_percent={{scale}} % # Loading indicator messages -loading_error_indicator=Greška +loading=Učitavanje… loading_error=Došlo je do greške pri učitavanju PDF-a. invalid_file_error=Neispravna ili oštećena PDF datoteka. missing_file_error=Nedostaje PDF datoteka. diff --git a/cps/static/locale/hsb/viewer.properties b/cps/static/locale/hsb/viewer.properties index 9ba3c15a2..86c2d79f0 100644 --- a/cps/static/locale/hsb/viewer.properties +++ b/cps/static/locale/hsb/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Aktualny napohlad tools.title=Nastroje tools_label=Nastroje first_page.title=K prěnjej stronje -first_page.label=K prěnjej stronje first_page_label=K prěnjej stronje last_page.title=K poslednjej stronje -last_page.label=K poslednjej stronje last_page_label=K poslednjej stronje page_rotate_cw.title=K směrej časnika wjerćeć -page_rotate_cw.label=K směrej časnika wjerćeć page_rotate_cw_label=K směrej časnika wjerćeć page_rotate_ccw.title=Přećiwo směrej časnika wjerćeć -page_rotate_ccw.label=Přećiwo směrej časnika wjerćeć page_rotate_ccw_label=Přećiwo směrej časnika wjerćeć cursor_text_select_tool.title=Nastroj za wuběranje teksta zmóžnić @@ -65,8 +61,10 @@ cursor_text_select_tool_label=Nastroj za wuběranje teksta cursor_hand_tool.title=Ručny nastroj zmóžnić cursor_hand_tool_label=Ručny nastroj +scroll_page.title=Kulenje strony wužiwać +scroll_page_label=Kulenje strony scroll_vertical.title=Wertikalne suwanje wužiwać -scroll_vertical_label=Wertikalnje suwanje +scroll_vertical_label=Wertikalne suwanje scroll_horizontal.title=Horicontalne suwanje wužiwać scroll_horizontal_label=Horicontalne suwanje scroll_wrapped.title=Postupne suwanje wužiwać @@ -137,19 +135,24 @@ print_progress_close=Přetorhnyć # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Bóčnicu pokazać/schować -toggle_sidebar_notification.title=Bóčnicu přepinać (dokument wobsahuje wobrys/přiwěški) +toggle_sidebar_notification2.title=Bóčnicu přepinać (dokument rozrjad/přiwěški/woršty wobsahuje) toggle_sidebar_label=Bóčnicu pokazać/schować document_outline.title=Dokumentowy naćisk pokazać (dwójne kliknjenje, zo bychu so wšě zapiski pokazali/schowali) document_outline_label=Dokumentowa struktura attachments.title=Přiwěški pokazać attachments_label=Přiwěški +layers.title=Woršty pokazać (klikńće dwójce, zo byšće wšě woršty na standardny staw wróćo stajił) +layers_label=Woršty thumbs.title=Miniatury pokazać thumbs_label=Miniatury +current_outline_item.title=Aktualny rozrjadowy zapisk pytać +current_outline_item_label=Aktualny rozrjadowy zapisk findbar.title=W dokumenće pytać findbar_label=Pytać -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Strona {{page}} +additional_layers=Dalše woršty +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Strona {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Přichodne wustupowanje pytanskeho wuraza pytać find_next_label=Dale find_highlight=Wšě wuzběhnyć find_match_case_label=Wulkopisanje wobkedźbować +find_match_diacritics_label=Diakritiske znamješka wužiwać find_entire_word_label=Cyłe słowa find_reached_top=Spočatk dokumenta docpěty, pokročuje so z kóncom find_reached_bottom=Kónc dokument docpěty, pokročuje so ze spočatkom @@ -222,7 +226,7 @@ page_scale_actual=Aktualna wulkosć page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Zmylk +loading=Začituje so… loading_error=Při začitowanju PDF je zmylk wustupił. invalid_file_error=Njepłaćiwa abo wobškodźena PDF-dataja. missing_file_error=Falowaca PDF-dataja. @@ -245,3 +249,33 @@ password_cancel=Přetorhnyć printing_not_supported=Warnowanje: Ćišćenje so přez tutón wobhladowak połnje njepodpěruje. printing_not_ready=Warnowanje: PDF njeje so za ćišćenje dospołnje začitał. web_fonts_disabled=Webpisma su znjemóžnjene: njeje móžno, zasadźene PDF-pisma wužiwać. + +# Editor +editor_none.title=Wobdźěłowanje anotacijow znjemóžnić +editor_none_label=Wobdźěłowanje znjemóžnić +editor_free_text.title=Anotaciju FreeText přidać +editor_free_text_label=Anotacija FreeText +editor_ink.title=Tintowu anotaciju přidać +editor_ink_label=Tintowa anotacija + +freetext_default_content=Zapodajće trochu teksta… + +free_text_default_content=Tekst zapodać… + +# Editor Parameters +editor_free_text_font_color=Pismowa barba +editor_free_text_font_size=Pismowa wulkosć +editor_ink_line_color=Linijowa barba +editor_ink_line_thickness=Linijowa tołstosć + +# Editor Parameters +editor_free_text_color=Barba +editor_free_text_size=Wulkosć +editor_ink_color=Barba +editor_ink_thickness=Tołstosć +editor_ink_opacity=Opacita + +# Editor aria +editor_free_text_aria_label=Darmotny tekstowy editor +editor_ink_aria_label=Tintowy editor +editor_ink_canvas_aria_label=Wobraz wutworjeny wot wužiwarja diff --git a/cps/static/locale/hu/viewer.properties b/cps/static/locale/hu/viewer.properties index 88c1d0796..f7a48511f 100644 --- a/cps/static/locale/hu/viewer.properties +++ b/cps/static/locale/hu/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Aktuális nézet tools.title=Eszközök tools_label=Eszközök first_page.title=Ugrás az első oldalra -first_page.label=Ugrás az első oldalra first_page_label=Ugrás az első oldalra last_page.title=Ugrás az utolsó oldalra -last_page.label=Ugrás az utolsó oldalra last_page_label=Ugrás az utolsó oldalra page_rotate_cw.title=Forgatás az óramutató járásával egyezően -page_rotate_cw.label=Forgatás az óramutató járásával egyezően page_rotate_cw_label=Forgatás az óramutató járásával egyezően page_rotate_ccw.title=Forgatás az óramutató járásával ellentétesen -page_rotate_ccw.label=Forgatás az óramutató járásával ellentétesen page_rotate_ccw_label=Forgatás az óramutató járásával ellentétesen cursor_text_select_tool.title=Szövegkijelölő eszköz bekapcsolása @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Szövegkijelölő eszköz cursor_hand_tool.title=Kéz eszköz bekapcsolása cursor_hand_tool_label=Kéz eszköz +scroll_page.title=Oldalgörgetés használata +scroll_page_label=Oldalgörgetés scroll_vertical.title=Függőleges görgetés használata scroll_vertical_label=Függőleges görgetés scroll_horizontal.title=Vízszintes görgetés használata @@ -137,19 +135,24 @@ print_progress_close=Mégse # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Oldalsáv be/ki -toggle_sidebar_notification.title=Oldalsáv be/ki (a dokumentum vázlatot/mellékleteket tartalmaz) +toggle_sidebar_notification2.title=Oldalsáv be/ki (a dokumentum vázlatot/mellékleteket/rétegeket tartalmaz) toggle_sidebar_label=Oldalsáv be/ki document_outline.title=Dokumentum megjelenítése online (dupla kattintás minden elem kinyitásához/összecsukásához) document_outline_label=Dokumentumvázlat attachments.title=Mellékletek megjelenítése attachments_label=Van melléklet +layers.title=Rétegek megjelenítése (dupla kattintás az összes réteg alapértelmezett állapotra visszaállításához) +layers_label=Rétegek thumbs.title=Bélyegképek megjelenítése thumbs_label=Bélyegképek +current_outline_item.title=Jelenlegi vázlatelem megkeresése +current_outline_item_label=Jelenlegi vázlatelem findbar.title=Keresés a dokumentumban findbar_label=Keresés -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas={{page}}. oldal +additional_layers=További rétegek +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark={{page}}. oldal # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=A kifejezés következő előfordulásának keresése find_next_label=Tovább find_highlight=Összes kiemelése find_match_case_label=Kis- és nagybetűk megkülönböztetése +find_match_diacritics_label=Diakritikus jelek find_entire_word_label=Teljes szavak find_reached_top=A dokumentum eleje elérve, folytatás a végétől find_reached_bottom=A dokumentum vége elérve, folytatás az elejétől @@ -222,7 +226,7 @@ page_scale_actual=Valódi méret page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Hiba +loading=Betöltés… loading_error=Hiba történt a PDF betöltésekor. invalid_file_error=Érvénytelen vagy sérült PDF fájl. missing_file_error=Hiányzó PDF fájl. @@ -245,3 +249,33 @@ password_cancel=Mégse printing_not_supported=Figyelmeztetés: Ez a böngésző nem teljesen támogatja a nyomtatást. printing_not_ready=Figyelmeztetés: A PDF nincs teljesen betöltve a nyomtatáshoz. web_fonts_disabled=Webes betűkészletek letiltva: nem használhatók a beágyazott PDF betűkészletek. + +# Editor +editor_none.title=Kommentárszerkesztés letiltása +editor_none_label=Szerkesztés letiltása +editor_free_text.title=FreeText kommentár hozzáadása +editor_free_text_label=FreeText kommentár +editor_ink.title=Tintajegyzet hozzáadása +editor_ink_label=Tintajegyzet + +freetext_default_content=Írj be egy szöveget… + +free_text_default_content=Írjon be szöveget… + +# Editor Parameters +editor_free_text_font_color=Betűszín +editor_free_text_font_size=Betűméret +editor_ink_line_color=Vonalszín +editor_ink_line_thickness=Vonalvastagság + +# Editor Parameters +editor_free_text_color=Szín +editor_free_text_size=Méret +editor_ink_color=Szín +editor_ink_thickness=Vastagság +editor_ink_opacity=Átlátszatlanság + +# Editor aria +editor_free_text_aria_label=Szabad szöveges szerkesztő +editor_ink_aria_label=Tollat használó szerkesztő +editor_ink_canvas_aria_label=Felhasználó által készített kép diff --git a/cps/static/locale/hy-AM/viewer.properties b/cps/static/locale/hy-AM/viewer.properties index 09394f7d8..a97ae3cef 100644 --- a/cps/static/locale/hy-AM/viewer.properties +++ b/cps/static/locale/hy-AM/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Ընթացիկ տեսքը tools.title=Գործիքներ tools_label=Գործիքներ first_page.title=Անցնել առաջին էջին -first_page.label=Անցնել առաջին էջին first_page_label=Անցնել առաջին էջին last_page.title=Անցնել վերջին էջին -last_page.label=Անցնել վերջին էջին last_page_label=Անցնել վերջին էջին page_rotate_cw.title=Պտտել ըստ ժամացույցի սլաքի -page_rotate_cw.label=Պտտել ըստ ժամացույցի սլաքի page_rotate_cw_label=Պտտել ըստ ժամացույցի սլաքի page_rotate_ccw.title=Պտտել հակառակ ժամացույցի սլաքի -page_rotate_ccw.label=Պտտել հակառակ ժամացույցի սլաքի page_rotate_ccw_label=Պտտել հակառակ ժամացույցի սլաքի cursor_text_select_tool.title=Միացնել գրույթ ընտրելու գործիքը @@ -137,7 +133,6 @@ print_progress_close=Չեղարկել # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Բացել/Փակել Կողային վահանակը -toggle_sidebar_notification.title=Փոխարկել Կողային փեղկը (փաստաթուղթը պարունակում է ուրվագիծ/կցորդներ) toggle_sidebar_label=Բացել/Փակել Կողային վահանակը document_outline.title=Ցուցադրել փաստաթղթի ուրվագիծը (կրկնակի սեղմեք՝ միավորները ընդարձակելու/կոծկելու համար) document_outline_label=Փաստաթղթի բովանդակությունը @@ -148,8 +143,6 @@ thumbs_label=Մանրապատկերը findbar.title=Գտնել փաստաթղթում findbar_label=Որոնում -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Էջ {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -221,8 +214,6 @@ page_scale_actual=Իրական չափը # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Սխալ loading_error=Սխալ՝ PDF ֆայլը բացելիս։ invalid_file_error=Սխալ կամ վնասված PDF ֆայլ: missing_file_error=PDF ֆայլը բացակայում է: diff --git a/cps/static/locale/hye/viewer.properties b/cps/static/locale/hye/viewer.properties index 80d43019e..d531b9d28 100644 --- a/cps/static/locale/hye/viewer.properties +++ b/cps/static/locale/hye/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Ընթացիկ տեսք tools.title=Գործիքներ tools_label=Գործիքներ first_page.title=Գնալ դէպի առաջին էջ -first_page.label=Գնալ դէպի առաջին էջ first_page_label=Գնալ դէպի առաջին էջ last_page.title=Գնալ դէպի վերջին էջ -last_page.label=Գնալ դէպի վերջին էջ last_page_label=Գնալ դէպի վերջին էջ page_rotate_cw.title=Պտտել ժամացոյցի սլաքի ուղղութեամբ -page_rotate_cw.label=Պտտել ժամացոյցի սլաքի ուղղութեամբ page_rotate_cw_label=Պտտել ժամացոյցի սլաքի ուղղութեամբ page_rotate_ccw.title=Պտտել ժամացոյցի սլաքի հակառակ ուղղութեամբ -page_rotate_ccw.label=Պտտել ժամացոյցի սլաքի հակառակ ուղղութեամբ page_rotate_ccw_label=Պտտել ժամացոյցի սլաքի հակառակ ուղղութեամբ cursor_text_select_tool.title=Միացնել գրոյթ ընտրելու գործիքը @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Գրուածք ընտրելու գործիք cursor_hand_tool.title=Միացնել ձեռքի գործիքը cursor_hand_tool_label=Ձեռքի գործիք +scroll_page.title=Աւգտագործել էջի ոլորում +scroll_page_label=Էջի ոլորում scroll_vertical.title=Աւգտագործել ուղղահայեաց ոլորում scroll_vertical_label=Ուղղահայեաց ոլորում scroll_horizontal.title=Աւգտագործել հորիզոնական ոլորում @@ -77,6 +75,7 @@ spread_none_label=Չկայ կոնտեքստ spread_odd.title=Միացէք էջի կոնտեքստին սկսելով՝ կենտ համարակալուած էջերով spread_odd_label=Տարաւրինակ կոնտեքստ spread_even.title=Միացէք էջի կոնտեքստին սկսելով՝ զոյգ համարակալուած էջերով +spread_even_label=Հաւասար վերածածկեր # Document properties dialog box document_properties.title=Փաստաթղթի հատկութիւնները… @@ -136,19 +135,24 @@ print_progress_close=Չեղարկել # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Փոխարկել կողային վահանակը -toggle_sidebar_notification.title=Փոխարկել կողային վահանակը (փաստաթուղթը պարունակում է ուրուագիծ/կցորդ) +toggle_sidebar_notification2.title=Փոխանջատել կողմնասիւնը (փաստաթուղթը պարունակում է ուրուագիծ/կցորդներ/շերտեր) toggle_sidebar_label=Փոխարկել կողային վահանակը document_outline.title=Ցուցադրել փաստաթղթի ուրուագիծը (կրկնակի սեղմէք՝ միաւորները ընդարձակելու/կոծկելու համար) document_outline_label=Փաստաթղթի ուրուագիծ attachments.title=Ցուցադրել կցորդները attachments_label=Կցորդներ +layers.title=Ցուցադրել շերտերը (կրկնահպել վերակայելու բոլոր շերտերը սկզբնադիր վիճակի) +layers_label=Շերտեր thumbs.title=Ցուցադրել մանրապատկերը thumbs_label=Մանրապատկեր +current_outline_item.title=Գտէք ընթացիկ գծագրման տարրը +current_outline_item_label=Ընթացիկ գծագրման տարր findbar.title=Գտնել փաստաթղթում findbar_label=Որոնում -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Էջ {{page}} +additional_layers=Լրացուցիչ շերտեր +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Էջ {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -166,6 +170,7 @@ find_next.title=Գտիր արտայայտութեան յաջորդ արտայա find_next_label=Հաջորդը find_highlight=Գունանշել բոլորը find_match_case_label=Հաշուի առնել հանգամանքը +find_match_diacritics_label=Հնչիւնատարբերիչ նշանների համապատասխանեցում find_entire_word_label=Ամբողջ բառերը find_reached_top=Հասել եք փաստաթղթի վերեւին,շարունակել ներքեւից find_reached_bottom=Հասել էք փաստաթղթի վերջին, շարունակել վերեւից @@ -174,7 +179,7 @@ find_reached_bottom=Հասել էք փաստաթղթի վերջին, շարու # "{{current}}" and "{{total}}" will be replaced by a number representing the # index of the currently active find result, respectively a number representing # the total number of matches in the document. -find_match_count={[ հոգնակի(ընդհանուր) ]} +find_match_count={[ plural(total) ]} find_match_count[one]={{current}} {{total}}-ի համընկնումից find_match_count[two]={{current}} {{total}}-ի համընկնումներից find_match_count[few]={{current}} {{total}}-ի համընկնումներից @@ -183,7 +188,7 @@ find_match_count[other]={{current}} {{total}}-ի համընկնումներից # LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are # [zero|one|two|few|many|other], with [other] as the default value. # "{{limit}}" will be replaced by a numerical value. -find_match_count_limit={[ հոգնակի (սահմանը) ]} +find_match_count_limit={[ plural(limit) ]} find_match_count_limit[zero]=Աւելին քան {{limit}} համընկնումները find_match_count_limit[one]=Աւելին քան {{limit}} համընկնումը find_match_count_limit[two]=Աւելին քան {{limit}} համընկնումները @@ -212,7 +217,7 @@ error_line=Տողը. {{line}} rendering_error=Սխալ է տեղի ունեցել էջի մեկնաբանման ժամանակ # Predefined zoom values -page_scale_width=Էջի լայնքը +page_scale_width=Էջի լայնութիւն page_scale_fit=Հարմարեցնել էջը page_scale_auto=Ինքնաշխատ խոշորացում page_scale_actual=Իրական չափը @@ -221,7 +226,7 @@ page_scale_actual=Իրական չափը page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Սխալ +loading=Բեռնում… loading_error=PDF նիշքը բացելիս սխալ է տեղի ունեցել։ invalid_file_error=Սխալ կամ վնասուած PDF նիշք։ missing_file_error=PDF նիշքը բացակաիւմ է։ diff --git a/cps/static/locale/ia/viewer.properties b/cps/static/locale/ia/viewer.properties index 167547adc..d64acf6ff 100644 --- a/cps/static/locale/ia/viewer.properties +++ b/cps/static/locale/ia/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vista actual tools.title=Instrumentos tools_label=Instrumentos first_page.title=Ir al prime pagina -first_page.label=Ir al prime pagina first_page_label=Ir al prime pagina last_page.title=Ir al prime pagina -last_page.label=Ir al prime pagina last_page_label=Ir al prime pagina page_rotate_cw.title=Rotar in senso horari -page_rotate_cw.label=Rotar in senso horari page_rotate_cw_label=Rotar in senso horari page_rotate_ccw.title=Rotar in senso antihorari -page_rotate_ccw.label=Rotar in senso antihorari page_rotate_ccw_label=Rotar in senso antihorari cursor_text_select_tool.title=Activar le instrumento de selection de texto @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Instrumento de selection de texto cursor_hand_tool.title=Activar le instrumento mano cursor_hand_tool_label=Instrumento mano +scroll_page.title=Usar rolamento de pagina +scroll_page_label=Rolamento de pagina scroll_vertical.title=Usar rolamento vertical scroll_vertical_label=Rolamento vertical scroll_horizontal.title=Usar rolamento horizontal @@ -137,19 +135,24 @@ print_progress_close=Cancellar # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Monstrar/celar le barra lateral -toggle_sidebar_notification.title=Monstrar/celar le barra lateral (le documento contine structura/attachamentos) +toggle_sidebar_notification2.title=Monstrar/celar le barra lateral (le documento contine structura/attachamentos/stratos) toggle_sidebar_label=Monstrar/celar le barra lateral document_outline.title=Monstrar le schema del documento (clic duple pro expander/contraher tote le elementos) document_outline_label=Schema del documento attachments.title=Monstrar le annexos attachments_label=Annexos +layers.title=Monstrar stratos (clicca duple pro remontar tote le stratos al stato predefinite) +layers_label=Stratos thumbs.title=Monstrar le vignettes thumbs_label=Vignettes +current_outline_item.title=Trovar le elemento de structura actual +current_outline_item_label=Elemento de structura actual findbar.title=Cercar in le documento findbar_label=Cercar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Pagina {{page}} +additional_layers=Altere stratos +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Pagina {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Trovar le successive occurrentia del phrase find_next_label=Sequente find_highlight=Evidentiar toto find_match_case_label=Distinguer majusculas/minusculas +find_match_diacritics_label=Differentiar diacriticos find_entire_word_label=Parolas integre find_reached_top=Initio del documento attingite, continuation ab fin find_reached_bottom=Fin del documento attingite, continuation ab initio @@ -213,16 +217,16 @@ error_line=Linea: {{line}} rendering_error=Un error occurreva durante que on processava le pagina. # Predefined zoom values -page_scale_width=Largessa pagina plen +page_scale_width=Plen largor del pagina page_scale_fit=Pagina integre page_scale_auto=Zoom automatic -page_scale_actual=Dimension actual +page_scale_actual=Dimension real # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a # numerical scale value. page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=Cargante… loading_error=Un error occurreva durante que on cargava le file PDF. invalid_file_error=File PDF corrumpite o non valide. missing_file_error=File PDF mancante. @@ -245,3 +249,33 @@ password_cancel=Cancellar printing_not_supported=Attention : le impression non es totalmente supportate per ce navigator. printing_not_ready=Attention: le file PDF non es integremente cargate pro lo poter imprimer. web_fonts_disabled=Le typos de litteras web es disactivate: impossibile usar le typos de litteras PDF incorporate. + +# Editor +editor_none.title=Disactivar modificationes del annotationes +editor_none_label=Disactivar redaction +editor_free_text.title=Add annotation FreeText +editor_free_text_label=Annotation FreeText +editor_ink.title=Adder annotation Ink +editor_ink_label=Annotation Ink + +freetext_default_content=Scribe alcun texto… + +free_text_default_content=Insere le texto… + +# Editor Parameters +editor_free_text_font_color=Color de character +editor_free_text_font_size=Dimension del characteres +editor_ink_line_color=Colores del linea +editor_ink_line_thickness=Spissor del linea + +# Editor Parameters +editor_free_text_color=Color +editor_free_text_size=Dimension +editor_ink_color=Color +editor_ink_thickness=Spissor +editor_ink_opacity=Opacitate + +# Editor aria +editor_free_text_aria_label=Redactor de texto libere +editor_ink_aria_label=Editor penna +editor_ink_canvas_aria_label=Imagine create per le usator diff --git a/cps/static/locale/id/viewer.properties b/cps/static/locale/id/viewer.properties index b9b9a730b..83ab35324 100644 --- a/cps/static/locale/id/viewer.properties +++ b/cps/static/locale/id/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Tampilan Sekarang tools.title=Alat tools_label=Alat first_page.title=Buka Halaman Pertama -first_page.label=Ke Halaman Pertama first_page_label=Buka Halaman Pertama last_page.title=Buka Halaman Terakhir -last_page.label=Ke Halaman Terakhir last_page_label=Buka Halaman Terakhir page_rotate_cw.title=Putar Searah Jarum Jam -page_rotate_cw.label=Putar Searah Jarum Jam page_rotate_cw_label=Putar Searah Jarum Jam page_rotate_ccw.title=Putar Berlawanan Arah Jarum Jam -page_rotate_ccw.label=Putar Berlawanan Arah Jarum Jam page_rotate_ccw_label=Putar Berlawanan Arah Jarum Jam cursor_text_select_tool.title=Aktifkan Alat Seleksi Teks @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Alat Seleksi Teks cursor_hand_tool.title=Aktifkan Alat Tangan cursor_hand_tool_label=Alat Tangan +scroll_page.title=Gunakan Pengguliran Laman +scroll_page_label=Pengguliran Laman scroll_vertical.title=Gunakan Penggeseran Vertikal scroll_vertical_label=Penggeseran Vertikal scroll_horizontal.title=Gunakan Penggeseran Horizontal @@ -137,19 +135,24 @@ print_progress_close=Batalkan # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Aktif/Nonaktifkan Bilah Samping -toggle_sidebar_notification.title=Aktif/Nonaktifkan Bilah Samping (dokumen berisi kerangka/lampiran) +toggle_sidebar_notification2.title=Aktif/Nonaktifkan Bilah Samping (dokumen berisi kerangka/lampiran/lapisan) toggle_sidebar_label=Aktif/Nonaktifkan Bilah Samping document_outline.title=Tampilkan Kerangka Dokumen (klik ganda untuk membentangkan/menciutkan semua item) document_outline_label=Kerangka Dokumen attachments.title=Tampilkan Lampiran attachments_label=Lampiran +layers.title=Tampilkan Lapisan (klik ganda untuk mengatur ulang semua lapisan ke keadaan baku) +layers_label=Lapisan thumbs.title=Tampilkan Miniatur thumbs_label=Miniatur +current_outline_item.title=Cari Butir Ikhtisar Saat Ini +current_outline_item_label=Butir Ikhtisar Saat Ini findbar.title=Temukan di Dokumen findbar_label=Temukan -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Laman {{page}} +additional_layers=Lapisan Tambahan +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Halaman {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Temukan lebih lanjut find_next_label=Selanjutnya find_highlight=Sorot semuanya find_match_case_label=Cocokkan BESAR/kecil +find_match_diacritics_label=Pencocokan Diakritik find_entire_word_label=Seluruh teks find_reached_top=Sampai di awal dokumen, dilanjutkan dari bawah find_reached_bottom=Sampai di akhir dokumen, dilanjutkan dari atas @@ -222,7 +226,7 @@ page_scale_actual=Ukuran Asli page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Galat +loading=Memuat… loading_error=Galat terjadi saat memuat PDF. invalid_file_error=Berkas PDF tidak valid atau rusak. missing_file_error=Berkas PDF tidak ada. @@ -245,3 +249,33 @@ password_cancel=Batal printing_not_supported=Peringatan: Pencetakan tidak didukung secara lengkap pada peramban ini. printing_not_ready=Peringatan: Berkas PDF masih belum dimuat secara lengkap untuk dapat dicetak. web_fonts_disabled=Font web dinonaktifkan: tidak dapat menggunakan font PDF yang tersemat. + +# Editor +editor_none.title=Nonaktifkan Penyuntingan Anotasi +editor_none_label=Nonaktifkan Penyuntingan +editor_free_text.title=Tambahkan Notasi FreeText +editor_free_text_label=Notasi FreeText +editor_ink.title=Tambahkan Notasi Tinta +editor_ink_label=Notasi Tinta + +freetext_default_content=Masukkan beberapa teks… + +free_text_default_content=Masukkan teks… + +# Editor Parameters +editor_free_text_font_color=Warna Fon +editor_free_text_font_size=Ukuran Fon +editor_ink_line_color=Warna Garis +editor_ink_line_thickness=Ketebalan Garis + +# Editor Parameters +editor_free_text_color=Warna +editor_free_text_size=Ukuran +editor_ink_color=Warna +editor_ink_thickness=Ketebalan +editor_ink_opacity=Opasitas + +# Editor aria +editor_free_text_aria_label=Editor FreeText +editor_ink_aria_label=Editor Tinta +editor_ink_canvas_aria_label=Gambar yang dibuat pengguna diff --git a/cps/static/locale/is/viewer.properties b/cps/static/locale/is/viewer.properties index 72dc8acd6..b150f2eac 100644 --- a/cps/static/locale/is/viewer.properties +++ b/cps/static/locale/is/viewer.properties @@ -28,10 +28,10 @@ of_pages=af {{pagesCount}} # respectively a number representing the total number of pages in the document. page_of_pages=({{pageNumber}} af {{pagesCount}}) -zoom_out.title=Minnka -zoom_out_label=Minnka -zoom_in.title=Stækka -zoom_in_label=Stækka +zoom_out.title=Minnka aðdrátt +zoom_out_label=Minnka aðdrátt +zoom_in.title=Auka aðdrátt +zoom_in_label=Auka aðdrátt zoom.title=Aðdráttur presentation_mode.title=Skipta yfir á kynningarham presentation_mode_label=Kynningarhamur @@ -48,16 +48,12 @@ bookmark_label=Núverandi sýn tools.title=Verkfæri tools_label=Verkfæri first_page.title=Fara á fyrstu síðu -first_page.label=Fara á fyrstu síðu first_page_label=Fara á fyrstu síðu last_page.title=Fara á síðustu síðu -last_page.label=Fara á síðustu síðu last_page_label=Fara á síðustu síðu page_rotate_cw.title=Snúa réttsælis -page_rotate_cw.label=Snúa réttsælis page_rotate_cw_label=Snúa réttsælis page_rotate_ccw.title=Snúa rangsælis -page_rotate_ccw.label=Snúa rangsælis page_rotate_ccw_label=Snúa rangsælis cursor_text_select_tool.title=Virkja textavalsáhald @@ -65,10 +61,14 @@ cursor_text_select_tool_label=Textavalsáhald cursor_hand_tool.title=Virkja handarverkfæri cursor_hand_tool_label=Handarverkfæri +scroll_page.title=Nota síðuskrun +scroll_page_label=Síðuskrun scroll_vertical.title=Nota lóðrétt skrun scroll_vertical_label=Lóðrétt skrun scroll_horizontal.title=Nota lárétt skrun scroll_horizontal_label=Lárétt skrun +scroll_wrapped.title=Nota línuskipt síðuskrun +scroll_wrapped_label=Línuskipt síðuskrun spread_none.title=Ekki taka þátt í dreifingu síðna spread_none_label=Engin dreifing @@ -120,6 +120,7 @@ document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) # LOCALIZATION NOTE (document_properties_linearized): The linearization status of # the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized=Fljótleg vefskoðun: document_properties_linearized_yes=Já document_properties_linearized_no=Nei document_properties_close=Loka @@ -133,18 +134,25 @@ print_progress_close=Hætta við # Tooltips and alt text for side panel toolbar buttons # (the _label strings are alt text for the buttons, the .title strings are # tooltips) -toggle_sidebar.title=Víxla hliðslá -toggle_sidebar_notification.title=Víxla hliðarslá (skjal inniheldur yfirlit/viðhengi) -toggle_sidebar_label=Víxla hliðslá +toggle_sidebar.title=Víxla hliðarspjaldi af/á +toggle_sidebar_notification2.title=Víxla hliðarslá (skjal inniheldur yfirlit/viðhengi/lög) +toggle_sidebar_label=Víxla hliðarspjaldi af/á document_outline.title=Sýna yfirlit skjals (tvísmelltu til að opna/loka öllum hlutum) document_outline_label=Efnisskipan skjals attachments.title=Sýna viðhengi attachments_label=Viðhengi +layers.title=Birta lög (tvísmelltu til að endurstilla öll lög í sjálfgefna stöðu) +layers_label=Lög thumbs.title=Sýna smámyndir thumbs_label=Smámyndir +current_outline_item.title=Finna núverandi atriði efnisskipunar +current_outline_item_label=Núverandi atriði efnisskipunar findbar.title=Leita í skjali findbar_label=Leita +additional_layers=Viðbótarlög +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Síða {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -162,6 +170,7 @@ find_next.title=Leita að næsta tilfelli þessara orða find_next_label=Næsti find_highlight=Lita allt find_match_case_label=Passa við stafstöðu +find_match_diacritics_label=Passa við broddstafi find_entire_word_label=Heil orð find_reached_top=Náði efst í skjal, held áfram neðst find_reached_bottom=Náði enda skjals, held áfram efst @@ -217,12 +226,16 @@ page_scale_actual=Raunstærð page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Villa +loading=Hleður… loading_error=Villa kom upp við að hlaða inn PDF. invalid_file_error=Ógild eða skemmd PDF skrá. missing_file_error=Vantar PDF skrá. unexpected_response_error=Óvænt svar frá netþjóni. +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. +annotation_date_string={{date}}, {{time}} + # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). @@ -236,3 +249,33 @@ password_cancel=Hætta við printing_not_supported=Aðvörun: Prentun er ekki með fyllilegan stuðning á þessum vafra. printing_not_ready=Aðvörun: Ekki er búið að hlaða inn allri PDF skránni fyrir prentun. web_fonts_disabled=Vef leturgerðir eru óvirkar: get ekki notað innbyggðar PDF leturgerðir. + +# Editor +editor_none.title=Gera breytingar á glósum óvirkar +editor_none_label=Gera breytingar óvirkar +editor_free_text.title=Bæta við FreeText-glósu +editor_free_text_label=FreeText-glósa +editor_ink.title=Bæta við Ink-glósu +editor_ink_label=Ink-glósa + +freetext_default_content=Settu inn einhvern texta… + +free_text_default_content=Settu inn texta… + +# Editor Parameters +editor_free_text_font_color=Litur leturs +editor_free_text_font_size=Leturstærð +editor_ink_line_color=Línulitur +editor_ink_line_thickness=Línubreidd + +# Editor Parameters +editor_free_text_color=Litur +editor_free_text_size=Stærð +editor_ink_color=Litur +editor_ink_thickness=Þykkt +editor_ink_opacity=Ógegnsæi + +# Editor aria +editor_free_text_aria_label=FreeText-ritill +editor_ink_aria_label=Ink-ritill +editor_ink_canvas_aria_label=Mynd gerð af notanda diff --git a/cps/static/locale/it/viewer.properties b/cps/static/locale/it/viewer.properties index 87c4050d8..6a2ef4d7f 100644 --- a/cps/static/locale/it/viewer.properties +++ b/cps/static/locale/it/viewer.properties @@ -44,16 +44,12 @@ bookmark_label = Visualizzazione corrente tools.title = Strumenti tools_label = Strumenti first_page.title = Vai alla prima pagina -first_page.label = Vai alla prima pagina first_page_label = Vai alla prima pagina last_page.title = Vai all’ultima pagina -last_page.label = Vai all’ultima pagina last_page_label = Vai all’ultima pagina page_rotate_cw.title = Ruota in senso orario -page_rotate_cw.label = Ruota in senso orario page_rotate_cw_label = Ruota in senso orario page_rotate_ccw.title = Ruota in senso antiorario -page_rotate_ccw.label = Ruota in senso antiorario page_rotate_ccw_label = Ruota in senso antiorario cursor_text_select_tool.title = Attiva strumento di selezione testo @@ -61,6 +57,8 @@ cursor_text_select_tool_label = Strumento di selezione testo cursor_hand_tool.title = Attiva strumento mano cursor_hand_tool_label = Strumento mano +scroll_page.title = Utilizza scorrimento pagine +scroll_page_label = Scorrimento pagine scroll_vertical.title = Scorri le pagine in verticale scroll_vertical_label = Scorrimento verticale scroll_horizontal.title = Scorri le pagine in orizzontale @@ -113,18 +111,23 @@ print_progress_percent = {{progress}}% print_progress_close = Annulla toggle_sidebar.title = Attiva/disattiva barra laterale -toggle_sidebar_notification.title = Attiva/disattiva barra laterale (il documento contiene struttura/allegati) +toggle_sidebar_notification2.title = Attiva/disattiva barra laterale (il documento contiene struttura/allegati/livelli) toggle_sidebar_label = Attiva/disattiva barra laterale document_outline.title = Visualizza la struttura del documento (doppio clic per visualizzare/comprimere tutti gli elementi) document_outline_label = Struttura documento attachments.title = Visualizza allegati attachments_label = Allegati +layers.title = Visualizza livelli (doppio clic per ripristinare tutti i livelli allo stato predefinito) +layers_label = Livelli thumbs.title = Mostra le miniature thumbs_label = Miniature +current_outline_item.title = Trova elemento struttura corrente +current_outline_item_label = Elemento struttura corrente findbar.title = Trova nel documento findbar_label = Trova -page_canvas = Pagina {{page}} +additional_layers = Livelli aggiuntivi +page_landmark = Pagina {{page}} thumb_page_title = Pagina {{page}} thumb_page_canvas = Miniatura della pagina {{page}} @@ -136,6 +139,7 @@ find_next.title = Trova l’occorrenza successiva del testo da cercare find_next_label = Successivo find_highlight = Evidenzia find_match_case_label = Maiuscole/minuscole +find_match_diacritics_label = Segni diacritici find_entire_word_label = Parole intere find_reached_top = Raggiunto l’inizio della pagina, continua dalla fine find_reached_bottom = Raggiunta la fine della pagina, continua dall’inizio @@ -170,7 +174,7 @@ page_scale_auto = Zoom automatico page_scale_actual = Dimensioni effettive page_scale_percent = {{scale}}% -loading_error_indicator = Errore +loading = Caricamento in corso… loading_error = Si è verificato un errore durante il caricamento del PDF. invalid_file_error = File PDF non valido o danneggiato. missing_file_error = File PDF non disponibile. @@ -187,3 +191,29 @@ password_cancel = Annulla printing_not_supported = Attenzione: la stampa non è completamente supportata da questo browser. printing_not_ready = Attenzione: il PDF non è ancora stato caricato completamente per la stampa. web_fonts_disabled = I web font risultano disattivati: impossibile utilizzare i caratteri incorporati nel PDF. + +# Editor +editor_none.title = Disattiva modifica annotazioni +editor_none_label = Disattiva modifica +editor_free_text.title = Aggiungi annotazione testo libero +editor_free_text_label = Annotazione testo libero +editor_ink.title = Aggiungi annotazione a penna +editor_ink_label = Annotazione a penna + +free_text_default_content = Inserisci testo… + +# Editor Parameters +editor_free_text_font_color = Colore carattere +editor_free_text_font_size = Dimensione carattere +editor_ink_line_color = Colore linea +editor_ink_line_thickness = Spessore linea +editor_free_text_color = Colore +editor_free_text_size = Dimensione +editor_ink_color = Colore +editor_ink_thickness = Spessore +editor_ink_opacity = Opacità + +# Editor aria +editor_free_text_aria_label = Editor testo libero +editor_ink_aria_label = Editor penna +editor_ink_canvas_aria_label = Immagine creata dall’utente diff --git a/cps/static/locale/ja/viewer.properties b/cps/static/locale/ja/viewer.properties index 95732a07f..88a9de2a8 100644 --- a/cps/static/locale/ja/viewer.properties +++ b/cps/static/locale/ja/viewer.properties @@ -48,35 +48,33 @@ bookmark_label=現在のビュー tools.title=ツール tools_label=ツール first_page.title=最初のページへ移動します -first_page.label=最初のページへ移動 first_page_label=最初のページへ移動 last_page.title=最後のページへ移動します -last_page.label=最後のページへ移動 last_page_label=最後のページへ移動 page_rotate_cw.title=ページを右へ回転します -page_rotate_cw.label=右回転 page_rotate_cw_label=右回転 page_rotate_ccw.title=ページを左へ回転します -page_rotate_ccw.label=左回転 page_rotate_ccw_label=左回転 -cursor_text_select_tool.title=テキスト選択ツールを有効にする +cursor_text_select_tool.title=テキスト選択ツールを有効にします cursor_text_select_tool_label=テキスト選択ツール -cursor_hand_tool.title=手のひらツールを有効にする +cursor_hand_tool.title=手のひらツールを有効にします cursor_hand_tool_label=手のひらツール -scroll_vertical.title=縦スクロールにする +scroll_page.title=ページ単位でスクロールします +scroll_page_label=ページ単位でスクロール +scroll_vertical.title=縦スクロールにします scroll_vertical_label=縦スクロール -scroll_horizontal.title=横スクロールにする +scroll_horizontal.title=横スクロールにします scroll_horizontal_label=横スクロール -scroll_wrapped.title=折り返しスクロールにする +scroll_wrapped.title=折り返しスクロールにします scroll_wrapped_label=折り返しスクロール -spread_none.title=見開きにしない +spread_none.title=見開きにしません spread_none_label=見開きにしない -spread_odd.title=奇数ページ開始で見開きにする +spread_odd.title=奇数ページ開始で見開きにします spread_odd_label=奇数ページ見開き -spread_even.title=偶数ページ開始で見開きにする +spread_even.title=偶数ページ開始で見開きにします spread_even_label=偶数ページ見開き # Document properties dialog box @@ -86,10 +84,10 @@ document_properties_file_name=ファイル名: document_properties_file_size=ファイルサイズ: # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" # will be replaced by the PDF file size in kilobytes, respectively in bytes. -document_properties_kb={{size_kb}} KB ({{size_b}} bytes) +document_properties_kb={{size_kb}} KB ({{size_b}} バイト) # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" # will be replaced by the PDF file size in megabytes, respectively in bytes. -document_properties_mb={{size_mb}} MB ({{size_b}} bytes) +document_properties_mb={{size_mb}} MB ({{size_b}} バイト) document_properties_title=タイトル: document_properties_author=作成者: document_properties_subject=件名: @@ -137,19 +135,24 @@ print_progress_close=キャンセル # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=サイドバー表示を切り替えます -toggle_sidebar_notification.title=サイドバー表示を切り替えます (文書に含まれるアウトライン / 添付) +toggle_sidebar_notification2.title=サイドバー表示を切り替えます (文書に含まれるアウトライン / 添付 / レイヤー) toggle_sidebar_label=サイドバーの切り替え document_outline.title=文書の目次を表示します (ダブルクリックで項目を開閉します) document_outline_label=文書の目次 attachments.title=添付ファイルを表示します attachments_label=添付ファイル +layers.title=レイヤーを表示します (ダブルクリックですべてのレイヤーが初期状態に戻ります) +layers_label=レイヤー thumbs.title=縮小版を表示します thumbs_label=縮小版 +current_outline_item.title=現在のアウトライン項目を検索 +current_outline_item_label=現在のアウトライン項目 findbar.title=文書内を検索します findbar_label=検索 -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas={{page}} ページ +additional_layers=追加レイヤー +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark={{page}} ページ # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=現在より後の位置で指定文字列が現れる部分を find_next_label=次へ find_highlight=すべて強調表示 find_match_case_label=大文字/小文字を区別 +find_match_diacritics_label=発音区別符号を区別 find_entire_word_label=単語一致 find_reached_top=文書先頭に到達したので末尾から続けて検索します find_reached_bottom=文書末尾に到達したので先頭から続けて検索します @@ -222,7 +226,7 @@ page_scale_actual=実際のサイズ page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=エラー +loading=読み込み中... loading_error=PDF の読み込み中にエラーが発生しました。 invalid_file_error=無効または破損した PDF ファイル。 missing_file_error=PDF ファイルが見つかりません。 @@ -245,4 +249,33 @@ password_cancel=キャンセル printing_not_supported=警告: このブラウザーでは印刷が完全にサポートされていません。 printing_not_ready=警告: PDF を印刷するための読み込みが終了していません。 web_fonts_disabled=ウェブフォントが無効になっています: 埋め込まれた PDF のフォントを使用できません。 -document_colors_not_allowed=PDF 文書は、ウェブページが指定した配色を使用することができません: 'ウェブページが指定した配色' はブラウザーで無効になっています。 + +# Editor +editor_none.title=注釈の編集を無効にする +editor_none_label=編集を無効にする +editor_free_text.title=フリーテキスト注釈を追加 +editor_free_text_label=フリーテキスト注釈 +editor_ink.title=インク注釈を追加 +editor_ink_label=インク注釈 + +freetext_default_content=テキストを入力してください... + +free_text_default_content=テキストを入力してください... + +# Editor Parameters +editor_free_text_font_color=フォントの色 +editor_free_text_font_size=フォントサイズ +editor_ink_line_color=線の色 +editor_ink_line_thickness=線の太さ + +# Editor Parameters +editor_free_text_color=色 +editor_free_text_size=サイズ +editor_ink_color=色 +editor_ink_thickness=太さ +editor_ink_opacity=不透明度 + +# Editor aria +editor_free_text_aria_label=フリーテキスト注釈エディター +editor_ink_aria_label=インク注釈エディター +editor_ink_canvas_aria_label=ユーザー作成画像 diff --git a/cps/static/locale/ka/viewer.properties b/cps/static/locale/ka/viewer.properties index 86e91bbd1..14bddd42d 100644 --- a/cps/static/locale/ka/viewer.properties +++ b/cps/static/locale/ka/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=მიმდინარე ხედი tools.title=ხელსაწყოები tools_label=ხელსაწყოები first_page.title=პირველ გვერდზე გადასვლა -first_page.label=პირველ გვერდზე გადასვლა first_page_label=პირველ გვერდზე გადასვლა last_page.title=ბოლო გვერდზე გადასვლა -last_page.label=ბოლო გვერდზე გადასვლა last_page_label=ბოლო გვერდზე გადასვლა page_rotate_cw.title=საათის ისრის მიმართულებით შებრუნება -page_rotate_cw.label=მარჯვნივ გადაბრუნება page_rotate_cw_label=მარჯვნივ გადაბრუნება page_rotate_ccw.title=საათის ისრის საპირისპიროდ შებრუნება -page_rotate_ccw.label=მარცხნივ გადაბრუნება page_rotate_ccw_label=მარცხნივ გადაბრუნება cursor_text_select_tool.title=მოსანიშნი მაჩვენებლის გამოყენება @@ -65,6 +61,8 @@ cursor_text_select_tool_label=მოსანიშნი მაჩვენე cursor_hand_tool.title=გადასაადგილებელი მაჩვენებლის გამოყენება cursor_hand_tool_label=გადასაადგილებელი +scroll_page.title=გვერდზე გადაადგილების გამოყენება +scroll_page_label=გვერდზე გადაადგილება scroll_vertical.title=გვერდების შვეულად ჩვენება scroll_vertical_label=შვეული გადაადგილება scroll_horizontal.title=გვერდების თარაზულად ჩვენება @@ -91,18 +89,18 @@ document_properties_kb={{size_kb}} კბ ({{size_b}} ბაიტი) # will be replaced by the PDF file size in megabytes, respectively in bytes. document_properties_mb={{size_mb}} მბ ({{size_b}} ბაიტი) document_properties_title=სათაური: -document_properties_author=შემდგენი: +document_properties_author=შემქმნელი: document_properties_subject=თემა: document_properties_keywords=საკვანძო სიტყვები: -document_properties_creation_date=შექმნის თარიღი: -document_properties_modification_date=ჩასწორების თარიღი: +document_properties_creation_date=შექმნის დრო: +document_properties_modification_date=ჩასწორების დრო: # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" # will be replaced by the creation/modification date, and time, of the PDF file. document_properties_date_string={{date}}, {{time}} -document_properties_creator=შემქმნელი: -document_properties_producer=PDF-შემქმნელი: +document_properties_creator=გამომშვები: +document_properties_producer=PDF-გამომშვები: document_properties_version=PDF-ვერსია: -document_properties_page_count=გვერდების რაოდენობა: +document_properties_page_count=გვერდები: document_properties_page_size=გვერდის ზომა: document_properties_page_size_unit_inches=დუიმი document_properties_page_size_unit_millimeters=მმ @@ -137,19 +135,24 @@ print_progress_close=გაუქმება # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=გვერდითა ზოლის გამოჩენა/დამალვა -toggle_sidebar_notification.title=გვერდითა ზოლის ჩართვა/გამორთვა (დოკუმენტი შეიცავს სარჩევს/დანართს) +toggle_sidebar_notification2.title=გვერდითი ზოლის გამოჩენა (შეიცავს სარჩევს/დანართს/ფენებს) toggle_sidebar_label=გვერდითა ზოლის გამოჩენა/დამალვა -document_outline.title=დოკუმენტის სარჩევის ჩვენება (ორჯერ დაწკაპებით ყველა ელემენტის ჩამოშლა/აკეცვა) +document_outline.title=დოკუმენტის სარჩევის ჩვენება (ორმაგი წკაპით თითოეულის ჩამოშლა/აკეცვა) document_outline_label=დოკუმენტის სარჩევი attachments.title=დანართების ჩვენება attachments_label=დანართები +layers.title=ფენების გამოჩენა (ორმაგი წკაპით ყველა ფენის ნაგულისხმევზე დაბრუნება) +layers_label=ფენები thumbs.title=შეთვალიერება thumbs_label=ესკიზები +current_outline_item.title=მიმდინარე გვერდის მონახვა სარჩევში +current_outline_item_label=მიმდინარე გვერდი სარჩევში findbar.title=პოვნა დოკუმენტში findbar_label=ძიება -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=გვერდი {{page}} +additional_layers=დამატებითი ფენები +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=გვერდი {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -166,7 +169,8 @@ find_previous_label=წინა find_next.title=ფრაზის შემდეგი კონტექსტის პოვნა find_next_label=შემდეგი find_highlight=ყველას მონიშვნა -find_match_case_label=ემთხვევა მთავრული +find_match_case_label=მთავრულით +find_match_diacritics_label=ნიშნებით find_entire_word_label=მთლიანი სიტყვები find_reached_top=მიღწეულია დოკუმენტის დასაწყისი, გრძელდება ბოლოდან find_reached_bottom=მიღწეულია დოკუმენტის ბოლო, გრძელდება დასაწყისიდან @@ -185,12 +189,12 @@ find_match_count[other]={{current}} / {{total}} თანხვედრიდ # [zero|one|two|few|many|other], with [other] as the default value. # "{{limit}}" will be replaced by a numerical value. find_match_count_limit={[ plural(limit) ]} -find_match_count_limit[zero]={{limit}}-ზე მეტი თანხვედრა -find_match_count_limit[one]={{limit}}-ზე მეტი თანხვედრა -find_match_count_limit[two]={{limit}}-ზე მეტი თანხვედრა -find_match_count_limit[few]={{limit}}-ზე მეტი თანხვედრა -find_match_count_limit[many]={{limit}}-ზე მეტი თანხვედრა -find_match_count_limit[other]={{limit}}-ზე მეტი თანხვედრა +find_match_count_limit[zero]=არანაკლებ {{limit}} თანხვედრა +find_match_count_limit[one]=არანაკლებ {{limit}} თანხვედრა +find_match_count_limit[two]=არანაკლებ {{limit}} თანხვედრა +find_match_count_limit[few]=არანაკლებ {{limit}} თანხვედრა +find_match_count_limit[many]=არანაკლებ {{limit}} თანხვედრა +find_match_count_limit[other]=არანაკლებ {{limit}} თანხვედრა find_not_found=ფრაზა ვერ მოიძებნა # Error panel labels @@ -222,7 +226,7 @@ page_scale_actual=საწყისი ზომა page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=შეცდომა +loading=ჩატვირთვა… loading_error=შეცდომა, PDF-ფაილის ჩატვირთვისას. invalid_file_error=არამართებული ან დაზიანებული PDF-ფაილი. missing_file_error=ნაკლული PDF-ფაილი. @@ -245,3 +249,33 @@ password_cancel=გაუქმება printing_not_supported=გაფრთხილება: ამობეჭდვა ამ ბრაუზერში არაა სრულად მხარდაჭერილი. printing_not_ready=გაფრთხილება: PDF სრულად ჩატვირთული არაა, ამობეჭდვის დასაწყებად. web_fonts_disabled=ვებშრიფტები გამორთულია: ჩაშენებული PDF-შრიფტების გამოყენება ვერ ხერხდება. + +# Editor +editor_none.title=შენიშვნის ჩასწორების გათიშვა +editor_none_label=ჩასწორების გათიშვა +editor_free_text.title=FreeText-სახის შენიშვნის დართვა +editor_free_text_label=FreeText-სახის შენიშვნა +editor_ink.title=ხელნაწერი შენიშვნის დართვა +editor_ink_label=ხელნაწერი შენიშვნა + +freetext_default_content=შეიყვანეთ რამე ტექსტი… + +free_text_default_content=შეიყვანეთ ტექსტი… + +# Editor Parameters +editor_free_text_font_color=შრიფტის ფერი +editor_free_text_font_size=შრიფტის ზომა +editor_ink_line_color=ხაზის ფერი +editor_ink_line_thickness=ხაზის სისქე + +# Editor Parameters +editor_free_text_color=ფერი +editor_free_text_size=ზომა +editor_ink_color=ფერი +editor_ink_thickness=სისქე +editor_ink_opacity=გაუმჭვირვალობა + +# Editor aria +editor_free_text_aria_label=FreeText-ჩამსწორებელი +editor_ink_aria_label=ხელნაწერის ჩამსწორებელი +editor_ink_canvas_aria_label=მომხმარებლის შექმნილი სურათი diff --git a/cps/static/locale/kab/viewer.properties b/cps/static/locale/kab/viewer.properties index a6f07f169..1b5385517 100644 --- a/cps/static/locale/kab/viewer.properties +++ b/cps/static/locale/kab/viewer.properties @@ -39,7 +39,7 @@ open_file.title=Ldi Afaylu open_file_label=Ldi print.title=Siggez print_label=Siggez -download.title=Sider +download.title=Sader download_label=Azdam bookmark.title=Timeẓri tamirant (nɣel neɣ ldi ɣef usfaylu amaynut) bookmark_label=Askan amiran @@ -48,16 +48,12 @@ bookmark_label=Askan amiran tools.title=Ifecka tools_label=Ifecka first_page.title=Ddu ɣer usebter amezwaru -first_page.label=Ddu ɣer usebter amezwaru first_page_label=Ddu ɣer usebter amezwaru last_page.title=Ddu ɣer usebter aneggaru -last_page.label=Ddu ɣer usebter aneggaru last_page_label=Ddu ɣer usebter aneggaru page_rotate_cw.title=Tuzzya tusrigt -page_rotate_cw.label=Tuzzya tusrigt page_rotate_cw_label=Tuzzya tusrigt page_rotate_ccw.title=Tuzzya amgal-usrig -page_rotate_ccw.label=Tuzzya amgal-usrig page_rotate_ccw_label=Tuzzya amgal-usrig cursor_text_select_tool.title=Rmed afecku n tefrant n uḍris @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Afecku n tefrant n uḍris cursor_hand_tool.title=Rmed afecku afus cursor_hand_tool_label=Afecku afus +scroll_page.title=Seqdec adrurem n usebter +scroll_page_label=Adrurem n usebter scroll_vertical.title=Seqdec adrurem ubdid scroll_vertical_label=Adrurem ubdid scroll_horizontal.title=Seqdec adrurem aglawan @@ -102,7 +100,7 @@ document_properties_date_string={{date}}, {{time}} document_properties_creator=Yerna-t: document_properties_producer=Afecku n uselket PDF: document_properties_version=Lqem PDF: -document_properties_page_count=Amḍan n isebtar: +document_properties_page_count=Amḍan n yisebtar: document_properties_page_size=Tuγzi n usebter: document_properties_page_size_unit_inches=deg document_properties_page_size_unit_millimeters=mm @@ -137,19 +135,24 @@ print_progress_close=Sefsex # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Sken/Fer agalis adisan -toggle_sidebar_notification.title=Ffer/Sken agalis adisan (isemli yegber aɣawas/imeddayen) +toggle_sidebar_notification2.title=Ffer/Sekn agalis adisan (isemli yegber aɣawas/ticeqqufin yeddan/tissiwin) toggle_sidebar_label=Sken/Fer agalis adisan document_outline.title=Sken isemli (Senned snat tikal i wesemɣer/Afneẓ n iferdisen meṛṛa) document_outline_label=Isɣalen n isebtar attachments.title=Sken ticeqqufin yeddan attachments_label=Ticeqqufin yeddan +layers.title=Skeen tissiwin (sit sin yiberdan i uwennez n meṛṛa tissiwin ɣer waddad amezwer) +layers_label=Tissiwin thumbs.title=Sken tanfult. thumbs_label=Tinfulin +current_outline_item.title=Af-d aferdis n uɣawas amiran +current_outline_item_label=Aferdis n uɣawas amiran findbar.title=Nadi deg isemli findbar_label=Nadi -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Asebter {{page}} +additional_layers=Tissiwin-nniḍen +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Asebter {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Aff-d timseḍriwt n twinest d-iteddun find_next_label=Ddu ɣer zdat find_highlight=Err izirig imaṛṛa find_match_case_label=Qadeṛ amasal n isekkilen +find_match_diacritics_label=Qadeṛ ifeskilen find_entire_word_label=Awalen iččuranen find_reached_top=Yabbeḍ s afella n usebter, tuɣalin s wadda find_reached_bottom=Tebḍeḍ s adda n usebter, tuɣalin s afella @@ -222,7 +226,7 @@ page_scale_actual=Teɣzi tilawt page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error +loading=Asali… loading_error=Teḍra-d tuccḍa deg alluy n PDF: invalid_file_error=Afaylu PDF arameɣtu neɣ yexṣeṛ. missing_file_error=Ulac afaylu PDF. @@ -245,3 +249,33 @@ password_cancel=Sefsex printing_not_supported=Ɣuṛ-k: Asiggez ur ittusefrak ara yakan imaṛṛa deg iminig-a. printing_not_ready=Ɣuṛ-k: Afaylu PDF ur d-yuli ara imeṛṛa akken ad ittusiggez. web_fonts_disabled=Tisefsiyin web ttwassensent; D awezɣi useqdec n tsefsiyin yettwarnan ɣer PDF. + +# Editor +editor_none.title=Sens aseẓreg n telɣut +editor_none_label=Sens aseẓreg +editor_free_text.title=Rnu talɣut i FreeText +editor_free_text_label=Talɣut n FreeText +editor_ink.title=Suneɣ +editor_ink_label=Asuneɣ + +freetext_default_content=Sekcem kra n uḍris… + +free_text_default_content=Sekcem aḍris… + +# Editor Parameters +editor_free_text_font_color=Ini n tsefsit +editor_free_text_font_size=Teɣzi n tsefsit +editor_ink_line_color=Ini n yizirig +editor_ink_line_thickness=Tuzert n yizirig + +# Editor Parameters +editor_free_text_color=Initen +editor_free_text_size=Teɣzi +editor_ink_color=Ini +editor_ink_thickness=Tuzert +editor_ink_opacity=Tebrek + +# Editor aria +editor_free_text_aria_label=Amaẓrag n FreeText +editor_ink_aria_label=Amaẓrag n lmidad +editor_ink_canvas_aria_label=Tugna yettwarnan sɣur useqdac diff --git a/cps/static/locale/kk/viewer.properties b/cps/static/locale/kk/viewer.properties index afd679ac7..7c9876d96 100644 --- a/cps/static/locale/kk/viewer.properties +++ b/cps/static/locale/kk/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Ағымдағы көрініс tools.title=Құралдар tools_label=Құралдар first_page.title=Алғашқы параққа өту -first_page.label=Алғашқы параққа өту first_page_label=Алғашқы параққа өту last_page.title=Соңғы параққа өту -last_page.label=Соңғы параққа өту last_page_label=Соңғы параққа өту page_rotate_cw.title=Сағат тілі бағытымен айналдыру -page_rotate_cw.label=Сағат тілі бағытымен бұру page_rotate_cw_label=Сағат тілі бағытымен бұру page_rotate_ccw.title=Сағат тілі бағытына қарсы бұру -page_rotate_ccw.label=Сағат тілі бағытына қарсы бұру page_rotate_ccw_label=Сағат тілі бағытына қарсы бұру cursor_text_select_tool.title=Мәтінді таңдау құралын іске қосу @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Мәтінді таңдау құралы cursor_hand_tool.title=Қол құралын іске қосу cursor_hand_tool_label=Қол құралы +scroll_page.title=Беттерді айналдыруды пайдалану +scroll_page_label=Беттерді айналдыру scroll_vertical.title=Вертикалды айналдыруды қолдану scroll_vertical_label=Вертикалды айналдыру scroll_horizontal.title=Горизонталды айналдыруды қолдану @@ -137,19 +135,24 @@ print_progress_close=Бас тарту # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Бүйір панелін көрсету/жасыру -toggle_sidebar_notification.title=Бүйір панелін көрсету/жасыру (құжатта құрылымы/салынымдар бар) +toggle_sidebar_notification2.title=Бүйір панелін көрсету/жасыру (құжатта құрылымы/салынымдар/қабаттар бар) toggle_sidebar_label=Бүйір панелін көрсету/жасыру document_outline.title=Құжат құрылымын көрсету (барлық нәрселерді жазық қылу/жинау үшін қос шерту керек) document_outline_label=Құжат құрамасы attachments.title=Салынымдарды көрсету attachments_label=Салынымдар +layers.title=Қабаттарды көрсету (барлық қабаттарды бастапқы күйге келтіру үшін екі рет шертіңіз) +layers_label=Қабаттар thumbs.title=Кіші көріністерді көрсету thumbs_label=Кіші көріністер +current_outline_item.title=Құрылымның ағымдағы элементін табу +current_outline_item_label=Құрылымның ағымдағы элементі findbar.title=Құжаттан табу findbar_label=Табу -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Бет {{page}} +additional_layers=Қосымша қабаттар +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Бет {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Осы сөздердің мәтіннен келесі кезд find_next_label=Келесі find_highlight=Барлығын түспен ерекшелеу find_match_case_label=Регистрді ескеру +find_match_diacritics_label=Диакритиканы ескеру find_entire_word_label=Сөздер толығымен find_reached_top=Құжаттың басына жеттік, соңынан бастап жалғастырамыз find_reached_bottom=Құжаттың соңына жеттік, басынан бастап жалғастырамыз @@ -222,7 +226,7 @@ page_scale_actual=Нақты өлшемі page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Қате +loading=Жүктелуде… loading_error=PDF жүктеу кезінде қате кетті. invalid_file_error=Зақымдалған немесе қате PDF файл. missing_file_error=PDF файлы жоқ. @@ -245,3 +249,32 @@ password_cancel=Бас тарту printing_not_supported=Ескерту: Баспаға шығаруды бұл браузер толығымен қолдамайды. printing_not_ready=Ескерту: Баспаға шығару үшін, бұл PDF толығымен жүктеліп алынбады. web_fonts_disabled=Веб қаріптері сөндірілген: құрамына енгізілген PDF қаріптерін қолдану мүмкін емес. + +# Editor +editor_none.title=Аңдатпаларды түзету мүмкіндігін сөндіру +editor_none_label=Түзету мүмкіндігін сөндіру +editor_free_text.title=FreeText аңдатпасын қосу +editor_free_text_label=FreeText аңдатпасы +editor_ink.title=Қолдан аңдатпаны қосу +editor_ink_label=Қолдан аңдатпа + +freetext_default_content=Мәтінді енгізіңіз… + +free_text_default_content=Мәтінді енгізу… + +# Editor Parameters +editor_free_text_font_color=Қаріп түсі +editor_free_text_font_size=Қаріп өлшемі +editor_ink_line_color=Сызық түсі +editor_ink_line_thickness=Сызық қалыңдығы + +# Editor Parameters +editor_free_text_color=Түс +editor_free_text_size=Өлшемі +editor_ink_color=Түс +editor_ink_thickness=Қалыңдығы +editor_ink_opacity=Мөлдірсіздігі + +# Editor aria +editor_free_text_aria_label=FreeText түзеткіші +editor_ink_aria_label=Сия түзеткіші diff --git a/cps/static/locale/km/viewer.properties b/cps/static/locale/km/viewer.properties index 8615e8389..3dcac78d7 100644 --- a/cps/static/locale/km/viewer.properties +++ b/cps/static/locale/km/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=ទិដ្ឋភាព​បច្ចុប្បន្ន tools.title=ឧបករណ៍ tools_label=ឧបករណ៍ first_page.title=ទៅកាន់​ទំព័រ​ដំបូង​ -first_page.label=ទៅកាន់​ទំព័រ​ដំបូង​ first_page_label=ទៅកាន់​ទំព័រ​ដំបូង​ last_page.title=ទៅកាន់​ទំព័រ​ចុងក្រោយ​ -last_page.label=ទៅកាន់​ទំព័រ​ចុងក្រោយ​ last_page_label=ទៅកាន់​ទំព័រ​ចុងក្រោយ page_rotate_cw.title=បង្វិល​ស្រប​ទ្រនិច​នាឡិកា -page_rotate_cw.label=បង្វិល​ស្រប​ទ្រនិច​នាឡិកា page_rotate_cw_label=បង្វិល​ស្រប​ទ្រនិច​នាឡិកា page_rotate_ccw.title=បង្វិល​ច្រាស​ទ្រនិច​នាឡិកា​​ -page_rotate_ccw.label=បង្វិល​ច្រាស​ទ្រនិច​នាឡិកា​​ page_rotate_ccw_label=បង្វិល​ច្រាស​ទ្រនិច​នាឡិកា​​ cursor_text_select_tool.title=បើក​ឧបករណ៍​ជ្រើស​អត្ថបទ @@ -65,6 +61,8 @@ cursor_text_select_tool_label=ឧបករណ៍​ជ្រើស​អត្ cursor_hand_tool.title=បើក​ឧបករណ៍​ដៃ cursor_hand_tool_label=ឧបករណ៍​ដៃ + + # Document properties dialog box document_properties.title=លក្ខណ​សម្បត្តិ​ឯកសារ… document_properties_label=លក្ខណ​សម្បត្តិ​ឯកសារ… @@ -89,6 +87,25 @@ document_properties_creator=អ្នក​បង្កើត៖ document_properties_producer=កម្មវិធី​បង្កើត PDF ៖ document_properties_version=កំណែ PDF ៖ document_properties_page_count=ចំនួន​ទំព័រ៖ +document_properties_page_size_unit_inches=អ៊ីញ +document_properties_page_size_unit_millimeters=មម +document_properties_page_size_orientation_portrait=បញ្ឈរ +document_properties_page_size_orientation_landscape=ផ្តេក +document_properties_page_size_name_a3=A3 +document_properties_page_size_name_a4=A4 +document_properties_page_size_name_letter=សំបុត្រ +# LOCALIZATION NOTE (document_properties_page_size_dimension_string): +# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement and orientation, of the (current) page. +document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} ({{orientation}}) +# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): +# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement, name, and orientation, of the (current) page. +document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) +# LOCALIZATION NOTE (document_properties_linearized): The linearization status of +# the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized_yes=បាទ/ចាស +document_properties_linearized_no=ទេ document_properties_close=បិទ print_progress_message=កំពុង​រៀបចំ​ឯកសារ​សម្រាប់​បោះពុម្ព… @@ -101,7 +118,6 @@ print_progress_close=បោះបង់ # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=បិទ/បើក​គ្រាប់​រំកិល -toggle_sidebar_notification.title=បិទ/បើក​របារ​ចំហៀង (ឯកសារ​មាន​មាតិកា​នៅ​ក្រៅ/attachments) toggle_sidebar_label=បិទ/បើក​គ្រាប់​រំកិល document_outline.title=បង្ហាញ​គ្រោង​ឯកសារ (ចុច​ទ្វេ​ដង​ដើម្បី​ពង្រីក/បង្រួម​ធាតុ​ទាំងអស់) document_outline_label=គ្រោង​ឯកសារ @@ -112,6 +128,7 @@ thumbs_label=រួបភាព​តូចៗ findbar.title=រក​នៅ​ក្នុង​ឯកសារ findbar_label=រក +# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -131,6 +148,14 @@ find_highlight=បន្លិច​ទាំងអស់ find_match_case_label=ករណី​ដំណូច find_reached_top=បាន​បន្ត​ពី​ខាង​ក្រោម ទៅ​ដល់​ខាង​​លើ​នៃ​ឯកសារ find_reached_bottom=បាន​បន្ត​ពី​ខាងលើ ទៅដល់​ចុង​​នៃ​ឯកសារ +# LOCALIZATION NOTE (find_match_count): The supported plural forms are +# [one|two|few|many|other], with [other] as the default value. +# "{{current}}" and "{{total}}" will be replaced by a number representing the +# index of the currently active find result, respectively a number representing +# the total number of matches in the document. +# LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are +# [zero|one|two|few|many|other], with [other] as the default value. +# "{{limit}}" will be replaced by a numerical value. find_not_found=រក​មិន​ឃើញ​ពាក្យ ឬ​ឃ្លា # Error panel labels @@ -161,13 +186,14 @@ page_scale_actual=ទំហំ​ជាក់ស្ដែង # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=កំហុស loading_error=មាន​កំហុស​បាន​កើតឡើង​ពេល​កំពុង​ផ្ទុក PDF ។ invalid_file_error=ឯកសារ PDF ខូច ឬ​មិន​ត្រឹមត្រូវ ។ missing_file_error=បាត់​ឯកសារ PDF unexpected_response_error=ការ​ឆ្លើយ​តម​ម៉ាស៊ីន​មេ​ដែល​មិន​បាន​រំពឹង។ +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. + # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). diff --git a/cps/static/locale/kn/viewer.properties b/cps/static/locale/kn/viewer.properties index b37a71c2e..79c043753 100644 --- a/cps/static/locale/kn/viewer.properties +++ b/cps/static/locale/kn/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=ಪ್ರಸಕ್ತ ನೋಟ tools.title=ಉಪಕರಣಗಳು tools_label=ಉಪಕರಣಗಳು first_page.title=ಮೊದಲ ಪುಟಕ್ಕೆ ತೆರಳು -first_page.label=ಮೊದಲ ಪುಟಕ್ಕೆ ತೆರಳು first_page_label=ಮೊದಲ ಪುಟಕ್ಕೆ ತೆರಳು last_page.title=ಕೊನೆಯ ಪುಟಕ್ಕೆ ತೆರಳು -last_page.label=ಕೊನೆಯ ಪುಟಕ್ಕೆ ತೆರಳು last_page_label=ಕೊನೆಯ ಪುಟಕ್ಕೆ ತೆರಳು page_rotate_cw.title=ಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು -page_rotate_cw.label=ಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು page_rotate_cw_label=ಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು page_rotate_ccw.title=ಅಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು -page_rotate_ccw.label=ಅಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು page_rotate_ccw_label=ಅಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು cursor_text_select_tool.title=ಪಠ್ಯ ಆಯ್ಕೆ ಉಪಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ @@ -170,8 +166,6 @@ page_scale_actual=ನಿಜವಾದ ಗಾತ್ರ # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=ದೋಷ loading_error=PDF ಅನ್ನು ಲೋಡ್ ಮಾಡುವಾಗ ಒಂದು ದೋಷ ಎದುರಾಗಿದೆ. invalid_file_error=ಅಮಾನ್ಯವಾದ ಅಥವ ಹಾಳಾದ PDF ಕಡತ. missing_file_error=PDF ಕಡತ ಇಲ್ಲ. diff --git a/cps/static/locale/ko/viewer.properties b/cps/static/locale/ko/viewer.properties index 727f8d5c9..218dd73b0 100644 --- a/cps/static/locale/ko/viewer.properties +++ b/cps/static/locale/ko/viewer.properties @@ -41,23 +41,19 @@ print.title=인쇄 print_label=인쇄 download.title=다운로드 download_label=다운로드 -bookmark.title=현재 보기 (복사 또는 새 창에 열기) +bookmark.title=현재 보기 (복사 또는 새 창에서 열기) bookmark_label=현재 보기 # Secondary toolbar and context menu tools.title=도구 tools_label=도구 first_page.title=첫 페이지로 이동 -first_page.label=첫 페이지로 이동 first_page_label=첫 페이지로 이동 last_page.title=마지막 페이지로 이동 -last_page.label=마지막 페이지로 이동 last_page_label=마지막 페이지로 이동 page_rotate_cw.title=시계방향으로 회전 -page_rotate_cw.label=시계방향으로 회전 page_rotate_cw_label=시계방향으로 회전 page_rotate_ccw.title=시계 반대방향으로 회전 -page_rotate_ccw.label=시계 반대방향으로 회전 page_rotate_ccw_label=시계 반대방향으로 회전 cursor_text_select_tool.title=텍스트 선택 도구 활성화 @@ -65,18 +61,20 @@ cursor_text_select_tool_label=텍스트 선택 도구 cursor_hand_tool.title=손 도구 활성화 cursor_hand_tool_label=손 도구 +scroll_page.title=페이지 스크롤 사용 +scroll_page_label=페이지 스크롤 scroll_vertical.title=세로 스크롤 사용 scroll_vertical_label=세로 스크롤 scroll_horizontal.title=가로 스크롤 사용 scroll_horizontal_label=가로 스크롤 -scroll_wrapped.title=감싼 스크롤 사용 -scroll_wrapped_label=감싼 스크롤 +scroll_wrapped.title=래핑(자동 줄 바꿈) 스크롤 사용 +scroll_wrapped_label=래핑 스크롤 -spread_none.title=펼쳐진 페이지를 합치지 않음 +spread_none.title=한 페이지 보기 spread_none_label=펼쳐짐 없음 -spread_odd.title=홀수 페이지로 시작하게 펼쳐진 페이지 합침 +spread_odd.title=홀수 페이지로 시작하는 두 페이지 보기 spread_odd_label=홀수 펼쳐짐 -spread_even.title=짝수 페이지로 시작하게 펼쳐진 페이지 합침 +spread_even.title=짝수 페이지로 시작하는 두 페이지 보기 spread_even_label=짝수 펼쳐짐 # Document properties dialog box @@ -137,19 +135,24 @@ print_progress_close=취소 # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=탐색창 표시/숨기기 -toggle_sidebar_notification.title=탐색창 표시/숨기기 (문서에 아웃라인/첨부파일 포함됨) +toggle_sidebar_notification2.title=탐색창 표시/숨기기 (문서에 아웃라인/첨부파일/레이어 포함됨) toggle_sidebar_label=탐색창 표시/숨기기 -document_outline.title=문서 아웃라인 보기(더블 클릭해서 모든 항목 펼치기/접기) +document_outline.title=문서 아웃라인 보기 (더블 클릭해서 모든 항목 펼치기/접기) document_outline_label=문서 아웃라인 attachments.title=첨부파일 보기 attachments_label=첨부파일 +layers.title=레이어 보기 (더블 클릭해서 모든 레이어를 기본 상태로 재설정) +layers_label=레이어 thumbs.title=미리보기 thumbs_label=미리보기 +current_outline_item.title=현재 아웃라인 항목 찾기 +current_outline_item_label=현재 아웃라인 항목 findbar.title=검색 findbar_label=검색 -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas={{page}} 페이지 +additional_layers=추가 레이어 +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark={{page}} 페이지 # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=지정 문자열에 일치하는 다음 부분을 검색 find_next_label=다음 find_highlight=모두 강조 표시 find_match_case_label=대/소문자 구분 +find_match_diacritics_label=분음 부호 일치 find_entire_word_label=단어 단위로 find_reached_top=문서 처음까지 검색하고 끝으로 돌아와 검색했습니다. find_reached_bottom=문서 끝까지 검색하고 앞으로 돌아와 검색했습니다. @@ -194,7 +198,7 @@ find_match_count_limit[other]={{limit}} 이상 일치 find_not_found=검색 결과 없음 # Error panel labels -error_more_info=정보 더 보기 +error_more_info=자세한 정보 error_less_info=정보 간단히 보기 error_close=닫기 # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be @@ -213,16 +217,16 @@ error_line=줄 번호: {{line}} rendering_error=페이지를 렌더링하는 동안 오류가 발생했습니다. # Predefined zoom values -page_scale_width=페이지 너비에 맞춤 -page_scale_fit=페이지에 맞춤 -page_scale_auto=자동 맞춤 -page_scale_actual=실제 크기에 맞춤 +page_scale_width=페이지 너비에 맞추기 +page_scale_fit=페이지에 맞추기 +page_scale_auto=자동 +page_scale_actual=실제 크기 # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a # numerical scale value. page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=오류 +loading=로드 중… loading_error=PDF를 로드하는 동안 오류가 발생했습니다. invalid_file_error=잘못되었거나 손상된 PDF 파일. missing_file_error=PDF 파일 없음. @@ -245,3 +249,31 @@ password_cancel=취소 printing_not_supported=경고: 이 브라우저는 인쇄를 완전히 지원하지 않습니다. printing_not_ready=경고: 이 PDF를 인쇄를 할 수 있을 정도로 읽어들이지 못했습니다. web_fonts_disabled=웹 폰트가 비활성화됨: 내장된 PDF 글꼴을 사용할 수 없습니다. + +# Editor +editor_none.title=주석 편집 사용 안 함 +editor_none_label=편집 비활성화 +editor_free_text.title=텍스트 주석 추가 +editor_free_text_label=텍스트 주석 +editor_ink.title=잉크 주석 추가 +editor_ink_label=잉크 주석 + +free_text_default_content=텍스트를 입력하세요… + +# Editor Parameters +editor_free_text_font_color=글꼴 색상 +editor_free_text_font_size=글꼴 크기 +editor_ink_line_color=선 색상 +editor_ink_line_thickness=선 두께 + +# Editor Parameters +editor_free_text_color=색상 +editor_free_text_size=크기 +editor_ink_color=색상 +editor_ink_thickness=두께 +editor_ink_opacity=불투명도 + +# Editor aria +editor_free_text_aria_label=텍스트 편집기 +editor_ink_aria_label=잉크 편집기 +editor_ink_canvas_aria_label=사용자 생성 이미지 diff --git a/cps/static/locale/lij/viewer.properties b/cps/static/locale/lij/viewer.properties index 0cfa7d27f..b89981c28 100644 --- a/cps/static/locale/lij/viewer.properties +++ b/cps/static/locale/lij/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vixon corente tools.title=Atressi tools_label=Atressi first_page.title=Vanni a-a primma pagina -first_page.label=Vanni a-a primma pagina first_page_label=Vanni a-a primma pagina last_page.title=Vanni a l'urtima pagina -last_page.label=Vanni a l'urtima pagina last_page_label=Vanni a l'urtima pagina page_rotate_cw.title=Gia into verso oraio -page_rotate_cw.label=Gia in senso do releuio page_rotate_cw_label=Gia into verso oraio page_rotate_ccw.title=Gia into verso antioraio -page_rotate_ccw.label=Gia in senso do releuio a-a reversa page_rotate_ccw_label=Gia into verso antioraio cursor_text_select_tool.title=Abilita strumento de seleçion do testo @@ -137,7 +133,6 @@ print_progress_close=Anulla # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Ativa/dizativa bara de scianco -toggle_sidebar_notification.title=Cangia bara de löo (o documento o contegne di alegæ) toggle_sidebar_label=Ativa/dizativa bara de scianco document_outline.title=Fanni vedde o contorno do documento (scicca doggio pe espande/ridue tutti i elementi) document_outline_label=Contorno do documento @@ -219,8 +214,6 @@ page_scale_actual=Dimenscioin efetive # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Erô loading_error=S'é verificou 'n'erô itno caregamento do PDF. invalid_file_error=O schedaio PDF o l'é no valido ò aroinou. missing_file_error=O schedaio PDF o no gh'é. diff --git a/cps/static/locale/lo/viewer.properties b/cps/static/locale/lo/viewer.properties index 00d3309c0..8b877d00a 100644 --- a/cps/static/locale/lo/viewer.properties +++ b/cps/static/locale/lo/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=ມຸມມອງປະຈຸບັນ tools.title=ເຄື່ອງມື tools_label=ເຄື່ອງມື first_page.title=ໄປທີ່ຫນ້າທຳອິດ -first_page.label=ໄປທີ່ຫນ້າທຳອິດ first_page_label=ໄປທີ່ຫນ້າທຳອິດ last_page.title=ໄປທີ່ຫນ້າສຸດທ້າຍ -last_page.label=ໄປທີ່ຫນ້າສຸດທ້າຍ last_page_label=ໄປທີ່ຫນ້າສຸດທ້າຍ page_rotate_cw.title=ຫມູນຕາມເຂັມໂມງ -page_rotate_cw.label=ຫມູນຕາມເຂັມໂມງ page_rotate_cw_label=ຫມູນຕາມເຂັມໂມງ page_rotate_ccw.title=ຫມູນທວນເຂັມໂມງ -page_rotate_ccw.label=ຫມູນທວນເຂັມໂມງ page_rotate_ccw_label=ຫມູນທວນເຂັມໂມງ @@ -98,7 +94,6 @@ print_progress_close=ຍົກເລີກ # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=ເປີດ/ປິດແຖບຂ້າງ -toggle_sidebar_notification.title=ເປີດ/ປິດແຖບຂ້າງ (ເອກະສານມີເຄົ້າຮ່າງ/ໄຟລ໌ແນບ) toggle_sidebar_label=ເປີດ/ປິດແຖບຂ້າງ document_outline_label=ເຄົ້າຮ່າງເອກະສານ findbar_label=ຄົ້ນຫາ @@ -138,8 +133,6 @@ rendering_error=ມີຂໍ້ຜິດພາດເກີດຂື້ນຂະ # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a # numerical scale value. -# Loading indicator messages -loading_error_indicator=ຂໍ້ຜິດພາດ loading_error=ມີຂໍ້ຜິດພາດເກີດຂື້ນຂະນະທີ່ກຳລັງໂຫລດ PDF. invalid_file_error=ໄຟລ໌ PDF ບໍ່ຖືກຕ້ອງຫລືເສຍຫາຍ. diff --git a/cps/static/locale/locale.properties b/cps/static/locale/locale.properties index 372dd5d32..ae79f4739 100644 --- a/cps/static/locale/locale.properties +++ b/cps/static/locale/locale.properties @@ -244,9 +244,18 @@ [ru] @import url(ru/viewer.properties) +[sat] +@import url(sat/viewer.properties) + +[sc] +@import url(sc/viewer.properties) + [scn] @import url(scn/viewer.properties) +[sco] +@import url(sco/viewer.properties) + [si] @import url(si/viewer.properties) @@ -277,6 +286,9 @@ [te] @import url(te/viewer.properties) +[tg] +@import url(tg/viewer.properties) + [th] @import url(th/viewer.properties) diff --git a/cps/static/locale/lt/viewer.properties b/cps/static/locale/lt/viewer.properties index daa76787c..390fa092c 100644 --- a/cps/static/locale/lt/viewer.properties +++ b/cps/static/locale/lt/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Esamasis rodinys tools.title=Priemonės tools_label=Priemonės first_page.title=Eiti į pirmą puslapį -first_page.label=Eiti į pirmą puslapį first_page_label=Eiti į pirmą puslapį last_page.title=Eiti į paskutinį puslapį -last_page.label=Eiti į paskutinį puslapį last_page_label=Eiti į paskutinį puslapį page_rotate_cw.title=Pasukti pagal laikrodžio rodyklę -page_rotate_cw.label=Pasukti pagal laikrodžio rodyklę page_rotate_cw_label=Pasukti pagal laikrodžio rodyklę page_rotate_ccw.title=Pasukti prieš laikrodžio rodyklę -page_rotate_ccw.label=Pasukti prieš laikrodžio rodyklę page_rotate_ccw_label=Pasukti prieš laikrodžio rodyklę cursor_text_select_tool.title=Įjungti teksto žymėjimo įrankį @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Teksto žymėjimo įrankis cursor_hand_tool.title=Įjungti vilkimo įrankį cursor_hand_tool_label=Vilkimo įrankis +scroll_page.title=Naudoti puslapio slinkimą +scroll_page_label=Puslapio slinkimas scroll_vertical.title=Naudoti vertikalų slinkimą scroll_vertical_label=Vertikalus slinkimas scroll_horizontal.title=Naudoti horizontalų slinkimą @@ -72,12 +70,12 @@ scroll_horizontal_label=Horizontalus slinkimas scroll_wrapped.title=Naudoti išklotą slinkimą scroll_wrapped_label=Išklotas slinkimas -spread_none.title=Nesujungti puslapių sklaidų -spread_none_label=Be sklaidų -spread_odd.title=Sujungti puslapių sklaidas pradedant nelyginiais puslapiais -spread_odd_label=Nelyginės sklaidos -spread_even.title=Sujungti puslapių sklaidas pradedant lyginiais puslapiais -spread_even_label=Lyginės sklaidos +spread_none.title=Nejungti puslapių į dvilapius +spread_none_label=Be dvilapių +spread_odd.title=Sujungti į dvilapius pradedant nelyginiais puslapiais +spread_odd_label=Nelyginiai dvilapiai +spread_even.title=Sujungti į dvilapius pradedant lyginiais puslapiais +spread_even_label=Lyginiai dvilapiai # Document properties dialog box document_properties.title=Dokumento savybės… @@ -137,19 +135,24 @@ print_progress_close=Atsisakyti # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Rodyti / slėpti šoninį polangį -toggle_sidebar_notification.title=Parankinė (dokumentas turi struktūrą / priedų) +toggle_sidebar_notification2.title=Parankinė (dokumentas turi struktūrą / priedų / sluoksnių) toggle_sidebar_label=Šoninis polangis document_outline.title=Rodyti dokumento struktūrą (spustelėkite dukart norėdami išplėsti/suskleisti visus elementus) document_outline_label=Dokumento struktūra attachments.title=Rodyti priedus attachments_label=Priedai +layers.title=Rodyti sluoksnius (spustelėkite dukart, norėdami atstatyti visus sluoksnius į numatytąją būseną) +layers_label=Sluoksniai thumbs.title=Rodyti puslapių miniatiūras thumbs_label=Miniatiūros +current_outline_item.title=Rasti dabartinį struktūros elementą +current_outline_item_label=Dabartinis struktūros elementas findbar.title=Ieškoti dokumente findbar_label=Rasti -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas={{page}} puslapis +additional_layers=Papildomi sluoksniai +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark={{page}} puslapis # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Ieškoti tolesnio frazės egzemplioriaus find_next_label=Tolesnis find_highlight=Viską paryškinti find_match_case_label=Skirti didžiąsias ir mažąsias raides +find_match_diacritics_label=Skirti diakritinius ženklus find_entire_word_label=Ištisi žodžiai find_reached_top=Pasiekus dokumento pradžią, paieška pratęsta nuo pabaigos find_reached_bottom=Pasiekus dokumento pabaigą, paieška pratęsta nuo pradžios @@ -222,7 +226,7 @@ page_scale_actual=Tikras dydis page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Klaida +loading=Įkeliama… loading_error=Įkeliant PDF failą įvyko klaida. invalid_file_error=Tai nėra PDF failas arba jis yra sugadintas. missing_file_error=PDF failas nerastas. @@ -245,3 +249,13 @@ password_cancel=Atsisakyti printing_not_supported=Dėmesio! Spausdinimas šioje naršyklėje nėra pilnai realizuotas. printing_not_ready=Dėmesio! PDF failas dar nėra pilnai įkeltas spausdinimui. web_fonts_disabled=Saityno šriftai išjungti – PDF faile esančių šriftų naudoti negalima. + +# Editor +editor_none.title=Išjungti komentarų redagavimą +editor_none_label=Išjungti redagavimą +editor_free_text.title=Pridėti „FreeText“ komentarą +editor_free_text_label=„FreeText“ komentaras +editor_ink.title=Pridėti laisvo stiliaus komentarą +editor_ink_label=Laisvo stiliaus komentaras + +freetext_default_content=Įveskite tekstą… diff --git a/cps/static/locale/ltg/viewer.properties b/cps/static/locale/ltg/viewer.properties index 4fffa864d..b0e202d2e 100644 --- a/cps/static/locale/ltg/viewer.properties +++ b/cps/static/locale/ltg/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Pošreizejais skots tools.title=Reiki tools_label=Reiki first_page.title=Īt iz pyrmū lopu -first_page.label=Īt iz pyrmū lopu first_page_label=Īt iz pyrmū lopu last_page.title=Īt iz piedejū lopu -last_page.label=Īt iz piedejū lopu last_page_label=Īt iz piedejū lopu page_rotate_cw.title=Pagrīzt pa pulksteni -page_rotate_cw.label=Pagrīzt pa pulksteni page_rotate_cw_label=Pagrīzt pa pulksteni page_rotate_ccw.title=Pagrīzt pret pulksteni -page_rotate_ccw.label=Pagrīzt pret pulksteni page_rotate_ccw_label=Pagrīzt pret pulksteni cursor_text_select_tool.title=Aktivizēt teksta izvieles reiku @@ -137,7 +133,6 @@ print_progress_close=Atceļt # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Puorslēgt suonu jūslu -toggle_sidebar_notification.title=Toggle Sidebar (document contains outline/attachments) toggle_sidebar_label=Puorslēgt suonu jūslu document_outline.title=Show Document Outline (double-click to expand/collapse all items) document_outline_label=Dokumenta saturs @@ -197,8 +192,6 @@ page_scale_actual=Patīsais izmārs # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Klaida loading_error=Īluodejūt PDF nūtyka klaida. invalid_file_error=Nadereigs voi būjuots PDF fails. missing_file_error=PDF fails nav atrosts. diff --git a/cps/static/locale/lv/viewer.properties b/cps/static/locale/lv/viewer.properties index b6d6ad38f..b9b5c0336 100644 --- a/cps/static/locale/lv/viewer.properties +++ b/cps/static/locale/lv/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Pašreizējais skats tools.title=Rīki tools_label=Rīki first_page.title=Iet uz pirmo lapu -first_page.label=Iet uz pirmo lapu first_page_label=Iet uz pirmo lapu last_page.title=Iet uz pēdējo lapu -last_page.label=Iet uz pēdējo lapu last_page_label=Iet uz pēdējo lapu page_rotate_cw.title=Pagriezt pa pulksteni -page_rotate_cw.label=Pagriezt pa pulksteni page_rotate_cw_label=Pagriezt pa pulksteni page_rotate_ccw.title=Pagriezt pret pulksteni -page_rotate_ccw.label=Pagriezt pret pulksteni page_rotate_ccw_label=Pagriezt pret pulksteni cursor_text_select_tool.title=Aktivizēt teksta izvēles rīku @@ -137,7 +133,6 @@ print_progress_close=Atcelt # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Pārslēgt sānu joslu -toggle_sidebar_notification.title=Pārslēgt sānu joslu (dokumenta saturu un pielikumus) toggle_sidebar_label=Pārslēgt sānu joslu document_outline.title=Rādīt dokumenta struktūru (veiciet dubultklikšķi lai izvērstu/sakļautu visus vienumus) document_outline_label=Dokumenta saturs @@ -219,8 +214,6 @@ page_scale_actual=Patiesais izmērs # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Kļūda loading_error=Ielādējot PDF notika kļūda. invalid_file_error=Nederīgs vai bojāts PDF fails. missing_file_error=PDF fails nav atrasts. diff --git a/cps/static/locale/mk/viewer.properties b/cps/static/locale/mk/viewer.properties index c1b091ed6..24ff730b6 100644 --- a/cps/static/locale/mk/viewer.properties +++ b/cps/static/locale/mk/viewer.properties @@ -43,10 +43,6 @@ bookmark_label=Овој преглед # Secondary toolbar and context menu tools.title=Алатки -first_page.label=Оди до првата страница -last_page.label=Оди до последната страница -page_rotate_cw.label=Ротирај по стрелките на часовникот -page_rotate_ccw.label=Ротирај спротивно од стрелките на часовникот @@ -127,8 +123,6 @@ page_scale_actual=Вистинска големина # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a # numerical scale value. -# Loading indicator messages -loading_error_indicator=Грешка loading_error=Настана грешка при вчитувањето на PDF-от. invalid_file_error=Невалидна или корумпирана PDF датотека. missing_file_error=Недостасува PDF документ. diff --git a/cps/static/locale/mr/viewer.properties b/cps/static/locale/mr/viewer.properties index b33646f51..697c2a3f3 100644 --- a/cps/static/locale/mr/viewer.properties +++ b/cps/static/locale/mr/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=सध्याचे अवलोकन tools.title=साधने tools_label=साधने first_page.title=पहिल्या पृष्ठावर जा -first_page.label=पहिल्या पृष्ठावर जा first_page_label=पहिल्या पृष्ठावर जा last_page.title=शेवटच्या पृष्ठावर जा -last_page.label=शेवटच्या पृष्ठावर जा last_page_label=शेवटच्या पृष्ठावर जा page_rotate_cw.title=घड्याळाच्या काट्याच्या दिशेने फिरवा -page_rotate_cw.label=घड्याळाच्या काट्याच्या दिशेने फिरवा page_rotate_cw_label=घड्याळाच्या काट्याच्या दिशेने फिरवा page_rotate_ccw.title=घड्याळाच्या काट्याच्या उलट दिशेने फिरवा -page_rotate_ccw.label=घड्याळाच्या काट्याच्या उलट दिशेने फिरवा page_rotate_ccw_label=घड्याळाच्या काट्याच्या उलट दिशेने फिरवा cursor_text_select_tool.title=मजकूर निवड साधन कार्यान्वयीत करा @@ -129,7 +125,6 @@ print_progress_close=रद्द करा # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=बाजूचीपट्टी टॉगल करा -toggle_sidebar_notification.title=बाजूची पट्टी टॉगल करा (दस्तऐवजामध्ये रुपरेषा/जोडण्या आहेत) toggle_sidebar_label=बाजूचीपट्टी टॉगल करा document_outline.title=दस्तऐवज बाह्यरेखा दर्शवा (विस्तृत करण्यासाठी दोनवेळा क्लिक करा /सर्व घटक दाखवा) document_outline_label=दस्तऐवज रूपरेषा @@ -211,8 +206,6 @@ page_scale_actual=प्रत्यक्ष आकार # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=त्रुटी loading_error=PDF लोड करतेवेळी त्रुटी आढळली. invalid_file_error=अवैध किंवा दोषीत PDF फाइल. missing_file_error=न आढळणारी PDF फाइल. diff --git a/cps/static/locale/ms/viewer.properties b/cps/static/locale/ms/viewer.properties index 61f155397..a6d4ce8b6 100644 --- a/cps/static/locale/ms/viewer.properties +++ b/cps/static/locale/ms/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Paparan Semasa tools.title=Alatan tools_label=Alatan first_page.title=Pergi ke Halaman Pertama -first_page.label=Pergi ke Halaman Pertama first_page_label=Pergi ke Halaman Pertama last_page.title=Pergi ke Halaman Terakhir -last_page.label=Pergi ke Halaman Terakhir last_page_label=Pergi ke Halaman Terakhir page_rotate_cw.title=Berputar ikut arah Jam -page_rotate_cw.label=Berputar ikut arah Jam page_rotate_cw_label=Berputar ikut arah Jam page_rotate_ccw.title=Pusing berlawan arah jam -page_rotate_ccw.label=Pusing berlawan arah jam page_rotate_ccw_label=Pusing berlawan arah jam cursor_text_select_tool.title=Dayakan Alatan Pilihan Teks @@ -137,7 +133,6 @@ print_progress_close=Batal # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Togol Bar Sisi -toggle_sidebar_notification.title=Togol Sidebar (dokumen mengandungi rangka/attachments) toggle_sidebar_label=Togol Bar Sisi document_outline.title=Papar Rangka Dokumen (klik-dua-kali untuk kembangkan/kolaps semua item) document_outline_label=Rangka Dokumen @@ -219,8 +214,6 @@ page_scale_actual=Saiz Sebenar # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Ralat loading_error=Masalah berlaku semasa menuatkan sebuah PDF. invalid_file_error=Tidak sah atau fail PDF rosak. missing_file_error=Fail PDF Hilang. diff --git a/cps/static/locale/my/viewer.properties b/cps/static/locale/my/viewer.properties index 3e6f2c305..39944cdde 100644 --- a/cps/static/locale/my/viewer.properties +++ b/cps/static/locale/my/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=လက်ရှိ မြင်ကွင်း tools.title=ကိရိယာများ tools_label=ကိရိယာများ first_page.title=ပထမ စာမျက်နှာသို့ -first_page.label=ပထမ စာမျက်နှာသို့ first_page_label=ပထမ စာမျက်နှာသို့ last_page.title=နောက်ဆုံး စာမျက်နှာသို့ -last_page.label=နောက်ဆုံး စာမျက်နှာသို့ last_page_label=နောက်ဆုံး စာမျက်နှာသို့ page_rotate_cw.title=နာရီလက်တံ အတိုင်း -page_rotate_cw.label=နာရီလက်တံ အတိုင်း page_rotate_cw_label=နာရီလက်တံ အတိုင်း page_rotate_ccw.title=နာရီလက်တံ ပြောင်းပြန် -page_rotate_ccw.label=နာရီလက်တံ ပြောင်းပြန် page_rotate_ccw_label=နာရီလက်တံ ပြောင်းပြန် @@ -107,7 +103,6 @@ print_progress_close=ပယ်​ဖျက်ပါ # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=ဘေးတန်းဖွင့်ပိတ် -toggle_sidebar_notification.title=ဘေးဘားတန်းကို အဖွင့်/အပိတ် လုပ်ရန် (စာတမ်းတွင် outline/attachments ပါဝင်နိုင်သည်) toggle_sidebar_label=ဖွင့်ပိတ် ဆလိုက်ဒါ document_outline.title=စာတမ်းအကျဉ်းချုပ်ကို ပြပါ (စာရင်းအားလုံးကို ချုံ့/ချဲ့ရန် ကလစ်နှစ်ချက်နှိပ်ပါ) document_outline_label=စာတမ်းအကျဉ်းချုပ် @@ -175,8 +170,6 @@ page_scale_actual=အမှန်တကယ်ရှိတဲ့ အရွယ် # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=အမှား loading_error=PDF ဖိုင် ကိုဆွဲတင်နေချိန်မှာ အမှားတစ်ခုတွေ့ရပါတယ်။ invalid_file_error=မရသော သို့ ပျက်နေသော PDF ဖိုင် missing_file_error=PDF ပျောက်ဆုံး diff --git a/cps/static/locale/nb-NO/viewer.properties b/cps/static/locale/nb-NO/viewer.properties index 47b209048..5a72650a1 100644 --- a/cps/static/locale/nb-NO/viewer.properties +++ b/cps/static/locale/nb-NO/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Nåværende visning tools.title=Verktøy tools_label=Verktøy first_page.title=Gå til første side -first_page.label=Gå til første side first_page_label=Gå til første side last_page.title=Gå til siste side -last_page.label=Gå til siste side last_page_label=Gå til siste side page_rotate_cw.title=Roter med klokken -page_rotate_cw.label=Roter med klokken page_rotate_cw_label=Roter med klokken page_rotate_ccw.title=Roter mot klokken -page_rotate_ccw.label=Roter mot klokken page_rotate_ccw_label=Roter mot klokken cursor_text_select_tool.title=Aktiver tekstmarkeringsverktøy @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Tekstmarkeringsverktøy cursor_hand_tool.title=Aktiver handverktøy cursor_hand_tool_label=Handverktøy +scroll_page.title=Bruk siderulling +scroll_page_label=Siderulling scroll_vertical.title=Bruk vertikal rulling scroll_vertical_label=Vertikal rulling scroll_horizontal.title=Bruk horisontal rulling @@ -137,19 +135,24 @@ print_progress_close=Avbryt # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Slå av/på sidestolpe -toggle_sidebar_notification.title=Vis/gjem sidestolpe (dokumentet inneholder oversikt/vedlegg) +toggle_sidebar_notification2.title=Vis/gjem sidestolpe (dokumentet inneholder oversikt/vedlegg/lag) toggle_sidebar_label=Slå av/på sidestolpe document_outline.title=Vis dokumentdisposisjonen (dobbeltklikk for å utvide/skjule alle elementer) document_outline_label=Dokumentdisposisjon attachments.title=Vis vedlegg attachments_label=Vedlegg +layers.title=Vis lag (dobbeltklikk for å tilbakestille alle lag til standardtilstand) +layers_label=Lag thumbs.title=Vis miniatyrbilde thumbs_label=Miniatyrbilde +current_outline_item.title=Finn gjeldende disposisjonselement +current_outline_item_label=Gjeldende disposisjonselement findbar.title=Finn i dokumentet findbar_label=Finn -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Side {{page}} +additional_layers=Ytterligere lag +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Side {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Finn neste forekomst av frasen find_next_label=Neste find_highlight=Uthev alle find_match_case_label=Skill store/små bokstaver +find_match_diacritics_label=Samsvar diakritiske tegn find_entire_word_label=Hele ord find_reached_top=Nådde toppen av dokumentet, fortsetter fra bunnen find_reached_bottom=Nådde bunnen av dokumentet, fortsetter fra toppen @@ -222,7 +226,7 @@ page_scale_actual=Virkelig størrelse page_scale_percent={{scale}} % # Loading indicator messages -loading_error_indicator=Feil +loading=Laster… loading_error=En feil oppstod ved lasting av PDF. invalid_file_error=Ugyldig eller skadet PDF-fil. missing_file_error=Manglende PDF-fil. @@ -245,3 +249,33 @@ password_cancel=Avbryt printing_not_supported=Advarsel: Utskrift er ikke fullstendig støttet av denne nettleseren. printing_not_ready=Advarsel: PDF er ikke fullstendig innlastet for utskrift. web_fonts_disabled=Web-fonter er avslått: Kan ikke bruke innbundne PDF-fonter. + +# Editor +editor_none.title=Slå av kommentarredigering +editor_none_label=Slå av redigering +editor_free_text.title=Legg til fritekstkommentar +editor_free_text_label=Fritekstkommentar +editor_ink.title=Legg til håndskreven kommentar +editor_ink_label=Håndskreven kommentar + +freetext_default_content=Skriv inn litt tekst… + +free_text_default_content=Skriv inn tekst… + +# Editor Parameters +editor_free_text_font_color=Skriftfarge +editor_free_text_font_size=Skriftstørrelse +editor_ink_line_color=Linjefarge +editor_ink_line_thickness=Linjetykkelse + +# Editor Parameters +editor_free_text_color=Farge +editor_free_text_size=Størrelse +editor_ink_color=Farge +editor_ink_thickness=Tykkelse +editor_ink_opacity=Ugjennomsiktighet + +# Editor aria +editor_free_text_aria_label=FreeText-redigerer +editor_ink_aria_label=Ink-redigerer +editor_ink_canvas_aria_label=Brukerskapt bilde diff --git a/cps/static/locale/ne-NP/viewer.properties b/cps/static/locale/ne-NP/viewer.properties index 3bf8ed8f3..004416745 100644 --- a/cps/static/locale/ne-NP/viewer.properties +++ b/cps/static/locale/ne-NP/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=हालको दृश्य tools.title=औजारहरू tools_label=औजारहरू first_page.title=पहिलो पृष्ठमा जानुहोस् -first_page.label=पहिलो पृष्ठमा जानुहोस् first_page_label=पहिलो पृष्ठमा जानुहोस् last_page.title=पछिल्लो पृष्ठमा जानुहोस् -last_page.label=पछिल्लो पृष्ठमा जानुहोस् last_page_label=पछिल्लो पृष्ठमा जानुहोस् page_rotate_cw.title=घडीको दिशामा घुमाउनुहोस् -page_rotate_cw.label=घडीको दिशामा घुमाउनुहोस् page_rotate_cw_label=घडीको दिशामा घुमाउनुहोस् page_rotate_ccw.title=घडीको विपरित दिशामा घुमाउनुहोस् -page_rotate_ccw.label=घडीको विपरित दिशामा घुमाउनुहोस् page_rotate_ccw_label=घडीको विपरित दिशामा घुमाउनुहोस् cursor_text_select_tool.title=पाठ चयन उपकरण सक्षम गर्नुहोस् @@ -65,6 +61,16 @@ cursor_text_select_tool_label=पाठ चयन उपकरण cursor_hand_tool.title=हाते उपकरण सक्षम गर्नुहोस् cursor_hand_tool_label=हाते उपकरण +scroll_vertical.title=ठाडो स्क्रोलिङ्ग प्रयोग गर्नुहोस् +scroll_vertical_label=ठाडो स्क्र्रोलिङ्ग +scroll_horizontal.title=तेर्सो स्क्रोलिङ्ग प्रयोग गर्नुहोस् +scroll_horizontal_label=तेर्सो स्क्रोलिङ्ग +scroll_wrapped.title=लिपि स्क्रोलिङ्ग प्रयोग गर्नुहोस् +scroll_wrapped_label=लिपि स्क्रोलिङ्ग + +spread_none.title=पृष्ठ स्प्रेडमा सामेल हुनुहुन्न +spread_none_label=स्प्रेड छैन + # Document properties dialog box document_properties.title=कागजात विशेषताहरू... document_properties_label=कागजात विशेषताहरू... @@ -89,6 +95,23 @@ document_properties_creator=सर्जक: document_properties_producer=PDF निर्माता: document_properties_version=PDF संस्करण document_properties_page_count=पृष्ठ गणना: +document_properties_page_size=पृष्ठ आकार: +document_properties_page_size_unit_inches=इन्च +document_properties_page_size_unit_millimeters=मि.मि. +document_properties_page_size_orientation_portrait=पोट्रेट +document_properties_page_size_orientation_landscape=परिदृश्य +document_properties_page_size_name_letter=अक्षर +document_properties_page_size_name_legal=कानूनी +# LOCALIZATION NOTE (document_properties_page_size_dimension_string): +# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement and orientation, of the (current) page. +# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): +# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement, name, and orientation, of the (current) page. +# LOCALIZATION NOTE (document_properties_linearized): The linearization status of +# the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized_yes=हो +document_properties_linearized_no=होइन document_properties_close=बन्द गर्नुहोस् print_progress_message=मुद्रणका लागि कागजात तयारी गरिदै… @@ -101,7 +124,6 @@ print_progress_close=रद्द गर्नुहोस् # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=टगल साइडबार -toggle_sidebar_notification.title=साइडबार टगल गर्नुहोस् (कागजातमा समावेश भएको कुराहरू रूपरेखा/attachments) toggle_sidebar_label=टगल साइडबार document_outline.title=कागजातको रूपरेखा देखाउनुहोस् (सबै वस्तुहरू विस्तार/पतन गर्न डबल-क्लिक गर्नुहोस्) document_outline_label=दस्तावेजको रूपरेखा @@ -112,6 +134,7 @@ thumbs_label=थम्बनेलहरू findbar.title=कागजातमा फेला पार्नुहोस् findbar_label=फेला पार्नुहोस् +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -129,8 +152,17 @@ find_next.title=यस वाक्यांशको पछिल्लो घ find_next_label=अर्को find_highlight=सबै हाइलाइट गर्ने find_match_case_label=केस जोडा मिलाउनुहोस् +find_entire_word_label=पुरा शब्दहरु find_reached_top=पृष्ठको शिर्षमा पुगीयो, तलबाट जारी गरिएको थियो find_reached_bottom=पृष्ठको अन्त्यमा पुगीयो, शिर्षबाट जारी गरिएको थियो +# LOCALIZATION NOTE (find_match_count): The supported plural forms are +# [one|two|few|many|other], with [other] as the default value. +# "{{current}}" and "{{total}}" will be replaced by a number representing the +# index of the currently active find result, respectively a number representing +# the total number of matches in the document. +# LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are +# [zero|one|two|few|many|other], with [other] as the default value. +# "{{limit}}" will be replaced by a numerical value. find_not_found=वाक्यांश फेला परेन # Error panel labels @@ -162,12 +194,14 @@ page_scale_actual=वास्तविक आकार page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=त्रुटि loading_error=यो PDF लोड गर्दा एउटा त्रुटि देखापर्‍यो। invalid_file_error=अवैध वा दुषित PDF फाइल। missing_file_error=हराईरहेको PDF फाइल। unexpected_response_error=अप्रत्याशित सर्भर प्रतिक्रिया। +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. + # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). diff --git a/cps/static/locale/nl/viewer.properties b/cps/static/locale/nl/viewer.properties index b37f1abf5..eb659b6f1 100644 --- a/cps/static/locale/nl/viewer.properties +++ b/cps/static/locale/nl/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Huidige weergave tools.title=Hulpmiddelen tools_label=Hulpmiddelen first_page.title=Naar eerste pagina gaan -first_page.label=Naar eerste pagina gaan first_page_label=Naar eerste pagina gaan last_page.title=Naar laatste pagina gaan -last_page.label=Naar laatste pagina gaan last_page_label=Naar laatste pagina gaan page_rotate_cw.title=Rechtsom draaien -page_rotate_cw.label=Rechtsom draaien page_rotate_cw_label=Rechtsom draaien page_rotate_ccw.title=Linksom draaien -page_rotate_ccw.label=Linksom draaien page_rotate_ccw_label=Linksom draaien cursor_text_select_tool.title=Tekstselectiehulpmiddel inschakelen @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Tekstselectiehulpmiddel cursor_hand_tool.title=Handhulpmiddel inschakelen cursor_hand_tool_label=Handhulpmiddel +scroll_page.title=Paginascrollen gebruiken +scroll_page_label=Paginascrollen scroll_vertical.title=Verticaal scrollen gebruiken scroll_vertical_label=Verticaal scrollen scroll_horizontal.title=Horizontaal scrollen gebruiken @@ -93,7 +91,7 @@ document_properties_mb={{size_mb}} MB ({{size_b}} bytes) document_properties_title=Titel: document_properties_author=Auteur: document_properties_subject=Onderwerp: -document_properties_keywords=Trefwoorden: +document_properties_keywords=Sleutelwoorden: document_properties_creation_date=Aanmaakdatum: document_properties_modification_date=Wijzigingsdatum: # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" @@ -137,19 +135,24 @@ print_progress_close=Annuleren # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Zijbalk in-/uitschakelen -toggle_sidebar_notification.title=Zijbalk in-/uitschakelen (document bevat overzicht/bijlagen) +toggle_sidebar_notification2.title=Zijbalk in-/uitschakelen (document bevat overzicht/bijlagen/lagen) toggle_sidebar_label=Zijbalk in-/uitschakelen document_outline.title=Documentoverzicht tonen (dubbelklik om alle items uit/samen te vouwen) document_outline_label=Documentoverzicht attachments.title=Bijlagen tonen attachments_label=Bijlagen +layers.title=Lagen tonen (dubbelklik om alle lagen naar de standaardstatus terug te zetten) +layers_label=Lagen thumbs.title=Miniaturen tonen thumbs_label=Miniaturen +current_outline_item.title=Huidig item in inhoudsopgave zoeken +current_outline_item_label=Huidig item in inhoudsopgave findbar.title=Zoeken in document findbar_label=Zoeken -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Pagina {{page}} +additional_layers=Aanvullende lagen +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Pagina {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=De volgende overeenkomst van de tekst zoeken find_next_label=Volgende find_highlight=Alles markeren find_match_case_label=Hoofdlettergevoelig +find_match_diacritics_label=Diakritische tekens gebruiken find_entire_word_label=Hele woorden find_reached_top=Bovenkant van document bereikt, doorgegaan vanaf onderkant find_reached_bottom=Onderkant van document bereikt, doorgegaan vanaf bovenkant @@ -222,7 +226,7 @@ page_scale_actual=Werkelijke grootte page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Fout +loading=Laden… loading_error=Er is een fout opgetreden bij het laden van de PDF. invalid_file_error=Ongeldig of beschadigd PDF-bestand. missing_file_error=PDF-bestand ontbreekt. @@ -245,3 +249,26 @@ password_cancel=Annuleren printing_not_supported=Waarschuwing: afdrukken wordt niet volledig ondersteund door deze browser. printing_not_ready=Waarschuwing: de PDF is niet volledig geladen voor afdrukken. web_fonts_disabled=Weblettertypen zijn uitgeschakeld: gebruik van ingebedde PDF-lettertypen is niet mogelijk. + +# Editor +editor_none.title=Bewerken van annotaties uitschakelen +editor_none_label=Bewerken uitschakelen +editor_free_text.title=FreeText-annotatie toevoegen +editor_free_text_label=FreeText-annotatie +editor_ink.title=Ink-annotatie toevoegen +editor_ink_label=Ink-annotatie + +freetext_default_content=Voer wat tekst in… + +free_text_default_content=Voer tekst in… + +# Editor Parameters +editor_free_text_font_color=Letterkleur +editor_free_text_font_size=Lettergrootte +editor_ink_line_color=Lijnkleur +editor_ink_line_thickness=Lijndikte + +# Editor aria +editor_free_text_aria_label=FreeText-bewerker +editor_ink_aria_label=Ink-bewerker +editor_ink_canvas_aria_label=Door gebruiker gemaakte afbeelding diff --git a/cps/static/locale/nn-NO/viewer.properties b/cps/static/locale/nn-NO/viewer.properties index c9bac1010..e93a7adb4 100644 --- a/cps/static/locale/nn-NO/viewer.properties +++ b/cps/static/locale/nn-NO/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Gjeldande vising tools.title=Verktøy tools_label=Verktøy first_page.title=Gå til første side -first_page.label=Gå til første side first_page_label=Gå til første side last_page.title=Gå til siste side -last_page.label=Gå til siste side last_page_label=Gå til siste side page_rotate_cw.title=Roter med klokka -page_rotate_cw.label=Roter med klokka page_rotate_cw_label=Roter med klokka page_rotate_ccw.title=Roter mot klokka -page_rotate_ccw.label=Roter mot klokka page_rotate_ccw_label=Roter mot klokka cursor_text_select_tool.title=Aktiver tekstmarkeringsverktøy @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Tekstmarkeringsverktøy cursor_hand_tool.title=Aktiver handverktøy cursor_hand_tool_label=Handverktøy +scroll_page.title=Bruk siderulling +scroll_page_label=Siderulling scroll_vertical.title=Bruk vertikal rulling scroll_vertical_label=Vertikal rulling scroll_horizontal.title=Bruk horisontal rulling @@ -137,19 +135,24 @@ print_progress_close=Avbryt # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Slå av/på sidestolpe -toggle_sidebar_notification.title=Vis/gøym sidestolpen (dokumentet inneheld oversikt/vedlegg) +toggle_sidebar_notification2.title=Vis/gøym sidestolpe (dokumentet inneheld oversikt/vedlegg/lag) toggle_sidebar_label=Slå av/på sidestolpe document_outline.title=Vis dokumentdisposisjonen (dobbelklikk for å utvide/gøyme alle elementa) document_outline_label=Dokumentdisposisjon attachments.title=Vis vedlegg attachments_label=Vedlegg +layers.title=Vis lag (dobbeltklikk for å tilbakestille alle lag til standardtilstand) +layers_label=Lag thumbs.title=Vis miniatyrbilde thumbs_label=Miniatyrbilde +current_outline_item.title=Finn gjeldande disposisjonselement +current_outline_item_label=Gjeldande disposisjonselement findbar.title=Finn i dokumentet findbar_label=Finn -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Side {{page}} +additional_layers=Ytterlegare lag +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Side {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Finn neste førekomst av frasen find_next_label=Neste find_highlight=Uthev alle find_match_case_label=Skil store/små bokstavar +find_match_diacritics_label=Samsvar diakritiske teikn find_entire_word_label=Heile ord find_reached_top=Nådde toppen av dokumentet, fortset frå botnen find_reached_bottom=Nådde botnen av dokumentet, fortset frå toppen @@ -222,7 +226,7 @@ page_scale_actual=Verkeleg storleik page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Feil +loading=Lastar… loading_error=Ein feil oppstod ved lasting av PDF. invalid_file_error=Ugyldig eller korrupt PDF-fil. missing_file_error=Manglande PDF-fil. @@ -245,3 +249,33 @@ password_cancel=Avbryt printing_not_supported=Åtvaring: Utskrift er ikkje fullstendig støtta av denne nettlesaren. printing_not_ready=Åtvaring: PDF ikkje fullstendig innlasta for utskrift. web_fonts_disabled=Web-skrifter er slått av: Kan ikkje bruke innbundne PDF-skrifter. + +# Editor +editor_none.title=Slå av kommentarredigering +editor_none_label=Slå av redigering +editor_free_text.title=Legg til fritekstkommentar +editor_free_text_label=Fritekstkommentar +editor_ink.title=Legg til handskriven kommentar +editor_ink_label=Handskriven kommentar + +freetext_default_content=Skriv inn litt tekst… + +free_text_default_content=Skriv inn tekst… + +# Editor Parameters +editor_free_text_font_color=Skriftfarge +editor_free_text_font_size=Skriftstorleik +editor_ink_line_color=Linjefarge +editor_ink_line_thickness=Linjetjukkleik + +# Editor Parameters +editor_free_text_color=Farge +editor_free_text_size=Storleik +editor_ink_color=Farge +editor_ink_thickness=Tjukkleik +editor_ink_opacity=Ugjennomskinleg + +# Editor aria +editor_free_text_aria_label=FreeText-redigerar +editor_ink_aria_label=Ink-redigerar +editor_ink_canvas_aria_label=Brukarskapt bilde diff --git a/cps/static/locale/oc/viewer.properties b/cps/static/locale/oc/viewer.properties index b1c6a3a0c..c3356a4c4 100644 --- a/cps/static/locale/oc/viewer.properties +++ b/cps/static/locale/oc/viewer.properties @@ -26,7 +26,7 @@ of_pages=sus {{pagesCount}} # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" # will be replaced by a number representing the currently visible page, # respectively a number representing the total number of pages in the document. -page_of_pages=({{pageNumber}} sus {{pagesCount}}) +page_of_pages=({{pageNumber}} de {{pagesCount}}) zoom_out.title=Zoom arrièr zoom_out_label=Zoom arrièr @@ -48,16 +48,12 @@ bookmark_label=Afichatge actual tools.title=Aisinas tools_label=Aisinas first_page.title=Anar a la primièra pagina -first_page.label=Anar a la primièra pagina first_page_label=Anar a la primièra pagina last_page.title=Anar a la darrièra pagina -last_page.label=Anar a la darrièra pagina last_page_label=Anar a la darrièra pagina page_rotate_cw.title=Rotacion orària -page_rotate_cw.label=Rotacion orària page_rotate_cw_label=Rotacion orària page_rotate_ccw.title=Rotacion antiorària -page_rotate_ccw.label=Rotacion antiorària page_rotate_ccw_label=Rotacion antiorària cursor_text_select_tool.title=Activar l'aisina de seleccion de tèxte @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Aisina de seleccion de tèxte cursor_hand_tool.title=Activar l’aisina man cursor_hand_tool_label=Aisina man +scroll_page.title=Activar lo desfilament per pagina +scroll_page_label=Desfilament per pagina scroll_vertical.title=Utilizar lo desfilament vertical scroll_vertical_label=Desfilament vertical scroll_horizontal.title=Utilizar lo desfilament orizontal @@ -106,7 +104,7 @@ document_properties_page_count=Nombre de paginas : document_properties_page_size=Talha de la pagina : document_properties_page_size_unit_inches=in document_properties_page_size_unit_millimeters=mm -document_properties_page_size_orientation_portrait=retrait +document_properties_page_size_orientation_portrait=retrach document_properties_page_size_orientation_landscape=païsatge document_properties_page_size_name_a3=A3 document_properties_page_size_name_a4=A4 @@ -137,19 +135,24 @@ print_progress_close=Anullar # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Afichar/amagar lo panèl lateral -toggle_sidebar_notification.title=Afichar/amagar lo panèl lateral (lo document conten esquèmas/pèças juntas) +toggle_sidebar_notification2.title=Afichar/amagar lo panèl lateral (lo document conten esquèmas/pèças juntas/calques) toggle_sidebar_label=Afichar/amagar lo panèl lateral document_outline.title=Mostrar los esquèmas del document (dobleclicar per espandre/reduire totes los elements) document_outline_label=Marcapaginas del document attachments.title=Visualizar las pèças juntas attachments_label=Pèças juntas +layers.title=Afichar los calques (doble-clicar per reïnicializar totes los calques a l’estat per defaut) +layers_label=Calques thumbs.title=Afichar las vinhetas thumbs_label=Vinhetas +current_outline_item.title=Trobar l’element de plan actual +current_outline_item_label=Element de plan actual findbar.title=Cercar dins lo document findbar_label=Recercar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Pagina {{page}} +additional_layers=Calques suplementaris +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Pagina {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Tròba l'ocurréncia venenta de la frasa find_next_label=Seguent find_highlight=Suslinhar tot find_match_case_label=Respectar la cassa +find_match_diacritics_label=Respectar los diacritics find_entire_word_label=Mots entièrs find_reached_top=Naut de la pagina atenh, perseguida del bas find_reached_bottom=Bas de la pagina atench, perseguida al començament @@ -176,21 +180,21 @@ find_reached_bottom=Bas de la pagina atench, perseguida al començament # index of the currently active find result, respectively a number representing # the total number of matches in the document. find_match_count={[ plural(total) ]} -find_match_count[one]=Occuréncia {{current}} sus {{total}} -find_match_count[two]=Occuréncia {{current}} sus {{total}} -find_match_count[few]=Occuréncia {{current}} sus {{total}} -find_match_count[many]=Occuréncia {{current}} sus {{total}} -find_match_count[other]=Occuréncia {{current}} sus {{total}} +find_match_count[one]=Ocuréncia {{current}} sus {{total}} +find_match_count[two]=Ocuréncia {{current}} sus {{total}} +find_match_count[few]=Ocuréncia {{current}} sus {{total}} +find_match_count[many]=Ocuréncia {{current}} sus {{total}} +find_match_count[other]=Ocuréncia {{current}} sus {{total}} # LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are # [zero|one|two|few|many|other], with [other] as the default value. # "{{limit}}" will be replaced by a numerical value. find_match_count_limit={[ plural(limit) ]} -find_match_count_limit[zero]=Mai de {{limit}} occuréncias -find_match_count_limit[one]=Mai de {{limit}} occuréncia -find_match_count_limit[two]=Mai de {{limit}} occuréncias -find_match_count_limit[few]=Mai de {{limit}} occuréncias -find_match_count_limit[many]=Mai de {{limit}} occuréncias -find_match_count_limit[other]=Mai de {{limit}} occuréncias +find_match_count_limit[zero]=Mai de {{limit}} ocuréncias +find_match_count_limit[one]=Mai de {{limit}} ocuréncia +find_match_count_limit[two]=Mai de {{limit}} ocuréncias +find_match_count_limit[few]=Mai de {{limit}} ocuréncias +find_match_count_limit[many]=Mai de {{limit}} ocuréncias +find_match_count_limit[other]=Mai de {{limit}} ocuréncias find_not_found=Frasa pas trobada # Error panel labels @@ -210,7 +214,7 @@ error_stack=Pila : {{stack}} error_file=Fichièr : {{file}} # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number error_line=Linha : {{line}} -rendering_error=Una error s'es produita pendent l'afichatge de la pagina. +rendering_error=Una error s'es producha pendent l'afichatge de la pagina. # Predefined zoom values page_scale_width=Largor plena @@ -222,8 +226,8 @@ page_scale_actual=Talha vertadièra page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Error -loading_error=Una error s'es produita pendent lo cargament del fichièr PDF. +loading=Cargament… +loading_error=Una error s'es producha pendent lo cargament del fichièr PDF. invalid_file_error=Fichièr PDF invalid o corromput. missing_file_error=Fichièr PDF mancant. unexpected_response_error=Responsa de servidor imprevista. @@ -244,4 +248,30 @@ password_cancel=Anullar printing_not_supported=Atencion : l'impression es pas completament gerida per aqueste navegador. printing_not_ready=Atencion : lo PDF es pas entièrament cargat per lo poder imprimir. -web_fonts_disabled=Las poliças web son desactivadas : impossible d'utilizar las poliças integradas al PDF. +web_fonts_disabled=Las polissas web son desactivadas : impossible d'utilizar las polissas integradas al PDF. + +# Editor +editor_none.title=Desactivar l’edicion d’anotacions +editor_none_label=Desactivar l’edicion +editor_free_text.title=Apondre de tèxte +editor_free_text_label=Tèxte +editor_ink.title=Dessenhar +editor_ink_label=Dessenh + +freetext_default_content=Picatz de tèxte… + +free_text_default_content=Picatz de tèxt… + +# Editor Parameters +editor_free_text_font_color=Color de polissa +editor_free_text_font_size=Talha de polissa +editor_ink_line_color=Color de linha +editor_ink_line_thickness=Espessor de la linha + +# Editor Parameters +editor_free_text_color=Color +editor_free_text_size=Talha +editor_ink_color=Color +editor_ink_opacity=Opacitat + +# Editor aria diff --git a/cps/static/locale/pa-IN/viewer.properties b/cps/static/locale/pa-IN/viewer.properties index 0ab56319e..153bf5c4f 100644 --- a/cps/static/locale/pa-IN/viewer.properties +++ b/cps/static/locale/pa-IN/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=ਮੌਜੂਦਾ ਝਲਕ tools.title=ਟੂਲ tools_label=ਟੂਲ first_page.title=ਪਹਿਲੇ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ -first_page.label=ਪਹਿਲੇ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ first_page_label=ਪਹਿਲੇ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ last_page.title=ਆਖਰੀ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ -last_page.label=ਆਖਰੀ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ last_page_label=ਆਖਰੀ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ page_rotate_cw.title=ਸੱਜੇ ਦਾਅ ਘੁੰਮਾਓ -page_rotate_cw.label=ਸੱਜੇ ਦਾਅ ਘੁੰਮਾਉ page_rotate_cw_label=ਸੱਜੇ ਦਾਅ ਘੁੰਮਾਓ page_rotate_ccw.title=ਖੱਬੇ ਦਾਅ ਘੁੰਮਾਓ -page_rotate_ccw.label=ਖੱਬੇ ਦਾਅ ਘੁੰਮਾਉ page_rotate_ccw_label=ਖੱਬੇ ਦਾਅ ਘੁੰਮਾਓ cursor_text_select_tool.title=ਲਿਖਤ ਚੋਣ ਟੂਲ ਸਮਰੱਥ ਕਰੋ @@ -65,6 +61,8 @@ cursor_text_select_tool_label=ਲਿਖਤ ਚੋਣ ਟੂਲ cursor_hand_tool.title=ਹੱਥ ਟੂਲ ਸਮਰੱਥ ਕਰੋ cursor_hand_tool_label=ਹੱਥ ਟੂਲ +scroll_page.title=ਸਫ਼ਾ ਖਿਸਕਾਉਣ ਨੂੰ ਵਰਤੋਂ +scroll_page_label=ਸਫ਼ਾ ਖਿਸਕਾਉਣਾ scroll_vertical.title=ਖੜ੍ਹਵੇਂ ਸਕਰਾਉਣ ਨੂੰ ਵਰਤੋਂ scroll_vertical_label=ਖੜ੍ਹਵਾਂ ਸਰਕਾਉਣਾ scroll_horizontal.title=ਲੇਟਵੇਂ ਸਰਕਾਉਣ ਨੂੰ ਵਰਤੋਂ @@ -74,8 +72,10 @@ scroll_wrapped_label=ਸਮੇਟਿਆ ਸਰਕਾਉਣਾ spread_none.title=ਸਫ਼ਾ ਫੈਲਾਅ ਵਿੱਚ ਸ਼ਾਮਲ ਨਾ ਹੋਵੋ spread_none_label=ਕੋਈ ਫੈਲਾਅ ਨਹੀਂ -spread_odd.title=ਅਜੀਬ-ਨੰਬਰ ਵਾਲੇ ਪੰਨਿਆਂ ਨਾਲ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੇ ਪੰਨੇ ਸਪਰਸ਼ਾਂ ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਵੋ -spread_even.title=ਜਿਸਤ ਨੰਬਰ ਵਾਲੇ ਸਫ਼ਿਆਂ ਨਾਲ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੇ ਸਫਿਆਂ ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਵੋ +spread_odd.title=ਟਾਂਕ ਅੰਕ ਵਾਲੇ ਸਫ਼ਿਆਂ ਨਾਲ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੇ ਸਫਿਆਂ ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਵੋ +spread_odd_label=ਟਾਂਕ ਫੈਲਾਅ +spread_even.title=ਜਿਸਤ ਅੰਕ ਵਾਲੇ ਸਫ਼ਿਆਂ ਨਾਲ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੇ ਸਫਿਆਂ ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਵੋ +spread_even_label=ਜਿਸਤ ਫੈਲਾਅ # Document properties dialog box document_properties.title=…ਦਸਤਾਵੇਜ਼ ਦੀ ਵਿਸ਼ੇਸ਼ਤਾ @@ -135,19 +135,24 @@ print_progress_close=ਰੱਦ ਕਰੋ # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=ਬਾਹੀ ਬਦਲੋ -toggle_sidebar_notification.title=ਬਾਹੀ ਨੂੰ ਬਦਲੋ (ਦਸਤਾਵੇਜ਼ ਖਾਕਾ/ਅਟੈਚਮੈਂਟਾਂ ਰੱਖਦਾ ਹੈ) +toggle_sidebar_notification2.title=ਬਾਹੀ ਨੂੰ ਬਦਲੋ (ਦਸਤਾਵੇਜ਼ ਖਾਕਾ/ਅਟੈਚਮੈਂਟ/ਪਰਤਾਂ ਰੱਖਦਾ ਹੈ) toggle_sidebar_label=ਬਾਹੀ ਬਦਲੋ document_outline.title=ਦਸਤਾਵੇਜ਼ ਖਾਕਾ ਦਿਖਾਓ (ਸਾਰੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਫੈਲਾਉਣ/ਸਮੇਟਣ ਲਈ ਦੋ ਵਾਰ ਕਲਿੱਕ ਕਰੋ) document_outline_label=ਦਸਤਾਵੇਜ਼ ਖਾਕਾ attachments.title=ਅਟੈਚਮੈਂਟ ਵੇਖਾਓ attachments_label=ਅਟੈਚਮੈਂਟਾਂ +layers.title=ਪਰਤਾਂ ਵੇਖਾਓ (ਸਾਰੀਆਂ ਪਰਤਾਂ ਨੂੰ ਮੂਲ ਹਾਲਤ ਉੱਤੇ ਮੁੜ-ਸੈੱਟ ਕਰਨ ਲਈ ਦੋ ਵਾਰ ਕਲਿੱਕ ਕਰੋ) +layers_label=ਪਰਤਾਂ thumbs.title=ਥੰਮਨੇਲ ਨੂੰ ਵੇਖਾਓ thumbs_label=ਥੰਮਨੇਲ +current_outline_item.title=ਮੌੌਜੂਦਾ ਖਾਕਾ ਚੀਜ਼ ਲੱਭੋ +current_outline_item_label=ਮੌਜੂਦਾ ਖਾਕਾ ਚੀਜ਼ findbar.title=ਦਸਤਾਵੇਜ਼ ਵਿੱਚ ਲੱਭੋ findbar_label=ਲੱਭੋ -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=ਸਫ਼ਾ {{page}} +additional_layers=ਵਾਧੂ ਪਰਤਾਂ +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=ਸਫ਼ਾ {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -165,6 +170,7 @@ find_next.title=ਵਾਕ ਦੀ ਅਗਲੀ ਮੌਜੂਦਗੀ ਲੱਭੋ find_next_label=ਅੱਗੇ find_highlight=ਸਭ ਉਭਾਰੋ find_match_case_label=ਅੱਖਰ ਆਕਾਰ ਨੂੰ ਮਿਲਾਉ +find_match_diacritics_label=ਭੇਦਸੂਚਕ ਮੇਲ find_entire_word_label=ਪੂਰੇ ਸ਼ਬਦ find_reached_top=ਦਸਤਾਵੇਜ਼ ਦੇ ਉੱਤੇ ਆ ਗਏ ਹਾਂ, ਥੱਲੇ ਤੋਂ ਜਾਰੀ ਰੱਖਿਆ ਹੈ find_reached_bottom=ਦਸਤਾਵੇਜ਼ ਦੇ ਅੰਤ ਉੱਤੇ ਆ ਗਏ ਹਾਂ, ਉੱਤੇ ਤੋਂ ਜਾਰੀ ਰੱਖਿਆ ਹੈ @@ -220,7 +226,7 @@ page_scale_actual=ਆਟੋਮੈਟਿਕ ਆਕਾਰ page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=ਗਲਤੀ +loading=…ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ loading_error=PDF ਲੋਡ ਕਰਨ ਦੇ ਦੌਰਾਨ ਗਲਤੀ ਆਈ ਹੈ। invalid_file_error=ਗਲਤ ਜਾਂ ਨਿਕਾਰਾ PDF ਫਾਈਲ ਹੈ। missing_file_error=ਨਾ-ਮੌਜੂਦ PDF ਫਾਈਲ। @@ -243,3 +249,33 @@ password_cancel=ਰੱਦ ਕਰੋ printing_not_supported=ਸਾਵਧਾਨ: ਇਹ ਬਰਾਊਜ਼ਰ ਪਰਿੰਟ ਕਰਨ ਲਈ ਪੂਰੀ ਤਰ੍ਹਾਂ ਸਹਾਇਕ ਨਹੀਂ ਹੈ। printing_not_ready=ਸਾਵਧਾਨ: PDF ਨੂੰ ਪਰਿੰਟ ਕਰਨ ਲਈ ਪੂਰੀ ਤਰ੍ਹਾਂ ਲੋਡ ਨਹੀਂ ਹੈ। web_fonts_disabled=ਵੈਬ ਫੋਂਟ ਬੰਦ ਹਨ: ਇੰਬੈਡ PDF ਫੋਂਟ ਨੂੰ ਵਰਤਣ ਲਈ ਅਸਮਰੱਥ ਹੈ। + +# Editor +editor_none.title=ਟਿੱਪਣੀ ਸੋਧਣਾ ਅਸਮਰੱਥ +editor_none_label=ਸੋਧਣਾ ਅਸਮਰੱਥ +editor_free_text.title=FreeText ਟਿੱਪਣੀ ਜੋੜੋ +editor_free_text_label=FreeText ਟਿੱਪਣੀ +editor_ink.title=ਸਿਆਹੀ ਟਿੱਪਣੀ ਜੋੜੋ +editor_ink_label=ਸਿਆਹੀ ਟਿੱਪਣੀ + +freetext_default_content=…ਕੁਝ ਲਿਖੋ + +free_text_default_content=…ਲਿਖੋ + +# Editor Parameters +editor_free_text_font_color=ਫੌਂਟ ਦਾ ਰੰਗ +editor_free_text_font_size=ਫ਼ੋਂਟ ਦਾ ਆਕਾਰ +editor_ink_line_color=ਲਾਈਨ ਦਾ ਰੰਗ +editor_ink_line_thickness=ਲਾਈਨ ਦੀ ਮੋਟਾਈ + +# Editor Parameters +editor_free_text_color=ਰੰਗ +editor_free_text_size=ਆਕਾਰ +editor_ink_color=ਰੰਗ +editor_ink_thickness=ਮੋਟਾਈ +editor_ink_opacity=ਧੁੰਦਲਾਪਨ + +# Editor aria +editor_free_text_aria_label=FreeText ਸੰਪਾਦਕ +editor_ink_aria_label=ਸਿਆਹੀ ਸੰਪਾਦਕ +editor_ink_canvas_aria_label=ਵਰਤੋਂਕਾਰ ਵਲੋਂ ਬਣਾਇਆ ਚਿੱਤਰ diff --git a/cps/static/locale/pl/viewer.properties b/cps/static/locale/pl/viewer.properties index cf170c8d2..9df1996d7 100644 --- a/cps/static/locale/pl/viewer.properties +++ b/cps/static/locale/pl/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Bieżąca pozycja tools.title=Narzędzia tools_label=Narzędzia first_page.title=Przejdź do pierwszej strony -first_page.label=Przejdź do pierwszej strony first_page_label=Przejdź do pierwszej strony last_page.title=Przejdź do ostatniej strony -last_page.label=Przejdź do ostatniej strony last_page_label=Przejdź do ostatniej strony page_rotate_cw.title=Obróć zgodnie z ruchem wskazówek zegara -page_rotate_cw.label=Obróć zgodnie z ruchem wskazówek zegara page_rotate_cw_label=Obróć zgodnie z ruchem wskazówek zegara page_rotate_ccw.title=Obróć przeciwnie do ruchu wskazówek zegara -page_rotate_ccw.label=Obróć przeciwnie do ruchu wskazówek zegara page_rotate_ccw_label=Obróć przeciwnie do ruchu wskazówek zegara cursor_text_select_tool.title=Włącz narzędzie zaznaczania tekstu @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Narzędzie zaznaczania tekstu cursor_hand_tool.title=Włącz narzędzie rączka cursor_hand_tool_label=Narzędzie rączka +scroll_page.title=Przewijaj strony +scroll_page_label=Przewijanie stron scroll_vertical.title=Przewijaj dokument w pionie scroll_vertical_label=Przewijanie pionowe scroll_horizontal.title=Przewijaj dokument w poziomie @@ -137,19 +135,24 @@ print_progress_close=Anuluj # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Przełącz panel boczny -toggle_sidebar_notification.title=Przełącz panel boczny (dokument zawiera konspekt/załączniki) +toggle_sidebar_notification2.title=Przełącz panel boczny (dokument zawiera konspekt/załączniki/warstwy) toggle_sidebar_label=Przełącz panel boczny document_outline.title=Konspekt dokumentu (podwójne kliknięcie rozwija lub zwija wszystkie pozycje) document_outline_label=Konspekt dokumentu attachments.title=Załączniki attachments_label=Załączniki +layers.title=Warstwy (podwójne kliknięcie przywraca wszystkie warstwy do stanu domyślnego) +layers_label=Warstwy thumbs.title=Miniatury thumbs_label=Miniatury +current_outline_item.title=Znajdź bieżący element konspektu +current_outline_item_label=Bieżący element konspektu findbar.title=Znajdź w dokumencie findbar_label=Znajdź -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas={{page}}. strona +additional_layers=Dodatkowe warstwy +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark={{page}}. strona # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Znajdź następne wystąpienie tekstu find_next_label=Następne find_highlight=Wyróżnianie wszystkich find_match_case_label=Rozróżnianie wielkości liter +find_match_diacritics_label=Rozróżnianie liter diakrytyzowanych find_entire_word_label=Całe słowa find_reached_top=Początek dokumentu. Wyszukiwanie od końca. find_reached_bottom=Koniec dokumentu. Wyszukiwanie od początku. @@ -222,7 +226,7 @@ page_scale_actual=Rozmiar oryginalny page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Błąd +loading=Wczytywanie… loading_error=Podczas wczytywania dokumentu PDF wystąpił błąd. invalid_file_error=Nieprawidłowy lub uszkodzony plik PDF. missing_file_error=Brak pliku PDF. @@ -236,7 +240,7 @@ annotation_date_string={{date}}, {{time}} # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). # Some common types are e.g.: "Check", "Text", "Comment", "Note" -text_annotation_type.alt=[Adnotacja: {{type}}] +text_annotation_type.alt=[Przypis: {{type}}] password_label=Wprowadź hasło, aby otworzyć ten dokument PDF. password_invalid=Nieprawidłowe hasło. Proszę spróbować ponownie. password_ok=OK @@ -245,3 +249,33 @@ password_cancel=Anuluj printing_not_supported=Ostrzeżenie: drukowanie nie jest w pełni obsługiwane przez tę przeglądarkę. printing_not_ready=Ostrzeżenie: dokument PDF nie jest całkowicie wczytany, więc nie można go wydrukować. web_fonts_disabled=Czcionki sieciowe są wyłączone: nie można użyć osadzonych czcionek PDF. + +# Editor +editor_none.title=Wyłącz edycję przypisów +editor_none_label=Wyłącz edycję +editor_free_text.title=Dodaj przypis tekstowy +editor_free_text_label=Przypis tekstowy +editor_ink.title=Dodaj zakreślenie +editor_ink_label=Zakreślenie + +freetext_default_content=Wpisz tekst… + +free_text_default_content=Wpisz tekst… + +# Editor Parameters +editor_free_text_font_color=Kolor czcionki +editor_free_text_font_size=Rozmiar czcionki +editor_ink_line_color=Kolor zakreślenia +editor_ink_line_thickness=Grubość zakreślenia + +# Editor Parameters +editor_free_text_color=Kolor +editor_free_text_size=Rozmiar +editor_ink_color=Kolor +editor_ink_thickness=Grubość +editor_ink_opacity=Nieprzezroczystość + +# Editor aria +editor_free_text_aria_label=Edytor tekstu +editor_ink_aria_label=Edytor zakreślenia +editor_ink_canvas_aria_label=Obraz utworzony przez użytkownika diff --git a/cps/static/locale/pt-BR/viewer.properties b/cps/static/locale/pt-BR/viewer.properties index ca592b8f1..7b4727beb 100644 --- a/cps/static/locale/pt-BR/viewer.properties +++ b/cps/static/locale/pt-BR/viewer.properties @@ -33,14 +33,14 @@ zoom_out_label=Reduzir zoom_in.title=Ampliar zoom_in_label=Ampliar zoom.title=Zoom -presentation_mode.title=Alternar para o modo de apresentação +presentation_mode.title=Mudar para o modo de apresentação presentation_mode_label=Modo de apresentação open_file.title=Abrir arquivo open_file_label=Abrir print.title=Imprimir print_label=Imprimir -download.title=Download -download_label=Download +download.title=Baixar +download_label=Baixar bookmark.title=Visão atual (copiar ou abrir em nova janela) bookmark_label=Visualização atual @@ -48,29 +48,27 @@ bookmark_label=Visualização atual tools.title=Ferramentas tools_label=Ferramentas first_page.title=Ir para a primeira página -first_page.label=Ir para a primeira página first_page_label=Ir para a primeira página last_page.title=Ir para a última página -last_page.label=Ir para a última página last_page_label=Ir para a última página page_rotate_cw.title=Girar no sentido horário -page_rotate_cw.label=Girar no sentido horário page_rotate_cw_label=Girar no sentido horário page_rotate_ccw.title=Girar no sentido anti-horário -page_rotate_ccw.label=Girar no sentido anti-horário page_rotate_ccw_label=Girar no sentido anti-horário cursor_text_select_tool.title=Ativar a ferramenta de seleção de texto cursor_text_select_tool_label=Ferramenta de seleção de texto -cursor_hand_tool.title=Ativar ferramenta de mão -cursor_hand_tool_label=Ferramenta de mão +cursor_hand_tool.title=Ativar ferramenta de deslocamento +cursor_hand_tool_label=Ferramenta de deslocamento -scroll_vertical.title=Usar rolagem vertical -scroll_vertical_label=Rolagem vertical -scroll_horizontal.title=Usar rolagem horizontal -scroll_horizontal_label=Rolagem horizontal -scroll_wrapped.title=Usar rolagem contida -scroll_wrapped_label=Rolagem contida +scroll_page.title=Usar rolagem de página +scroll_page_label=Rolagem de página +scroll_vertical.title=Usar deslocamento vertical +scroll_vertical_label=Deslocamento vertical +scroll_horizontal.title=Usar deslocamento horizontal +scroll_horizontal_label=Deslocamento horizontal +scroll_wrapped.title=Usar deslocamento contido +scroll_wrapped_label=Deslocamento contido spread_none.title=Não reagrupar páginas spread_none_label=Não estender @@ -122,7 +120,7 @@ document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) # LOCALIZATION NOTE (document_properties_linearized): The linearization status of # the document; usually called "Fast Web View" in English locales of Adobe software. -document_properties_linearized=Visualização rápida da Web: +document_properties_linearized=Exibição web rápida: document_properties_linearized_yes=Sim document_properties_linearized_no=Não document_properties_close=Fechar @@ -136,20 +134,25 @@ print_progress_close=Cancelar # Tooltips and alt text for side panel toolbar buttons # (the _label strings are alt text for the buttons, the .title strings are # tooltips) -toggle_sidebar.title=Alternar painel -toggle_sidebar_notification.title=Alternar o painel (documento contém marcadores e anexos) -toggle_sidebar_label=Alternar painel -document_outline.title=Mostrar a estrutura do documento (duplo-clique para expandir/recolher todos os ítens) +toggle_sidebar.title=Exibir/ocultar painel lateral +toggle_sidebar_notification2.title=Exibir/ocultar painel (documento contém estrutura/anexos/camadas) +toggle_sidebar_label=Exibir/ocultar painel +document_outline.title=Mostrar a estrutura do documento (dê um duplo-clique para expandir/recolher todos os itens) document_outline_label=Estrutura do documento attachments.title=Mostrar anexos attachments_label=Anexos +layers.title=Exibir camadas (duplo-clique para redefinir todas as camadas ao estado predefinido) +layers_label=Camadas thumbs.title=Mostrar miniaturas thumbs_label=Miniaturas +current_outline_item.title=Encontrar item atual da estrutura +current_outline_item_label=Item atual da estrutura findbar.title=Procurar no documento findbar_label=Procurar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Página {{page}} +additional_layers=Camadas adicionais +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Página {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Procurar a próxima ocorrência da frase find_next_label=Próxima find_highlight=Destacar tudo find_match_case_label=Diferenciar maiúsculas/minúsculas +find_match_diacritics_label=Considerar acentuação find_entire_word_label=Palavras completas find_reached_top=Início do documento alcançado, continuando do fim find_reached_bottom=Fim do documento alcançado, continuando do início @@ -222,7 +226,7 @@ page_scale_actual=Tamanho real page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Erro +loading=Carregando… loading_error=Ocorreu um erro ao carregar o PDF. invalid_file_error=Arquivo PDF corrompido ou inválido. missing_file_error=Arquivo PDF ausente. @@ -245,3 +249,33 @@ password_cancel=Cancelar printing_not_supported=Aviso: a impressão não é totalmente suportada neste navegador. printing_not_ready=Aviso: o PDF não está totalmente carregado para impressão. web_fonts_disabled=As fontes web estão desativadas: não foi possível usar fontes incorporadas do PDF. + +# Editor +editor_none.title=Desativar edição de anotações +editor_none_label=Desativar edição +editor_free_text.title=Adicionar anotação FreeText +editor_free_text_label=Anotação FreeText +editor_ink.title=Adicionar anotação à tinta +editor_ink_label=Anotação à tinta + +freetext_default_content=Digite algum texto… + +free_text_default_content=Digite o texto… + +# Editor Parameters +editor_free_text_font_color=Cor da fonte +editor_free_text_font_size=Tamanho da fonte +editor_ink_line_color=Cor da linha +editor_ink_line_thickness=Espessura da linha + +# Editor Parameters +editor_free_text_color=Cor +editor_free_text_size=Tamanho +editor_ink_color=Cor +editor_ink_thickness=Espessura +editor_ink_opacity=Opacidade + +# Editor aria +editor_free_text_aria_label=Editor FreeText +editor_ink_aria_label=Editor de tinta +editor_ink_canvas_aria_label=Imagem criada pelo usuário diff --git a/cps/static/locale/pt-PT/viewer.properties b/cps/static/locale/pt-PT/viewer.properties index 57f481416..9fcfdf394 100644 --- a/cps/static/locale/pt-PT/viewer.properties +++ b/cps/static/locale/pt-PT/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Visão atual tools.title=Ferramentas tools_label=Ferramentas first_page.title=Ir para a primeira página -first_page.label=Ir para a primeira página first_page_label=Ir para a primeira página last_page.title=Ir para a última página -last_page.label=Ir para a última página last_page_label=Ir para a última página page_rotate_cw.title=Rodar à direita -page_rotate_cw.label=Rodar à direita page_rotate_cw_label=Rodar à direita page_rotate_ccw.title=Rodar à esquerda -page_rotate_ccw.label=Rodar à esquerda page_rotate_ccw_label=Rodar à esquerda cursor_text_select_tool.title=Ativar ferramenta de seleção de texto @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Ferramenta de seleção de texto cursor_hand_tool.title=Ativar ferramenta de mão cursor_hand_tool_label=Ferramenta de mão +scroll_page.title=Utilizar deslocamento da página +scroll_page_label=Deslocamento da página scroll_vertical.title=Utilizar deslocação vertical scroll_vertical_label=Deslocação vertical scroll_horizontal.title=Utilizar deslocação horizontal @@ -137,19 +135,24 @@ print_progress_close=Cancelar # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Alternar barra lateral -toggle_sidebar_notification.title=Alternar barra lateral (documento contém contorno/anexos) +toggle_sidebar_notification2.title=Alternar barra lateral (o documento contém contornos/anexos/camadas) toggle_sidebar_label=Alternar barra lateral document_outline.title=Mostrar esquema do documento (duplo clique para expandir/colapsar todos os itens) document_outline_label=Esquema do documento attachments.title=Mostrar anexos attachments_label=Anexos +layers.title=Mostrar camadas (clique duas vezes para repor todas as camadas para o estado predefinido) +layers_label=Camadas thumbs.title=Mostrar miniaturas thumbs_label=Miniaturas +current_outline_item.title=Encontrar o item atualmente destacado +current_outline_item_label=Item atualmente destacado findbar.title=Localizar em documento findbar_label=Localizar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Página {{page}} +additional_layers=Camadas adicionais +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Página {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Localizar ocorrência seguinte da frase find_next_label=Seguinte find_highlight=Destacar tudo find_match_case_label=Correspondência +find_match_diacritics_label=Corresponder diacríticos find_entire_word_label=Palavras completas find_reached_top=Topo do documento atingido, a continuar a partir do fundo find_reached_bottom=Fim do documento atingido, a continuar a partir do topo @@ -222,7 +226,7 @@ page_scale_actual=Tamanho real page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Erro +loading=A carregar… loading_error=Ocorreu um erro ao carregar o PDF. invalid_file_error=Ficheiro PDF inválido ou danificado. missing_file_error=Ficheiro PDF inexistente. @@ -245,3 +249,33 @@ password_cancel=Cancelar printing_not_supported=Aviso: a impressão não é totalmente suportada por este navegador. printing_not_ready=Aviso: o PDF ainda não está totalmente carregado. web_fonts_disabled=Os tipos de letra web estão desativados: não é possível utilizar os tipos de letra PDF embutidos. + +# Editor +editor_none.title=Desativar Edição de Anotações +editor_none_label=Desativar Edição +editor_free_text.title=Adicionar Anotação FreeText +editor_free_text_label=Anotação FreeText +editor_ink.title=Adicionar Anotação a Tinta +editor_ink_label=Anotação a Tinta + +freetext_default_content=Introduza algum texto… + +free_text_default_content=Introduza o texto… + +# Editor Parameters +editor_free_text_font_color=Cor da Fonte +editor_free_text_font_size=Tamanho da Fonte +editor_ink_line_color=Cor da Linha +editor_ink_line_thickness=Espessura da Linha + +# Editor Parameters +editor_free_text_color=Cor +editor_free_text_size=Tamanho +editor_ink_color=Cor +editor_ink_thickness=Espessura +editor_ink_opacity=Opacidade + +# Editor aria +editor_free_text_aria_label=Editor de texto livre +editor_ink_aria_label=Editor de tinta +editor_ink_canvas_aria_label=Imagem criada pelo utilizador diff --git a/cps/static/locale/rm/viewer.properties b/cps/static/locale/rm/viewer.properties index 8c8cab892..5f1954a28 100644 --- a/cps/static/locale/rm/viewer.properties +++ b/cps/static/locale/rm/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vista actuala tools.title=Utensils tools_label=Utensils first_page.title=Siglir a l'emprima pagina -first_page.label=Siglir a l'emprima pagina first_page_label=Siglir a l'emprima pagina last_page.title=Siglir a la davosa pagina -last_page.label=Siglir a la davosa pagina last_page_label=Siglir a la davosa pagina page_rotate_cw.title=Rotar en direcziun da l'ura -page_rotate_cw.label=Rotar en direcziun da l'ura page_rotate_cw_label=Rotar en direcziun da l'ura page_rotate_ccw.title=Rotar en direcziun cuntraria a l'ura -page_rotate_ccw.label=Rotar en direcziun cuntraria a l'ura page_rotate_ccw_label=Rotar en direcziun cuntraria a l'ura cursor_text_select_tool.title=Activar l'utensil per selecziunar text @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Utensil per selecziunar text cursor_hand_tool.title=Activar l'utensil da maun cursor_hand_tool_label=Utensil da maun +scroll_page.title=Utilisar la defilada per pagina +scroll_page_label=Defilada per pagina scroll_vertical.title=Utilisar il defilar vertical scroll_vertical_label=Defilar vertical scroll_horizontal.title=Utilisar il defilar orizontal @@ -137,19 +135,24 @@ print_progress_close=Interrumper # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Activar/deactivar la trav laterala -toggle_sidebar_notification.title=Activar/deactivar la trav laterala (structura dal document/agiuntas) +toggle_sidebar_notification2.title=Activar/deactivar la trav laterala (il document cuntegna structura dal document/agiuntas/nivels) toggle_sidebar_label=Activar/deactivar la trav laterala document_outline.title=Mussar la structura dal document (cliccar duas giadas per extender/cumprimer tut ils elements) document_outline_label=Structura dal document attachments.title=Mussar agiuntas attachments_label=Agiuntas +layers.title=Mussar ils nivels (cliccar dubel per restaurar il stadi da standard da tut ils nivels) +layers_label=Nivels thumbs.title=Mussar las miniaturas thumbs_label=Miniaturas +current_outline_item.title=Tschertgar l'element da structura actual +current_outline_item_label=Element da structura actual findbar.title=Tschertgar en il document findbar_label=Tschertgar -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Pagina {{page}} +additional_layers=Nivels supplementars +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Pagina {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Tschertgar la proxima posiziun da l'expressiun find_next_label=Enavant find_highlight=Relevar tuts find_match_case_label=Resguardar maiusclas/minusclas +find_match_diacritics_label=Resguardar ils segns diacritics find_entire_word_label=Pleds entirs find_reached_top=Il cumenzament dal document è cuntanschì, la tschertga cuntinuescha a la fin dal document find_reached_bottom=La fin dal document è cuntanschì, la tschertga cuntinuescha al cumenzament dal document @@ -222,7 +226,7 @@ page_scale_actual=Grondezza actuala page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Errur +loading=Chargiar… loading_error=Ina errur è cumparida cun chargiar il PDF. invalid_file_error=Datoteca PDF nunvalida u donnegiada. missing_file_error=Datoteca PDF manconta. @@ -245,3 +249,13 @@ password_cancel=Interrumper printing_not_supported=Attenziun: Il stampar na funcziunescha anc betg dal tut en quest navigatur. printing_not_ready=Attenziun: Il PDF n'è betg chargià cumplettamain per stampar. web_fonts_disabled=Scrittiras dal web èn deactivadas: impussibel dad utilisar las scrittiras integradas en il PDF. + +# Editor +editor_none.title=Deactivar la modificaziun dad annotaziuns +editor_none_label=Deactivar la modificaziun +editor_free_text.title=Agiuntar ina annotaziun da text liber +editor_free_text_label=Annotaziun da text liber +editor_ink.title=Agiuntar ina annotaziun stilograf +editor_ink_label=Annotaziun stilograf + +freetext_default_content=Endatar text… diff --git a/cps/static/locale/ro/viewer.properties b/cps/static/locale/ro/viewer.properties index 0e4fbf70e..7c4ed2836 100644 --- a/cps/static/locale/ro/viewer.properties +++ b/cps/static/locale/ro/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Vizualizare actuală tools.title=Instrumente tools_label=Instrumente first_page.title=Mergi la prima pagină -first_page.label=Mergi la prima pagină first_page_label=Mergi la prima pagină last_page.title=Mergi la ultima pagină -last_page.label=Mergi la ultima pagină last_page_label=Mergi la ultima pagină page_rotate_cw.title=Rotește în sensul acelor de ceas -page_rotate_cw.label=Rotește în sensul acelor de ceas page_rotate_cw_label=Rotește în sensul acelor de ceas page_rotate_ccw.title=Rotește în sens invers al acelor de ceas -page_rotate_ccw.label=Rotește în sens invers al acelor de ceas page_rotate_ccw_label=Rotește în sens invers al acelor de ceas cursor_text_select_tool.title=Activează instrumentul de selecție a textului @@ -137,7 +133,6 @@ print_progress_close=Renunță # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Comută bara laterală -toggle_sidebar_notification.title=Comută bara laterală (documentul conține schițe/atașamente) toggle_sidebar_label=Comută bara laterală document_outline.title=Afișează schița documentului (dublu-clic pentru a extinde/restrânge toate elementele) document_outline_label=Schița documentului @@ -148,8 +143,7 @@ thumbs_label=Miniaturi findbar.title=Caută în document findbar_label=Caută -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Pagina {{page}} +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -222,7 +216,6 @@ page_scale_actual=Mărime reală page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Eroare loading_error=A intervenit o eroare la încărcarea PDF-ului. invalid_file_error=Fișier PDF nevalid sau corupt. missing_file_error=Fișier PDF lipsă. @@ -239,7 +232,7 @@ annotation_date_string={{date}}, {{time}} text_annotation_type.alt=[Adnotare {{type}}] password_label=Introdu parola pentru a deschide acest fișier PDF. password_invalid=Parolă nevalidă. Te rugăm să încerci din nou. -password_ok=Ok +password_ok=OK password_cancel=Renunță printing_not_supported=Avertisment: Tipărirea nu este suportată în totalitate de acest browser. diff --git a/cps/static/locale/ru/viewer.properties b/cps/static/locale/ru/viewer.properties index dd4ee4810..70c898a52 100644 --- a/cps/static/locale/ru/viewer.properties +++ b/cps/static/locale/ru/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Текущий вид tools.title=Инструменты tools_label=Инструменты first_page.title=Перейти на первую страницу -first_page.label=Перейти на первую страницу first_page_label=Перейти на первую страницу last_page.title=Перейти на последнюю страницу -last_page.label=Перейти на последнюю страницу last_page_label=Перейти на последнюю страницу page_rotate_cw.title=Повернуть по часовой стрелке -page_rotate_cw.label=Повернуть по часовой стрелке page_rotate_cw_label=Повернуть по часовой стрелке page_rotate_ccw.title=Повернуть против часовой стрелки -page_rotate_ccw.label=Повернуть против часовой стрелки page_rotate_ccw_label=Повернуть против часовой стрелки cursor_text_select_tool.title=Включить Инструмент «Выделение текста» @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Инструмент «Выделение текс cursor_hand_tool.title=Включить Инструмент «Рука» cursor_hand_tool_label=Инструмент «Рука» +scroll_page.title=Использовать прокрутку страниц +scroll_page_label=Прокрутка страниц scroll_vertical.title=Использовать вертикальную прокрутку scroll_vertical_label=Вертикальная прокрутка scroll_horizontal.title=Использовать горизонтальную прокрутку @@ -137,19 +135,24 @@ print_progress_close=Отмена # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Показать/скрыть боковую панель -toggle_sidebar_notification.title=Показать/скрыть боковую панель (документ имеет содержание/вложения) +toggle_sidebar_notification2.title=Показать/скрыть боковую панель (документ имеет содержание/вложения/слои) toggle_sidebar_label=Показать/скрыть боковую панель document_outline.title=Показать содержание документа (двойной щелчок, чтобы развернуть/свернуть все элементы) document_outline_label=Содержание документа attachments.title=Показать вложения attachments_label=Вложения +layers.title=Показать слои (дважды щёлкните, чтобы сбросить все слои к состоянию по умолчанию) +layers_label=Слои thumbs.title=Показать миниатюры thumbs_label=Миниатюры +current_outline_item.title=Найти текущий элемент структуры +current_outline_item_label=Текущий элемент структуры findbar.title=Найти в документе findbar_label=Найти -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Страница {{page}} +additional_layers=Дополнительные слои +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Страница {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Найти следующее вхождение фразы в find_next_label=Далее find_highlight=Подсветить все find_match_case_label=С учётом регистра +find_match_diacritics_label=С учётом диакритических знаков find_entire_word_label=Слова целиком find_reached_top=Достигнут верх документа, продолжено снизу find_reached_bottom=Достигнут конец документа, продолжено сверху @@ -222,7 +226,7 @@ page_scale_actual=Реальный размер page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Ошибка +loading=Загрузка… loading_error=При загрузке PDF произошла ошибка. invalid_file_error=Некорректный или повреждённый PDF-файл. missing_file_error=PDF-файл отсутствует. @@ -244,4 +248,34 @@ password_cancel=Отмена printing_not_supported=Предупреждение: В этом браузере не полностью поддерживается печать. printing_not_ready=Предупреждение: PDF не полностью загружен для печати. -web_fonts_disabled=Веб-шрифты отключены: невозможно использовать встроенные PDF-шрифты. +web_fonts_disabled=Веб-шрифты отключены: не удалось задействовать встроенные PDF-шрифты. + +# Editor +editor_none.title=Отключить редактирование аннотаций +editor_none_label=Отключить редактирование +editor_free_text.title=Добавить аннотацию FreeText +editor_free_text_label=Аннотация FreeText +editor_ink.title=Добавить рукописную аннотацию +editor_ink_label=Рукописная аннотация + +freetext_default_content=Введите текст… + +free_text_default_content=Введите текст… + +# Editor Parameters +editor_free_text_font_color=Цвет шрифта +editor_free_text_font_size=Размер шрифта +editor_ink_line_color=Цвет линии +editor_ink_line_thickness=Толщина линии + +# Editor Parameters +editor_free_text_color=Цвет +editor_free_text_size=Размер +editor_ink_color=Цвет +editor_ink_thickness=Толщина +editor_ink_opacity=Прозрачность + +# Editor aria +editor_free_text_aria_label=Редактор FreeText +editor_ink_aria_label=Редактор чернил +editor_ink_canvas_aria_label=Созданное пользователем изображение diff --git a/cps/static/locale/sat/viewer.properties b/cps/static/locale/sat/viewer.properties new file mode 100644 index 000000000..9cfa1f5a8 --- /dev/null +++ b/cps/static/locale/sat/viewer.properties @@ -0,0 +1,197 @@ +# Copyright 2012 Mozilla Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Main toolbar buttons (tooltips and alt text for images) +previous.title=ᱢᱟᱲᱟᱝ ᱥᱟᱦᱴᱟ +previous_label=ᱢᱟᱲᱟᱝᱟᱜ +next.title=ᱤᱱᱟᱹ ᱛᱟᱭᱚᱢ ᱥᱟᱦᱴᱟ +next_label=ᱤᱱᱟᱹ ᱛᱟᱭᱚᱢ + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=ᱥᱟᱦᱴᱟ +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=ᱨᱮᱭᱟᱜ {{pagesCount}} +# LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" +# will be replaced by a number representing the currently visible page, +# respectively a number representing the total number of pages in the document. +page_of_pages=({{pageNumber}} ᱠᱷᱚᱱ {{pagesCount}}) + +zoom_out.title=ᱦᱤᱲᱤᱧ ᱛᱮᱭᱟᱨ +zoom_out_label=ᱦᱤᱲᱤᱧ ᱛᱮᱭᱟᱨ +zoom_in.title=ᱢᱟᱨᱟᱝ ᱛᱮᱭᱟᱨ +zoom_in_label=ᱢᱟᱨᱟᱝ ᱛᱮᱭᱟᱨ +zoom.title=ᱡᱩᱢ +presentation_mode.title=ᱩᱫᱩᱜ ᱥᱚᱫᱚᱨ ᱚᱵᱚᱥᱛᱟ ᱨᱮ ᱚᱛᱟᱭ ᱢᱮ +presentation_mode_label=ᱩᱫᱩᱜ ᱥᱚᱫᱚᱨ ᱚᱵᱚᱥᱛᱟ ᱨᱮ +open_file.title=ᱨᱮᱫ ᱡᱷᱤᱡᱽ ᱢᱮ +open_file_label=ᱡᱷᱤᱡᱽ ᱢᱮ +print.title=ᱪᱷᱟᱯᱟ +print_label=ᱪᱷᱟᱯᱟ +download.title=ᱰᱟᱩᱱᱞᱚᱰ +download_label=ᱰᱟᱩᱱᱞᱚᱰ +bookmark.title=ᱱᱤᱛᱚᱜᱟᱜ ᱧᱮᱞ (ᱱᱚᱶᱟ ᱡᱷᱚᱨᱠᱟ ᱨᱮ ᱱᱚᱠᱚᱞ ᱟᱨ ᱵᱟᱝ ᱡᱷᱤᱡᱽ ᱢᱮ ) +bookmark_label=ᱱᱤᱛᱚᱜᱟᱜ ᱧᱮᱞ + +# Secondary toolbar and context menu +tools.title=ᱦᱟᱹᱛᱤᱭᱟᱹᱨ ᱠᱚ +tools_label=ᱦᱟᱹᱛᱤᱭᱟᱹᱨ ᱠᱚ +first_page.title=ᱯᱩᱭᱞᱩ ᱥᱟᱦᱴᱟ ᱥᱮᱫ ᱪᱟᱞᱟᱜ ᱢᱮ +first_page_label=ᱯᱩᱭᱞᱩ ᱥᱟᱦᱴᱟ ᱥᱮᱫ ᱪᱟᱞᱟᱜ ᱢᱮ +last_page.title=ᱢᱩᱪᱟᱹᱫ ᱥᱟᱦᱴᱟ ᱥᱮᱫ ᱪᱟᱞᱟᱜ ᱢᱮ +last_page_label=ᱢᱩᱪᱟᱹᱫ ᱥᱟᱦᱴᱟ ᱥᱮᱫ ᱪᱟᱞᱟᱜ ᱢᱮ +page_rotate_cw.title=ᱜᱷᱚᱰᱤ ᱦᱤᱥᱟᱹᱵ ᱛᱮ ᱟᱹᱪᱩᱨ +page_rotate_cw_label=ᱜᱷᱚᱰᱤ ᱦᱤᱥᱟᱹᱵ ᱛᱮ ᱟᱹᱪᱩᱨ +page_rotate_ccw.title=ᱜᱷᱚᱰᱤ ᱦᱤᱥᱟᱹᱵ ᱛᱮ ᱩᱞᱴᱟᱹ ᱟᱹᱪᱩᱨ +page_rotate_ccw_label=ᱜᱷᱚᱰᱤ ᱦᱤᱥᱟᱹᱵ ᱛᱮ ᱩᱞᱴᱟᱹ ᱟᱹᱪᱩᱨ + +cursor_text_select_tool.title=ᱚᱞ ᱵᱟᱪᱷᱟᱣ ᱦᱟᱹᱛᱤᱭᱟᱨ ᱮᱢ ᱪᱷᱚᱭ ᱢᱮ +cursor_text_select_tool_label=ᱚᱞ ᱵᱟᱪᱷᱟᱣ ᱦᱟᱹᱛᱤᱭᱟᱨ +cursor_hand_tool.title=ᱛᱤ ᱦᱟᱹᱛᱤᱭᱟᱨ ᱮᱢ ᱪᱷᱚᱭ ᱢᱮ +cursor_hand_tool_label=ᱛᱤ ᱦᱟᱹᱛᱤᱭᱟᱨ + +scroll_page.title=ᱥᱟᱦᱴᱟ ᱜᱩᱲᱟᱹᱣ ᱵᱮᱵᱷᱟᱨ ᱢᱮ +scroll_page_label=ᱥᱟᱦᱴᱟ ᱜᱩᱲᱟᱹᱣ +scroll_vertical.title=ᱥᱤᱫᱽ ᱜᱩᱲᱟᱹᱣ ᱵᱮᱵᱷᱟᱨ ᱢᱮ +scroll_vertical_label=ᱥᱤᱫᱽ ᱜᱩᱲᱟᱹᱣ +scroll_horizontal.title=ᱜᱤᱛᱤᱡ ᱛᱮ ᱜᱩᱲᱟᱹᱣ ᱵᱮᱵᱷᱟᱨ ᱢᱮ + + +# Document properties dialog box +document_properties_file_name=ᱨᱮᱫᱽ ᱧᱩᱛᱩᱢ : +document_properties_file_size=ᱨᱮᱫᱽ ᱢᱟᱯ : +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in bytes. +document_properties_kb={{size_kb}} KB ({{size_b}} ᱵᱟᱭᱤᱴ ᱠᱚ) +# LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" +# will be replaced by the PDF file size in megabytes, respectively in bytes. +document_properties_mb={{size_mb}} MB ({{size_b}} ᱵᱟᱭᱤᱴ ᱠᱚ) +document_properties_title=ᱧᱩᱛᱩᱢ : +document_properties_author=ᱚᱱᱚᱞᱤᱭᱟᱹ : +document_properties_subject=ᱵᱤᱥᱚᱭ : +document_properties_keywords=ᱠᱟᱹᱴᱷᱤ ᱥᱟᱵᱟᱫᱽ : +document_properties_creation_date=ᱛᱮᱭᱟᱨ ᱢᱟᱸᱦᱤᱛ : +document_properties_modification_date=ᱵᱚᱫᱚᱞ ᱦᱚᱪᱚ ᱢᱟᱹᱦᱤᱛ : +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. +document_properties_date_string={{date}}, {{time}} +document_properties_creator=ᱵᱮᱱᱟᱣᱤᱡ : +document_properties_producer=PDF ᱛᱮᱭᱟᱨ ᱚᱰᱚᱠᱤᱡ : +document_properties_version=PDF ᱵᱷᱟᱹᱨᱥᱚᱱ : +document_properties_page_count=ᱥᱟᱦᱴᱟ ᱞᱮᱠᱷᱟ : +document_properties_page_size=ᱥᱟᱦᱴᱟ ᱢᱟᱯ : +document_properties_page_size_unit_inches=ᱤᱧᱪ +document_properties_page_size_unit_millimeters=ᱢᱤᱢᱤ +document_properties_page_size_orientation_portrait=ᱯᱚᱴᱨᱮᱴ +document_properties_page_size_orientation_landscape=ᱞᱮᱱᱰᱥᱠᱮᱯ +document_properties_page_size_name_a3=A3 +document_properties_page_size_name_a4=A4 +document_properties_page_size_name_letter=ᱪᱤᱴᱷᱤ +document_properties_page_size_name_legal=ᱠᱟᱹᱱᱩᱱᱤ +# LOCALIZATION NOTE (document_properties_page_size_dimension_string): +# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement and orientation, of the (current) page. +document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} ({{orientation}}) +# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): +# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement, name, and orientation, of the (current) page. +# LOCALIZATION NOTE (document_properties_linearized): The linearization status of +# the document; usually called "Fast Web View" in English locales of Adobe software. + +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. + +# Tooltips and alt text for side panel toolbar buttons +# (the _label strings are alt text for the buttons, the .title strings are +# tooltips) +document_outline_label=ᱫᱚᱞᱤᱞ ᱛᱮᱭᱟᱨ ᱛᱮᱫ +attachments.title=ᱞᱟᱴᱷᱟ ᱥᱮᱞᱮᱫ ᱠᱚ ᱩᱫᱩᱜᱽ ᱢᱮ +attachments_label=ᱞᱟᱴᱷᱟ ᱥᱮᱞᱮᱫ ᱠᱚ +thumbs.title=ᱪᱤᱛᱟᱹᱨ ᱟᱦᱞᱟ ᱠᱚ ᱩᱫᱩᱜᱽ ᱢᱮ +thumbs_label=ᱪᱤᱛᱟᱹᱨ ᱟᱦᱞᱟ ᱠᱚ +findbar.title=ᱫᱚᱞᱤᱞ ᱨᱮ ᱯᱟᱱᱛᱮ +findbar_label=ᱥᱮᱸᱫᱽᱨᱟᱭ ᱢᱮ + +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +# Thumbnails panel item (tooltip and alt text for images) +# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page +# number. +thumb_page_title={{page}} ᱥᱟᱦᱴᱟ +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas={{page}} ᱥᱟᱦᱴᱟ ᱨᱮᱭᱟᱜ ᱪᱤᱛᱟᱹᱨ ᱟᱦᱞᱟ + +# Find panel button title and messages +find_previous.title=ᱟᱭᱟᱛ ᱦᱤᱸᱥ ᱨᱮᱭᱟᱜ ᱯᱟᱹᱦᱤᱞ ᱥᱮᱫᱟᱜ ᱚᱰᱚᱠ ᱧᱟᱢ ᱢᱮ +find_next.title=ᱟᱭᱟᱛ ᱦᱤᱸᱥ ᱨᱮᱭᱟᱜ ᱤᱱᱟᱹ ᱛᱟᱭᱚᱢ ᱚᱰᱚᱠ ᱧᱟᱢ ᱢᱮ +find_highlight=ᱡᱷᱚᱛᱚ ᱩᱫᱩᱜ ᱨᱟᱠᱟᱵ +find_match_case_label=ᱡᱚᱲ ᱠᱟᱛᱷᱟ +find_reached_top=ᱫᱚᱞᱤᱞ ᱨᱮᱭᱟᱜ ᱪᱤᱴ ᱨᱮ ᱥᱮᱴᱮᱨ, ᱞᱟᱛᱟᱨ ᱠᱷᱚᱱ ᱞᱮᱛᱟᱲ +find_reached_bottom=ᱫᱚᱞᱤᱞ ᱨᱮᱭᱟᱜ ᱢᱩᱪᱟᱹᱫ ᱨᱮ ᱥᱮᱴᱮᱨ, ᱪᱚᱴ ᱠᱷᱚᱱ ᱞᱮᱛᱟᱲ +# LOCALIZATION NOTE (find_match_count): The supported plural forms are +# [one|two|few|many|other], with [other] as the default value. +# "{{current}}" and "{{total}}" will be replaced by a number representing the +# index of the currently active find result, respectively a number representing +# the total number of matches in the document. +# LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are +# [zero|one|two|few|many|other], with [other] as the default value. +# "{{limit}}" will be replaced by a numerical value. +find_not_found=ᱛᱚᱯᱚᱞ ᱫᱚᱱᱚᱲ ᱵᱟᱝ ᱧᱟᱢ ᱞᱮᱱᱟ + +# Error panel labels +error_more_info=ᱵᱟᱹᱲᱛᱤ ᱞᱟᱹᱭ ᱥᱚᱫᱚᱨ +error_less_info=ᱠᱚᱢ ᱞᱟᱹᱭ ᱥᱚᱫᱚᱨ +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=PDF.js v{{version}} (build: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=ᱠᱷᱚᱵᱚᱨ : {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=ᱵᱟᱝ : {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=ᱨᱮᱫᱽ : {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=ᱜᱟᱨ : {{line}} +rendering_error=ᱥᱟᱦᱴᱟ ᱮᱢ ᱡᱚᱦᱚᱠ ᱢᱤᱫ ᱵᱷᱩᱞ ᱦᱩᱭ ᱮᱱᱟ ᱾ + +# Predefined zoom values +page_scale_width=ᱥᱟᱦᱴᱟ ᱚᱥᱟᱨ +page_scale_fit=ᱥᱟᱦᱴᱟ ᱠᱷᱟᱯ +page_scale_auto=ᱟᱡᱼᱟᱡ ᱛᱮ ᱦᱩᱰᱤᱧ ᱞᱟᱹᱴᱩ ᱛᱮᱭᱟᱨ +page_scale_actual=ᱴᱷᱤᱠ ᱢᱟᱨᱟᱝ ᱛᱮᱫ +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error=PDF ᱞᱟᱫᱮ ᱡᱚᱦᱚᱜ ᱢᱤᱫ ᱵᱷᱩᱞ ᱦᱩᱭ ᱮᱱᱟ ᱾ +invalid_file_error=ᱵᱟᱝ ᱵᱟᱛᱟᱣ ᱟᱨᱵᱟᱝᱠᱷᱟᱱ ᱰᱤᱜᱟᱹᱣ PDF ᱨᱮᱫᱽ ᱾ +missing_file_error=ᱟᱫᱟᱜ PDF ᱨᱮᱫᱽ ᱾ + +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. + +# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. +# "{{type}}" will be replaced with an annotation type from a list defined in +# the PDF spec (32000-1:2008 Table 169 – Annotation types). +# Some common types are e.g.: "Check", "Text", "Comment", "Note" +text_annotation_type.alt=[{{type}} ᱢᱚᱱᱛᱚ ᱮᱢ] +password_label=ᱱᱚᱶᱟ PDF ᱨᱮᱫᱽ ᱡᱷᱤᱡᱽ ᱞᱟᱹᱜᱤᱫ ᱫᱟᱱᱟᱝ ᱥᱟᱵᱟᱫᱽ ᱟᱫᱮᱨ ᱢᱮ ᱾ +password_invalid=ᱵᱷᱩᱞ ᱫᱟᱱᱟᱝ ᱥᱟᱵᱟᱫᱽ ᱾ ᱫᱟᱭᱟᱠᱟᱛᱮ ᱫᱩᱦᱲᱟᱹ ᱪᱮᱥᱴᱟᱭ ᱢᱮ ᱾ +password_ok=ᱴᱷᱤᱠ + +printing_not_supported=ᱦᱚᱥᱤᱭᱟᱨ : ᱪᱷᱟᱯᱟ ᱱᱚᱣᱟ ᱯᱟᱱᱛᱮᱭᱟᱜ ᱫᱟᱨᱟᱭ ᱛᱮ ᱯᱩᱨᱟᱹᱣ ᱵᱟᱭ ᱜᱚᱲᱚᱣᱟᱠᱟᱱᱟ ᱾ +printing_not_ready=ᱦᱩᱥᱤᱭᱟᱹᱨ : ᱪᱷᱟᱯᱟ ᱞᱟᱹᱜᱤᱫ PDF ᱯᱩᱨᱟᱹ ᱵᱟᱭ ᱞᱟᱫᱮ ᱟᱠᱟᱱᱟ ᱾ +web_fonts_disabled=ᱣᱮᱵᱽ ᱪᱤᱠᱤ ᱵᱟᱝ ᱦᱩᱭ ᱦᱚᱪᱚ ᱠᱟᱱᱟ : ᱵᱷᱤᱛᱤᱨ ᱛᱷᱟᱯᱚᱱ PDF ᱪᱤᱠᱤ ᱵᱮᱵᱷᱟᱨ ᱵᱟᱝ ᱦᱩᱭ ᱠᱮᱭᱟ ᱾ diff --git a/cps/static/locale/sc/viewer.properties b/cps/static/locale/sc/viewer.properties new file mode 100644 index 000000000..5a6f46cfe --- /dev/null +++ b/cps/static/locale/sc/viewer.properties @@ -0,0 +1,239 @@ +# Copyright 2012 Mozilla Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Main toolbar buttons (tooltips and alt text for images) +previous.title=Pàgina anteriore +previous_label=S'ischeda chi b'est primu +next.title=Pàgina imbeniente +next_label=Imbeniente + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Pàgina +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=de {{pagesCount}} +# LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" +# will be replaced by a number representing the currently visible page, +# respectively a number representing the total number of pages in the document. +page_of_pages=({{pageNumber}} de {{pagesCount}}) + +zoom_out.title=Impitica +zoom_out_label=Impitica +zoom_in.title=Ismànnia +zoom_in_label=Ismànnia +zoom.title=Ismànnia +presentation_mode.title=Cola a sa modalidade de presentatzione +presentation_mode_label=Modalidade de presentatzione +open_file.title=Aberi s'archìviu +open_file_label=Abertu +print.title=Imprenta +print_label=Imprenta +download.title=Iscàrriga +download_label=Iscàrriga +bookmark.title=Visualizatzione atuale (còpia o aberi in una ventana noa) +bookmark_label=Visualizatzione atuale + +# Secondary toolbar and context menu +tools.title=Istrumentos +tools_label=Istrumentos +first_page.title=Bae a sa prima pàgina +first_page_label=Bae a sa prima pàgina +last_page.title=Bae a s'ùrtima pàgina +last_page_label=Bae a s'ùrtima pàgina +page_rotate_cw.title=Gira in sensu oràriu +page_rotate_cw_label=Gira in sensu oràriu +page_rotate_ccw.title=Gira in sensu anti-oràriu +page_rotate_ccw_label=Gira in sensu anti-oràriu + +cursor_text_select_tool.title=Ativa s'aina de seletzione de testu +cursor_text_select_tool_label=Aina de seletzione de testu +cursor_hand_tool.title=Ativa s'aina de manu +cursor_hand_tool_label=Aina de manu + +scroll_page.title=Imprea s'iscurrimentu de pàgina +scroll_page_label=Iscurrimentu de pàgina +scroll_vertical.title=Imprea s'iscurrimentu verticale +scroll_vertical_label=Iscurrimentu verticale +scroll_horizontal.title=Imprea s'iscurrimentu orizontale +scroll_horizontal_label=Iscurrimentu orizontale +scroll_wrapped.title=Imprea s'iscurrimentu continu +scroll_wrapped_label=Iscurrimentu continu + + +# Document properties dialog box +document_properties.title=Propiedades de su documentu… +document_properties_label=Propiedades de su documentu… +document_properties_file_name=Nòmine de s'archìviu: +document_properties_file_size=Mannària de s'archìviu: +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in bytes. +document_properties_kb={{size_kb}} KB ({{size_b}} bytes) +# LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" +# will be replaced by the PDF file size in megabytes, respectively in bytes. +document_properties_mb={{size_mb}} MB ({{size_b}} bytes) +document_properties_title=Tìtulu: +document_properties_author=Autoria: +document_properties_subject=Ogetu: +document_properties_keywords=Faeddos crae: +document_properties_creation_date=Data de creatzione: +document_properties_modification_date=Data de modìfica: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. +document_properties_date_string={{date}}, {{time}} +document_properties_creator=Creatzione: +document_properties_producer=Produtore de PDF: +document_properties_version=Versione de PDF: +document_properties_page_count=Contu de pàginas: +document_properties_page_size=Mannària de sa pàgina: +document_properties_page_size_unit_inches=pòddighes +document_properties_page_size_unit_millimeters=mm +document_properties_page_size_orientation_portrait=verticale +document_properties_page_size_orientation_landscape=orizontale +document_properties_page_size_name_a3=A3 +document_properties_page_size_name_a4=A4 +document_properties_page_size_name_letter=Lìtera +document_properties_page_size_name_legal=Legale +# LOCALIZATION NOTE (document_properties_page_size_dimension_string): +# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement and orientation, of the (current) page. +document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} ({{orientation}}) +# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): +# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement, name, and orientation, of the (current) page. +document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) +# LOCALIZATION NOTE (document_properties_linearized): The linearization status of +# the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized=Visualizatzione web lestra: +document_properties_linearized_yes=Eja +document_properties_linearized_no=Nono +document_properties_close=Serra + +print_progress_message=Aparitzende s'imprenta de su documentu… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Cantzella + +# Tooltips and alt text for side panel toolbar buttons +# (the _label strings are alt text for the buttons, the .title strings are +# tooltips) +toggle_sidebar.title=Ativa/disativa sa barra laterale +toggle_sidebar_notification2.title=Ativa/disativa sa barra laterale (su documentu cuntenet un'ischema, alligongiados o livellos) +toggle_sidebar_label=Ativa/disativa sa barra laterale +document_outline_label=Ischema de su documentu +attachments.title=Ammustra alligongiados +attachments_label=Alliongiados +layers.title=Ammustra livellos (clic dòpiu pro ripristinare totu is livellos a s'istadu predefinidu) +layers_label=Livellos +thumbs.title=Ammustra miniaturas +thumbs_label=Miniaturas +current_outline_item.title=Agata s'elementu atuale de s'ischema +current_outline_item_label=Elementu atuale de s'ischema +findbar.title=Agata in su documentu +findbar_label=Agata + +additional_layers=Livellos additzionales +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Pàgina {{page}} +# Thumbnails panel item (tooltip and alt text for images) +# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page +# number. +thumb_page_title=Pàgina {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatura de sa pàgina {{page}} + +# Find panel button title and messages +find_input.title=Agata +find_input.placeholder=Agata in su documentu… +find_previous.title=Agata s'ocurrèntzia pretzedente de sa fràsia +find_previous_label=S'ischeda chi b'est primu +find_next.title=Agata s'ocurrèntzia imbeniente de sa fràsia +find_next_label=Imbeniente +find_highlight=Evidèntzia totu +find_match_case_label=Distinghe intre majùsculas e minùsculas +find_match_diacritics_label=Respeta is diacrìticos +find_entire_word_label=Faeddos intreos +find_reached_top=S'est lòmpidu a su cumintzu de su documentu, si sighit dae su bàsciu +find_reached_bottom=S'est lòmpidu a s'acabbu de su documentu, si sighit dae s'artu +# LOCALIZATION NOTE (find_match_count): The supported plural forms are +# [one|two|few|many|other], with [other] as the default value. +# "{{current}}" and "{{total}}" will be replaced by a number representing the +# index of the currently active find result, respectively a number representing +# the total number of matches in the document. +find_match_count={[ plural(total) ]} +find_match_count[one]={{current}} dae {{total}} currispondèntzia +find_match_count[two]={{current}} dae {{total}} currispondèntzias +find_match_count[few]={{current}} dae {{total}} currispondèntzias +find_match_count[many]={{current}} dae {{total}} currispondèntzias +find_match_count[other]={{current}} dae {{total}} currispondèntzias +# LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are +# [zero|one|two|few|many|other], with [other] as the default value. +# "{{limit}}" will be replaced by a numerical value. +find_match_count_limit={[ plural(limit) ]} +find_match_count_limit[zero]=Prus de {{limit}} currispondèntzias +find_match_count_limit[one]=Prus de {{limit}} currispondèntzia +find_match_count_limit[two]=Prus de {{limit}} currispondèntzias +find_match_count_limit[few]=Prus de {{limit}} currispondèntzias +find_match_count_limit[many]=Prus de {{limit}} currispondèntzias +find_match_count_limit[other]=Prus de {{limit}} currispondèntzias +find_not_found=Testu no agatadu + +# Error panel labels +error_more_info=Àteras informatziones +error_less_info=Prus pagu informatziones +error_close=Serra +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=PDF.js v{{version}} (build: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Messàgiu: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Archìviu: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Lìnia: {{line}} +rendering_error=Faddina in sa visualizatzione de sa pàgina. + +# Predefined zoom values +page_scale_auto=Ingrandimentu automàticu +page_scale_actual=Mannària reale +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading=Carrighende… +loading_error=Faddina in sa càrriga de su PDF. +invalid_file_error=Archìviu PDF non vàlidu o corrùmpidu. +missing_file_error=Ammancat s'archìviu PDF. + +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. +annotation_date_string={{date}}, {{time}} + +# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. +# "{{type}}" will be replaced with an annotation type from a list defined in +# the PDF spec (32000-1:2008 Table 169 – Annotation types). +# Some common types are e.g.: "Check", "Text", "Comment", "Note" +password_label=Inserta sa crae pro abèrrere custu archìviu PDF. +password_invalid=Sa crae no est curreta. Torra·bi a proare. +password_ok=Andat bene +password_cancel=Cantzella + +printing_not_supported=Atentzione: s'imprenta no est funtzionende de su totu in custu navigadore. +printing_not_ready=Atentzione: su PDF no est istadu carrigadu de su totu pro s'imprenta. +web_fonts_disabled=Is tipografias web sunt disativadas: is tipografias incrustadas a su PDF non podent èssere impreadas. diff --git a/cps/static/locale/sco/viewer.properties b/cps/static/locale/sco/viewer.properties new file mode 100644 index 000000000..656f9950b --- /dev/null +++ b/cps/static/locale/sco/viewer.properties @@ -0,0 +1,248 @@ +# Copyright 2012 Mozilla Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Main toolbar buttons (tooltips and alt text for images) +previous.title=Page Afore +previous_label=Previous +next.title=Page Efter +next_label=Neist + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Page +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=o {{pagesCount}} +# LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" +# will be replaced by a number representing the currently visible page, +# respectively a number representing the total number of pages in the document. +page_of_pages=({{pageNumber}} o {{pagesCount}}) + +zoom_out.title=Zoom Oot +zoom_out_label=Zoom Oot +zoom_in.title=Zoom In +zoom_in_label=Zoom In +zoom.title=Zoom +presentation_mode.title=Flit tae Presentation Mode +presentation_mode_label=Presentation Mode +open_file.title=Open File +open_file_label=Open +print.title=Prent +print_label=Prent +download.title=Doonload +download_label=Doonload +bookmark.title=View the noo (copy or open in new windae) +bookmark_label=View The Noo + +# Secondary toolbar and context menu +tools.title=Tools +tools_label=Tools +first_page.title=Gang tae First Page +first_page_label=Gang tae First Page +last_page.title=Gang tae Lest Page +last_page_label=Gang tae Lest Page +page_rotate_cw.title=Rotate Clockwise +page_rotate_cw_label=Rotate Clockwise +page_rotate_ccw.title=Rotate Coonterclockwise +page_rotate_ccw_label=Rotate Coonterclockwise + +cursor_text_select_tool.title=Enable Text Walin Tool +cursor_text_select_tool_label=Text Walin Tool +cursor_hand_tool.title=Enable Haun Tool +cursor_hand_tool_label=Haun Tool + +scroll_vertical.title=Yaise Vertical Scrollin +scroll_vertical_label=Vertical Scrollin +scroll_horizontal.title=Yaise Horizontal Scrollin +scroll_horizontal_label=Horizontal Scrollin +scroll_wrapped.title=Yaise Wrapped Scrollin +scroll_wrapped_label=Wrapped Scrollin + +spread_none.title=Dinnae jyn page spreids +spread_none_label=Nae Spreids +spread_odd.title=Jyn page spreids stertin wi odd-numbered pages +spread_odd_label=Odd Spreids +spread_even.title=Jyn page spreids stertin wi even-numbered pages +spread_even_label=Even Spreids + +# Document properties dialog box +document_properties.title=Document Properties… +document_properties_label=Document Properties… +document_properties_file_name=File nemme: +document_properties_file_size=File size: +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in bytes. +document_properties_kb={{size_kb}} KB ({{size_b}} bytes) +# LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" +# will be replaced by the PDF file size in megabytes, respectively in bytes. +document_properties_mb={{size_mb}} MB ({{size_b}} bytes) +document_properties_title=Title: +document_properties_author=Author: +document_properties_subject=Subjeck: +document_properties_keywords=Keywirds: +document_properties_creation_date=Date o Makkin: +document_properties_modification_date=Date o Chynges: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. +document_properties_date_string={{date}}, {{time}} +document_properties_creator=Makker: +document_properties_producer=PDF Producer: +document_properties_version=PDF Version: +document_properties_page_count=Page Coont: +document_properties_page_size=Page Size: +document_properties_page_size_unit_inches=in +document_properties_page_size_unit_millimeters=mm +document_properties_page_size_orientation_portrait=portrait +document_properties_page_size_orientation_landscape=landscape +document_properties_page_size_name_a3=A3 +document_properties_page_size_name_a4=A4 +document_properties_page_size_name_letter=Letter +document_properties_page_size_name_legal=Legal +# LOCALIZATION NOTE (document_properties_page_size_dimension_string): +# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement and orientation, of the (current) page. +document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} ({{orientation}}) +# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): +# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement, name, and orientation, of the (current) page. +document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) +# LOCALIZATION NOTE (document_properties_linearized): The linearization status of +# the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized=Fast Wab View: +document_properties_linearized_yes=Aye +document_properties_linearized_no=Naw +document_properties_close=Sneck + +print_progress_message=Reddin document fur prentin… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Stap + +# Tooltips and alt text for side panel toolbar buttons +# (the _label strings are alt text for the buttons, the .title strings are +# tooltips) +toggle_sidebar.title=Toggle Sidebaur +toggle_sidebar_notification2.title=Toggle Sidebaur (document conteens ootline/attachments/layers) +toggle_sidebar_label=Toggle Sidebaur +document_outline.title=Kythe Document Ootline (double-click fur tae oot-fauld/in-fauld aw items) +document_outline_label=Document Ootline +attachments.title=Kythe Attachments +attachments_label=Attachments +layers.title=Kythe Layers (double-click fur tae reset aw layers tae the staunart state) +layers_label=Layers +thumbs.title=Kythe Thumbnails +thumbs_label=Thumbnails +current_outline_item.title=Find Current Ootline Item +current_outline_item_label=Current Ootline Item +findbar.title=Find in Document +findbar_label=Find + +additional_layers=Mair Layers +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Page {{page}} +# Thumbnails panel item (tooltip and alt text for images) +# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page +# number. +thumb_page_title=Page {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Thumbnail o Page {{page}} + +# Find panel button title and messages +find_input.title=Find +find_input.placeholder=Find in document… +find_previous.title=Airt oot the last time this phrase occurred +find_previous_label=Previous +find_next.title=Airt oot the neist time this phrase occurs +find_next_label=Neist +find_highlight=Highlicht aw +find_match_case_label=Match case +find_entire_word_label=Hale Wirds +find_reached_top=Raxed tap o document, went on fae the dowp end +find_reached_bottom=Raxed end o document, went on fae the tap +# LOCALIZATION NOTE (find_match_count): The supported plural forms are +# [one|two|few|many|other], with [other] as the default value. +# "{{current}}" and "{{total}}" will be replaced by a number representing the +# index of the currently active find result, respectively a number representing +# the total number of matches in the document. +find_match_count={[ plural(total) ]} +find_match_count[one]={{current}} o {{total}} match +find_match_count[two]={{current}} o {{total}} matches +find_match_count[few]={{current}} o {{total}} matches +find_match_count[many]={{current}} o {{total}} matches +find_match_count[other]={{current}} o {{total}} matches +# LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are +# [zero|one|two|few|many|other], with [other] as the default value. +# "{{limit}}" will be replaced by a numerical value. +find_match_count_limit={[ plural(limit) ]} +find_match_count_limit[zero]=Mair nor {{limit}} matches +find_match_count_limit[one]=Mair nor {{limit}} match +find_match_count_limit[two]=Mair nor {{limit}} matches +find_match_count_limit[few]=Mair nor {{limit}} matches +find_match_count_limit[many]=Mair nor {{limit}} matches +find_match_count_limit[other]=Mair nor {{limit}} matches +find_not_found=Phrase no fund + +# Error panel labels +error_more_info=Mair Information +error_less_info=Less Information +error_close=Sneck +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=PDF.js v{{version}} (build: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Message: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stack: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=File: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Line: {{line}} +rendering_error=A mishanter tuik place while renderin the page. + +# Predefined zoom values +page_scale_width=Page Width +page_scale_fit=Page Fit +page_scale_auto=Automatic Zoom +page_scale_actual=Actual Size +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading=Loadin… +loading_error=An mishanter tuik place while loadin the PDF. +invalid_file_error=No suithfest or camshauchlet PDF file. +missing_file_error=PDF file tint. +unexpected_response_error=Unexpectit server repone. + +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. +annotation_date_string={{date}}, {{time}} + +# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. +# "{{type}}" will be replaced with an annotation type from a list defined in +# the PDF spec (32000-1:2008 Table 169 – Annotation types). +# Some common types are e.g.: "Check", "Text", "Comment", "Note" +text_annotation_type.alt=[{{type}} Annotation] +password_label=Inpit the passwird fur tae open this PDF file. +password_invalid=Passwird no suithfest. Gonnae gie it anither shot. +password_ok=OK +password_cancel=Stap + +printing_not_supported=Tak tent: Prentin isnae richt supportit by this stravaiger. +printing_not_ready=Tak tent: The PDF isnae richt loadit fur prentin. +web_fonts_disabled=Wab fonts are disabled: cannae yaise embeddit PDF fonts. diff --git a/cps/static/locale/si/viewer.properties b/cps/static/locale/si/viewer.properties index 9a1d1e8bc..88e6efb21 100644 --- a/cps/static/locale/si/viewer.properties +++ b/cps/static/locale/si/viewer.properties @@ -13,10 +13,10 @@ # limitations under the License. # Main toolbar buttons (tooltips and alt text for images) -previous.title=මීට පෙර පිටුව -previous_label=පෙර -next.title=මීළඟ පිටුව -next_label=මීළඟ +previous.title=කලින් පිටුව +previous_label=කලින් +next.title=ඊළඟ පිටුව +next_label=ඊළඟ # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. page.title=පිටුව @@ -26,69 +26,61 @@ page.title=පිටුව # will be replaced by a number representing the currently visible page, # respectively a number representing the total number of pages in the document. -zoom_out.title=කුඩා කරන්න -zoom_out_label=කුඩා කරන්න -zoom_in.title=විශාල කරන්න -zoom_in_label=විශාල කරන්න -zoom.title=විශාලණය -presentation_mode.title=ඉදිරිපත්කිරීම් ප්‍රකාරය වෙත මාරුවන්න -presentation_mode_label=ඉදිරිපත්කිරීම් ප්‍රකාරය -open_file.title=ගොනුව විවෘත කරන්න -open_file_label=විවෘත කරන්න +zoom_out.title=කුඩාලනය +zoom_out_label=කුඩාලනය +zoom_in.title=විශාලනය +zoom_in_label=විශාලනය +zoom.title=විශාල කරන්න +presentation_mode.title=සමර්පණ ප්‍රකාරය වෙත මාරුවන්න +presentation_mode_label=සමර්පණ ප්‍රකාරය +open_file.title=ගොනුව අරින්න +open_file_label=අරින්න print.title=මුද්‍රණය print_label=මුද්‍රණය download.title=බාගන්න download_label=බාගන්න -bookmark.title=දැනට ඇති දසුන (පිටපත් කරන්න හෝ නව කවුළුවක විවෘත කරන්න) -bookmark_label=දැනට ඇති දසුන +bookmark.title=වත්මන් දැක්ම (පිටපත් කරන්න හෝ නව කවුළුවක අරින්න) +bookmark_label=වත්මන් දැක්ම # Secondary toolbar and context menu tools.title=මෙවලම් tools_label=මෙවලම් first_page.title=මුල් පිටුවට යන්න -first_page.label=මුල් පිටුවට යන්න first_page_label=මුල් පිටුවට යන්න last_page.title=අවසන් පිටුවට යන්න -last_page.label=අවසන් පිටුවට යන්න last_page_label=අවසන් පිටුවට යන්න -page_rotate_cw.title=දක්ශිණාවර්තව භ්‍රමණය -page_rotate_cw.label=දක්ශිණාවර්තව භ්‍රමණය -page_rotate_cw_label=දක්ශිණාවර්තව භ්‍රමණය -page_rotate_ccw.title=වාමාවර්තව භ්‍රමණය -page_rotate_ccw.label=වාමාවර්තව භ්‍රමණය -page_rotate_ccw_label=වාමාවර්තව භ්‍රමණය cursor_hand_tool_label=අත් මෙවලම # Document properties dialog box -document_properties.title=ලේඛන වත්කම්... -document_properties_label=ලේඛන වත්කම්... -document_properties_file_name=ගොනු නම: -document_properties_file_size=ගොනු ප්‍රමාණය: +document_properties.title=ලේඛනයේ ගුණාංග… +document_properties_label=ලේඛනයේ ගුණාංග… +document_properties_file_name=ගොනුවේ නම: +document_properties_file_size=ගොනුවේ ප්‍රමාණය: # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" # will be replaced by the PDF file size in kilobytes, respectively in bytes. -document_properties_kb={{size_kb}} KB ({{size_b}} බයිට) +document_properties_kb=කි.බ. {{size_kb}} (බයිට {{size_b}}) # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" # will be replaced by the PDF file size in megabytes, respectively in bytes. -document_properties_mb={{size_mb}} MB ({{size_b}} බයිට) -document_properties_title=සිරස්තලය: -document_properties_author=කතෲ +document_properties_mb=මෙ.බ. {{size_mb}} (බයිට {{size_b}}) +document_properties_title=සිරැසිය: +document_properties_author=කතෘ: document_properties_subject=මාතෘකාව: -document_properties_keywords=යතුරු වදන්: -document_properties_creation_date=නිර්මිත දිනය: -document_properties_modification_date=වෙනස්කල දිනය: +document_properties_keywords=මූල පද: +document_properties_creation_date=සෑදූ දිනය: +document_properties_modification_date=සංශෝධිත දිනය: # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" # will be replaced by the creation/modification date, and time, of the PDF file. document_properties_date_string={{date}}, {{time}} -document_properties_creator=නිර්මාපක: -document_properties_producer=PDF නිශ්පාදක: -document_properties_version=PDF නිකුතුව: +document_properties_creator=නිර්මාතෘ: +document_properties_producer=පීඩීඑෆ් සම්පාදක: +document_properties_version=පීඩීඑෆ් අනුවාදය: document_properties_page_count=පිටු ගණන: -document_properties_page_size=පිටුවේ විශාලත්වය: +document_properties_page_size=පිටුවේ තරම: document_properties_page_size_unit_inches=අඟල් -document_properties_page_size_unit_millimeters=මිමි +document_properties_page_size_unit_millimeters=මි.මී. document_properties_page_size_orientation_portrait=සිරස් document_properties_page_size_orientation_landscape=තිරස් document_properties_page_size_name_a3=A3 @@ -103,12 +95,12 @@ document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} document_properties_page_size_dimension_name_string={{width}}×{{height}}{{unit}}{{name}}{{orientation}} # LOCALIZATION NOTE (document_properties_linearized): The linearization status of # the document; usually called "Fast Web View" in English locales of Adobe software. -document_properties_linearized=වේගවත් ජාල දසුන: +document_properties_linearized=වේගවත් වියමන දැක්ම: document_properties_linearized_yes=ඔව් document_properties_linearized_no=නැහැ document_properties_close=වසන්න -print_progress_message=ලේඛනය මුද්‍රණය සඳහා සූදානම් කරමින්… +print_progress_message=මුද්‍රණය සඳහා ලේඛනය සූදානම් වෙමින්… # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by # a numerical per cent value. print_progress_percent={{progress}}% @@ -117,35 +109,33 @@ print_progress_close=අවලංගු කරන්න # Tooltips and alt text for side panel toolbar buttons # (the _label strings are alt text for the buttons, the .title strings are # tooltips) -toggle_sidebar.title=පැති තීරුවට මාරුවන්න -toggle_sidebar_label=පැති තීරුවට මාරුවන්න -document_outline_label=ලේඛනයේ පිට මායිම -attachments.title=ඇමිණුම් පෙන්වන්න -attachments_label=ඇමිණුම් +document_outline_label=ලේඛනයේ වටසන +attachments.title=ඇමුණුම් පෙන්වන්න +attachments_label=ඇමුණුම් thumbs.title=සිඟිති රූ පෙන්වන්න thumbs_label=සිඟිති රූ -findbar.title=ලේඛනය තුළ සොයන්න +findbar.title=ලේඛනයෙහි සොයන්න findbar_label=සොයන්න +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. thumb_page_title=පිටුව {{page}} # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page # number. -thumb_page_canvas=පිටුවෙ සිඟිත රූව {{page}} +thumb_page_canvas=පිටුවේ සිඟිත රූව {{page}} # Find panel button title and messages find_input.title=සොයන්න -find_previous.title=මේ වාක්‍ය ඛණ්ඩය මීට පෙර යෙදුණු ස්ථානය සොයන්න -find_previous_label=පෙර: -find_next.title=මේ වාක්‍ය ඛණ්ඩය මීළඟට යෙදෙන ස්ථානය සොයන්න -find_next_label=මීළඟ +find_previous.title=මෙම වැකිකඩ කලින් යෙදුණු ස්ථානය සොයන්න +find_previous_label=කලින් +find_next.title=මෙම වැකිකඩ ඊළඟට යෙදෙන ස්ථානය සොයන්න +find_next_label=ඊළඟ find_highlight=සියල්ල උද්දීපනය -find_match_case_label=අකුරු ගළපන්න -find_entire_word_label=සම්පූර්ණ වචන -find_reached_top=පිටුවේ ඉහළ කෙළවරට ලගාවිය, පහළ සිට ඉදිරියට යමින් -find_reached_bottom=පිටුවේ පහළ කෙළවරට ලගාවිය, ඉහළ සිට ඉදිරියට යමින් +find_entire_word_label=සමස්ත වචන +find_reached_top=ලේඛනයේ මුදුනට ළඟා විය, පහළ සිට ඉහළට +find_reached_bottom=ලේඛනයේ අවසානයට ළඟා විය, ඉහළ සිට පහළට # LOCALIZATION NOTE (find_match_count): The supported plural forms are # [one|two|few|many|other], with [other] as the default value. # "{{current}}" and "{{total}}" will be replaced by a number representing the @@ -154,54 +144,61 @@ find_reached_bottom=පිටුවේ පහළ කෙළවරට ලගාව # LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are # [zero|one|two|few|many|other], with [other] as the default value. # "{{limit}}" will be replaced by a numerical value. -find_match_count_limit[zero]=ගැලපුම් {{limit}} ට වඩා -find_not_found=ඔබ සෙව් වචන හමු නොවීය +find_match_count_limit[zero]=ගැළපීම් {{limit}} කට වඩා +find_not_found=වැකිකඩ හමු නොවිණි # Error panel labels -error_more_info=බොහෝ තොරතුරු +error_more_info=තව තොරතුරු error_less_info=අවම තොරතුරු error_close=වසන්න # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be # replaced by the PDF.JS version and build ID. -error_version_info=PDF.js v{{version}} (නිකුතුව: {{build}}) +error_version_info=පීඩීඑෆ්.js v{{version}} (තැනීම: {{build}}) # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an # english string describing the error. error_message=පණිවිඩය: {{message}} # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack # trace. -error_stack=Stack: {{stack}} # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename error_file=ගොනුව: {{file}} # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number error_line=පේළිය: {{line}} -rendering_error=පිටුව රෙන්ඩර් විමේදි ගැටලුවක් හට ගැනුණි. # Predefined zoom values page_scale_width=පිටුවේ පළල -page_scale_fit=පිටුවට සුදුසු ලෙස -page_scale_auto=ස්වයංක්‍රීය විශාලණය -page_scale_actual=නියමිත ප්‍රමාණය +page_scale_auto=ස්වයංක්‍රීය විශාලනය +page_scale_actual=සැබෑ ප්‍රමාණය # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a # numerical scale value. page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=දෝෂය -loading_error=PDF පූරණය විමේදි දෝෂයක් හට ගැනුණි. -invalid_file_error=දූශිත හෝ සාවද්‍ය PDF ගොනුව. -missing_file_error=නැතිවූ PDF ගොනුව. -unexpected_response_error=බලාපොරොත්තු නොවූ සේවාදායක ප්‍රතිචාරය. +loading_error=පීඩීඑෆ් පූරණය කිරීමේදී දෝෂයක් සිදු විය. +invalid_file_error=වලංගු නොවන හෝ හානිවූ පීඩීඑෆ් ගොනුවකි. +missing_file_error=මඟහැරුණු පීඩීඑෆ් ගොනුවකි. +unexpected_response_error=අනපේක්‍ෂිත සේවාදායක ප්‍රතිචාරයකි. + +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). # Some common types are e.g.: "Check", "Text", "Comment", "Note" -text_annotation_type.alt=[{{type}} විස්තරය] -password_label=මෙම PDF ගොනුව විවෘත කිරීමට මුරපදය ඇතුළත් කරන්න. -password_invalid=වැරදි මුරපදයක්. කරුණාකර නැවත උත්සහ කරන්න. +password_label=මෙම පීඩීඑෆ් ගොනුව විවෘත කිරීමට මුරපදය යොදන්න. +password_invalid=වැරදි මුරපදයකි. නැවත උත්සාහ කරන්න. password_ok=හරි -password_cancel=එපා +password_cancel=අවලංගු -printing_not_supported=අවවාදයයි: මෙම ගවේශකය මුද්‍රණය සඳහා සම්පූර්ණයෙන් සහය නොදක්වයි. -printing_not_ready=අවවාදයයි: මුද්‍රණය සඳහා PDF සම්පූර්ණයෙන් පූර්ණය වී නොමැත. -web_fonts_disabled=ජාල අකුරු අක්‍රීයයි: තිළැලි PDF අකුරු භාවිත කළ නොහැක. +printing_not_supported=අවවාදයයි: මෙම අතිරික්සුව මුද්‍රණය සඳහා හොඳින් සහාය නොදක්වයි. +printing_not_ready=අවවාදයයි: මුද්‍රණයට පීඩීඑෆ් ගොනුව සම්පූර්ණයෙන් පූරණය වී නැත. +web_fonts_disabled=වියමන අකුරු අබලයි: පීඩීඑෆ් වෙත කාවැද්දූ අකුරු භාවිතා කළ නොහැකිය. + +# Editor + + +# Editor Parameters + +# Editor Parameters + +# Editor aria diff --git a/cps/static/locale/sk/viewer.properties b/cps/static/locale/sk/viewer.properties index d86d77cfa..854496849 100644 --- a/cps/static/locale/sk/viewer.properties +++ b/cps/static/locale/sk/viewer.properties @@ -39,8 +39,8 @@ open_file.title=Otvoriť súbor open_file_label=Otvoriť print.title=Tlačiť print_label=Tlačiť -download.title=Prevziať -download_label=Prevziať +download.title=Stiahnuť +download_label=Stiahnuť bookmark.title=Aktuálne zobrazenie (kopírovať alebo otvoriť v novom okne) bookmark_label=Aktuálne zobrazenie @@ -48,16 +48,12 @@ bookmark_label=Aktuálne zobrazenie tools.title=Nástroje tools_label=Nástroje first_page.title=Prejsť na prvú stranu -first_page.label=Prejsť na prvú stranu first_page_label=Prejsť na prvú stranu last_page.title=Prejsť na poslednú stranu -last_page.label=Prejsť na poslednú stranu last_page_label=Prejsť na poslednú stranu page_rotate_cw.title=Otočiť v smere hodinových ručičiek -page_rotate_cw.label=Otočiť v smere hodinových ručičiek page_rotate_cw_label=Otočiť v smere hodinových ručičiek page_rotate_ccw.title=Otočiť proti smeru hodinových ručičiek -page_rotate_ccw.label=Otočiť proti smeru hodinových ručičiek page_rotate_ccw_label=Otočiť proti smeru hodinových ručičiek cursor_text_select_tool.title=Povoliť výber textu @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Výber textu cursor_hand_tool.title=Povoliť nástroj ruka cursor_hand_tool_label=Nástroj ruka +scroll_page.title=Použiť rolovanie po stránkach +scroll_page_label=Rolovanie po stránkach scroll_vertical.title=Používať zvislé posúvanie scroll_vertical_label=Zvislé posúvanie scroll_horizontal.title=Používať vodorovné posúvanie @@ -137,19 +135,24 @@ print_progress_close=Zrušiť # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Prepnúť bočný panel -toggle_sidebar_notification.title=Prepnúť bočný panel (dokument obsahuje osnovu/prílohy) +toggle_sidebar_notification2.title=Prepnúť bočný panel (dokument obsahuje osnovu/prílohy/vrstvy) toggle_sidebar_label=Prepnúť bočný panel document_outline.title=Zobraziť osnovu dokumentu (dvojitým kliknutím rozbalíte/zbalíte všetky položky) document_outline_label=Osnova dokumentu attachments.title=Zobraziť prílohy attachments_label=Prílohy +layers.title=Zobraziť vrstvy (dvojitým kliknutím uvediete všetky vrstvy do pôvodného stavu) +layers_label=Vrstvy thumbs.title=Zobraziť miniatúry thumbs_label=Miniatúry +current_outline_item.title=Nájsť aktuálnu položku v osnove +current_outline_item_label=Aktuálna položka v osnove findbar.title=Hľadať v dokumente findbar_label=Hľadať -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Strana {{page}} +additional_layers=Ďalšie vrstvy +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Strana {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Vyhľadať ďalší výskyt reťazca find_next_label=Ďalšie find_highlight=Zvýrazniť všetky find_match_case_label=Rozlišovať veľkosť písmen +find_match_diacritics_label=Rozlišovať diakritiku find_entire_word_label=Celé slová find_reached_top=Bol dosiahnutý začiatok stránky, pokračuje sa od konca find_reached_bottom=Bol dosiahnutý koniec stránky, pokračuje sa od začiatku @@ -194,7 +198,7 @@ find_match_count_limit[other]=Viac než {{limit}} výsledkov find_not_found=Výraz nebol nájdený # Error panel labels -error_more_info=Viac informácií +error_more_info=Ďalšie informácie error_less_info=Menej informácií error_close=Zavrieť # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be @@ -222,7 +226,7 @@ page_scale_actual=Skutočná veľkosť page_scale_percent={{scale}} % # Loading indicator messages -loading_error_indicator=Chyba +loading=Načítava sa… loading_error=Počas načítavania dokumentu PDF sa vyskytla chyba. invalid_file_error=Neplatný alebo poškodený súbor PDF. missing_file_error=Chýbajúci súbor PDF. @@ -245,3 +249,33 @@ password_cancel=Zrušiť printing_not_supported=Upozornenie: tlač nie je v tomto prehliadači plne podporovaná. printing_not_ready=Upozornenie: súbor PDF nie je plne načítaný pre tlač. web_fonts_disabled=Webové písma sú vypnuté: nie je možné použiť písma vložené do súboru PDF. + +# Editor +editor_none.title=Zakázať úpravu poznámok +editor_none_label=Zakázať úpravy +editor_free_text.title=Pridať textovú poznámku +editor_free_text_label=Textová poznámka +editor_ink.title=Pridať poznámku písanú rukou +editor_ink_label=Poznámka písaná rukou + +freetext_default_content=Zadajte nejaký text… + +free_text_default_content=Zadajte text… + +# Editor Parameters +editor_free_text_font_color=Farba písma +editor_free_text_font_size=Veľkosť písma +editor_ink_line_color=Farba čiary +editor_ink_line_thickness=Hrúbka čiary + +# Editor Parameters +editor_free_text_color=Farba +editor_free_text_size=Veľkosť +editor_ink_color=Farba +editor_ink_thickness=Hrúbka +editor_ink_opacity=Priehľadnosť + +# Editor aria +editor_free_text_aria_label=Textový editor +editor_ink_aria_label=Editor pre písanie rukou +editor_ink_canvas_aria_label=Obrázok vytvorený používateľom diff --git a/cps/static/locale/sl/viewer.properties b/cps/static/locale/sl/viewer.properties index 25a5e9c50..3b0052ceb 100644 --- a/cps/static/locale/sl/viewer.properties +++ b/cps/static/locale/sl/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Trenutni pogled tools.title=Orodja tools_label=Orodja first_page.title=Pojdi na prvo stran -first_page.label=Pojdi na prvo stran first_page_label=Pojdi na prvo stran last_page.title=Pojdi na zadnjo stran -last_page.label=Pojdi na zadnjo stran last_page_label=Pojdi na zadnjo stran page_rotate_cw.title=Zavrti v smeri urnega kazalca -page_rotate_cw.label=Zavrti v smeri urnega kazalca page_rotate_cw_label=Zavrti v smeri urnega kazalca page_rotate_ccw.title=Zavrti v nasprotni smeri urnega kazalca -page_rotate_ccw.label=Zavrti v nasprotni smeri urnega kazalca page_rotate_ccw_label=Zavrti v nasprotni smeri urnega kazalca cursor_text_select_tool.title=Omogoči orodje za izbor besedila @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Orodje za izbor besedila cursor_hand_tool.title=Omogoči roko cursor_hand_tool_label=Roka +scroll_page.title=Uporabi drsenje po strani +scroll_page_label=Drsenje po strani scroll_vertical.title=Uporabi navpično drsenje scroll_vertical_label=Navpično drsenje scroll_horizontal.title=Uporabi vodoravno drsenje @@ -137,19 +135,24 @@ print_progress_close=Prekliči # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Preklopi stransko vrstico -toggle_sidebar_notification.title=Preklopi stransko vrstico (dokument vsebuje oris/priponke) +toggle_sidebar_notification2.title=Preklopi stransko vrstico (dokument vsebuje oris/priponke/plasti) toggle_sidebar_label=Preklopi stransko vrstico document_outline.title=Prikaži oris dokumenta (dvokliknite za razširitev/strnitev vseh predmetov) document_outline_label=Oris dokumenta attachments.title=Prikaži priponke attachments_label=Priponke +layers.title=Prikaži plasti (dvokliknite za ponastavitev vseh plasti na privzeto stanje) +layers_label=Plasti thumbs.title=Prikaži sličice thumbs_label=Sličice +current_outline_item.title=Najdi trenutni predmet orisa +current_outline_item_label=Trenutni predmet orisa findbar.title=Iskanje po dokumentu findbar_label=Najdi -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Stran {{page}} +additional_layers=Dodatne plasti +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Stran {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Najdi naslednjo ponovitev iskanega find_next_label=Najdi naprej find_highlight=Označi vse find_match_case_label=Razlikuj velike/male črke +find_match_diacritics_label=Razlikuj diakritične znake find_entire_word_label=Cele besede find_reached_top=Dosežen začetek dokumenta iz smeri konca find_reached_bottom=Doseženo konec dokumenta iz smeri začetka @@ -222,7 +226,7 @@ page_scale_actual=Dejanska velikost page_scale_percent={{scale}} % # Loading indicator messages -loading_error_indicator=Napaka +loading=Nalaganje … loading_error=Med nalaganjem datoteke PDF je prišlo do napake. invalid_file_error=Neveljavna ali pokvarjena datoteka PDF. missing_file_error=Ni datoteke PDF. @@ -245,3 +249,33 @@ password_cancel=Prekliči printing_not_supported=Opozorilo: ta brskalnik ne podpira vseh možnosti tiskanja. printing_not_ready=Opozorilo: PDF ni v celoti naložen za tiskanje. web_fonts_disabled=Spletne pisave so onemogočene: vgradnih pisav za PDF ni mogoče uporabiti. + +# Editor +editor_none.title=Onemogoči urejanje pripomb +editor_none_label=Onemogoči urejanje +editor_free_text.title=Dodaj opombo FreeText +editor_free_text_label=Opomba FreeText +editor_ink.title=Dodaj opombo z rokopisom +editor_ink_label=Opomba z rokopisom + +freetext_default_content=Vnesite besedilo … + +free_text_default_content=Vnesite besedilo … + +# Editor Parameters +editor_free_text_font_color=Barva pisave +editor_free_text_font_size=Velikost pisave +editor_ink_line_color=Barva črte +editor_ink_line_thickness=Debelina črte + +# Editor Parameters +editor_free_text_color=Barva +editor_free_text_size=Velikost +editor_ink_color=Barva +editor_ink_thickness=Debelina +editor_ink_opacity=Neprosojnost + +# Editor aria +editor_free_text_aria_label=Urejevalnik FreeText +editor_ink_aria_label=Urejevalnik s črnilom +editor_ink_canvas_aria_label=Uporabnikova slika diff --git a/cps/static/locale/son/viewer.properties b/cps/static/locale/son/viewer.properties index 683ed14d4..bd5e5ac7e 100644 --- a/cps/static/locale/son/viewer.properties +++ b/cps/static/locale/son/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Sohõ gunaroo tools.title=Goyjinawey tools_label=Goyjinawey first_page.title=Koy moo jinaa ga -first_page.label=Koy moo jinaa ga first_page_label=Koy moo jinaa ga last_page.title=Koy moo koraa ga -last_page.label=Koy moo koraa ga last_page_label=Koy moo koraa ga page_rotate_cw.title=Kuubi kanbe guma here -page_rotate_cw.label=Kuubi kanbe guma here page_rotate_cw_label=Kuubi kanbe guma here page_rotate_ccw.title=Kuubi kanbe wowa here -page_rotate_ccw.label=Kuubi kanbe wowa here page_rotate_ccw_label=Kuubi kanbe wowa here @@ -97,7 +93,6 @@ print_progress_close=Naŋ # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Kanjari ceraw zuu -toggle_sidebar_notification.title=Kanjari ceraw-zuu (takaddaa goo nda filla-boŋ/hangandiyaŋ) toggle_sidebar_label=Kanjari ceraw zuu document_outline.title=Takaddaa korfur alhaaloo cebe (naagu cee hinka ka haya-izey kul hayandi/kankamandi) document_outline_label=Takadda filla-boŋ @@ -157,8 +152,6 @@ page_scale_actual=Adadu cimi # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Firka loading_error=Firka bangay kaŋ PDF goo ma zumandi. invalid_file_error=PDF tuku laala wala laybante. missing_file_error=PDF tuku kumante. diff --git a/cps/static/locale/sq/viewer.properties b/cps/static/locale/sq/viewer.properties index f0710af5f..3ff4e4d24 100644 --- a/cps/static/locale/sq/viewer.properties +++ b/cps/static/locale/sq/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Pamja e Tanishme tools.title=Mjete tools_label=Mjete first_page.title=Kaloni te Faqja e Parë -first_page.label=Kaloni te Faqja e Parë first_page_label=Kaloni te Faqja e Parë last_page.title=Kaloni te Faqja e Fundit -last_page.label=Kaloni te Faqja e Fundit last_page_label=Kaloni te Faqja e Fundit page_rotate_cw.title=Rrotullojeni Në Kahun Orar -page_rotate_cw.label=Rrotulloje Në Kahun Orar page_rotate_cw_label=Rrotulloje Në Kahun Orar page_rotate_ccw.title=Rrotullojeni Në Kahun Kundërorar -page_rotate_ccw.label=Rrotulloje Në Kahun Kundërorar page_rotate_ccw_label=Rrotulloje Në Kahun Kundërorar cursor_text_select_tool.title=Aktivizo Mjet Përzgjedhjeje Teksti @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Mjet Përzgjedhjeje Teksti cursor_hand_tool.title=Aktivizo Mjetin Dorë cursor_hand_tool_label=Mjeti Dorë +scroll_page.title=Përdor Rrëshqitje Në Faqe +scroll_page_label=Rrëshqitje Në Faqe scroll_vertical.title=Përdor Rrëshqitje Vertikale scroll_vertical_label=Rrëshqitje Vertikale scroll_horizontal.title=Përdor Rrëshqitje Horizontale @@ -116,6 +114,7 @@ document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) # LOCALIZATION NOTE (document_properties_linearized): The linearization status of # the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized=Parje e Shpjetë në Web: document_properties_linearized_yes=Po document_properties_linearized_no=Jo document_properties_close=Mbylleni @@ -130,19 +129,24 @@ print_progress_close=Anuloje # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Shfaqni/Fshihni Anështyllën -toggle_sidebar_notification.title=Shfaqni Anështyllën (dokumenti përmban përvijim/bashkëngjitje) +toggle_sidebar_notification2.title=Hap/Mbyll Anështylë (dokumenti përmban përvijim/nashkëngjitje/shtresa) toggle_sidebar_label=Shfaq/Fshih Anështyllën document_outline.title=Shfaqni Përvijim Dokumenti (dyklikoni që të shfaqen/fshihen krejt elementët) document_outline_label=Përvijim Dokumenti attachments.title=Shfaqni Bashkëngjitje attachments_label=Bashkëngjitje +layers.title=Shfaq Shtresa (dyklikoni që të rikthehen krejt shtresat në gjendjen e tyre parazgjedhje) +layers_label=Shtresa thumbs.title=Shfaqni Miniatura thumbs_label=Miniatura +current_outline_item.title=Gjej Objektin e Tanishëm të Përvijuar +current_outline_item_label=Objekt i Tanishëm i Përvijuar findbar.title=Gjeni në Dokument findbar_label=Gjej -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Faqja {{page}} +additional_layers=Shtresa Shtesë +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Faqja {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -215,7 +219,7 @@ page_scale_actual=Madhësia Faktike page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Gabim +loading=Po ngarkohet… loading_error=Ndodhi një gabim gjatë ngarkimit të PDF-së. invalid_file_error=Kartelë PDF e pavlefshme ose e dëmtuar. missing_file_error=Kartelë PDF që mungon. diff --git a/cps/static/locale/sr/viewer.properties b/cps/static/locale/sr/viewer.properties index 8c4e92411..3f38aebd0 100644 --- a/cps/static/locale/sr/viewer.properties +++ b/cps/static/locale/sr/viewer.properties @@ -41,23 +41,19 @@ print.title=Штампај print_label=Штампај download.title=Преузми download_label=Преузми -bookmark.title=Тренутни приказ (копирај или отвори нови прозор) +bookmark.title=Тренутни приказ (копирај или отвори у новом прозору) bookmark_label=Тренутни приказ # Secondary toolbar and context menu tools.title=Алатке tools_label=Алатке first_page.title=Иди на прву страницу -first_page.label=Иди на прву страницу first_page_label=Иди на прву страницу last_page.title=Иди на последњу страницу -last_page.label=Иди на последњу страницу last_page_label=Иди на последњу страницу page_rotate_cw.title=Ротирај у смеру казаљке на сату -page_rotate_cw.label=Ротирај у смеру казаљке на сату page_rotate_cw_label=Ротирај у смеру казаљке на сату page_rotate_ccw.title=Ротирај у смеру супротном од казаљке на сату -page_rotate_ccw.label=Ротирај у смеру супротном од казаљке на сату page_rotate_ccw_label=Ротирај у смеру супротном од казаљке на сату cursor_text_select_tool.title=Омогући алат за селектовање текста @@ -137,19 +133,24 @@ print_progress_close=Откажи # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Прикажи додатну палету -toggle_sidebar_notification.title=Прикажи додатну траку (докуменат садржи оквире/прилоге) +toggle_sidebar_notification2.title=Прикажи/сакриј бочну траку (документ садржи контуру/прилоге/слојеве) toggle_sidebar_label=Прикажи додатну палету -document_outline.title=Прикажи контуру документа (дупли клик за проширење/скупљање елемената) +document_outline.title=Прикажи структуру документа (двоструким кликом проширујете/скупљате све ставке) document_outline_label=Контура документа attachments.title=Прикажи прилоге attachments_label=Прилози +layers.title=Прикажи слојеве (дупли клик за враћање свих слојева у подразумевано стање) +layers_label=Слојеви thumbs.title=Прикажи сличице thumbs_label=Сличице +current_outline_item.title=Пронађите тренутни елемент структуре +current_outline_item_label=Тренутна контура findbar.title=Пронађи у документу findbar_label=Пронађи -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Страница {{page}} +additional_layers=Додатни слојеви +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Страница {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -161,9 +162,9 @@ thumb_page_canvas=Сличица од странице {{page}} # Find panel button title and messages find_input.title=Пронађи find_input.placeholder=Пронађи у документу… -find_previous.title=Пронађи претходну појаву фразе +find_previous.title=Пронађи претходно појављивање фразе find_previous_label=Претходна -find_next.title=Пронађи следећу појаву фразе +find_next.title=Пронађи следеће појављивање фразе find_next_label=Следећа find_highlight=Истакнути све find_match_case_label=Подударања @@ -222,10 +223,10 @@ page_scale_actual=Стварна величина page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Грешка +loading=Учитавање… loading_error=Дошло је до грешке приликом учитавања PDF-а. -invalid_file_error=PDF датотека је оштећена или је неисправна. -missing_file_error=PDF датотека није пронађена. +invalid_file_error=PDF датотека је неважећа или је оштећена. +missing_file_error=Недостаје PDF датотека. unexpected_response_error=Неочекиван одговор од сервера. # LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be @@ -245,3 +246,10 @@ password_cancel=Откажи printing_not_supported=Упозорење: Штампање није у потпуности подржано у овом прегледачу. printing_not_ready=Упозорење: PDF није у потпуности учитан за штампу. web_fonts_disabled=Веб фонтови су онемогућени: не могу користити уграђене PDF фонтове. + +# Editor + + + +# Editor Parameters +editor_free_text_font_size=Величина фонта diff --git a/cps/static/locale/sv-SE/viewer.properties b/cps/static/locale/sv-SE/viewer.properties index 7c75281c3..94c077434 100644 --- a/cps/static/locale/sv-SE/viewer.properties +++ b/cps/static/locale/sv-SE/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Aktuell vy tools.title=Verktyg tools_label=Verktyg first_page.title=Gå till första sidan -first_page.label=Gå till första sidan first_page_label=Gå till första sidan last_page.title=Gå till sista sidan -last_page.label=Gå till sista sidan last_page_label=Gå till sista sidan page_rotate_cw.title=Rotera medurs -page_rotate_cw.label=Rotera medurs page_rotate_cw_label=Rotera medurs page_rotate_ccw.title=Rotera moturs -page_rotate_ccw.label=Rotera moturs page_rotate_ccw_label=Rotera moturs cursor_text_select_tool.title=Aktivera textmarkeringsverktyg @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Textmarkeringsverktyg cursor_hand_tool.title=Aktivera handverktyg cursor_hand_tool_label=Handverktyg +scroll_page.title=Använd sidrullning +scroll_page_label=Sidrullning scroll_vertical.title=Använd vertikal rullning scroll_vertical_label=Vertikal rullning scroll_horizontal.title=Använd horisontell rullning @@ -137,22 +135,24 @@ print_progress_close=Avbryt # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Visa/dölj sidofält -toggle_sidebar_notification2.title=Visa/dölj sidofält (dokument innehåller översikt/bilagor/lager) +toggle_sidebar_notification2.title=Växla sidofält (dokumentet innehåller dokumentstruktur/bilagor/lager) toggle_sidebar_label=Visa/dölj sidofält document_outline.title=Visa dokumentdisposition (dubbelklicka för att expandera/komprimera alla objekt) document_outline_label=Dokumentöversikt attachments.title=Visa Bilagor attachments_label=Bilagor -layers.title=Visa lager (dubbelklicka för att återställa alla lager till ursrungligt läge) +layers.title=Visa lager (dubbelklicka för att återställa alla lager till standardläge) layers_label=Lager thumbs.title=Visa miniatyrer thumbs_label=Miniatyrer +current_outline_item.title=Hitta aktuellt dispositionsobjekt +current_outline_item_label=Aktuellt dispositionsobjekt findbar.title=Sök i dokument findbar_label=Sök additional_layers=Ytterligare lager -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Sida {{page}} +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Sida {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -170,6 +170,7 @@ find_next.title=Hitta nästa förekomst av frasen find_next_label=Nästa find_highlight=Markera alla find_match_case_label=Matcha versal/gemen +find_match_diacritics_label=Matcha diakritiska tecken find_entire_word_label=Hela ord find_reached_top=Nådde början av dokumentet, började från slutet find_reached_bottom=Nådde slutet på dokumentet, började från början @@ -225,7 +226,7 @@ page_scale_actual=Verklig storlek page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Fel +loading=Laddar… loading_error=Ett fel uppstod vid laddning av PDF-filen. invalid_file_error=Ogiltig eller korrupt PDF-fil. missing_file_error=Saknad PDF-fil. @@ -248,3 +249,33 @@ password_cancel=Avbryt printing_not_supported=Varning: Utskrifter stöds inte helt av den här webbläsaren. printing_not_ready=Varning: PDF:en är inte klar för utskrift. web_fonts_disabled=Webbtypsnitt är inaktiverade: kan inte använda inbäddade PDF-typsnitt. + +# Editor +editor_none.title=Inaktivera redigering av anteckningar +editor_none_label=Inaktivera redigering +editor_free_text.title=Lägg till FreeText-kommentar +editor_free_text_label=FreeText-kommentar +editor_ink.title=Lägg till bläckanteckning +editor_ink_label=Bläckanteckning + +freetext_default_content=Skriv in lite text… + +free_text_default_content=Ange text… + +# Editor Parameters +editor_free_text_font_color=Textfärg +editor_free_text_font_size=Textstorlek +editor_ink_line_color=Linjefärg +editor_ink_line_thickness=Linjetjocklek + +# Editor Parameters +editor_free_text_color=Färg +editor_free_text_size=Storlek +editor_ink_color=Färg +editor_ink_thickness=Tjocklek +editor_ink_opacity=Opacitet + +# Editor aria +editor_free_text_aria_label=FreeText-redigerare +editor_ink_aria_label=Ink-redigerare +editor_ink_canvas_aria_label=Användarskapad bild diff --git a/cps/static/locale/szl/viewer.properties b/cps/static/locale/szl/viewer.properties index 282c59509..6706afc34 100644 --- a/cps/static/locale/szl/viewer.properties +++ b/cps/static/locale/szl/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Aktualny widok tools.title=Noczynia tools_label=Noczynia first_page.title=Idź ku piyrszyj strōnie -first_page.label=Idź ku piyrszyj strōnie first_page_label=Idź ku piyrszyj strōnie last_page.title=Idź ku ôstatnij strōnie -last_page.label=Idź ku ôstatnij strōnie last_page_label=Idź ku ôstatnij strōnie page_rotate_cw.title=Zwyrtnij w prawo -page_rotate_cw.label=Zwyrtnij w prawo page_rotate_cw_label=Zwyrtnij w prawo page_rotate_ccw.title=Zwyrtnij w lewo -page_rotate_ccw.label=Zwyrtnij w lewo page_rotate_ccw_label=Zwyrtnij w lewo cursor_text_select_tool.title=Załōncz noczynie ôbiyranio tekstu @@ -74,10 +70,10 @@ scroll_wrapped_label=Szichtowe przewijanie spread_none.title=Niy dowej strōn w widoku po dwie spread_none_label=Po jednyj strōnie -spread_odd.title=Dej strōny po dwie: niyparzysto i parzysto -spread_odd_label=Niyparzysto i parzysto -spread_even.title=Dej strōny po dwie: parzysto i niyparzysto -spread_even_label=Parzysto i niyparzysto +spread_odd.title=Pokoż strōny po dwie; niyporziste po lewyj +spread_odd_label=Niyporziste po lewyj +spread_even.title=Pokoż strōny po dwie; porziste po lewyj +spread_even_label=Porziste po lewyj # Document properties dialog box document_properties.title=Włosności dokumyntu… @@ -137,19 +133,21 @@ print_progress_close=Pociep # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Przełōncz posek na rancie -toggle_sidebar_notification.title=Przełōncz posek na rancie (dokumynt mo struktura/przidowki) +toggle_sidebar_notification2.title=Przełōncz posek na rancie (dokumynt mo struktura/przidowki/warstwy) toggle_sidebar_label=Przełōncz posek na rancie -document_outline.title=Pokoż struktura dokumyntu (tuplowane klikniyncie rozszyrzo/swijo wszyskie elymynty) +document_outline.title=Pokoż struktura dokumyntu (tuplowane klikniyncie rozszyrzo/swijo wszyskie elymynta) document_outline_label=Struktura dokumyntu attachments.title=Pokoż przidowki attachments_label=Przidowki +layers.title=Pokoż warstwy (tuplowane klikniyncie resetuje wszyskie warstwy do bazowego stanu) +layers_label=Warstwy thumbs.title=Pokoż miniatury thumbs_label=Miniatury findbar.title=Znojdź w dokumyncie findbar_label=Znojdź -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Strōna {{page}} +additional_layers=Nadbytnie warstwy +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -165,7 +163,7 @@ find_previous.title=Znojdź piyrwyjsze pokozanie sie tyj frazy find_previous_label=Piyrwyjszo find_next.title=Znojdź nastympne pokozanie sie tyj frazy find_next_label=Dalij -find_highlight=Ôbznocz wszysko +find_highlight=Zaznacz wszysko find_match_case_label=Poznowej srogość liter find_entire_word_label=Cołke słowa find_reached_top=Doszło do samego wiyrchu strōny, dalij ôd spodku @@ -191,7 +189,7 @@ find_match_count_limit[two]=Wiyncyj jak {{limit}}, co pasujōm find_match_count_limit[few]=Wiyncyj jak {{limit}}, co pasujōm find_match_count_limit[many]=Wiyncyj jak {{limit}}, co pasujōm find_match_count_limit[other]=Wiyncyj jak {{limit}}, co pasujōm -find_not_found=Fraza niy ma znodniynto +find_not_found=Fraza niy znaleziōno # Error panel labels error_more_info=Wiyncyj informacyji @@ -222,7 +220,6 @@ page_scale_actual=Aktualno srogość page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Feler loading_error=Przi ladowaniu PDFa pokozoł sie feler. invalid_file_error=Zły abo felerny zbiōr PDF. missing_file_error=Chybio zbioru PDF. diff --git a/cps/static/locale/ta/viewer.properties b/cps/static/locale/ta/viewer.properties index 669ba0c56..d07a337d0 100644 --- a/cps/static/locale/ta/viewer.properties +++ b/cps/static/locale/ta/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=தற்போதைய காட்சி tools.title=கருவிகள் tools_label=கருவிகள் first_page.title=முதல் பக்கத்திற்கு செல்லவும் -first_page.label=முதல் பக்கத்திற்கு செல்லவும் first_page_label=முதல் பக்கத்திற்கு செல்லவும் last_page.title=கடைசி பக்கத்திற்கு செல்லவும் -last_page.label=கடைசி பக்கத்திற்கு செல்லவும் last_page_label=கடைசி பக்கத்திற்கு செல்லவும் page_rotate_cw.title=வலஞ்சுழியாக சுழற்று -page_rotate_cw.label=வலஞ்சுழியாக சுழற்று page_rotate_cw_label=வலஞ்சுழியாக சுழற்று page_rotate_ccw.title=இடஞ்சுழியாக சுழற்று -page_rotate_ccw.label=இடஞ்சுழியாக சுழற்று page_rotate_ccw_label=இடஞ்சுழியாக சுழற்று cursor_text_select_tool.title=உரைத் தெரிவு கருவியைச் செயல்படுத்து @@ -118,7 +114,6 @@ print_progress_close=ரத்து # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=பக்கப் பட்டியை நிலைமாற்று -toggle_sidebar_notification.title=பக்கப்பட்டையை நிலைமாற்று (வெளிக்கோடு/இணைப்புகளை ஆவணம் கொண்டுள்ளது) toggle_sidebar_label=பக்கப் பட்டியை நிலைமாற்று document_outline.title=ஆவண அடக்கத்தைக் காட்டு (இருமுறைச் சொடுக்கி அனைத்து உறுப்பிடிகளையும் விரி/சேர்) document_outline_label=ஆவண வெளிவரை @@ -178,8 +173,6 @@ page_scale_actual=உண்மையான அளவு # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=பிழை loading_error=PDF ஐ ஏற்றும் போது ஒரு பிழை ஏற்பட்டது. invalid_file_error=செல்லுபடியாகாத அல்லது சிதைந்த PDF கோப்பு. missing_file_error=PDF கோப்பு காணவில்லை. diff --git a/cps/static/locale/te/viewer.properties b/cps/static/locale/te/viewer.properties index 498b64c8d..6cd691a01 100644 --- a/cps/static/locale/te/viewer.properties +++ b/cps/static/locale/te/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=ప్రస్తుత దర్శనం tools.title=పనిముట్లు tools_label=పనిముట్లు first_page.title=మొదటి పేజీకి వెళ్ళు -first_page.label=మొదటి పేజీకి వెళ్ళు first_page_label=మొదటి పేజీకి వెళ్ళు last_page.title=చివరి పేజీకి వెళ్ళు -last_page.label=చివరి పేజీకి వెళ్ళు last_page_label=చివరి పేజీకి వెళ్ళు page_rotate_cw.title=సవ్యదిశలో తిప్పు -page_rotate_cw.label=సవ్యదిశలో తిప్పు page_rotate_cw_label=సవ్యదిశలో తిప్పు page_rotate_ccw.title=అపసవ్యదిశలో తిప్పు -page_rotate_ccw.label=అపసవ్యదిశలో తిప్పు page_rotate_ccw_label=అపసవ్యదిశలో తిప్పు cursor_text_select_tool.title=టెక్స్ట్ ఎంపిక సాధనాన్ని ప్రారంభించండి @@ -130,11 +126,13 @@ document_outline.title=పత్రము రూపము చూపించు document_outline_label=పత్రము అవుట్‌లైన్ attachments.title=అనుబంధాలు చూపు attachments_label=అనుబంధాలు +layers_label=పొరలు thumbs.title=థంబ్‌నైల్స్ చూపు thumbs_label=థంబ్‌నైల్స్ findbar.title=పత్రములో కనుగొనుము findbar_label=కనుగొను +additional_layers=అదనపు పొరలు # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -195,8 +193,6 @@ page_scale_actual=యథార్ధ పరిమాణం # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=దోషం loading_error=PDF లోడవుచున్నప్పుడు ఒక దోషం ఎదురైంది. invalid_file_error=చెల్లని లేదా పాడైన PDF ఫైలు. missing_file_error=దొరకని PDF ఫైలు. diff --git a/cps/static/locale/tg/viewer.properties b/cps/static/locale/tg/viewer.properties new file mode 100644 index 000000000..cac204774 --- /dev/null +++ b/cps/static/locale/tg/viewer.properties @@ -0,0 +1,281 @@ +# Copyright 2012 Mozilla Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Main toolbar buttons (tooltips and alt text for images) +previous.title=Саҳифаи қаблӣ +previous_label=Қаблӣ +next.title=Саҳифаи навбатӣ +next_label=Навбатӣ + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Саҳифа +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=аз {{pagesCount}} +# LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" +# will be replaced by a number representing the currently visible page, +# respectively a number representing the total number of pages in the document. +page_of_pages=({{pageNumber}} аз {{pagesCount}}) + +zoom_out.title=Хурд кардан +zoom_out_label=Хурд кардан +zoom_in.title=Калон кардан +zoom_in_label=Калон кардан +zoom.title=Танзими андоза +presentation_mode.title=Гузариш ба реҷаи тақдим +presentation_mode_label=Реҷаи тақдим +open_file.title=Кушодани файл +open_file_label=Кушодан +print.title=Чоп кардан +print_label=Чоп кардан +download.title=Боргирӣ кардан +download_label=Боргирӣ кардан +bookmark.title=Намуди ҷорӣ (нусха бардоштан ё кушодан дар равзанаи нав) +bookmark_label=Намуди ҷорӣ + +# Secondary toolbar and context menu +tools.title=Абзорҳо +tools_label=Абзорҳо +first_page.title=Ба саҳифаи аввал гузаред +first_page_label=Ба саҳифаи аввал гузаред +last_page.title=Ба саҳифаи охирин гузаред +last_page_label=Ба саҳифаи охирин гузаред +page_rotate_cw.title=Ба самти ҳаракати ақрабаки соат давр задан +page_rotate_cw_label=Ба самти ҳаракати ақрабаки соат давр задан +page_rotate_ccw.title=Ба муқобили самти ҳаракати ақрабаки соат давр задан +page_rotate_ccw_label=Ба муқобили самти ҳаракати ақрабаки соат давр задан + +cursor_text_select_tool.title=Фаъол кардани «Абзори интихоби матн» +cursor_text_select_tool_label=Абзори интихоби матн +cursor_hand_tool.title=Фаъол кардани «Абзори даст» +cursor_hand_tool_label=Абзори даст + +scroll_page.title=Истифодаи варақзанӣ +scroll_page_label=Варақзанӣ +scroll_vertical.title=Истифодаи варақзании амудӣ +scroll_vertical_label=Варақзании амудӣ +scroll_horizontal.title=Истифодаи варақзании уфуқӣ +scroll_horizontal_label=Варақзании уфуқӣ +scroll_wrapped.title=Истифодаи варақзании миқёсбандӣ +scroll_wrapped_label=Варақзании миқёсбандӣ + +spread_none.title=Густариши саҳифаҳо истифода бурда нашавад +spread_none_label=Бе густурдани саҳифаҳо +spread_odd.title=Густариши саҳифаҳо аз саҳифаҳо бо рақамҳои тоқ оғоз карда мешавад +spread_odd_label=Саҳифаҳои тоқ аз тарафи чап +spread_even.title=Густариши саҳифаҳо аз саҳифаҳо бо рақамҳои ҷуфт оғоз карда мешавад +spread_even_label=Саҳифаҳои ҷуфт аз тарафи чап + +# Document properties dialog box +document_properties.title=Хусусиятҳои ҳуҷҷат… +document_properties_label=Хусусиятҳои ҳуҷҷат… +document_properties_file_name=Номи файл: +document_properties_file_size=Андозаи файл: +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in bytes. +document_properties_kb={{size_kb}} КБ ({{size_b}} байт) +# LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" +# will be replaced by the PDF file size in megabytes, respectively in bytes. +document_properties_mb={{size_mb}} МБ ({{size_b}} байт) +document_properties_title=Сарлавҳа: +document_properties_author=Муаллиф: +document_properties_subject=Мавзуъ: +document_properties_keywords=Калимаҳои калидӣ: +document_properties_creation_date=Санаи эҷод: +document_properties_modification_date=Санаи тағйирот: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. +document_properties_date_string={{date}}, {{time}} +document_properties_creator=Эҷодкунанда: +document_properties_producer=Таҳиякунандаи PDF: +document_properties_version=Версияи PDF: +document_properties_page_count=Шумораи саҳифаҳо: +document_properties_page_size=Андозаи саҳифа: +document_properties_page_size_unit_inches=дюйм +document_properties_page_size_unit_millimeters=мм +document_properties_page_size_orientation_portrait=амудӣ +document_properties_page_size_orientation_landscape=уфуқӣ +document_properties_page_size_name_a3=A3 +document_properties_page_size_name_a4=A4 +document_properties_page_size_name_letter=Мактуб +document_properties_page_size_name_legal=Ҳуқуқӣ +# LOCALIZATION NOTE (document_properties_page_size_dimension_string): +# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement and orientation, of the (current) page. +document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} ({{orientation}}) +# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): +# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by +# the size, respectively their unit of measurement, name, and orientation, of the (current) page. +document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) +# LOCALIZATION NOTE (document_properties_linearized): The linearization status of +# the document; usually called "Fast Web View" in English locales of Adobe software. +document_properties_linearized=Намоиши тез дар Интернет: +document_properties_linearized_yes=Ҳа +document_properties_linearized_no=Не +document_properties_close=Пӯшидан + +print_progress_message=Омодасозии ҳуҷҷат барои чоп… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Бекор кардан + +# Tooltips and alt text for side panel toolbar buttons +# (the _label strings are alt text for the buttons, the .title strings are +# tooltips) +toggle_sidebar.title=Фаъол кардани навори ҷонибӣ +toggle_sidebar_notification2.title=Фаъол кардани навори ҷонибӣ (ҳуҷҷат дорои сохтор/замимаҳо/қабатҳо мебошад) +toggle_sidebar_label=Фаъол кардани навори ҷонибӣ +document_outline.title=Намоиш додани сохтори ҳуҷҷат (барои баркушодан/пеҷондани ҳамаи унсурҳо дубора зер кунед) +document_outline_label=Сохтори ҳуҷҷат +attachments.title=Намоиш додани замимаҳо +attachments_label=Замимаҳо +layers.title=Намоиш додани қабатҳо (барои барқарор кардани ҳамаи қабатҳо ба вазъияти пешфарз дубора зер кунед) +layers_label=Қабатҳо +thumbs.title=Намоиш додани тасвирчаҳо +thumbs_label=Тасвирчаҳо +current_outline_item.title=Ёфтани унсури сохтори ҷорӣ +current_outline_item_label=Унсури сохтори ҷорӣ +findbar.title=Ёфтан дар ҳуҷҷат +findbar_label=Ёфтан + +additional_layers=Қабатҳои иловагӣ +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Саҳифаи {{page}} +# Thumbnails panel item (tooltip and alt text for images) +# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page +# number. +thumb_page_title=Саҳифаи {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Тасвирчаи саҳифаи {{page}} + +# Find panel button title and messages +find_input.title=Ёфтан +find_input.placeholder=Ёфтан дар ҳуҷҷат… +find_previous.title=Ҷустуҷӯи мавриди қаблии ибораи пешниҳодшуда +find_previous_label=Қаблӣ +find_next.title=Ҷустуҷӯи мавриди навбатии ибораи пешниҳодшуда +find_next_label=Навбатӣ +find_highlight=Ҳамаашро бо ранг ҷудо кардан +find_match_case_label=Бо дарназардошти ҳарфҳои хурду калон +find_match_diacritics_label=Бо дарназардошти аломатҳои диакритикӣ +find_entire_word_label=Калимаҳои пурра +find_reached_top=Ба болои ҳуҷҷат расид, аз поён идома ёфт +find_reached_bottom=Ба поёни ҳуҷҷат расид, аз боло идома ёфт +# LOCALIZATION NOTE (find_match_count): The supported plural forms are +# [one|two|few|many|other], with [other] as the default value. +# "{{current}}" and "{{total}}" will be replaced by a number representing the +# index of the currently active find result, respectively a number representing +# the total number of matches in the document. +find_match_count={[ plural(total) ]} +find_match_count[one]={{current}} аз {{total}} мувофиқат +find_match_count[two]={{current}} аз {{total}} мувофиқат +find_match_count[few]={{current}} аз {{total}} мувофиқат +find_match_count[many]={{current}} аз {{total}} мувофиқат +find_match_count[other]={{current}} аз {{total}} мувофиқат +# LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are +# [zero|one|two|few|many|other], with [other] as the default value. +# "{{limit}}" will be replaced by a numerical value. +find_match_count_limit={[ plural(limit) ]} +find_match_count_limit[zero]=Зиёда аз {{limit}} мувофиқат +find_match_count_limit[one]=Зиёда аз {{limit}} мувофиқат +find_match_count_limit[two]=Зиёда аз {{limit}} мувофиқат +find_match_count_limit[few]=Зиёда аз {{limit}} мувофиқат +find_match_count_limit[many]=Зиёда аз {{limit}} мувофиқат +find_match_count_limit[other]=Зиёда аз {{limit}} мувофиқат +find_not_found=Ибора ёфт нашуд + +# Error panel labels +error_more_info=Маълумоти бештар +error_less_info=Маълумоти камтар +error_close=Пӯшидан +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=PDF.js v{{version}} (сохт: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Паём: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Даста: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Файл: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Сатр: {{line}} +rendering_error=Ҳангоми шаклсозии саҳифа хато ба миён омад. + +# Predefined zoom values +page_scale_width=Аз рӯи паҳнои саҳифа +page_scale_fit=Аз рӯи андозаи саҳифа +page_scale_auto=Андозаи худкор +page_scale_actual=Андозаи воқеӣ +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading=Бор шуда истодааст… +loading_error=Ҳангоми боркунии PDF хато ба миён омад. +invalid_file_error=Файли PDF нодуруст ё вайроншуда мебошад. +missing_file_error=Файли PDF ғоиб аст. +unexpected_response_error=Ҷавоби ногаҳон аз сервер. + +# LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be +# replaced by the modification date, and time, of the annotation. +annotation_date_string={{date}}, {{time}} + +# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. +# "{{type}}" will be replaced with an annotation type from a list defined in +# the PDF spec (32000-1:2008 Table 169 – Annotation types). +# Some common types are e.g.: "Check", "Text", "Comment", "Note" +text_annotation_type.alt=[Ҳошиянависӣ - {{type}}] +password_label=Барои кушодани ин файли PDF ниҳонвожаро ворид кунед. +password_invalid=Ниҳонвожаи нодуруст. Лутфан, аз нав кӯшиш кунед. +password_ok=ХУБ +password_cancel=Бекор кардан + +printing_not_supported=Диққат: Чопкунӣ аз тарафи ин браузер ба таври пурра дастгирӣ намешавад. +printing_not_ready=Диққат: Файли PDF барои чопкунӣ пурра бор карда нашуд. +web_fonts_disabled=Шрифтҳои интернетӣ ғайрифаъоланд: истифодаи шрифтҳои дарунсохти PDF ғайриимкон аст. + +# Editor +editor_none.title=Ғайрифаъол кардани таҳрири ҳошиянависӣ +editor_none_label=Ғайрифаъл кардани таҳрири матн +editor_free_text.title=Илова кардани ҳошиянависии «FreeText» +editor_free_text_label=Ҳошиянависии «FreeText» +editor_ink.title=Илова кардани ҳошиянависии дастнавис +editor_ink_label=Ҳошиянависии дастнавис + +freetext_default_content=Ягон матнро ворид намоед… + +free_text_default_content=Матнро ворид намоед… + +# Editor Parameters +editor_free_text_font_color=Ранги ҳуруф +editor_free_text_font_size=Андозаи ҳуруф +editor_ink_line_color=Ранги сатр +editor_ink_line_thickness=Ғафсии сатр + +# Editor Parameters +editor_free_text_color=Ранг +editor_free_text_size=Андоза +editor_ink_color=Ранг +editor_ink_thickness=Ғафсӣ +editor_ink_opacity=Шаффофӣ + +# Editor aria +editor_free_text_aria_label=Муҳаррири «FreeText» +editor_ink_aria_label=Муҳаррири ранг +editor_ink_canvas_aria_label=Тасвири эҷодкардаи корбар diff --git a/cps/static/locale/th/viewer.properties b/cps/static/locale/th/viewer.properties index a4ef7db14..7612bedd4 100644 --- a/cps/static/locale/th/viewer.properties +++ b/cps/static/locale/th/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=มุมมองปัจจุบัน tools.title=เครื่องมือ tools_label=เครื่องมือ first_page.title=ไปยังหน้าแรก -first_page.label=ไปยังหน้าแรก first_page_label=ไปยังหน้าแรก last_page.title=ไปยังหน้าสุดท้าย -last_page.label=ไปยังหน้าสุดท้าย last_page_label=ไปยังหน้าสุดท้าย page_rotate_cw.title=หมุนตามเข็มนาฬิกา -page_rotate_cw.label=หมุนตามเข็มนาฬิกา page_rotate_cw_label=หมุนตามเข็มนาฬิกา page_rotate_ccw.title=หมุนทวนเข็มนาฬิกา -page_rotate_ccw.label=หมุนทวนเข็มนาฬิกา page_rotate_ccw_label=หมุนทวนเข็มนาฬิกา cursor_text_select_tool.title=เปิดใช้งานเครื่องมือการเลือกข้อความ @@ -65,6 +61,8 @@ cursor_text_select_tool_label=เครื่องมือการเลื cursor_hand_tool.title=เปิดใช้งานเครื่องมือมือ cursor_hand_tool_label=เครื่องมือมือ +scroll_page.title=ใช้การเลื่อนหน้า +scroll_page_label=การเลื่อนหน้า scroll_vertical.title=ใช้การเลื่อนแนวตั้ง scroll_vertical_label=การเลื่อนแนวตั้ง scroll_horizontal.title=ใช้การเลื่อนแนวนอน @@ -137,19 +135,24 @@ print_progress_close=ยกเลิก # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=เปิด/ปิดแถบข้าง -toggle_sidebar_notification.title=เปิด/ปิดแถบข้าง (เอกสารมีเค้าร่าง/ไฟล์แนบ) +toggle_sidebar_notification2.title=เปิด/ปิดแถบข้าง (เอกสารมีเค้าร่าง/ไฟล์แนบ/เลเยอร์) toggle_sidebar_label=เปิด/ปิดแถบข้าง document_outline.title=แสดงเค้าร่างเอกสาร (คลิกสองครั้งเพื่อขยาย/ยุบรายการทั้งหมด) document_outline_label=เค้าร่างเอกสาร attachments.title=แสดงไฟล์แนบ attachments_label=ไฟล์แนบ +layers.title=แสดงเลเยอร์ (คลิกสองครั้งเพื่อรีเซ็ตเลเยอร์ทั้งหมดเป็นสถานะเริ่มต้น) +layers_label=เลเยอร์ thumbs.title=แสดงภาพขนาดย่อ thumbs_label=ภาพขนาดย่อ +current_outline_item.title=ค้นหารายการเค้าร่างปัจจุบัน +current_outline_item_label=รายการเค้าร่างปัจจุบัน findbar.title=ค้นหาในเอกสาร findbar_label=ค้นหา -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=หน้า {{page}} +additional_layers=เลเยอร์เพิ่มเติม +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=หน้า {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=หาตำแหน่งถัดไปของวลี find_next_label=ถัดไป find_highlight=เน้นสีทั้งหมด find_match_case_label=ตัวพิมพ์ใหญ่เล็กตรงกัน +find_match_diacritics_label=เครื่องหมายกำกับการออกเสียงตรงกัน find_entire_word_label=ทั้งคำ find_reached_top=ค้นหาถึงจุดเริ่มต้นของหน้า เริ่มค้นต่อจากด้านล่าง find_reached_bottom=ค้นหาถึงจุดสิ้นสุดหน้า เริ่มค้นต่อจากด้านบน @@ -222,7 +226,7 @@ page_scale_actual=ขนาดจริง page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=ข้อผิดพลาด +loading=กำลังโหลด… loading_error=เกิดข้อผิดพลาดขณะโหลด PDF invalid_file_error=ไฟล์ PDF ไม่ถูกต้องหรือเสียหาย missing_file_error=ไฟล์ PDF หายไป @@ -245,3 +249,18 @@ password_cancel=ยกเลิก printing_not_supported=คำเตือน: เบราว์เซอร์นี้ไม่ได้สนับสนุนการพิมพ์อย่างเต็มที่ printing_not_ready=คำเตือน: PDF ไม่ได้รับการโหลดอย่างเต็มที่สำหรับการพิมพ์ web_fonts_disabled=แบบอักษรเว็บถูกปิดใช้งาน: ไม่สามารถใช้แบบอักษร PDF ฝังตัว + +# Editor +editor_none_label=ปิดใช้งานการแก้ไข + + +free_text_default_content=ป้อนข้อความ… + +# Editor Parameters +editor_free_text_font_color=สีตัวอักษร +editor_free_text_font_size=ขนาดแบบอักษร + +# Editor Parameters +editor_ink_opacity=ความทึบ + +# Editor aria diff --git a/cps/static/locale/tl/viewer.properties b/cps/static/locale/tl/viewer.properties index 0209da154..1e988e75e 100644 --- a/cps/static/locale/tl/viewer.properties +++ b/cps/static/locale/tl/viewer.properties @@ -33,14 +33,14 @@ zoom_out_label=Paliitin zoom_in.title=Palakihin zoom_in_label=Palakihin zoom.title=Mag-zoom -presentation_mode.title=Switch to Presentation Mode +presentation_mode.title=Lumipat sa Presentation Mode presentation_mode_label=Presentation Mode open_file.title=Magbukas ng file open_file_label=Buksan print.title=i-Print print_label=i-Print -download.title=Download -download_label=Download +download.title=i-Download +download_label=i-Download bookmark.title=Kasalukuyang tingin (kopyahin o buksan sa bagong window) bookmark_label=Kasalukuyang tingin @@ -48,40 +48,36 @@ bookmark_label=Kasalukuyang tingin tools.title=Mga Kagamitan tools_label=Mga Kagamitan first_page.title=Pumunta sa Unang Pahina -first_page.label=Pumunta sa Unang Pahina first_page_label=Pumunta sa Unang Pahina last_page.title=Pumunta sa Huling Pahina -last_page.label=Pumunta sa Huling Pahina last_page_label=Pumunta sa Huling Pahina -page_rotate_cw.title=Paikutin ang Clockwise -page_rotate_cw.label=Paikutin ang Clockwise -page_rotate_cw_label=Paikutin ang Clockwise -page_rotate_ccw.title=Paikutin ang Counterclockwise -page_rotate_ccw.label=Paikutin ang Counterclockwise -page_rotate_ccw_label=Paikutin ang Counterclockwise +page_rotate_cw.title=Paikutin Pakanan +page_rotate_cw_label=Paikutin Pakanan +page_rotate_ccw.title=Paikutin Pakaliwa +page_rotate_ccw_label=Paikutin Pakaliwa -cursor_text_select_tool.title=Enable Text Selection Tool +cursor_text_select_tool.title=I-enable ang Text Selection Tool cursor_text_select_tool_label=Text Selection Tool -cursor_hand_tool.title=Enable Hand Tool +cursor_hand_tool.title=I-enable ang Hand Tool cursor_hand_tool_label=Hand Tool -scroll_vertical.title=Use Vertical Scrolling +scroll_vertical.title=Gumamit ng Vertical Scrolling scroll_vertical_label=Vertical Scrolling -scroll_horizontal.title=Use Horizontal Scrolling +scroll_horizontal.title=Gumamit ng Horizontal Scrolling scroll_horizontal_label=Horizontal Scrolling -scroll_wrapped.title=Use Wrapped Scrolling +scroll_wrapped.title=Gumamit ng Wrapped Scrolling scroll_wrapped_label=Wrapped Scrolling -spread_none.title=Do not join page spreads +spread_none.title=Huwag pagsamahin ang mga page spread spread_none_label=No Spreads spread_odd.title=Join page spreads starting with odd-numbered pages -spread_odd_label=Odd Spreads -spread_even.title=Join page spreads starting with even-numbered pages -spread_even_label=Even Spreads +spread_odd_label=Mga Odd Spread +spread_even.title=Pagsamahin ang mga page spread na nagsisimula sa mga even-numbered na pahina +spread_even_label=Mga Even Spread # Document properties dialog box -document_properties.title=Document Properties… -document_properties_label=Document Properties… +document_properties.title=Mga Katangian ng Dokumento… +document_properties_label=Mga Katangian ng Dokumento… document_properties_file_name=File name: document_properties_file_size=File size: # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" @@ -91,23 +87,23 @@ document_properties_kb={{size_kb}} KB ({{size_b}} bytes) # will be replaced by the PDF file size in megabytes, respectively in bytes. document_properties_mb={{size_mb}} MB ({{size_b}} bytes) document_properties_title=Pamagat: -document_properties_author=May Akda: -document_properties_subject=Subject: +document_properties_author=May-akda: +document_properties_subject=Paksa: document_properties_keywords=Mga keyword: -document_properties_creation_date=Creation Date: -document_properties_modification_date=Modification Date: +document_properties_creation_date=Petsa ng Pagkakagawa: +document_properties_modification_date=Petsa ng Pagkakabago: # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" # will be replaced by the creation/modification date, and time, of the PDF file. document_properties_date_string={{date}}, {{time}} -document_properties_creator=Creator: +document_properties_creator=Tagalikha: document_properties_producer=PDF Producer: document_properties_version=PDF Version: -document_properties_page_count=Page Count: -document_properties_page_size=Page Size: -document_properties_page_size_unit_inches=in +document_properties_page_count=Bilang ng Pahina: +document_properties_page_size=Laki ng Pahina: +document_properties_page_size_unit_inches=pulgada document_properties_page_size_unit_millimeters=mm -document_properties_page_size_orientation_portrait=portrait -document_properties_page_size_orientation_landscape=landscape +document_properties_page_size_orientation_portrait=patayo +document_properties_page_size_orientation_landscape=pahiga document_properties_page_size_name_a3=A3 document_properties_page_size_name_a4=A4 document_properties_page_size_name_letter=Letter @@ -127,7 +123,7 @@ document_properties_linearized_yes=Oo document_properties_linearized_no=Hindi document_properties_close=Isara -print_progress_message=Preparing document for printing… +print_progress_message=Inihahanda ang dokumento para sa pag-print… # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by # a numerical per cent value. print_progress_percent={{progress}}% @@ -136,20 +132,21 @@ print_progress_close=Kanselahin # Tooltips and alt text for side panel toolbar buttons # (the _label strings are alt text for the buttons, the .title strings are # tooltips) -toggle_sidebar.title=Toggle Sidebar -toggle_sidebar_notification.title=Toggle Sidebar (document contains outline/attachments) -toggle_sidebar_label=Toggle Sidebar -document_outline.title=Show Document Outline (double-click to expand/collapse all items) -document_outline_label=Document Outline -attachments.title=Show Attachments -attachments_label=Attachments -thumbs.title=Ipakita ang mga Thumbnails -thumbs_label=Thumbnails -findbar.title=Find in Document +toggle_sidebar.title=Ipakita/Itago ang Sidebar +toggle_sidebar_notification2.title=Ipakita/Itago ang Sidebar (nagtataglay ang dokumento ng balangkas/mga attachment/mga layer) +toggle_sidebar_label=Ipakita/Itago ang Sidebar +document_outline.title=Ipakita ang Document Outline (mag-double-click para i-expand/collapse ang laman) +document_outline_label=Balangkas ng Dokumento +attachments.title=Ipakita ang mga Attachment +attachments_label=Mga attachment +layers.title=Ipakita ang mga Layer (mag-double click para mareset ang lahat ng layer sa orihinal na estado) +layers_label=Mga layer +thumbs.title=Ipakita ang mga Thumbnail +thumbs_label=Mga thumbnail +findbar.title=Hanapin sa Dokumento findbar_label=Hanapin -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Pahina {{page}} +additional_layers=Mga Karagdagang Layer # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -160,43 +157,43 @@ thumb_page_canvas=Thumbnail ng Pahina {{page}} # Find panel button title and messages find_input.title=Hanapin -find_input.placeholder=Find in document… +find_input.placeholder=Hanapin sa dokumento… find_previous.title=Hanapin ang nakaraang pangyayari ng parirala -find_previous_label=Nakaraang +find_previous_label=Nakaraan find_next.title=Hanapin ang susunod na pangyayari ng parirala find_next_label=Susunod find_highlight=I-highlight lahat -find_match_case_label=Match case -find_entire_word_label=Whole words -find_reached_top=Reached top of document, continued from bottom -find_reached_bottom=Reached end of document, continued from top +find_match_case_label=Itugma ang case +find_entire_word_label=Buong salita +find_reached_top=Naabot na ang tuktok ng dokumento, ipinagpatuloy mula sa ilalim +find_reached_bottom=Naabot na ang dulo ng dokumento, ipinagpatuloy mula sa tuktok # LOCALIZATION NOTE (find_match_count): The supported plural forms are # [one|two|few|many|other], with [other] as the default value. # "{{current}}" and "{{total}}" will be replaced by a number representing the # index of the currently active find result, respectively a number representing # the total number of matches in the document. find_match_count={[ plural(total) ]} -find_match_count[one]={{current}} of {{total}} match -find_match_count[two]={{current}} of {{total}} matches -find_match_count[few]={{current}} of {{total}} matches -find_match_count[many]={{current}} of {{total}} matches -find_match_count[other]={{current}} of {{total}} matches +find_match_count[one]={{current}} ng {{total}} tugma +find_match_count[two]={{current}} ng {{total}} tugma +find_match_count[few]={{current}} ng {{total}} tugma +find_match_count[many]={{current}} ng {{total}} tugma +find_match_count[other]={{current}} ng {{total}} tugma # LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are # [zero|one|two|few|many|other], with [other] as the default value. # "{{limit}}" will be replaced by a numerical value. find_match_count_limit={[ plural(limit) ]} -find_match_count_limit[zero]=More than {{limit}} matches -find_match_count_limit[one]=More than {{limit}} match -find_match_count_limit[two]=More than {{limit}} matches -find_match_count_limit[few]=More than {{limit}} matches -find_match_count_limit[many]=More than {{limit}} matches -find_match_count_limit[other]=More than {{limit}} matches -find_not_found=Hindi nakita ang prasko +find_match_count_limit[zero]=Higit sa {{limit}} tugma +find_match_count_limit[one]=Higit sa {{limit}} tugma +find_match_count_limit[two]=Higit sa {{limit}} tugma +find_match_count_limit[few]=Higit sa {{limit}} tugma +find_match_count_limit[many]=Higit sa {{limit}} tugma +find_match_count_limit[other]=Higit sa {{limit}} tugma +find_not_found=Hindi natagpuan ang parirala # Error panel labels error_more_info=Karagdagang Impormasyon error_less_info=Mas Kaunting Impormasyon -error_close=Sarado +error_close=Isara # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be # replaced by the PDF.JS version and build ID. error_version_info=PDF.js v{{version}} (build: {{build}}) @@ -210,21 +207,19 @@ error_stack=Stack: {{stack}} error_file=File: {{file}} # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number error_line=Linya: {{line}} -rendering_error=May naganap na pagkakamali habang pagsasalin sa pahina. +rendering_error=Nagkaproblema habang nirerender ang pahina. # Predefined zoom values page_scale_width=Lapad ng Pahina -page_scale_fit=ang pahina ay angkop +page_scale_fit=Pagkasyahin ang Pahina page_scale_auto=Automatic Zoom page_scale_actual=Totoong sukat # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Error -loading_error=May maling nangyari habang kinakarga ang PDF. -invalid_file_error=Di-wasto o masira ang PDF file. +loading_error=Nagkaproblema habang niloload ang PDF. +invalid_file_error=Di-wasto o sira ang PDF file. missing_file_error=Nawawalang PDF file. unexpected_response_error=Hindi inaasahang tugon ng server. @@ -238,10 +233,10 @@ annotation_date_string={{date}}, {{time}} # Some common types are e.g.: "Check", "Text", "Comment", "Note" text_annotation_type.alt=[{{type}} Annotation] password_label=Ipasok ang password upang buksan ang PDF file na ito. -password_invalid=Invalid password. Please try again. +password_invalid=Maling password. Subukan uli. password_ok=OK password_cancel=Kanselahin -printing_not_supported=Warning: Printing is not fully supported by this browser. -printing_not_ready=Warning: The PDF is not fully loaded for printing. -web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts. +printing_not_supported=Babala: Hindi pa ganap na suportado ang pag-print sa browser na ito. +printing_not_ready=Babala: Hindi ganap na nabuksan ang PDF para sa pag-print. +web_fonts_disabled=Naka-disable ang mga Web font: hindi kayang gamitin ang mga naka-embed na PDF font. diff --git a/cps/static/locale/tr/viewer.properties b/cps/static/locale/tr/viewer.properties index b189186c2..09d5e72ea 100644 --- a/cps/static/locale/tr/viewer.properties +++ b/cps/static/locale/tr/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Geçerli görünüm tools.title=Araçlar tools_label=Araçlar first_page.title=İlk sayfaya git -first_page.label=İlk sayfaya git first_page_label=İlk sayfaya git last_page.title=Son sayfaya git -last_page.label=Son sayfaya git last_page_label=Son sayfaya git page_rotate_cw.title=Saat yönünde döndür -page_rotate_cw.label=Saat yönünde döndür page_rotate_cw_label=Saat yönünde döndür page_rotate_ccw.title=Saat yönünün tersine döndür -page_rotate_ccw.label=Saat yönünün tersine döndür page_rotate_ccw_label=Saat yönünün tersine döndür cursor_text_select_tool.title=Metin seçme aracını etkinleştir @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Metin seçme aracı cursor_hand_tool.title=El aracını etkinleştir cursor_hand_tool_label=El aracı +scroll_page.title=Sayfa kaydırmayı kullan +scroll_page_label=Sayfa kaydırma scroll_vertical.title=Dikey kaydırma kullan scroll_vertical_label=Dikey kaydırma scroll_horizontal.title=Yatay kaydırma kullan @@ -137,19 +135,24 @@ print_progress_close=İptal # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Kenar çubuğunu aç/kapat -toggle_sidebar_notification.title=Kenar çubuğunu aç/kapat (Belge ana hat/ekler içeriyor) +toggle_sidebar_notification2.title=Kenar çubuğunu aç/kapat (Belge ana hat/ekler/katmanlar içeriyor) toggle_sidebar_label=Kenar çubuğunu aç/kapat document_outline.title=Belge ana hatlarını göster (Tüm öğeleri genişletmek/daraltmak için çift tıklayın) document_outline_label=Belge ana hatları attachments.title=Ekleri göster attachments_label=Ekler +layers.title=Katmanları göster (tüm katmanları varsayılan duruma sıfırlamak için çift tıklayın) +layers_label=Katmanlar thumbs.title=Küçük resimleri göster thumbs_label=Küçük resimler +current_outline_item.title=Mevcut ana hat öğesini bul +current_outline_item_label=Mevcut ana hat öğesi findbar.title=Belgede bul findbar_label=Bul -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Sayfa {{page}} +additional_layers=Ek katmanlar +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Sayfa {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Sonraki eşleşmeyi bul find_next_label=Sonraki find_highlight=Tümünü vurgula find_match_case_label=Büyük-küçük harfe duyarlı +find_match_diacritics_label=Fonetik işaretleri bul find_entire_word_label=Tam sözcükler find_reached_top=Belgenin başına ulaşıldı, sonundan devam edildi find_reached_bottom=Belgenin sonuna ulaşıldı, başından devam edildi @@ -222,7 +226,7 @@ page_scale_actual=Gerçek boyut page_scale_percent=%{{scale}} # Loading indicator messages -loading_error_indicator=Hata +loading=Yükleniyor… loading_error=PDF yüklenirken bir hata oluştu. invalid_file_error=Geçersiz veya bozulmuş PDF dosyası. missing_file_error=PDF dosyası eksik. @@ -245,3 +249,33 @@ password_cancel=İptal printing_not_supported=Uyarı: Yazdırma bu tarayıcı tarafından tam olarak desteklenmemektedir. printing_not_ready=Uyarı: PDF tamamen yüklenmedi ve yazdırmaya hazır değil. web_fonts_disabled=Web fontları devre dışı: Gömülü PDF fontları kullanılamıyor. + +# Editor +editor_none.title=Açıklama düzenlemeyi kapat +editor_none_label=Düzenlemeyi kapat +editor_free_text.title=FreeText açıklaması ekle +editor_free_text_label=FreeText açıklaması +editor_ink.title=Mürekkep açıklaması ekle +editor_ink_label=Mürekkep açıklaması + +freetext_default_content=Bir metin girin… + +free_text_default_content=Metni girin… + +# Editor Parameters +editor_free_text_font_color=Yazı tipi rengi +editor_free_text_font_size=Yazı tipi boyutu +editor_ink_line_color=Çizgi rengi +editor_ink_line_thickness=Çizgi kalınlığı + +# Editor Parameters +editor_free_text_color=Renk +editor_free_text_size=Boyut +editor_ink_color=Renk +editor_ink_thickness=Kalınlık +editor_ink_opacity=Saydamlık + +# Editor aria +editor_free_text_aria_label=Serbest metin düzenleyici +editor_ink_aria_label=Mürekkep düzenleyici +editor_ink_canvas_aria_label=Kullanıcı tarafından oluşturulan resim diff --git a/cps/static/locale/trs/viewer.properties b/cps/static/locale/trs/viewer.properties index 65252f7fe..8bd1fe1db 100644 --- a/cps/static/locale/trs/viewer.properties +++ b/cps/static/locale/trs/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Daj hua ma tools.title=Rasun tools_label=Nej rasùun first_page.title=gun' riña pajina asiniin -first_page.label=Gun' riña pajina asiniin first_page_label=Gun' riña pajina asiniin last_page.title=Gun' riña pajina rukù ni'in -last_page.label=Gun' riña pajina rukù ni'inj last_page_label=Gun' riña pajina rukù ni'inj page_rotate_cw.title=Tanikaj ne' huat -page_rotate_cw.label=Tanikaj ne' huat page_rotate_cw_label=Tanikaj ne' huat page_rotate_ccw.title=Tanikaj ne' chînt' -page_rotate_ccw.label=Tanikaj ne' chint page_rotate_ccw_label=Tanikaj ne' chint cursor_text_select_tool.title=Dugi'iaj sun' sa ganahui texto @@ -198,9 +194,6 @@ page_scale_actual=Dàj yàchi akuan' nín # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Nitaj si hua hue'ej - # LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be # replaced by the modification date, and time, of the annotation. diff --git a/cps/static/locale/uk/viewer.properties b/cps/static/locale/uk/viewer.properties index 7b3a69c55..e981adf73 100644 --- a/cps/static/locale/uk/viewer.properties +++ b/cps/static/locale/uk/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Поточний вигляд tools.title=Інструменти tools_label=Інструменти first_page.title=На першу сторінку -first_page.label=На першу сторінку first_page_label=На першу сторінку last_page.title=На останню сторінку -last_page.label=На останню сторінку last_page_label=На останню сторінку page_rotate_cw.title=Повернути за годинниковою стрілкою -page_rotate_cw.label=Повернути за годинниковою стрілкою page_rotate_cw_label=Повернути за годинниковою стрілкою page_rotate_ccw.title=Повернути проти годинникової стрілки -page_rotate_ccw.label=Повернути проти годинникової стрілки page_rotate_ccw_label=Повернути проти годинникової стрілки cursor_text_select_tool.title=Увімкнути інструмент вибору тексту @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Інструмент вибору тексту cursor_hand_tool.title=Увімкнути інструмент "Рука" cursor_hand_tool_label=Інструмент "Рука" +scroll_page.title=Використовувати прокручування сторінки +scroll_page_label=Прокручування сторінки scroll_vertical.title=Використовувати вертикальне прокручування scroll_vertical_label=Вертикальне прокручування scroll_horizontal.title=Використовувати горизонтальне прокручування @@ -137,19 +135,24 @@ print_progress_close=Скасувати # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Бічна панель -toggle_sidebar_notification.title=Перемкнути бічну панель (документ має вміст/вкладення) +toggle_sidebar_notification2.title=Перемкнути бічну панель (документ містить ескіз/вкладення/шари) toggle_sidebar_label=Перемкнути бічну панель document_outline.title=Показати схему документу (подвійний клік для розгортання/згортання елементів) document_outline_label=Схема документа attachments.title=Показати прикріплення attachments_label=Прикріплення +layers.title=Показати шари (двічі клацніть, щоб скинути всі шари до типового стану) +layers_label=Шари thumbs.title=Показувати ескізи thumbs_label=Ескізи +current_outline_item.title=Знайти поточний елемент змісту +current_outline_item_label=Поточний елемент змісту findbar.title=Знайти в документі -findbar_label=Пошук +findbar_label=Знайти -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Сторінка {{page}} +additional_layers=Додаткові шари +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Сторінка {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Знайти наступне входження фрази find_next_label=Наступне find_highlight=Підсвітити все find_match_case_label=З урахуванням регістру +find_match_diacritics_label=Відповідність діакритичних знаків find_entire_word_label=Цілі слова find_reached_top=Досягнуто початку документу, продовжено з кінця find_reached_bottom=Досягнуто кінця документу, продовжено з початку @@ -222,7 +226,7 @@ page_scale_actual=Дійсний розмір page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Помилка +loading=Завантаження… loading_error=Під час завантаження PDF сталася помилка. invalid_file_error=Недійсний або пошкоджений PDF-файл. missing_file_error=Відсутній PDF-файл. @@ -236,7 +240,7 @@ annotation_date_string={{date}}, {{time}} # "{{type}}" will be replaced with an annotation type from a list defined in # the PDF spec (32000-1:2008 Table 169 – Annotation types). # Some common types are e.g.: "Check", "Text", "Comment", "Note" -text_annotation_type.alt=[{{type}}-аннотація] +text_annotation_type.alt=[{{type}}-анотація] password_label=Введіть пароль для відкриття цього PDF-файла. password_invalid=Невірний пароль. Спробуйте ще. password_ok=Гаразд @@ -245,3 +249,33 @@ password_cancel=Скасувати printing_not_supported=Попередження: Цей браузер не повністю підтримує друк. printing_not_ready=Попередження: PDF не повністю завантажений для друку. web_fonts_disabled=Веб-шрифти вимкнено: неможливо використати вбудовані у PDF шрифти. + +# Editor +editor_none.title=Вимкнути редагування анотацій +editor_none_label=Вимкнути редагування +editor_free_text.title=Додати анотацію FreeText +editor_free_text_label=Анотація FreeText +editor_ink.title=Додати анотацію чорнилом +editor_ink_label=Анотація чорнилом + +freetext_default_content=Введіть текст… + +free_text_default_content=Уведіть текст… + +# Editor Parameters +editor_free_text_font_color=Колір шрифту +editor_free_text_font_size=Розмір шрифту +editor_ink_line_color=Колір лінії +editor_ink_line_thickness=Товщина лінії + +# Editor Parameters +editor_free_text_color=Колір +editor_free_text_size=Розмір +editor_ink_color=Колір +editor_ink_thickness=Товщина +editor_ink_opacity=Прозорість + +# Editor aria +editor_free_text_aria_label=Редактор FreeText +editor_ink_aria_label=Рукописний редактор +editor_ink_canvas_aria_label=Зображення, створене користувачем diff --git a/cps/static/locale/ur/viewer.properties b/cps/static/locale/ur/viewer.properties index 162ca1475..6235c159f 100644 --- a/cps/static/locale/ur/viewer.properties +++ b/cps/static/locale/ur/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=حالیہ نظارہ tools.title=آلات tools_label=آلات first_page.title=پہلے صفحہ پر جائیں -first_page.label=پہلے صفحہ پر جائیں first_page_label=پہلے صفحہ پر جائیں last_page.title=آخری صفحہ پر جائیں -last_page.label=آخری صفحہ پر جائیں last_page_label=آخری صفحہ پر جائیں page_rotate_cw.title=گھڑی وار گھمائیں -page_rotate_cw.label=گھڑی وار گھمائیں page_rotate_cw_label=گھڑی وار گھمائیں page_rotate_ccw.title=ضد گھڑی وار گھمائیں -page_rotate_ccw.label=ضد گھڑی وار گھمائیں page_rotate_ccw_label=ضد گھڑی وار گھمائیں cursor_text_select_tool.title=متن کے انتخاب کے ٹول کو فعال بناے @@ -143,8 +139,8 @@ thumbs_label=مجمل findbar.title=دستاویز میں ڈھونڈیں findbar_label=ڈھونڈیں -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=صفحہ {{page}} +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=صفحہ {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -216,7 +212,6 @@ page_scale_actual=اصل سائز page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=نقص loading_error=PDF لوڈ کرتے وقت نقص آ گیا۔ invalid_file_error=ناجائز یا خراب PDF مسل missing_file_error=PDF مسل غائب ہے۔ @@ -239,3 +234,5 @@ password_cancel=منسوخ کریں printing_not_supported=تنبیہ:چھاپنا اس براؤزر پر پوری طرح معاونت شدہ نہیں ہے۔ printing_not_ready=تنبیہ: PDF چھپائی کے لیے پوری طرح لوڈ نہیں ہوئی۔ web_fonts_disabled=ویب فانٹ نا اہل ہیں: شامل PDF فانٹ استعمال کرنے میں ناکام۔ +# LOCALIZATION NOTE (unsupported_feature_signatures): Should contain the same +# exact string as in the `chrome.properties` file. diff --git a/cps/static/locale/uz/viewer.properties b/cps/static/locale/uz/viewer.properties index 6ad24319e..a17eb6b3b 100644 --- a/cps/static/locale/uz/viewer.properties +++ b/cps/static/locale/uz/viewer.properties @@ -46,16 +46,12 @@ bookmark_label=Joriy koʻrinish tools.title=Vositalar tools_label=Vositalar first_page.title=Birinchi sahifaga oʻtish -first_page.label=Birinchi sahifaga oʻtish first_page_label=Birinchi sahifaga oʻtish last_page.title=Soʻnggi sahifaga oʻtish -last_page.label=Soʻnggi sahifaga oʻtish last_page_label=Soʻnggi sahifaga oʻtish page_rotate_cw.title=Soat yoʻnalishi boʻyicha burish -page_rotate_cw.label=Soat yoʻnalishi boʻyicha burish page_rotate_cw_label=Soat yoʻnalishi boʻyicha burish page_rotate_ccw.title=Soat yoʻnalishiga qarshi burish -page_rotate_ccw.label=Soat yoʻnalishiga qarshi burish page_rotate_ccw_label=Soat yoʻnalishiga qarshi burish @@ -147,8 +143,6 @@ page_scale_actual=Haqiqiy hajmi # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Xato loading_error=PDF yuklanayotganda xato yuz berdi. invalid_file_error=Xato yoki buzuq PDF fayli. missing_file_error=PDF fayl kerak. diff --git a/cps/static/locale/vi/viewer.properties b/cps/static/locale/vi/viewer.properties index 64ae6e3a2..18ef487d3 100644 --- a/cps/static/locale/vi/viewer.properties +++ b/cps/static/locale/vi/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Chế độ xem hiện tại tools.title=Công cụ tools_label=Công cụ first_page.title=Về trang đầu -first_page.label=Về trang đầu first_page_label=Về trang đầu last_page.title=Đến trang cuối -last_page.label=Đến trang cuối last_page_label=Đến trang cuối page_rotate_cw.title=Xoay theo chiều kim đồng hồ -page_rotate_cw.label=Xoay theo chiều kim đồng hồ page_rotate_cw_label=Xoay theo chiều kim đồng hồ page_rotate_ccw.title=Xoay ngược chiều kim đồng hồ -page_rotate_ccw.label=Xoay ngược chiều kim đồng hồ page_rotate_ccw_label=Xoay ngược chiều kim đồng hồ cursor_text_select_tool.title=Kích hoạt công cụ chọn vùng văn bản @@ -65,6 +61,8 @@ cursor_text_select_tool_label=Công cụ chọn vùng văn bản cursor_hand_tool.title=Kích hoạt công cụ con trỏ cursor_hand_tool_label=Công cụ con trỏ +scroll_page.title=Sử dụng cuộn trang hiện tại +scroll_page_label=Cuộn trang hiện tại scroll_vertical.title=Sử dụng cuộn dọc scroll_vertical_label=Cuộn dọc scroll_horizontal.title=Sử dụng cuộn ngang @@ -137,19 +135,24 @@ print_progress_close=Hủy bỏ # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Bật/Tắt thanh lề -toggle_sidebar_notification.title=Bật tắt thanh lề (tài liệu bao gồm bản phác thảo/tập tin đính kèm) +toggle_sidebar_notification2.title=Bật tắt thanh lề (tài liệu bao gồm bản phác thảo/tập tin đính kèm/lớp) toggle_sidebar_label=Bật/Tắt thanh lề -document_outline.title=Hiện tài liệu phác thảo (nhấp đúp vào để mở rộng/thu gọn tất cả các mục) +document_outline.title=Hiển thị tài liệu phác thảo (nhấp đúp vào để mở rộng/thu gọn tất cả các mục) document_outline_label=Bản phác tài liệu attachments.title=Hiện nội dung đính kèm attachments_label=Nội dung đính kèm +layers.title=Hiển thị các lớp (nhấp đúp để đặt lại tất cả các lớp về trạng thái mặc định) +layers_label=Lớp thumbs.title=Hiển thị ảnh thu nhỏ thumbs_label=Ảnh thu nhỏ +current_outline_item.title=Tìm mục phác thảo hiện tại +current_outline_item_label=Mục phác thảo hiện tại findbar.title=Tìm trong tài liệu findbar_label=Tìm -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=Trang {{page}} +additional_layers=Các lớp bổ sung +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=Trang {{page}} # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=Tìm cụm từ ở phần sau find_next_label=Tiếp find_highlight=Tô sáng tất cả find_match_case_label=Phân biệt hoa, thường +find_match_diacritics_label=Khớp dấu phụ find_entire_word_label=Toàn bộ từ find_reached_top=Đã đến phần đầu tài liệu, quay trở lại từ cuối find_reached_bottom=Đã đến phần cuối của tài liệu, quay trở lại từ đầu @@ -222,7 +226,7 @@ page_scale_actual=Kích thước thực page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=Lỗi +loading=Đang tải… loading_error=Lỗi khi tải tài liệu PDF. invalid_file_error=Tập tin PDF hỏng hoặc không hợp lệ. missing_file_error=Thiếu tập tin PDF. @@ -245,3 +249,33 @@ password_cancel=Hủy bỏ printing_not_supported=Cảnh báo: In ấn không được hỗ trợ đầy đủ ở trình duyệt này. printing_not_ready=Cảnh báo: PDF chưa được tải hết để in. web_fonts_disabled=Phông chữ Web bị vô hiệu hóa: không thể sử dụng các phông chữ PDF được nhúng. + +# Editor +editor_none.title=Tắt chỉnh sửa chú thích +editor_none_label=Tắt chỉnh sửa +editor_free_text.title=Thêm chú thích FreeText +editor_free_text_label=Chú thích FreeText +editor_ink.title=Thêm chú thích mực +editor_ink_label=Chú thích mực + +freetext_default_content=Nhập vài văn bản… + +free_text_default_content=Nhập văn bản… + +# Editor Parameters +editor_free_text_font_color=Màu chữ +editor_free_text_font_size=Cỡ chữ +editor_ink_line_color=Màu đường kẻ +editor_ink_line_thickness=Độ dày đường kẻ + +# Editor Parameters +editor_free_text_color=Màu +editor_free_text_size=Kích cỡ +editor_ink_color=Màu +editor_ink_thickness=Độ dày +editor_ink_opacity=Độ mờ + +# Editor aria +editor_free_text_aria_label=Trình chỉnh sửa FreeText +editor_ink_aria_label=Trình chỉnh sửa mực +editor_ink_canvas_aria_label=Hình ảnh do người dùng tạo diff --git a/cps/static/locale/wo/viewer.properties b/cps/static/locale/wo/viewer.properties index 38c7bc184..ca3f4c316 100644 --- a/cps/static/locale/wo/viewer.properties +++ b/cps/static/locale/wo/viewer.properties @@ -108,8 +108,6 @@ page_scale_actual=Dayo bi am # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a # numerical scale value. -# Loading indicator messages -loading_error_indicator=Njumte loading_error=Am na njumte ci yebum dencukaay PDF bi. invalid_file_error=Dencukaay PDF bi baaxul walla mu sankar. diff --git a/cps/static/locale/xh/viewer.properties b/cps/static/locale/xh/viewer.properties index 52cd75e5b..541ddbfc9 100644 --- a/cps/static/locale/xh/viewer.properties +++ b/cps/static/locale/xh/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=Imbonakalo ekhoyo tools.title=Izixhobo zemiyalelo tools_label=Izixhobo zemiyalelo first_page.title=Yiya kwiphepha lokuqala -first_page.label=Yiya kwiphepha lokuqala first_page_label=Yiya kwiphepha lokuqala last_page.title=Yiya kwiphepha lokugqibela -last_page.label=Yiya kwiphepha lokugqibela last_page_label=Yiya kwiphepha lokugqibela page_rotate_cw.title=Jikelisa ngasekunene -page_rotate_cw.label=Jikelisa ngasekunene page_rotate_cw_label=Jikelisa ngasekunene page_rotate_ccw.title=Jikelisa ngasekhohlo -page_rotate_ccw.label=Jikelisa ngasekhohlo page_rotate_ccw_label=Jikelisa ngasekhohlo cursor_text_select_tool.title=Vumela iSixhobo sokuKhetha iTeksti @@ -101,7 +97,6 @@ print_progress_close=Rhoxisa # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=Togola ngebha eseCaleni -toggle_sidebar_notification.title=ISidebar yeQhosha (uxwebhu lunolwandlalo/iziqhotyoshelwa) toggle_sidebar_label=Togola ngebha eseCaleni document_outline.title=Bonisa uLwandlalo loXwebhu (cofa kabini ukuze wandise/diliza zonke izinto) document_outline_label=Isishwankathelo soxwebhu @@ -161,8 +156,6 @@ page_scale_actual=Ubungakanani bokwenene # numerical scale value. page_scale_percent={{scale}}% -# Loading indicator messages -loading_error_indicator=Imposiso loading_error=Imposiso yenzekile xa kulayishwa i-PDF. invalid_file_error=Ifayile ye-PDF engeyiyo okanye eyonakalisiweyo. missing_file_error=Ifayile ye-PDF edukileyo. diff --git a/cps/static/locale/zh-CN/viewer.properties b/cps/static/locale/zh-CN/viewer.properties index 214c746f1..5a33d65b9 100644 --- a/cps/static/locale/zh-CN/viewer.properties +++ b/cps/static/locale/zh-CN/viewer.properties @@ -48,16 +48,12 @@ bookmark_label=当前在看 tools.title=工具 tools_label=工具 first_page.title=转到第一页 -first_page.label=转到第一页 first_page_label=转到第一页 last_page.title=转到最后一页 -last_page.label=转到最后一页 last_page_label=转到最后一页 page_rotate_cw.title=顺时针旋转 -page_rotate_cw.label=顺时针旋转 page_rotate_cw_label=顺时针旋转 page_rotate_ccw.title=逆时针旋转 -page_rotate_ccw.label=逆时针旋转 page_rotate_ccw_label=逆时针旋转 cursor_text_select_tool.title=启用文本选择工具 @@ -65,6 +61,8 @@ cursor_text_select_tool_label=文本选择工具 cursor_hand_tool.title=启用手形工具 cursor_hand_tool_label=手形工具 +scroll_page.title=使用页面滚动 +scroll_page_label=页面滚动 scroll_vertical.title=使用垂直滚动 scroll_vertical_label=垂直滚动 scroll_horizontal.title=使用水平滚动 @@ -137,23 +135,28 @@ print_progress_close=取消 # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=切换侧栏 -toggle_sidebar_notification.title=切换侧栏(文档所含的大纲/附件) +toggle_sidebar_notification2.title=切换侧栏(文档所含的大纲/附件/图层) toggle_sidebar_label=切换侧栏 document_outline.title=显示文档大纲(双击展开/折叠所有项) document_outline_label=文档大纲 attachments.title=显示附件 attachments_label=附件 +layers.title=显示图层(双击即可将所有图层重置为默认状态) +layers_label=图层 thumbs.title=显示缩略图 thumbs_label=缩略图 +current_outline_item.title=查找当前大纲项目 +current_outline_item_label=当前大纲项目 findbar.title=在文档中查找 findbar_label=查找 -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=页码 {{page}} +additional_layers=其他图层 +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=第 {{page}} 页 # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. -thumb_page_title=页码 {{page}} +thumb_page_title=第 {{page}} 页 # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page # number. thumb_page_canvas=页面 {{page}} 的缩略图 @@ -167,6 +170,7 @@ find_next.title=查找词语后一次出现的位置 find_next_label=下一页 find_highlight=全部高亮显示 find_match_case_label=区分大小写 +find_match_diacritics_label=匹配变音符号 find_entire_word_label=字词匹配 find_reached_top=到达文档开头,从末尾继续 find_reached_bottom=到达文档末尾,从开头继续 @@ -222,7 +226,7 @@ page_scale_actual=实际大小 page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=错误 +loading=正在载入… loading_error=载入 PDF 时发生错误。 invalid_file_error=无效或损坏的 PDF 文件。 missing_file_error=缺少 PDF 文件。 @@ -245,3 +249,33 @@ password_cancel=取消 printing_not_supported=警告:此浏览器尚未完整支持打印功能。 printing_not_ready=警告:此 PDF 未完成载入,无法打印。 web_fonts_disabled=Web 字体已被禁用:无法使用嵌入的 PDF 字体。 + +# Editor +editor_none.title=禁用编辑注释 +editor_none_label=禁用编辑 +editor_free_text.title=添加文本注释 +editor_free_text_label=文本注释 +editor_ink.title=添加墨迹注释 +editor_ink_label=墨迹注释 + +freetext_default_content=输入一段文本… + +free_text_default_content=输入文本… + +# Editor Parameters +editor_free_text_font_color=字体颜色 +editor_free_text_font_size=字体大小 +editor_ink_line_color=线条颜色 +editor_ink_line_thickness=线条粗细 + +# Editor Parameters +editor_free_text_color=颜色 +editor_free_text_size=字号 +editor_ink_color=颜色 +editor_ink_thickness=粗细 +editor_ink_opacity=不透明度 + +# Editor aria +editor_free_text_aria_label=文本编辑器 +editor_ink_aria_label=墨迹编辑器 +editor_ink_canvas_aria_label=用户创建图像 diff --git a/cps/static/locale/zh-TW/viewer.properties b/cps/static/locale/zh-TW/viewer.properties index 55626cabd..b673653e6 100644 --- a/cps/static/locale/zh-TW/viewer.properties +++ b/cps/static/locale/zh-TW/viewer.properties @@ -41,23 +41,19 @@ print.title=列印 print_label=列印 download.title=下載 download_label=下載 -bookmark.title=目前檢視的內容(複製或開啟於新視窗) +bookmark.title=目前畫面(複製或開啟於新視窗) bookmark_label=目前檢視 # Secondary toolbar and context menu tools.title=工具 tools_label=工具 first_page.title=跳到第一頁 -first_page.label=跳到第一頁 first_page_label=跳到第一頁 last_page.title=跳到最後一頁 -last_page.label=跳到最後一頁 last_page_label=跳到最後一頁 page_rotate_cw.title=順時針旋轉 -page_rotate_cw.label=順時針旋轉 page_rotate_cw_label=順時針旋轉 page_rotate_ccw.title=逆時針旋轉 -page_rotate_ccw.label=逆時針旋轉 page_rotate_ccw_label=逆時針旋轉 cursor_text_select_tool.title=開啟文字選擇工具 @@ -65,6 +61,8 @@ cursor_text_select_tool_label=文字選擇工具 cursor_hand_tool.title=開啟頁面移動工具 cursor_hand_tool_label=頁面移動工具 +scroll_page.title=使用頁面捲動功能 +scroll_page_label=頁面捲動功能 scroll_vertical.title=使用垂直捲動版面 scroll_vertical_label=垂直捲動 scroll_horizontal.title=使用水平捲動版面 @@ -137,19 +135,24 @@ print_progress_close=取消 # (the _label strings are alt text for the buttons, the .title strings are # tooltips) toggle_sidebar.title=切換側邊欄 -toggle_sidebar_notification.title=切換側邊攔(文件包含大綱或附件) +toggle_sidebar_notification2.title=切換側邊欄(包含大綱、附件、圖層的文件) toggle_sidebar_label=切換側邊欄 document_outline.title=顯示文件大綱(雙擊展開/摺疊所有項目) document_outline_label=文件大綱 attachments.title=顯示附件 attachments_label=附件 +layers.title=顯示圖層(滑鼠雙擊即可將所有圖層重設為預設狀態) +layers_label=圖層 thumbs.title=顯示縮圖 thumbs_label=縮圖 +current_outline_item.title=尋找目前的大綱項目 +current_outline_item_label=目前的大綱項目 findbar.title=在文件中尋找 findbar_label=尋找 -# LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. -page_canvas=第 {{page}} 頁 +additional_layers=其他圖層 +# LOCALIZATION NOTE (page_landmark): "{{page}}" will be replaced by the page number. +page_landmark=第 {{page}} 頁 # Thumbnails panel item (tooltip and alt text for images) # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page # number. @@ -167,6 +170,7 @@ find_next.title=尋找文字下次出現的位置 find_next_label=下一個 find_highlight=全部強調標示 find_match_case_label=區分大小寫 +find_match_diacritics_label=符合變音符號 find_entire_word_label=符合整個字 find_reached_top=已搜尋至文件頂端,自底端繼續搜尋 find_reached_bottom=已搜尋至文件底端,自頂端繼續搜尋 @@ -222,7 +226,7 @@ page_scale_actual=實際大小 page_scale_percent={{scale}}% # Loading indicator messages -loading_error_indicator=錯誤 +loading=載入中… loading_error=載入 PDF 時發生錯誤。 invalid_file_error=無效或毀損的 PDF 檔案。 missing_file_error=找不到 PDF 檔案。 @@ -245,3 +249,33 @@ password_cancel=取消 printing_not_supported=警告: 此瀏覽器未完整支援列印功能。 printing_not_ready=警告: 此 PDF 未完成下載以供列印。 web_fonts_disabled=已停用網路字型 (Web fonts): 無法使用 PDF 內嵌字型。 + +# Editor +editor_none.title=停用編輯注釋 +editor_none_label=停用編輯 +editor_free_text.title=新增文字注釋 +editor_free_text_label=文字注釋 +editor_ink.title=新增圖形注釋 +editor_ink_label=圖形注釋 + +freetext_default_content=輸入一些文字… + +free_text_default_content=請輸入文字… + +# Editor Parameters +editor_free_text_font_color=字型顏色 +editor_free_text_font_size=字型大小 +editor_ink_line_color=線條色彩 +editor_ink_line_thickness=線條粗細 + +# Editor Parameters +editor_free_text_color=色彩 +editor_free_text_size=大小 +editor_ink_color=色彩 +editor_ink_thickness=線條粗細 +editor_ink_opacity=透​明度 + +# Editor aria +editor_free_text_aria_label=FreeText 編輯器 +editor_ink_aria_label=筆跡編輯器 +editor_ink_canvas_aria_label=使用者建立的圖片 diff --git a/cps/static/standard_fonts/FoxitDingbats.pfb b/cps/static/standard_fonts/FoxitDingbats.pfb new file mode 100644 index 000000000..30d52963e Binary files /dev/null and b/cps/static/standard_fonts/FoxitDingbats.pfb differ diff --git a/cps/static/standard_fonts/FoxitFixed.pfb b/cps/static/standard_fonts/FoxitFixed.pfb new file mode 100644 index 000000000..f12dcbce5 Binary files /dev/null and b/cps/static/standard_fonts/FoxitFixed.pfb differ diff --git a/cps/static/standard_fonts/FoxitFixedBold.pfb b/cps/static/standard_fonts/FoxitFixedBold.pfb new file mode 100644 index 000000000..cf8e24aee Binary files /dev/null and b/cps/static/standard_fonts/FoxitFixedBold.pfb differ diff --git a/cps/static/standard_fonts/FoxitFixedBoldItalic.pfb b/cps/static/standard_fonts/FoxitFixedBoldItalic.pfb new file mode 100644 index 000000000..d2880017c Binary files /dev/null and b/cps/static/standard_fonts/FoxitFixedBoldItalic.pfb differ diff --git a/cps/static/standard_fonts/FoxitFixedItalic.pfb b/cps/static/standard_fonts/FoxitFixedItalic.pfb new file mode 100644 index 000000000..d71697d4b Binary files /dev/null and b/cps/static/standard_fonts/FoxitFixedItalic.pfb differ diff --git a/cps/static/standard_fonts/FoxitSans.pfb b/cps/static/standard_fonts/FoxitSans.pfb new file mode 100644 index 000000000..37f244bd9 Binary files /dev/null and b/cps/static/standard_fonts/FoxitSans.pfb differ diff --git a/cps/static/standard_fonts/FoxitSansBold.pfb b/cps/static/standard_fonts/FoxitSansBold.pfb new file mode 100644 index 000000000..affcf316d Binary files /dev/null and b/cps/static/standard_fonts/FoxitSansBold.pfb differ diff --git a/cps/static/standard_fonts/FoxitSansBoldItalic.pfb b/cps/static/standard_fonts/FoxitSansBoldItalic.pfb new file mode 100644 index 000000000..e1f60b754 Binary files /dev/null and b/cps/static/standard_fonts/FoxitSansBoldItalic.pfb differ diff --git a/cps/static/standard_fonts/FoxitSansItalic.pfb b/cps/static/standard_fonts/FoxitSansItalic.pfb new file mode 100644 index 000000000..c04b0a5ae Binary files /dev/null and b/cps/static/standard_fonts/FoxitSansItalic.pfb differ diff --git a/cps/static/standard_fonts/FoxitSerif.pfb b/cps/static/standard_fonts/FoxitSerif.pfb new file mode 100644 index 000000000..3fa682efb Binary files /dev/null and b/cps/static/standard_fonts/FoxitSerif.pfb differ diff --git a/cps/static/standard_fonts/FoxitSerifBold.pfb b/cps/static/standard_fonts/FoxitSerifBold.pfb new file mode 100644 index 000000000..ff7c6ddec Binary files /dev/null and b/cps/static/standard_fonts/FoxitSerifBold.pfb differ diff --git a/cps/static/standard_fonts/FoxitSerifBoldItalic.pfb b/cps/static/standard_fonts/FoxitSerifBoldItalic.pfb new file mode 100644 index 000000000..460231fb8 Binary files /dev/null and b/cps/static/standard_fonts/FoxitSerifBoldItalic.pfb differ diff --git a/cps/static/standard_fonts/FoxitSerifItalic.pfb b/cps/static/standard_fonts/FoxitSerifItalic.pfb new file mode 100644 index 000000000..d03a7c781 Binary files /dev/null and b/cps/static/standard_fonts/FoxitSerifItalic.pfb differ diff --git a/cps/static/standard_fonts/FoxitSymbol.pfb b/cps/static/standard_fonts/FoxitSymbol.pfb new file mode 100644 index 000000000..c8f9bca78 Binary files /dev/null and b/cps/static/standard_fonts/FoxitSymbol.pfb differ diff --git a/cps/static/standard_fonts/LICENSE_FOXIT b/cps/static/standard_fonts/LICENSE_FOXIT new file mode 100644 index 000000000..8b4ed6ddd --- /dev/null +++ b/cps/static/standard_fonts/LICENSE_FOXIT @@ -0,0 +1,27 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cps/static/standard_fonts/LICENSE_LIBERATION b/cps/static/standard_fonts/LICENSE_LIBERATION new file mode 100644 index 000000000..aba73e8a4 --- /dev/null +++ b/cps/static/standard_fonts/LICENSE_LIBERATION @@ -0,0 +1,102 @@ +Digitized data copyright (c) 2010 Google Corporation + with Reserved Font Arimo, Tinos and Cousine. +Copyright (c) 2012 Red Hat, Inc. + with Reserved Font Name Liberation. + +This Font Software is licensed under the SIL Open Font License, +Version 1.1. + +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + +PREAMBLE The goals of the Open Font License (OFL) are to stimulate +worldwide development of collaborative font projects, to support the font +creation efforts of academic and linguistic communities, and to provide +a free and open framework in which fonts may be shared and improved in +partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. +The fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply to +any document created using the fonts or their derivatives. + + + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. +This may include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components +as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting ? in part or in whole ? +any of the components of the Original Version, by changing formats or +by porting the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical writer +or other person who contributed to the Font Software. + + +PERMISSION & CONDITIONS + +Permission is hereby granted, free of charge, to any person obtaining a +copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components,in + Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, + redistributed and/or sold with any software, provided that each copy + contains the above copyright notice and this license. These can be + included either as stand-alone text files, human-readable headers or + in the appropriate machine-readable metadata fields within text or + binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font + Name(s) unless explicit written permission is granted by the + corresponding Copyright Holder. This restriction only applies to the + primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font + Software shall not be used to promote, endorse or advertise any + Modified Version, except to acknowledge the contribution(s) of the + Copyright Holder(s) and the Author(s) or with their explicit written + permission. + +5) The Font Software, modified or unmodified, in part or in whole, must + be distributed entirely under this license, and must not be distributed + under any other license. The requirement for fonts to remain under + this license does not apply to any document created using the Font + Software. + + + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + + + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER +DEALINGS IN THE FONT SOFTWARE. + diff --git a/cps/static/standard_fonts/LiberationSans-Bold.ttf b/cps/static/standard_fonts/LiberationSans-Bold.ttf new file mode 100644 index 000000000..ee2371540 Binary files /dev/null and b/cps/static/standard_fonts/LiberationSans-Bold.ttf differ diff --git a/cps/static/standard_fonts/LiberationSans-BoldItalic.ttf b/cps/static/standard_fonts/LiberationSans-BoldItalic.ttf new file mode 100644 index 000000000..42b5717dd Binary files /dev/null and b/cps/static/standard_fonts/LiberationSans-BoldItalic.ttf differ diff --git a/cps/static/standard_fonts/LiberationSans-Italic.ttf b/cps/static/standard_fonts/LiberationSans-Italic.ttf new file mode 100644 index 000000000..0cf612634 Binary files /dev/null and b/cps/static/standard_fonts/LiberationSans-Italic.ttf differ diff --git a/cps/static/standard_fonts/LiberationSans-Regular.ttf b/cps/static/standard_fonts/LiberationSans-Regular.ttf new file mode 100644 index 000000000..366d1489c Binary files /dev/null and b/cps/static/standard_fonts/LiberationSans-Regular.ttf differ diff --git a/cps/tasks/convert.py b/cps/tasks/convert.py old mode 100644 new mode 100755 index ada530055..df6ae1043 --- a/cps/tasks/convert.py +++ b/cps/tasks/convert.py @@ -16,36 +16,38 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys import os import re - from glob import glob from shutil import copyfile from markupsafe import escape from sqlalchemy.exc import SQLAlchemyError +from flask_babel import lazy_gettext as N_ from cps.services.worker import CalibreTask from cps import db from cps import logger, config from cps.subproc_wrapper import process_open from flask_babel import gettext as _ -from flask import url_for +from cps.kobo_sync_status import remove_synced_book +from cps.ub import init_db_thread from cps.tasks.mail import TaskEmail from cps import gdriveutils + + log = logger.create() class TaskConvert(CalibreTask): - def __init__(self, file_path, bookid, taskMessage, settings, kindle_mail, user=None): - super(TaskConvert, self).__init__(taskMessage) + def __init__(self, file_path, book_id, task_message, settings, ereader_mail, user=None): + super(TaskConvert, self).__init__(task_message) self.file_path = file_path - self.bookid = bookid + self.book_id = book_id self.title = "" self.settings = settings - self.kindle_mail = kindle_mail + self.ereader_mail = ereader_mail self.user = user self.results = dict() @@ -53,22 +55,22 @@ class TaskConvert(CalibreTask): def run(self, worker_thread): self.worker_thread = worker_thread if config.config_use_google_drive: - worker_db = db.CalibreDB(expire_on_commit=False) - cur_book = worker_db.get_book(self.bookid) + worker_db = db.CalibreDB(expire_on_commit=False, init=True) + cur_book = worker_db.get_book(self.book_id) self.title = cur_book.title - data = worker_db.get_book_format(self.bookid, self.settings['old_book_format']) + data = worker_db.get_book_format(self.book_id, self.settings['old_book_format']) df = gdriveutils.getFileFromEbooksFolder(cur_book.path, data.name + "." + self.settings['old_book_format'].lower()) if df: datafile = os.path.join(config.config_calibre_dir, cur_book.path, - data.name + u"." + self.settings['old_book_format'].lower()) + data.name + "." + self.settings['old_book_format'].lower()) if not os.path.exists(os.path.join(config.config_calibre_dir, cur_book.path)): os.makedirs(os.path.join(config.config_calibre_dir, cur_book.path)) df.GetContentFile(datafile) worker_db.session.close() else: - error_message = _(u"%(format)s not found on Google Drive: %(fn)s", + error_message = _("%(format)s not found on Google Drive: %(fn)s", format=self.settings['old_book_format'], fn=data.name + "." + self.settings['old_book_format'].lower()) worker_db.session.close() @@ -76,23 +78,23 @@ class TaskConvert(CalibreTask): filename = self._convert_ebook_format() if config.config_use_google_drive: - os.remove(self.file_path + u'.' + self.settings['old_book_format'].lower()) + os.remove(self.file_path + '.' + self.settings['old_book_format'].lower()) if filename: if config.config_use_google_drive: # Upload files to gdrive gdriveutils.updateGdriveCalibreFromLocal() self._handleSuccess() - if self.kindle_mail: - # if we're sending to kindle after converting, create a one-off task and run it immediately + if self.ereader_mail: + # if we're sending to E-Reader after converting, create a one-off task and run it immediately # todo: figure out how to incorporate this into the progress try: - EmailText = _(u"%(book)s send to Kindle", book=escape(self.title)) + EmailText = N_("%(book)s send to E-Reader", book=escape(self.title)) worker_thread.add(self.user, TaskEmail(self.settings['subject'], self.results["path"], filename, self.settings, - self.kindle_mail, + self.ereader_mail, EmailText, self.settings['body'], internal=True) @@ -102,25 +104,40 @@ class TaskConvert(CalibreTask): def _convert_ebook_format(self): error_message = None - local_db = db.CalibreDB(expire_on_commit=False) + local_db = db.CalibreDB(expire_on_commit=False, init=True) file_path = self.file_path - book_id = self.bookid - format_old_ext = u'.' + self.settings['old_book_format'].lower() - format_new_ext = u'.' + self.settings['new_book_format'].lower() + book_id = self.book_id + format_old_ext = '.' + self.settings['old_book_format'].lower() + format_new_ext = '.' + self.settings['new_book_format'].lower() # check to see if destination format already exists - or if book is in database # if it does - mark the conversion task as complete and return a success - # this will allow send to kindle workflow to continue to work + # this will allow send to E-Reader workflow to continue to work if os.path.isfile(file_path + format_new_ext) or\ - local_db.get_book_format(self.bookid, self.settings['new_book_format']): + local_db.get_book_format(self.book_id, self.settings['new_book_format']): log.info("Book id %d already converted to %s", book_id, format_new_ext) cur_book = local_db.get_book(book_id) self.title = cur_book.title - self.results['path'] = file_path + self.results['path'] = cur_book.path self.results['title'] = self.title - self._handleSuccess() - local_db.session.close() - return os.path.basename(file_path + format_new_ext) + new_format = local_db.session.query(db.Data).filter(db.Data.book == book_id)\ + .filter(db.Data.format == self.settings['new_book_format'].upper()).one_or_none() + if not new_format: + new_format = db.Data(name=os.path.basename(file_path), + book_format=self.settings['new_book_format'].upper(), + book=book_id, uncompressed_size=os.path.getsize(file_path + format_new_ext)) + try: + local_db.session.merge(new_format) + local_db.session.commit() + except SQLAlchemyError as e: + local_db.session.rollback() + log.error("Database error: %s", e) + local_db.session.close() + self._handleError(N_("Oops! Database Error: %(error)s.", error=e)) + return + self._handleSuccess() + local_db.session.close() + return os.path.basename(file_path + format_new_ext) else: log.info("Book id %d - target format of %s does not exist. Moving forward with convert.", book_id, @@ -133,26 +150,32 @@ class TaskConvert(CalibreTask): else: # check if calibre converter-executable is existing if not os.path.exists(config.config_converterpath): - # ToDo Text is not translated - self._handleError(_(u"Calibre ebook-convert %(tool)s not found", tool=config.config_converterpath)) + self._handleError(N_("Calibre ebook-convert %(tool)s not found", tool=config.config_converterpath)) return check, error_message = self._convert_calibre(file_path, format_old_ext, format_new_ext) if check == 0: cur_book = local_db.get_book(book_id) if os.path.isfile(file_path + format_new_ext): - new_format = db.Data(name=cur_book.data[0].name, + new_format = local_db.session.query(db.Data).filter(db.Data.book == book_id) \ + .filter(db.Data.format == self.settings['new_book_format'].upper()).one_or_none() + if not new_format: + new_format = db.Data(name=cur_book.data[0].name, book_format=self.settings['new_book_format'].upper(), book=book_id, uncompressed_size=os.path.getsize(file_path + format_new_ext)) - try: - local_db.session.merge(new_format) - local_db.session.commit() - except SQLAlchemyError as e: - local_db.session.rollback() - log.error("Database error: %s", e) - local_db.session.close() - self._handleError(error_message) - return + try: + local_db.session.merge(new_format) + local_db.session.commit() + if self.settings['new_book_format'].upper() in ['KEPUB', 'EPUB', 'EPUB3']: + ub_session = init_db_thread() + remove_synced_book(book_id, True, ub_session) + ub_session.close() + except SQLAlchemyError as e: + local_db.session.rollback() + log.error("Database error: %s", e) + local_db.session.close() + self._handleError(error_message) + return self.results['path'] = cur_book.path self.title = cur_book.title self.results['title'] = self.title @@ -160,11 +183,13 @@ class TaskConvert(CalibreTask): self._handleSuccess() return os.path.basename(file_path + format_new_ext) else: - error_message = _('%(format)s format not found on disk', format=format_new_ext.upper()) + error_message = N_('%(format)s format not found on disk', format=format_new_ext.upper()) local_db.session.close() log.info("ebook converter failed with error while converting book") if not error_message: - error_message = _('Ebook converter failed with unknown error') + error_message = N_('Ebook converter failed with unknown error') + else: + log.error(error_message) self._handleError(error_message) return @@ -174,7 +199,7 @@ class TaskConvert(CalibreTask): try: p = process_open(command, quotes) except OSError as e: - return 1, _(u"Kepubify-converter failed: %(error)s", error=e) + return 1, N_("Kepubify-converter failed: %(error)s", error=e) self.progress = 0.01 while True: nextline = p.stdout.readlines() @@ -195,7 +220,7 @@ class TaskConvert(CalibreTask): copyfile(converted_file[0], (file_path + format_new_ext)) os.unlink(converted_file[0]) else: - return 1, _(u"Converted file not found or more than one file in folder %(folder)s", + return 1, N_("Converted file not found or more than one file in folder %(folder)s", folder=os.path.dirname(file_path)) return check, None @@ -217,13 +242,16 @@ class TaskConvert(CalibreTask): quotes.append(quotes_index) quotes_index += 1 - p = process_open(command, quotes) + p = process_open(command, quotes, newlines=False) except OSError as e: - return 1, _(u"Ebook-converter failed: %(error)s", error=e) + return 1, N_("Ebook-converter failed: %(error)s", error=e) while p.poll() is None: nextline = p.stdout.readline() - log.debug(nextline.strip('\r\n')) + if isinstance(nextline, bytes): + nextline = nextline.decode('utf-8', errors="ignore").strip('\r\n') + if nextline: + log.debug(nextline) # parse progress string from calibre-converter progress = re.search(r"(\d+)%\s.*", nextline) if progress: @@ -236,11 +264,22 @@ class TaskConvert(CalibreTask): calibre_traceback = p.stderr.readlines() error_message = "" for ele in calibre_traceback: - log.debug(ele.strip('\n')) + ele = ele.decode('utf-8', errors="ignore").strip('\n') + log.debug(ele) if not ele.startswith('Traceback') and not ele.startswith(' File'): - error_message = _("Calibre failed with error: %(error)s", error=ele.strip('\n')) + error_message = N_("Calibre failed with error: %(error)s", error=ele) return check, error_message @property def name(self): - return "Convert" + return N_("Convert") + + def __str__(self): + if self.ereader_mail: + return "Convert {} {}".format(self.book_id, self.ereader_mail) + else: + return "Convert {}".format(self.book_id) + + @property + def is_cancellable(self): + return False diff --git a/cps/tasks/database.py b/cps/tasks/database.py new file mode 100644 index 000000000..afc4db2cc --- /dev/null +++ b/cps/tasks/database.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2020 mmonkey +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from urllib.request import urlopen + +from flask_babel import lazy_gettext as N_ + +from cps import config, logger +from cps.services.worker import CalibreTask + + +class TaskReconnectDatabase(CalibreTask): + def __init__(self, task_message=N_('Reconnecting Calibre database')): + super(TaskReconnectDatabase, self).__init__(task_message) + self.log = logger.create() + self.listen_address = config.get_config_ipaddress() + self.listen_port = config.config_port + + + def run(self, worker_thread): + address = self.listen_address if self.listen_address else 'localhost' + port = self.listen_port if self.listen_port else 8083 + + try: + urlopen('http://' + address + ':' + str(port) + '/reconnect') + self._handleSuccess() + except Exception as ex: + self._handleError('Unable to reconnect Calibre database: ' + str(ex)) + + @property + def name(self): + return "Reconnect Database" + + @property + def is_cancellable(self): + return False diff --git a/cps/tasks/mail.py b/cps/tasks/mail.py old mode 100644 new mode 100755 index 2e95ee98d..a7f0c2ecf --- a/cps/tasks/mail.py +++ b/cps/tasks/mail.py @@ -16,35 +16,25 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys import os import smtplib import threading import socket import mimetypes -try: - from StringIO import StringIO - from email.MIMEBase import MIMEBase - from email.MIMEMultipart import MIMEMultipart - from email.MIMEText import MIMEText -except ImportError: - from io import StringIO - from email.mime.base import MIMEBase - from email.mime.multipart import MIMEMultipart - from email.mime.text import MIMEText - - - -from email import encoders -from email.utils import formatdate, make_msgid +from io import StringIO +from email.message import EmailMessage +from email.utils import formatdate, parseaddr from email.generator import Generator +from flask_babel import lazy_gettext as N_ +from email.utils import formatdate from cps.services.worker import CalibreTask from cps.services import gmail from cps import logger, config from cps import gdriveutils +import uuid log = logger.create() @@ -119,33 +109,50 @@ class EmailSSL(EmailBase, smtplib.SMTP_SSL): class TaskEmail(CalibreTask): - def __init__(self, subject, filepath, attachment, settings, recipient, taskMessage, text, internal=False): - super(TaskEmail, self).__init__(taskMessage) + def __init__(self, subject, filepath, attachment, settings, recipient, task_message, text, internal=False): + super(TaskEmail, self).__init__(task_message) self.subject = subject self.attachment = attachment self.settings = settings self.filepath = filepath - self.recipent = recipient + self.recipient = recipient self.text = text self.asyncSMTP = None self.results = dict() + # from calibre code: + # https://github.com/kovidgoyal/calibre/blob/731ccd92a99868de3e2738f65949f19768d9104c/src/calibre/utils/smtp.py#L60 + def get_msgid_domain(self): + try: + # Parse out the address from the From line, and then the domain from that + from_email = parseaddr(self.settings["mail_from"])[1] + msgid_domain = from_email.partition('@')[2].strip() + # This can sometimes sneak through parseaddr if the input is malformed + msgid_domain = msgid_domain.rstrip('>').strip() + except Exception: + msgid_domain = '' + return msgid_domain or 'calibre-web.com' + def prepare_message(self): - message = MIMEMultipart() - message['to'] = self.recipent - message['from'] = self.settings["mail_from"] - message['subject'] = self.subject - message['Message-Id'] = make_msgid('calibre-web') + message = EmailMessage() + # message = MIMEMultipart() + message['From'] = self.settings["mail_from"] + message['To'] = self.recipient + message['Subject'] = self.subject message['Date'] = formatdate(localtime=True) - text = self.text - msg = MIMEText(text.encode('UTF-8'), 'plain', 'UTF-8') - message.attach(msg) + message['Message-Id'] = "{}@{}".format(uuid.uuid4(), self.get_msgid_domain()) # f"<{uuid.uuid4()}@{get_msgid_domain(from_)}>" # make_msgid('calibre-web') + message.set_content(self.text.encode('UTF-8'), "text", "plain") if self.attachment: - result = self._get_attachment(self.filepath, self.attachment) - if result: - message.attach(result) + data = self._get_attachment(self.filepath, self.attachment) + if data: + # Set mimetype + content_type, encoding = mimetypes.guess_type(self.attachment) + if content_type is None or encoding is not None: + content_type = 'application/octet-stream' + main_type, sub_type = content_type.split('/', 1) + message.add_attachment(data, maintype=main_type, subtype=sub_type, filename=self.attachment) else: - self._handleError(u"Attachment not found") + self._handleError("Attachment not found") return return message @@ -158,10 +165,10 @@ class TaskEmail(CalibreTask): else: self.send_gmail_email(msg) except MemoryError as e: - log.debug_or_exception(e) - self._handleError(u'MemoryError sending e-mail: {}'.format(str(e))) + log.error_or_exception(e, stacklevel=3) + self._handleError('MemoryError sending e-mail: {}'.format(str(e))) except (smtplib.SMTPException, smtplib.SMTPAuthenticationError) as e: - log.debug_or_exception(e) + log.error_or_exception(e, stacklevel=3) if hasattr(e, "smtp_error"): text = e.smtp_error.decode('utf-8').replace("\n", '. ') elif hasattr(e, "message"): @@ -170,13 +177,13 @@ class TaskEmail(CalibreTask): text = '\n'.join(e.args) else: text = '' - self._handleError(u'Smtplib Error sending e-mail: {}'.format(text)) - except socket.error as e: - log.debug_or_exception(e) - self._handleError(u'Socket Error sending e-mail: {}'.format(e.strerror)) + self._handleError('Smtplib Error sending e-mail: {}'.format(text)) + except (socket.error) as e: + log.error_or_exception(e, stacklevel=3) + self._handleError('Socket Error sending e-mail: {}'.format(e.strerror)) except Exception as ex: - log.debug_or_exception(ex) - self._handleError(u'Error sending e-mail: {}'.format(ex)) + log.error_or_exception(ex, stacklevel=3) + self._handleError('Error sending e-mail: {}'.format(ex)) def send_standard_email(self, msg): use_ssl = int(self.settings.get('mail_use_ssl', 0)) @@ -203,13 +210,14 @@ class TaskEmail(CalibreTask): gen = Generator(fp, mangle_from_=False) gen.flatten(msg) - self.asyncSMTP.sendmail(self.settings["mail_from"], self.recipent, fp.getvalue()) + self.asyncSMTP.sendmail(self.settings["mail_from"], self.recipient, fp.getvalue()) self.asyncSMTP.quit() self._handleSuccess() log.debug("E-mail send successfully") def send_gmail_email(self, message): - return gmail.send_messsage(self.settings.get('mail_gmail_token', None), message) + gmail.send_messsage(self.settings.get('mail_gmail_token', None), message) + self._handleSuccess() @property def progress(self): @@ -226,15 +234,15 @@ class TaskEmail(CalibreTask): self._progress = x @classmethod - def _get_attachment(cls, bookpath, filename): + def _get_attachment(cls, book_path, filename): """Get file as MIMEBase message""" calibre_path = config.config_calibre_dir if config.config_use_google_drive: - df = gdriveutils.getFileFromEbooksFolder(bookpath, filename) + df = gdriveutils.getFileFromEbooksFolder(book_path, filename) if df: - datafile = os.path.join(calibre_path, bookpath, filename) - if not os.path.exists(os.path.join(calibre_path, bookpath)): - os.makedirs(os.path.join(calibre_path, bookpath)) + datafile = os.path.join(calibre_path, book_path, filename) + if not os.path.exists(os.path.join(calibre_path, book_path)): + os.makedirs(os.path.join(calibre_path, book_path)) df.GetContentFile(datafile) else: return None @@ -244,27 +252,22 @@ class TaskEmail(CalibreTask): os.remove(datafile) else: try: - file_ = open(os.path.join(calibre_path, bookpath, filename), 'rb') + file_ = open(os.path.join(calibre_path, book_path, filename), 'rb') data = file_.read() file_.close() except IOError as e: - log.debug_or_exception(e) - log.error(u'The requested file could not be read. Maybe wrong permissions?') + log.error_or_exception(e, stacklevel=3) + log.error('The requested file could not be read. Maybe wrong permissions?') return None - # Set mimetype - content_type, encoding = mimetypes.guess_type(filename) - if content_type is None or encoding is not None: - content_type = 'application/octet-stream' - main_type, sub_type = content_type.split('/', 1) - attachment = MIMEBase(main_type, sub_type) - attachment.set_payload(data) - encoders.encode_base64(attachment) - attachment.add_header('Content-Disposition', 'attachment', filename=filename) - return attachment + return data @property def name(self): - return "E-mail" + return N_("E-mail") + + @property + def is_cancellable(self): + return False def __str__(self): - return "{}, {}".format(self.name, self.subject) + return "E-mail {}, {}".format(self.name, self.subject) diff --git a/cps/tasks/metadata_backup.py b/cps/tasks/metadata_backup.py new file mode 100644 index 000000000..0bcdf6c1c --- /dev/null +++ b/cps/tasks/metadata_backup.py @@ -0,0 +1,247 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2020 monkey +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +from lxml import objectify +from urllib.request import urlopen +from lxml import etree +from html import escape + +from cps import config, db, fs, gdriveutils, logger, ub +from cps.services.worker import CalibreTask, STAT_CANCELLED, STAT_ENDED +from flask_babel import lazy_gettext as N_ + +OPF_NAMESPACE = "http://www.idpf.org/2007/opf" +PURL_NAMESPACE = "http://purl.org/dc/elements/1.1/" + +OPF = "{%s}" % OPF_NAMESPACE +PURL = "{%s}" % PURL_NAMESPACE + +etree.register_namespace("opf", OPF_NAMESPACE) +etree.register_namespace("dc", PURL_NAMESPACE) + +OPF_NS = {None: OPF_NAMESPACE} # the default namespace (no prefix) +NSMAP = {'dc': PURL_NAMESPACE, 'opf': OPF_NAMESPACE} + + +class TaskBackupMetadata(CalibreTask): + + def __init__(self, export_language="en", + translated_title="Cover", + set_dirty=False, + task_message=N_('Backing up Metadata')): + super(TaskBackupMetadata, self).__init__(task_message) + self.log = logger.create() + self.calibre_db = db.CalibreDB(expire_on_commit=False, init=True) + self.export_language = export_language + self.translated_title = translated_title + self.set_dirty = set_dirty + + def run(self, worker_thread): + if self.set_dirty: + self.set_all_books_dirty() + else: + self.backup_metadata() + + def set_all_books_dirty(self): + try: + books = self.calibre_db.session.query(db.Books).all() + for book in books: + self.calibre_db.set_metadata_dirty(book.id) + self.calibre_db.session.commit() + self._handleSuccess() + except Exception as ex: + self.log.debug('Error adding book for backup: ' + str(ex)) + self._handleError('Error adding book for backup: ' + str(ex)) + self.calibre_db.session.rollback() + self.calibre_db.session.close() + + def backup_metadata(self): + try: + metadata_backup = self.calibre_db.session.query(db.Metadata_Dirtied).all() + custom_columns = self.calibre_db.session.query(db.CustomColumns).order_by(db.CustomColumns.label).all() + count = len(metadata_backup) + i = 0 + for backup in metadata_backup: + book = self.calibre_db.session.query(db.Books).filter(db.Books.id == backup.book).one_or_none() + self.calibre_db.session.query(db.Metadata_Dirtied).filter( + db.Metadata_Dirtied.book == backup.book).delete() + self.calibre_db.session.commit() + if book: + self.open_metadata(book, custom_columns) + else: + self.log.error("Book {} not found in database".format(backup.book)) + # self._handleError("Book {} not found in database".format(backup.book)) + i += 1 + self.progress = (1.0 / count) * i + self._handleSuccess() + self.calibre_db.session.close() + + except Exception as ex: + b = "NaN" if not hasattr(book, 'id') else book.id + self.log.debug('Error creating metadata backup for book {}: '.format(b) + str(ex)) + self._handleError('Error creating metadata backup: ' + str(ex)) + self.calibre_db.session.rollback() + self.calibre_db.session.close() + + def open_metadata(self, book, custom_columns): + if config.config_use_google_drive: + if not gdriveutils.is_gdrive_ready(): + raise Exception('Google Drive is configured but not ready') + + web_content_link = gdriveutils.get_metadata_backup_via_gdrive(book.path) + if not web_content_link: + raise Exception('Google Drive cover url not found') + + stream = None + try: + stream = urlopen(web_content_link) + except Exception as ex: + # Bubble exception to calling function + self.log.debug('Error reading metadata.opf: ' + str(ex)) # ToDo Check whats going on + raise ex + finally: + if stream is not None: + stream.close() + else: + # ToDo: Handle book folder not found or not readable + book_metadata_filepath = os.path.join(config.config_calibre_dir, book.path, 'metadata.opf') + #if not os.path.isfile(book_metadata_filepath): + self.create_new_metadata_backup(book, custom_columns, book_metadata_filepath) + # else: + '''namespaces = {'dc': PURL_NAMESPACE, 'opf': OPF_NAMESPACE} + test = etree.parse(book_metadata_filepath) + root = test.getroot() + for i in root.iter(): + self.log.info(i) + title = root.find("dc:metadata", namespaces) + pass + with open(book_metadata_filepath, "rb") as f: + xml = f.read() + + root = objectify.fromstring(xml) + # root.metadata['{http://purl.org/dc/elements/1.1/}title'] + # root.metadata[PURL + 'title'] + # getattr(root.metadata, PURL +'title') + # test = objectify.parse() + pass + # backup not found has to be created + #raise Exception('Book cover file not found')''' + + def create_new_metadata_backup(self, book, custom_columns, book_metadata_filepath): + # generate root package element + package = etree.Element(OPF + "package", nsmap=OPF_NS) + package.set("unique-identifier", "uuid_id") + package.set("version", "2.0") + + # generate metadata element and all subelements of it + metadata = etree.SubElement(package, "metadata", nsmap=NSMAP) + identifier = etree.SubElement(metadata, PURL + "identifier", id="calibre_id", nsmap=NSMAP) + identifier.set(OPF + "scheme", "calibre") + identifier.text = str(book.id) + identifier2 = etree.SubElement(metadata, PURL + "identifier", id="uuid_id", nsmap=NSMAP) + identifier2.set(OPF + "scheme", "uuid") + identifier2.text = book.uuid + title = etree.SubElement(metadata, PURL + "title", nsmap=NSMAP) + title.text = book.title + for author in book.authors: + creator = etree.SubElement(metadata, PURL + "creator", nsmap=NSMAP) + creator.text = str(author.name) + creator.set(OPF + "file-as", book.author_sort) # ToDo Check + creator.set(OPF + "role", "aut") + contributor = etree.SubElement(metadata, PURL + "contributor", nsmap=NSMAP) + contributor.text = "calibre (5.7.2) [https://calibre-ebook.com]" + contributor.set(OPF + "file-as", "calibre") # ToDo Check + contributor.set(OPF + "role", "bkp") + + date = etree.SubElement(metadata, PURL + "date", nsmap=NSMAP) + date.text = '{d.year:04}-{d.month:02}-{d.day:02}T{d.hour:02}:{d.minute:02}:{d.second:02}'.format(d=book.pubdate) + if book.comments: + for b in book.comments: + description = etree.SubElement(metadata, PURL + "description", nsmap=NSMAP) + description.text = b.text + if not book.languages: + language = etree.SubElement(metadata, PURL + "language", nsmap=NSMAP) + language.text = self.export_language + else: + for b in book.languages: + language = etree.SubElement(metadata, PURL + "language", nsmap=NSMAP) + language.text = str(b.lang_code) + for b in book.tags: + subject = etree.SubElement(metadata, PURL + "subject", nsmap=NSMAP) + subject.text = str(b.name) + etree.SubElement(metadata, "meta", name="calibre:author_link_map", + content="{" + ", ".join(['"' + str(a.name) + '": ""' for a in book.authors]) + "}", + nsmap=NSMAP) + for b in book.series: + etree.SubElement(metadata, "meta", name="calibre:series", + content=str(str(b.name)), + nsmap=NSMAP) + if book.series: + etree.SubElement(metadata, "meta", name="calibre:series_index", + content=str(book.series_index), + nsmap=NSMAP) + etree.SubElement(metadata, "meta", name="calibre:timestamp", + content='{d.year:04}-{d.month:02}-{d.day:02}T{d.hour:02}:{d.minute:02}:{d.second:02}'.format( + d=book.timestamp), + nsmap=NSMAP) + etree.SubElement(metadata, "meta", name="calibre:title_sort", + content=book.sort, + nsmap=NSMAP) + sequence = 0 + for cc in custom_columns: + value = None + extra = None + cc_entry = getattr(book, "custom_column_" + str(cc.id)) + if cc_entry.__len__(): + value = cc_entry[0].get("value") + extra = cc_entry[0].get("extra") + etree.SubElement(metadata, "meta", name="calibre:user_metadata:#{}".format(cc.label), + content=cc.to_json(value, extra, sequence), + nsmap=NSMAP) + sequence += 1 + + # generate guide element and all sub elements of it + # Title is translated from default export language + guide = etree.SubElement(package, "guide") + etree.SubElement(guide, "reference", type="cover", title=self.translated_title, href="cover.jpg") + + # prepare finalize everything and output + doc = etree.ElementTree(package) + # doc = etree.tostring(package, xml_declaration=True, encoding='utf-8', pretty_print=True) # .replace(b"&quot;", b""") + try: + with open(book_metadata_filepath, 'wb') as f: + # f.write(doc) + doc.write(f, xml_declaration=True, encoding='utf-8', pretty_print=True) + except Exception: + # ToDo: Folder not writeable error + pass + @property + def name(self): + return "Metadata backup" + + # needed for logging + def __str__(self): + if self.set_dirty: + return "Queue all books for metadata backup" + else: + return "Perform metadata backup" + + @property + def is_cancellable(self): + return True diff --git a/cps/tasks/thumbnail.py b/cps/tasks/thumbnail.py new file mode 100644 index 000000000..5bf0466b1 --- /dev/null +++ b/cps/tasks/thumbnail.py @@ -0,0 +1,514 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2020 monkey +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +from urllib.request import urlopen + +from .. import constants +from cps import config, db, fs, gdriveutils, logger, ub +from cps.services.worker import CalibreTask, STAT_CANCELLED, STAT_ENDED +from datetime import datetime +from sqlalchemy import func, text, or_ +from flask_babel import lazy_gettext as N_ + +try: + from wand.image import Image + use_IM = True +except (ImportError, RuntimeError) as e: + use_IM = False + + +def get_resize_height(resolution): + return int(225 * resolution) + + +def get_resize_width(resolution, original_width, original_height): + height = get_resize_height(resolution) + percent = (height / float(original_height)) + width = int((float(original_width) * float(percent))) + return width if width % 2 == 0 else width + 1 + + +def get_best_fit(width, height, image_width, image_height): + resize_width = int(width / 2.0) + resize_height = int(height / 2.0) + aspect_ratio = image_width / image_height + + # If this image's aspect ratio is different from the first image, then resize this image + # to fill the width and height of the first image + if aspect_ratio < width / height: + resize_width = int(width / 2.0) + resize_height = image_height * int(width / 2.0) / image_width + + elif aspect_ratio > width / height: + resize_width = image_width * int(height / 2.0) / image_height + resize_height = int(height / 2.0) + + return {'width': resize_width, 'height': resize_height} + + +class TaskGenerateCoverThumbnails(CalibreTask): + def __init__(self, book_id=-1, task_message=''): + super(TaskGenerateCoverThumbnails, self).__init__(task_message) + self.log = logger.create() + self.book_id = book_id + self.app_db_session = ub.get_new_session_instance() + # self.calibre_db = db.CalibreDB(expire_on_commit=False, init=True) + self.cache = fs.FileSystem() + self.resolutions = [ + constants.COVER_THUMBNAIL_SMALL, + constants.COVER_THUMBNAIL_MEDIUM + ] + + def run(self, worker_thread): + if use_IM and self.stat != STAT_CANCELLED and self.stat != STAT_ENDED: + self.message = 'Scanning Books' + books_with_covers = self.get_books_with_covers(self.book_id) + count = len(books_with_covers) + + total_generated = 0 + for i, book in enumerate(books_with_covers): + + # Generate new thumbnails for missing covers + generated = self.create_book_cover_thumbnails(book) + + # Increment the progress + self.progress = (1.0 / count) * i + + if generated > 0: + total_generated += generated + self.message = N_('Generated %(count)s cover thumbnails', count=total_generated) + + # Check if job has been cancelled or ended + if self.stat == STAT_CANCELLED: + self.log.info(f'GenerateCoverThumbnails task has been cancelled.') + return + + if self.stat == STAT_ENDED: + self.log.info(f'GenerateCoverThumbnails task has been ended.') + return + + if total_generated == 0: + self.self_cleanup = True + + self._handleSuccess() + self.app_db_session.remove() + + def get_books_with_covers(self, book_id=-1): + filter_exp = (db.Books.id == book_id) if book_id != -1 else True + calibre_db = db.CalibreDB(expire_on_commit=False, init=True) + books_cover = calibre_db.session.query(db.Books).filter(db.Books.has_cover == 1).filter(filter_exp).all() + calibre_db.session.close() + return books_cover + + def get_book_cover_thumbnails(self, book_id): + return self.app_db_session \ + .query(ub.Thumbnail) \ + .filter(ub.Thumbnail.type == constants.THUMBNAIL_TYPE_COVER) \ + .filter(ub.Thumbnail.entity_id == book_id) \ + .filter(or_(ub.Thumbnail.expiration.is_(None), ub.Thumbnail.expiration > datetime.utcnow())) \ + .all() + + def create_book_cover_thumbnails(self, book): + generated = 0 + book_cover_thumbnails = self.get_book_cover_thumbnails(book.id) + + # Generate new thumbnails for missing covers + resolutions = list(map(lambda t: t.resolution, book_cover_thumbnails)) + missing_resolutions = list(set(self.resolutions).difference(resolutions)) + for resolution in missing_resolutions: + generated += 1 + self.create_book_cover_single_thumbnail(book, resolution) + + # Replace outdated or missing thumbnails + for thumbnail in book_cover_thumbnails: + if book.last_modified > thumbnail.generated_at: + generated += 1 + self.update_book_cover_thumbnail(book, thumbnail) + + elif not self.cache.get_cache_file_exists(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS): + generated += 1 + self.update_book_cover_thumbnail(book, thumbnail) + return generated + + def create_book_cover_single_thumbnail(self, book, resolution): + thumbnail = ub.Thumbnail() + thumbnail.type = constants.THUMBNAIL_TYPE_COVER + thumbnail.entity_id = book.id + thumbnail.format = 'jpeg' + thumbnail.resolution = resolution + + self.app_db_session.add(thumbnail) + try: + self.app_db_session.commit() + self.generate_book_thumbnail(book, thumbnail) + except Exception as ex: + self.log.debug('Error creating book thumbnail: ' + str(ex)) + self._handleError('Error creating book thumbnail: ' + str(ex)) + self.app_db_session.rollback() + + def update_book_cover_thumbnail(self, book, thumbnail): + thumbnail.generated_at = datetime.utcnow() + + try: + self.app_db_session.commit() + self.cache.delete_cache_file(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS) + self.generate_book_thumbnail(book, thumbnail) + except Exception as ex: + self.log.debug('Error updating book thumbnail: ' + str(ex)) + self._handleError('Error updating book thumbnail: ' + str(ex)) + self.app_db_session.rollback() + + def generate_book_thumbnail(self, book, thumbnail): + if book and thumbnail: + if config.config_use_google_drive: + if not gdriveutils.is_gdrive_ready(): + raise Exception('Google Drive is configured but not ready') + + web_content_link = gdriveutils.get_cover_via_gdrive(book.path) + if not web_content_link: + raise Exception('Google Drive cover url not found') + + stream = None + try: + stream = urlopen(web_content_link) + with Image(file=stream) as img: + height = get_resize_height(thumbnail.resolution) + if img.height > height: + width = get_resize_width(thumbnail.resolution, img.width, img.height) + img.resize(width=width, height=height, filter='lanczos') + img.format = thumbnail.format + filename = self.cache.get_cache_file_path(thumbnail.filename, + constants.CACHE_TYPE_THUMBNAILS) + img.save(filename=filename) + except Exception as ex: + # Bubble exception to calling function + self.log.debug('Error generating thumbnail file: ' + str(ex)) + raise ex + finally: + if stream is not None: + stream.close() + else: + book_cover_filepath = os.path.join(config.config_calibre_dir, book.path, 'cover.jpg') + if not os.path.isfile(book_cover_filepath): + raise Exception('Book cover file not found') + + with Image(filename=book_cover_filepath) as img: + height = get_resize_height(thumbnail.resolution) + if img.height > height: + width = get_resize_width(thumbnail.resolution, img.width, img.height) + img.resize(width=width, height=height, filter='lanczos') + img.format = thumbnail.format + filename = self.cache.get_cache_file_path(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS) + img.save(filename=filename) + + @property + def name(self): + return N_('Cover Thumbnails') + + def __str__(self): + if self.book_id > 0: + return "Add Cover Thumbnails for Book {}".format(self.book_id) + else: + return "Generate Cover Thumbnails" + + @property + def is_cancellable(self): + return True + + +class TaskGenerateSeriesThumbnails(CalibreTask): + def __init__(self, task_message=''): + super(TaskGenerateSeriesThumbnails, self).__init__(task_message) + self.log = logger.create() + self.app_db_session = ub.get_new_session_instance() + self.calibre_db = db.CalibreDB(expire_on_commit=False, init=True) + self.cache = fs.FileSystem() + self.resolutions = [ + constants.COVER_THUMBNAIL_SMALL, + constants.COVER_THUMBNAIL_MEDIUM, + ] + + def run(self, worker_thread): + if self.calibre_db.session and use_IM and self.stat != STAT_CANCELLED and self.stat != STAT_ENDED: + self.message = 'Scanning Series' + all_series = self.get_series_with_four_plus_books() + count = len(all_series) + + total_generated = 0 + for i, series in enumerate(all_series): + generated = 0 + series_thumbnails = self.get_series_thumbnails(series.id) + series_books = self.get_series_books(series.id) + + # Generate new thumbnails for missing covers + resolutions = list(map(lambda t: t.resolution, series_thumbnails)) + missing_resolutions = list(set(self.resolutions).difference(resolutions)) + for resolution in missing_resolutions: + generated += 1 + self.create_series_thumbnail(series, series_books, resolution) + + # Replace outdated or missing thumbnails + for thumbnail in series_thumbnails: + if any(book.last_modified > thumbnail.generated_at for book in series_books): + generated += 1 + self.update_series_thumbnail(series_books, thumbnail) + + elif not self.cache.get_cache_file_exists(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS): + generated += 1 + self.update_series_thumbnail(series_books, thumbnail) + + # Increment the progress + self.progress = (1.0 / count) * i + + if generated > 0: + total_generated += generated + self.message = N_('Generated {0} series thumbnails').format(total_generated) + + # Check if job has been cancelled or ended + if self.stat == STAT_CANCELLED: + self.log.info(f'GenerateSeriesThumbnails task has been cancelled.') + return + + if self.stat == STAT_ENDED: + self.log.info(f'GenerateSeriesThumbnails task has been ended.') + return + + if total_generated == 0: + self.self_cleanup = True + + self._handleSuccess() + self.app_db_session.remove() + + def get_series_with_four_plus_books(self): + return self.calibre_db.session \ + .query(db.Series) \ + .join(db.books_series_link) \ + .join(db.Books) \ + .filter(db.Books.has_cover == 1) \ + .group_by(text('books_series_link.series')) \ + .having(func.count('book_series_link') > 3) \ + .all() + + def get_series_books(self, series_id): + return self.calibre_db.session \ + .query(db.Books) \ + .join(db.books_series_link) \ + .join(db.Series) \ + .filter(db.Books.has_cover == 1) \ + .filter(db.Series.id == series_id) \ + .all() + + def get_series_thumbnails(self, series_id): + return self.app_db_session \ + .query(ub.Thumbnail) \ + .filter(ub.Thumbnail.type == constants.THUMBNAIL_TYPE_SERIES) \ + .filter(ub.Thumbnail.entity_id == series_id) \ + .filter(or_(ub.Thumbnail.expiration.is_(None), ub.Thumbnail.expiration > datetime.utcnow())) \ + .all() + + def create_series_thumbnail(self, series, series_books, resolution): + thumbnail = ub.Thumbnail() + thumbnail.type = constants.THUMBNAIL_TYPE_SERIES + thumbnail.entity_id = series.id + thumbnail.format = 'jpeg' + thumbnail.resolution = resolution + + self.app_db_session.add(thumbnail) + try: + self.app_db_session.commit() + self.generate_series_thumbnail(series_books, thumbnail) + except Exception as ex: + self.log.debug('Error creating book thumbnail: ' + str(ex)) + self._handleError('Error creating book thumbnail: ' + str(ex)) + self.app_db_session.rollback() + + def update_series_thumbnail(self, series_books, thumbnail): + thumbnail.generated_at = datetime.utcnow() + + try: + self.app_db_session.commit() + self.cache.delete_cache_file(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS) + self.generate_series_thumbnail(series_books, thumbnail) + except Exception as ex: + self.log.debug('Error updating book thumbnail: ' + str(ex)) + self._handleError('Error updating book thumbnail: ' + str(ex)) + self.app_db_session.rollback() + + def generate_series_thumbnail(self, series_books, thumbnail): + # Get the last four books in the series based on series_index + books = sorted(series_books, key=lambda b: float(b.series_index), reverse=True)[:4] + + top = 0 + left = 0 + width = 0 + height = 0 + with Image() as canvas: + for book in books: + if config.config_use_google_drive: + if not gdriveutils.is_gdrive_ready(): + raise Exception('Google Drive is configured but not ready') + + web_content_link = gdriveutils.get_cover_via_gdrive(book.path) + if not web_content_link: + raise Exception('Google Drive cover url not found') + + stream = None + try: + stream = urlopen(web_content_link) + with Image(file=stream) as img: + # Use the first image in this set to determine the width and height to scale the + # other images in this set + if width == 0 or height == 0: + width = get_resize_width(thumbnail.resolution, img.width, img.height) + height = get_resize_height(thumbnail.resolution) + canvas.blank(width, height) + + dimensions = get_best_fit(width, height, img.width, img.height) + + # resize and crop the image + img.resize(width=int(dimensions['width']), height=int(dimensions['height']), + filter='lanczos') + img.crop(width=int(width / 2.0), height=int(height / 2.0), gravity='center') + + # add the image to the canvas + canvas.composite(img, left, top) + + except Exception as ex: + self.log.debug('Error generating thumbnail file: ' + str(ex)) + raise ex + finally: + if stream is not None: + stream.close() + + book_cover_filepath = os.path.join(config.config_calibre_dir, book.path, 'cover.jpg') + if not os.path.isfile(book_cover_filepath): + raise Exception('Book cover file not found') + + with Image(filename=book_cover_filepath) as img: + # Use the first image in this set to determine the width and height to scale the + # other images in this set + if width == 0 or height == 0: + width = get_resize_width(thumbnail.resolution, img.width, img.height) + height = get_resize_height(thumbnail.resolution) + canvas.blank(width, height) + + dimensions = get_best_fit(width, height, img.width, img.height) + + # resize and crop the image + img.resize(width=int(dimensions['width']), height=int(dimensions['height']), filter='lanczos') + img.crop(width=int(width / 2.0), height=int(height / 2.0), gravity='center') + + # add the image to the canvas + canvas.composite(img, left, top) + + # set the coordinates for the next iteration + if left == 0 and top == 0: + left = int(width / 2.0) + elif left == int(width / 2.0) and top == 0: + left = 0 + top = int(height / 2.0) + else: + left = int(width / 2.0) + + canvas.format = thumbnail.format + filename = self.cache.get_cache_file_path(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS) + canvas.save(filename=filename) + + @property + def name(self): + return N_('Cover Thumbnails') + + def __str__(self): + return "GenerateSeriesThumbnails" + + @property + def is_cancellable(self): + return True + + +class TaskClearCoverThumbnailCache(CalibreTask): + def __init__(self, book_id, task_message=N_('Clearing cover thumbnail cache')): + super(TaskClearCoverThumbnailCache, self).__init__(task_message) + self.log = logger.create() + self.book_id = book_id + self.app_db_session = ub.get_new_session_instance() + self.cache = fs.FileSystem() + + def run(self, worker_thread): + if self.app_db_session: + if self.book_id == 0: # delete superfluous thumbnails + calibre_db = db.CalibreDB(expire_on_commit=False, init=True) + thumbnails = (calibre_db.session.query(ub.Thumbnail) + .join(db.Books, ub.Thumbnail.entity_id == db.Books.id, isouter=True) + .filter(db.Books.id == None) + .all()) + calibre_db.session.close() + elif self.book_id > 0: # make sure single book is selected + thumbnails = self.get_thumbnails_for_book(self.book_id) + if self.book_id < 0: + self.delete_all_thumbnails() + else: + for thumbnail in thumbnails: + self.delete_thumbnail(thumbnail) + self._handleSuccess() + self.app_db_session.remove() + + def get_thumbnails_for_book(self, book_id): + return self.app_db_session \ + .query(ub.Thumbnail) \ + .filter(ub.Thumbnail.type == constants.THUMBNAIL_TYPE_COVER) \ + .filter(ub.Thumbnail.entity_id == book_id) \ + .all() + + def delete_thumbnail(self, thumbnail): + try: + self.cache.delete_cache_file(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS) + self.app_db_session \ + .query(ub.Thumbnail) \ + .filter(ub.Thumbnail.type == constants.THUMBNAIL_TYPE_COVER) \ + .filter(ub.Thumbnail.entity_id == thumbnail.entity_id) \ + .delete() + self.app_db_session.commit() + except Exception as ex: + self.log.debug('Error deleting book thumbnail: ' + str(ex)) + self._handleError('Error deleting book thumbnail: ' + str(ex)) + + def delete_all_thumbnails(self): + try: + self.app_db_session.query(ub.Thumbnail).filter(ub.Thumbnail.type == constants.THUMBNAIL_TYPE_COVER).delete() + self.app_db_session.commit() + self.cache.delete_cache_dir(constants.CACHE_TYPE_THUMBNAILS) + except Exception as ex: + self.log.debug('Error deleting thumbnail directory: ' + str(ex)) + self._handleError('Error deleting thumbnail directory: ' + str(ex)) + + @property + def name(self): + return N_('Cover Thumbnails') + + # needed for logging + def __str__(self): + if self.book_id > 0: + return "Replace/Delete Cover Thumbnails for book " + str(self.book_id) + else: + return "Delete Thumbnail cache directory" + + @property + def is_cancellable(self): + return False diff --git a/cps/tasks/upload.py b/cps/tasks/upload.py index 6a341cddb..bc8ba1e09 100644 --- a/cps/tasks/upload.py +++ b/cps/tasks/upload.py @@ -17,18 +17,29 @@ # along with this program. If not, see . from datetime import datetime + +from flask_babel import lazy_gettext as N_ + from cps.services.worker import CalibreTask, STAT_FINISH_SUCCESS class TaskUpload(CalibreTask): - def __init__(self, taskMessage): - super(TaskUpload, self).__init__(taskMessage) + def __init__(self, task_message, book_title): + super(TaskUpload, self).__init__(task_message) self.start_time = self.end_time = datetime.now() self.stat = STAT_FINISH_SUCCESS self.progress = 1 + self.book_title = book_title def run(self, worker_thread): """Upload task doesn't have anything to do, it's simply a way to add information to the task list""" @property def name(self): - return "Upload" + return N_("Upload") + + def __str__(self): + return "Upload {}".format(self.book_title) + + @property + def is_cancellable(self): + return False diff --git a/cps/tasks_status.py b/cps/tasks_status.py new file mode 100644 index 000000000..7043483c2 --- /dev/null +++ b/cps/tasks_status.py @@ -0,0 +1,106 @@ +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2022 OzzieIsaacs +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from markupsafe import escape + +from flask import Blueprint, jsonify +from flask_login import login_required, current_user +from flask_babel import gettext as _ +from flask_babel import format_datetime +from babel.units import format_unit + +from . import logger +from .render_template import render_title_template +from .services.worker import WorkerThread, STAT_WAITING, STAT_FAIL, STAT_STARTED, STAT_FINISH_SUCCESS, STAT_ENDED, \ + STAT_CANCELLED + +tasks = Blueprint('tasks', __name__) + +log = logger.create() + + +@tasks.route("/ajax/emailstat") +@login_required +def get_email_status_json(): + tasks = WorkerThread.get_instance().tasks + return jsonify(render_task_status(tasks)) + + +@tasks.route("/tasks") +@login_required +def get_tasks_status(): + # if current user admin, show all email, otherwise only own emails + tasks = WorkerThread.get_instance().tasks + answer = render_task_status(tasks) + return render_title_template('tasks.html', entries=answer, title=_("Tasks"), page="tasks") + + +# helper function to apply localize status information in tasklist entries +def render_task_status(tasklist): + rendered_tasklist = list() + for __, user, __, task, __ in tasklist: + if user == current_user.name or current_user.role_admin(): + ret = {} + if task.start_time: + ret['starttime'] = format_datetime(task.start_time, format='short') + ret['runtime'] = format_runtime(task.runtime) + + # localize the task status + if isinstance(task.stat, int): + if task.stat == STAT_WAITING: + ret['status'] = _('Waiting') + elif task.stat == STAT_FAIL: + ret['status'] = _('Failed') + elif task.stat == STAT_STARTED: + ret['status'] = _('Started') + elif task.stat == STAT_FINISH_SUCCESS: + ret['status'] = _('Finished') + elif task.stat == STAT_ENDED: + ret['status'] = _('Ended') + elif task.stat == STAT_CANCELLED: + ret['status'] = _('Cancelled') + else: + ret['status'] = _('Unknown Status') + + ret['taskMessage'] = "{}: {}".format(task.name, task.message) if task.message else task.name + ret['progress'] = "{} %".format(int(task.progress * 100)) + ret['user'] = escape(user) # prevent xss + + # Hidden fields + ret['task_id'] = task.id + ret['stat'] = task.stat + ret['is_cancellable'] = task.is_cancellable + + rendered_tasklist.append(ret) + + return rendered_tasklist + + +# helper function for displaying the runtime of tasks +def format_runtime(runtime): + ret_val = "" + if runtime.days: + ret_val = format_unit(runtime.days, 'duration-day', length="long") + ', ' + minutes, seconds = divmod(runtime.seconds, 60) + hours, minutes = divmod(minutes, 60) + # ToDo: locale.number_symbols._data['timeSeparator'] -> localize time separator ? + if hours: + ret_val += '{:d}:{:02d}:{:02d}s'.format(hours, minutes, seconds) + elif minutes: + ret_val += '{:2d}:{:02d}s'.format(minutes, seconds) + else: + ret_val += '{:2d}s'.format(seconds) + return ret_val diff --git a/cps/templates/admin.html b/cps/templates/admin.html index 9728cb6d4..1199b21fb 100644 --- a/cps/templates/admin.html +++ b/cps/templates/admin.html @@ -11,8 +11,8 @@ - - + + @@ -47,7 +47,9 @@ {% endfor %}
      {{_('Username')}}{{_('E-mail Address')}}{{_('Send to Kindle E-mail Address')}}{{_('Email')}}{{_('Send to eReader Email')}} {{_('Downloads')}}
      {% endif %} - {{_('Edit Users')}} + {% if not simple %} + {{_('Edit Users')}} + {% endif %} {{_('Add New User')}} {% if (config.config_login_type == 1) %}
      {{_('Import LDAP Users')}}
      @@ -57,7 +59,7 @@
      -

      {{_('E-mail Server Settings')}}

      +

      {{_('Email Server Settings')}}

      {% if config.get_mail_server_configured() %} {% if email.mail_server_type == 0 %}
      @@ -78,24 +80,24 @@
      {{email.mail_login}}
      -
      {{_('From E-mail')}}
      +
      {{_('From Email')}}
      {{email.mail_from}}
      {% else %}
      -
      {{_('E-Mail Service')}}
      +
      {{_('Email Service')}}
      {{_('Gmail via Oauth2')}}
      -
      {{_('From E-mail')}}
      +
      {{_('From Email')}}
      {{email.mail_gmail_token['email']}}
      {% endif %} {% endif %} - {{_('Edit E-mail Server Settings')}} + {{_('Edit Email Server Settings')}}
      @@ -159,21 +161,59 @@ {{_('Edit UI Configuration')}}
      +{% if feature_support['scheduler'] %} +
      +
      +

      {{_('Scheduled Tasks')}}

      +
      +
      +
      {{_('Start Time')}}
      +
      {{schedule_time}}
      +
      +
      +
      {{_('Maximum Duration')}}
      +
      {{schedule_duration}}
      +
      +
      +
      {{_('Generate Thumbnails')}}
      +
      {{ display_bool_setting(config.schedule_generate_book_covers) }}
      +
      + +
      +
      {{_('Reconnect Calibre Database')}}
      +
      {{ display_bool_setting(config.schedule_reconnect) }}
      +
      -
      -

      {{_('Administration')}}

      - {{_('Download Debug Package')}} - {{_('View Logs')}} +
      + {{_('Edit Scheduled Tasks Settings')}} + {% if config.schedule_generate_book_covers %} + {{_('Refresh Thumbnail Cache')}} + {% endif %}
      -
      -
      {{_('Reconnect Calibre Database')}}
      -
      {{_('Restart')}}
      -
      {{_('Shutdown')}}
      +
      +{% endif %} +
      +

      {{_('Administration')}}

      + {{_('Download Debug Package')}} + {{_('View Logs')}} +
      +
      +
      {{_('Reconnect Calibre Database')}}
      +
      +
      +
      {{_('Restart')}}
      +
      {{_('Shutdown')}}
      +
      +
      +
      {{_('Queue all books for metadata backup')}}
      -

      {{_('Update')}}

      +

      {{_('Version Information')}}

      @@ -184,13 +224,12 @@ - +
      {{commit}} {{_('Current version')}}{{_('Current Version')}}
      - - {% if feature_support['updater'] %} + {% if feature_support['updater'] %}
      {{_('Check for Update')}}
      @@ -251,3 +290,6 @@
      {% endblock %} +{% block modal %} +{{ change_confirm_modal() }} +{% endblock %} diff --git a/cps/templates/author.html b/cps/templates/author.html index f2b71eab1..b991e959f 100644 --- a/cps/templates/author.html +++ b/cps/templates/author.html @@ -5,11 +5,11 @@ {% if author is not none %}
      {%if author.image_url is not none %} - {{author.name|safe}} + {{author.name}} {% endif %} {%if author.about is not none %} -

      {{author.about|safe}}

      +

      {{author.about}}

      {% endif %} - {{_("via")}} Goodreads @@ -31,28 +31,27 @@
      - {% if entries[0] %} {% for entry in entries %}
      - -

      {{entry.title|shortentitle}}

      +
      +

      {{entry.Books.title|shortentitle}}

      - {% for author in entry.authors %} + {% for author in entry.Books.authors %} {% if loop.index > g.config_authors_max and g.config_authors_max != 0 %} {% if not loop.first %} & {% endif %} - {{author.name.replace('|',',')|shortentitle(30)}} + {{author.name.replace('|',',')|shortentitle(30)}} {% if loop.last %} (...) {% endif %} @@ -60,26 +59,26 @@ {% if not loop.first %} & {% endif %} - {{author.name.replace('|',',')|shortentitle(30)}} + {{author.name.replace('|',',')|shortentitle(30)}} {% endif %} {% endfor %} - {% for format in entry.data %} + {% for format in entry.Books.data %} {% if format.format|lower in g.constants.EXTENSIONS_AUDIO %} {% endif %} {% endfor %}

      - {% if entry.series.__len__() > 0 %} + {% if entry.Books.series.__len__() > 0 %}

      - - {{entry.series[0].name}} + + {{entry.Books.series[0].name}} - ({{entry.series_index|formatseriesindex}}) + ({{entry.Books.series_index|formatseriesindex}})

      {% endif %} - {% if entry.ratings.__len__() > 0 %} + {% if entry.Books.ratings.__len__() > 0 %}
      - {% for number in range((entry.ratings[0].rating/2)|int(2)) %} + {% for number in range((entry.Books.ratings[0].rating/2)|int(2)) %} {% if loop.last and loop.index < 5 %} {% for numer in range(5 - loop.index) %} @@ -92,13 +91,12 @@
      {% endfor %} - {% endif %}
      {% if other_books and author is not none %}
      -

      {{_("More by")}} {{ author.name.replace('|',',')|safe }}

      +

      {{_("More by")}} {{ author.name.replace('|',',') }}

      {% for entry in other_books %}
      @@ -123,7 +121,7 @@

      {% if entry.series.__len__() > 0 %}

      - + {{entry.series[0].name}} ({{entry.series_index|formatseriesindex}}) diff --git a/cps/templates/book_edit.html b/cps/templates/book_edit.html index 21ae98e6a..6552cd261 100644 --- a/cps/templates/book_edit.html +++ b/cps/templates/book_edit.html @@ -3,9 +3,10 @@ {% if book %}

      - {{ book.title }} + +
      -{% if g.user.role_delete_books() %} +{% if current_user.role_delete_books() %}
      @@ -22,7 +23,7 @@ {% if source_formats|length > 0 and conversion_formats|length > 0 %}

      {{_('Convert book format:')}}

      - +
      @@ -48,7 +49,7 @@ {% endif %}
      - +
      @@ -98,8 +99,7 @@
      - {% if g.user.role_upload() or g.user.role_admin()%} - {% if g.allow_upload %} + {% if current_user.role_upload() and g.allow_upload %}
      @@ -109,7 +109,6 @@
      - {% endif %} {% endif %}
      @@ -197,14 +196,12 @@
      {% endfor %} {% endif %} - {% if g.user.role_upload() or g.user.role_admin()%} - {% if g.allow_upload %} + {% if current_user.role_upload() and g.allow_upload %}
      - {% endif %} {% endif %}
      @@ -222,7 +219,7 @@ {% endblock %} {% block modal %} -{{ delete_book() }} +{{ delete_book(current_user.role_delete_books()) }} {{ delete_confirm_modal() }} @@ -269,17 +266,17 @@ >

      - <%= title %> + <%= title %>

      -

      {{_('Author')}}:<%= authors.join(" & ") %>

      +

      {{_('Author')}}:<%= authors.join(" & ") %>

      <% if (publisher) { %> -

      {{_('Publisher')}}:<%= publisher %>

      +

      {{_('Publisher')}}:<%= publisher %>

      <% } %> <% if (description) { %> -

      {{_('Description')}}: <%= description %>

      +

      {{_('Description')}}: <%= description %>

      <% } %>

      {{_('Source')}}: - <%= source.description %> + <%= source.description %>

      @@ -294,7 +291,7 @@ 'description': {{_('Description')|safe|tojson}}, 'source': {{_('Source')|safe|tojson}}, }; - var language = '{{ g.user.locale }}'; + var language = '{{ current_user.locale }}'; $("#add-identifier-line").click(function() { // create a random identifier type to have a valid name in form. This will not be used when dealing with the form @@ -316,8 +313,8 @@ -{% if not g.user.locale == 'en' %} - +{% if not current_user.locale == 'en' %} + {% endif %} diff --git a/cps/templates/book_exists_flash.html b/cps/templates/book_exists_flash.html index b0855120d..b55192ce2 100644 --- a/cps/templates/book_exists_flash.html +++ b/cps/templates/book_exists_flash.html @@ -1,3 +1,3 @@ - + {{entry.title|shortentitle}} - \ No newline at end of file + diff --git a/cps/templates/book_table.html b/cps/templates/book_table.html index fb0cfed81..16836b7b2 100644 --- a/cps/templates/book_table.html +++ b/cps/templates/book_table.html @@ -4,9 +4,9 @@ {% if sort %}data-sortable="true" {% endif %} data-visible = "{{visiblility.get(parameter)}}" data-escape="true" - {% if g.user.role_edit() %} + {% if current_user.role_edit() %} data-editable-type="text" - data-editable-url="{{ url_for('editbook.edit_list_book', param=parameter)}}" + data-editable-url="{{ url_for('edit-book.edit_list_book', param=parameter)}}" data-editable-title="{{ edit_text }}" data-edit="true" {% if validate %}data-edit-validate="{{ _('This Field is Required') }}" {% endif %} @@ -14,13 +14,13 @@ >{{ show_text }} {%- endmacro %} -{% macro book_checkbox_row(parameter, array_field, show_text, element, value, sort) -%} - + {%- endmacro %} @@ -53,10 +53,10 @@
      + data-url="{{url_for('web.list_books')}}" data-locale="{{ current_user.locale }}"> - {% if g.user.role_edit() %} + {% if current_user.role_edit() %} {% endif %} @@ -66,34 +66,37 @@ {{ text_table_row('authors', _('Enter Authors'),_('Authors'), true, true) }} {{ text_table_row('tags', _('Enter Categories'),_('Categories'), false, true) }} {{ text_table_row('series', _('Enter Series'),_('Series'), false, true) }} - + {{ text_table_row('languages', _('Enter Languages'),_('Languages'), false, true) }} {{ text_table_row('publishers', _('Enter Publishers'),_('Publishers'), false, true) }} - - + + {% if current_user.check_visibility(32768) %} + {{ book_checkbox_row('is_archived', _('Archive Status'), false)}} + {% endif %} + {{ book_checkbox_row('read_status', _('Read Status'), false)}} {% for c in cc %} {% if c.datatype == "int" %} - + {% elif c.datatype == "rating" %} - + {% elif c.datatype == "float" %} - + {% elif c.datatype == "enumeration" %} - + {% elif c.datatype in ["datetime"] %} {% elif c.datatype == "text" %} {{ text_table_row('custom_column_' + c.id|string, _('Enter ') + c.name, c.name, false, false) }} {% elif c.datatype == "comments" %} - + {% elif c.datatype == "bool" %} - {{ book_checkbox_row('custom_column_' + c.id|string, _('Enter ') + c.name, c.name, visiblility, all_roles, false)}} + {{ book_checkbox_row('custom_column_' + c.id|string, c.name, false)}} {% else %} {% endif %} {% endfor %} - {% if g.user.role_delete_books() and g.user.role_edit()%} + {% if current_user.role_delete_books() and current_user.role_edit()%} {% endif %} @@ -101,8 +104,8 @@
      {{_('Series Index')}}{{_('Series Index')}}{{_('Comments')}}{{_('Comments')}}{{c.name}}{{c.name}}{{c.name}}{{c.name}}{{c.name}}{{c.name}}{{c.name}}{{c.name}}{{c.name}}{{c.name}}{{_('Delete')}}
      {% endblock %} {% block modal %} -{{ delete_book() }} -{% if g.user.role_edit() %} +{{ delete_book(current_user.role_delete_books()) }} +{% if current_user.role_edit() %} @@ -134,8 +137,8 @@ -{% if not g.user.locale == 'en' %} - +{% if not current_user.locale == 'en' %} + {% endif %} diff --git a/cps/templates/config_edit.html b/cps/templates/config_edit.html index 4d6c68ce1..815fb1625 100644 --- a/cps/templates/config_edit.html +++ b/cps/templates/config_edit.html @@ -105,7 +105,7 @@
      - +
      @@ -124,7 +124,7 @@
      - +
      diff --git a/cps/templates/config_view_edit.html b/cps/templates/config_view_edit.html index 1dc02a5ea..e4fea44d7 100644 --- a/cps/templates/config_view_edit.html +++ b/cps/templates/config_view_edit.html @@ -162,8 +162,10 @@
      + {% if not simple %} {{_('Add Allowed/Denied Tags')}} {{_('Add Allowed/Denied custom column values')}} + {% endif %}
      diff --git a/cps/templates/detail.html b/cps/templates/detail.html index 0ecaf9031..c9cb81430 100644 --- a/cps/templates/detail.html +++ b/cps/templates/detail.html @@ -4,13 +4,14 @@
      - {{ entry.title }} + +
      {% endfor %} {% endif %} - {% if not g.user.is_anonymous %} + {% if not current_user.is_anonymous %}

      - {% if g.user.check_visibility(32768) %} + {% if current_user.check_visibility(32768) %}

      @@ -248,8 +250,8 @@
      - {% if g.user.is_authenticated %} - {% if g.user.shelf.all() or g.shelves_access %} + {% if current_user.is_authenticated %} + {% if current_user.shelf.all() or g.shelves_access %} {% endblock %} +{% block modal %} +{{ delete_book(current_user.role_delete_books()) }} +{% if current_user.role_admin() %} + +{% endif %} +{% endblock %} {% block js %} diff --git a/cps/templates/user_edit.html b/cps/templates/user_edit.html index edecbaf2e..0abb39ee4 100644 --- a/cps/templates/user_edit.html +++ b/cps/templates/user_edit.html @@ -5,19 +5,19 @@
      - {% if new_user or ( g.user and content.name != "Guest" and g.user.role_admin() ) %} + {% if new_user or ( current_user and content.name != "Guest" and current_user.role_admin() ) %}
      {% endif %}
      - +
      - {% if ( g.user and g.user.role_passwd() or g.user.role_admin() ) and not content.role_anonymous() %} - {% if g.user and g.user.role_admin() and not new_user and not profile and ( mail_configured and content.email if content.email != None ) %} - {{_('Reset user Password')}} + {% if ( current_user and current_user.role_passwd() or current_user.role_admin() ) and not content.role_anonymous() %} + {% if current_user and current_user.role_admin() and not new_user and not profile and ( mail_configured and content.email if content.email != None ) %} + {{_('Reset user Password')}} {% endif %}
      @@ -25,7 +25,7 @@
      {% endif %}
      - +
      {% if not content.role_anonymous() %} @@ -66,6 +66,9 @@ {{_('Create/View')}}
      +
      + +
      {% endif %}
      {% for element in sidebar %} @@ -80,13 +83,13 @@
      - {% if ( g.user and g.user.role_admin() and not new_user ) %} + {% if ( current_user and current_user.role_admin() and not new_user ) and not simple %} {{_('Add Allowed/Denied Tags')}} {{_('Add allowed/Denied Custom Column Values')}} {% endif %}
      - {% if g.user and g.user.role_admin() and not profile %} + {% if current_user and current_user.role_admin() and not profile %} {% if not content.role_anonymous() %}
      @@ -128,7 +131,7 @@
      {% endif %} {% endif %} - {% if kobo_support and not content.role_anonymous() %} + {% if kobo_support and not content.role_anonymous() and not simple%}
      @@ -140,7 +143,7 @@ {% if not profile %}
      {{_('Cancel')}}
      {% endif %} - {% if g.user and g.user.role_admin() and not profile and not new_user and not content.role_anonymous() %} + {% if current_user and current_user.role_admin() and not profile and not new_user and not content.role_anonymous() %}
      {{_('Delete User')}}
      {% endif %}
      diff --git a/cps/templates/user_table.html b/cps/templates/user_table.html index 84dd114b4..3f998f951 100644 --- a/cps/templates/user_table.html +++ b/cps/templates/user_table.html @@ -125,15 +125,15 @@
      + data-url="{{url_for('admin.list_users')}}" data-locale="{{ current_user.locale }}"> {{ user_table_row('name', _('Enter Username'), _('Username'), true) }} - {{ user_table_row('email', _('Enter E-mail Address'), _('E-mail Address'), true) }} - {{ user_table_row('kindle_mail', _('Enter Kindle E-mail Address'), _('Kindle E-mail'), false) }} + {{ user_table_row('email', _('Enter Email'), _('Email'), true) }} + {{ user_table_row('kindle_mail', _('Enter eReader Email'), _('eReader Email'), false) }} {{ user_select_translations('locale', url_for('admin.table_get_locale'), _('Locale'), true) }} {{ user_select_languages('default_language', url_for('admin.table_get_default_lang'), _('Visible Book Languages'), true) }} {{ user_table_row('allowed_tags', _("Edit Allowed Tags"), _("Allowed Tags"), false, tags) }} @@ -152,18 +152,18 @@ {{ user_single_checkbox_row("kobo_only_shelves_sync", _('Sync selected Shelves with Kobo'))}} {% endif %} {{ user_checkbox_row("sidebar_view", "detail_random", _('Show Random Books in Detail View'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_language", _('Show language selection'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_read_and_unread", _('Show read/unread selection'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_series", _('Show series selection'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_category", _('Show category selection'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_random", _('Show random books'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_author", _('Show author selection'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_language", _('Show Language Section'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_read_and_unread", _('Show Read/Unread Section'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_series", _('Show Series Section'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_category", _('Show Category Section'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_random", _('Show Random Books'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_author", _('Show Author Section'), visiblility, sidebar_settings)}} {{ user_checkbox_row("sidebar_view", "sidebar_best_rated", _('Show Top Rated Books'), visiblility, sidebar_settings)}} {{ user_checkbox_row("sidebar_view", "sidebar_read_and_unread", _('Show Random Books'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_publisher", _('Show publisher selection'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_rating", _('Show ratings selection'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_format", _('Show file formats selection'), visiblility, sidebar_settings)}} - {{ user_checkbox_row("sidebar_view", "sidebar_archived", _('Show archived books'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_publisher", _('Show Publisher Section'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_rating", _('Show Ratings Section'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_format", _('Show File Formats Section'), visiblility, sidebar_settings)}} + {{ user_checkbox_row("sidebar_view", "sidebar_archived", _('Show Archived Books'), visiblility, sidebar_settings)}} {{ user_checkbox_row("sidebar_view", "sidebar_download", _('Show Downloaded Books'), visiblility, sidebar_settings)}} {{ user_checkbox_row("sidebar_view", "sidebar_list", _('Show Books List'), visiblility, sidebar_settings)}} @@ -185,8 +185,8 @@ -{% if not g.user.locale == 'en' %} - +{% if not current_user.locale == 'en' %} + {% endif %} {% endblock %} diff --git a/cps/tornado_wsgi.py b/cps/tornado_wsgi.py new file mode 100644 index 000000000..af93219c6 --- /dev/null +++ b/cps/tornado_wsgi.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- + +# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) +# Copyright (C) 2022 OzzieIsaacs +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +from tornado.wsgi import WSGIContainer +import tornado + +from tornado import escape +from tornado import httputil + +from typing import List, Tuple, Optional, Callable, Any, Dict, Text +from types import TracebackType +import typing + +if typing.TYPE_CHECKING: + from typing import Type # noqa: F401 + from wsgiref.types import WSGIApplication as WSGIAppType # noqa: F4 + +class MyWSGIContainer(WSGIContainer): + + def __call__(self, request: httputil.HTTPServerRequest) -> None: + data = {} # type: Dict[str, Any] + response = [] # type: List[bytes] + + def start_response( + status: str, + headers: List[Tuple[str, str]], + exc_info: Optional[ + Tuple[ + "Optional[Type[BaseException]]", + Optional[BaseException], + Optional[TracebackType], + ] + ] = None, + ) -> Callable[[bytes], Any]: + data["status"] = status + data["headers"] = headers + return response.append + + app_response = self.wsgi_application( + MyWSGIContainer.environ(request), start_response + ) + try: + response.extend(app_response) + body = b"".join(response) + finally: + if hasattr(app_response, "close"): + app_response.close() # type: ignore + if not data: + raise Exception("WSGI app did not call start_response") + + status_code_str, reason = data["status"].split(" ", 1) + status_code = int(status_code_str) + headers = data["headers"] # type: List[Tuple[str, str]] + header_set = set(k.lower() for (k, v) in headers) + body = escape.utf8(body) + if status_code != 304: + if "content-length" not in header_set: + headers.append(("Content-Length", str(len(body)))) + if "content-type" not in header_set: + headers.append(("Content-Type", "text/html; charset=UTF-8")) + if "server" not in header_set: + headers.append(("Server", "TornadoServer/%s" % tornado.version)) + + start_line = httputil.ResponseStartLine("HTTP/1.1", status_code, reason) + header_obj = httputil.HTTPHeaders() + for key, value in headers: + header_obj.add(key, value) + assert request.connection is not None + request.connection.write_headers(start_line, header_obj, chunk=body) + request.connection.finish() + self._log(status_code, request) + + @staticmethod + def environ(request: httputil.HTTPServerRequest) -> Dict[Text, Any]: + environ = WSGIContainer.environ(request) + environ['RAW_URI'] = request.path + return environ + diff --git a/cps/translations/cs/LC_MESSAGES/messages.mo b/cps/translations/cs/LC_MESSAGES/messages.mo index 2168e8bee..11b1ed342 100644 Binary files a/cps/translations/cs/LC_MESSAGES/messages.mo and b/cps/translations/cs/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/cs/LC_MESSAGES/messages.po b/cps/translations/cs/LC_MESSAGES/messages.po index 3c8875ed8..5137582bc 100644 --- a/cps/translations/cs/LC_MESSAGES/messages.po +++ b/cps/translations/cs/LC_MESSAGES/messages.po @@ -6,589 +6,646 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2020-06-09 21:11+0100\n" "Last-Translator: Lukas Heroudek \n" "Language: cs_CZ\n" "Language-Team: \n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n>=2 && n<=4 ? 1 : 2)\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n>=2 && n<=4 ? 1 : 2);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "není nainstalováno" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "nainstalováno" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Statistika" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Server restartován, znovu načtěte stránku" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Vypínám server, zavřete okno" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Úspěšně obnovené připojení" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Neznámý příkaz" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Kniha byla úspěšně zařazena do fronty pro odeslání na %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Neznámý" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Stránka správce" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Základní konfigurace" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Konfigurace uživatelského rozhraní" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" msgstr "Uživatel admin" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Vše" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "Uživatel nenalezen" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Zobrazit vše" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "Nezbývá žádný správce, nelze odebrat roli správce" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Konfigurace Calibre-Web aktualizována" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "Opravdu chcete odstranit Kobo token?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Jste si jisti, že chcete odstranit tuto polici?" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Jste si jisti, že chcete odstranit tuto polici?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Jste si jisti, že chcete odstranit tuto polici?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Jste si jisti, že chcete odstranit tuto polici?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "Opravdu chcete vypnout?" -#: cps/admin.py:741 -msgid "Tag not found" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Zakázat" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Povolit" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json není nakonfigurováno pro webové aplikace" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "Umístění zápisového souboru není platné. Určete prosím platnou polohu" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "Umístění zápisového souboru pro přístup není platné. Určete prosím platnou polohu" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Prosím zadejte LDAP poskytovatele, port, DN a Identifikátor objektu uživatele" -#: cps/admin.py:1102 +#: cps/admin.py:1191 #, fuzzy msgid "Please Enter a LDAP Service Account and Password" msgstr "Zadejte platné uživatelské jméno pro obnovení hesla" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "Filtr objektů skupiny LDAP musí mít jeden “%s” formátový identifikátor" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "Filtr objektů skupiny LDAP má nesrovnatelnou závorku" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "Filtr uživatelských objektů LDAP musí mít jeden “%s” formátový identifikátor" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "Filtr uživatelských objektů LDAP má nesrovnatelnou závorku" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "Umístění databáze není platné, opravte prosím cestu" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "Databáze není zapisovatelná" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "Umístění souboru klíčů není platné, zadejte prosím správnou cestu" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "Umístění certifikátu není platné, zadejte prosím správnou cestu" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Nastavení e-mailového serveru aktualizováno" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Konfigurace funkcí" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Vyplňte všechna pole!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "E-mail není z platné domény" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "Přidat nového uživatele" -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Uživatel '%(user)s' vytvořen" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Byl nalezen existující účet pro tuto e-mailovou adresu nebo přezdívku." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Uživatel '%(nick)s' smazán" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Nezbývá žádný správce, nemůžete jej odstranit" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Upravit uživatele %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Uživatel '%(nick)s' aktualizován" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Neznámá chyba. Opakujte prosím později." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Změnit SMTP nastavení" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Chyba databáze: %(error)s." + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Při odesílání zkušebního e-mailu došlo k chybě: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Prvně nastavte svou e-mailovou adresu..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Nastavení e-mailového serveru aktualizováno" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Neznámá chyba. Opakujte prosím později." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Upravit uživatele %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Heslo pro uživatele %(user)s resetováno" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Nejprve nakonfigurujte nastavení pošty SMTP..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Prohlížeč log souborů" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Požadování balíčku aktualizace" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Stahování balíčku aktualizace" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Rozbalování balíčku aktualizace" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Nahrazování souborů" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Databázová připojení jsou uzavřena" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Zastavuji server" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Aktualizace dokončena, klepněte na tlačítko OK a znovu načtěte stránku" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Aktualizace selhala:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTP chyba" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Chyba připojení" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Vypršel časový limit při navazování spojení" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Všeobecná chyba" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "Aktualizační soubor nemohl být uložen do Temp Dir" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 #, fuzzy msgid "Failed to extract at least One LDAP User" msgstr "Nepodařilo se vytvořit nejméně jednoho uživatele LDAP" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "Nepodařilo se vytvořit nejméně jednoho uživatele LDAP" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Chyba: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Chyba: Žádná reakce od uživatele LDAP serveru" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "Nejméně jeden uživatel LDAP nenalezen v databázi" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "" -#: cps/converter.py:30 -msgid "not configured" -msgstr "není nakonfigurováno" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "Umístění databáze není platné, opravte prosím cestu" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "Databáze není zapisovatelná" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "Umístění souboru klíčů není platné, zadejte prosím správnou cestu" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "Umístění certifikátu není platné, zadejte prosím správnou cestu" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "Nastavení e-mailového serveru aktualizováno" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Konfigurace funkcí" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Vyplňte všechna pole!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "E-mail není z platné domény" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Přidat nového uživatele" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Uživatel '%(user)s' vytvořen" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Byl nalezen existující účet pro tuto e-mailovou adresu nebo přezdívku." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Uživatel '%(nick)s' smazán" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Nezbývá žádný správce, nemůžete jej odstranit" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Uživatel '%(nick)s' aktualizován" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "není nainstalováno" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Chybí povolení k exekuci" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 -#, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, fuzzy, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "Vlastní sloupec %(column)d neexistuje v databázi" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Formát knihy úspěšně smazán" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Žádné" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Kniha úspěšně smazána" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Jejda! Vybraná kniha není k dispozici. Soubor neexistuje nebo není přístupný" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "upravit metadata" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s není platným jazykem" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "Soubor s příponou '%(ext)s' nelze odeslat na tento server" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Soubor, který má být odeslán musí mít příponu" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Nepodařilo se vytvořit cestu %(path)s (oprávnění odepřeno)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Uložení souboru %(file)s se nezdařilo." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Chyba databáze: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Formát souboru %(ext)s přidán do %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Metadata úspěšně aktualizována" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Chyba při úpravách knihy, zkontrolujte prosím log pro podrobnosti" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Nahraná kniha pravděpodobně existuje v knihovně, zvažte prosím změnu před nahráním nové: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "Soubor %(filename)s nemohl být uložen do dočasného adresáře" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Nepodařilo se přesunout soubor obalu %(file)s: %(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Soubor %(file)s nahrán" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Chybí zdrojový nebo cílový formát pro převod" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Kniha byla úspěšně zařazena do fronty pro převod do %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Při převodu této knihy došlo k chybě: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Nahraná kniha pravděpodobně existuje v knihovně, zvažte prosím změnu před nahráním nové: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s není platným jazykem" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Soubor s příponou '%(ext)s' nelze odeslat na tento server" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Soubor, který má být odeslán musí mít příponu" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Soubor %(filename)s nemohl být uložen do dočasného adresáře" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Nepodařilo se přesunout soubor obalu %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Formát knihy úspěšně smazán" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Kniha úspěšně smazána" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "upravit metadata" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Nepodařilo se vytvořit cestu %(path)s (oprávnění odepřeno)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Uložení souboru %(file)s se nezdařilo." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Formát souboru %(ext)s přidán do %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Google Drive nastavení nebylo dokončeno, zkuste znovu deaktivovat a aktivovat Google Drive" @@ -602,166 +659,180 @@ msgstr "Doména zpětného volání není ověřena, postupujte podle pokynů k msgid "%(format)s format not found for book id: %(book)d" msgstr "%(format)s formát pro knihu: %(book)d nenalezen" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s nenalezen na Google Drive: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s nenalezen: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Poslat do Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Tento e-mail byl odeslán přes Calibre-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Calibre-Web zkušební e-mail" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Zkušební e-mail" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Začínáme s Calibre-Web" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Registrační e-mail pro uživatele: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "Převést %(orig)s do %(format)s a poslat do Kindle" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "Poslat %(format)s do Kindle" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Poslat do Kindle" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Požadovaný soubor nelze přečíst. Možná nesprávná oprávnění?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "Mazání knihy selhalo %(id)s failed: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, fuzzy, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "Mazání knihy %(id)s, cesta ke knize není platná %(path)s" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "Přejmenování názvu z: '%(src)s' na '%(dest)s' selhalo chybou: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Přejmenování souboru v cestě '%(src)s' na '%(dest)s' selhalo chybou: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Soubor %(file)s nenalezen na Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Přejmenování názvu z: '%(src)s' na '%(dest)s' selhalo chybou: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Cesta ke knize %(path)s nebyla nalezena na Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Byl nalezen existující účet pro tuto e-mailovou adresu." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Zadané uživatelské jméno je již použito" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Chyba stahování obalu" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "Chyba formátu obalu" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Vytvoření cesty obalu selhalo" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "Soubor obalu není platný, nebo nelze uložit" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Pouze jpg/jpeg jsou podporované soubory pro obal" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "Unrar binární soubor nenalezen" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" msgstr "Chyba provádění UnRar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Čekám" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Objevte" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Selhalo" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "Spuštěno" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Dokončeno" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Neznámý stav" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Pro získání platného api_endpoint pro zařízení Kobo, přístupte na calibre-web bez localhost" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Kobo nastavení" @@ -770,9 +841,9 @@ msgstr "Kobo nastavení" msgid "Register with %(provider)s" msgstr "Registrovat s %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "nyní jste přihlášen jako: '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -831,507 +902,613 @@ msgstr "Google Oauth chyba, prosím opakujte později." msgid "Google Oauth error: {}" msgstr "" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Přihlásit" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Token nenalezen" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Token vypršel" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Úspěch! Vraťte se prosím do zařízení" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Knihy" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Zobrazit nedávné knihy" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Žhavé knihy" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Zobrazit žhavé knihy" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Nejlépe hodnocené knihy" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Zobrazit nejlépe hodnocené knihy" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Přečtené knihy" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Zobrazit prečtené a nepřečtené" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Nepřečtené knihy" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Zobrazit nepřečtené" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Objevte" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Zobrazit náhodné knihy" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Kategorie" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Zobrazit výběr kategorie" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Série" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Zobrazit výběr sérií" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Autoři" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Zobrazit výběr autora" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Vydavatelé" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Zobrazit výběr vydavatele" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Jazyky" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Zobrazit výběr jazyka" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Hodnocení" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Zobrazit výběr hodnocení" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Formáty souborů" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Zobrazit výběr formátů" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Archivované knihy" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" msgstr "Zobrazit archivované knihy" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Zadána neplatná police" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Lituji, nejste oprávněni přidat knihu do police: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Kniha je již součástí police: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Kniha byla přidána do police: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Nejste oprávněni přidat knihu do police: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Knihy jsou již součástí police: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Knihy byly přidány do police: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Nelze přidat knihy do police: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Kniha byla odebrána z police: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Lituji, nejste oprávněni odebrat knihu z této police: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Vytvořit polici" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Lituji, nejste oprávněni odebrat knihu z této police: %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Upravit polici" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Police %(title)s vytvořena" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Police %(title)s změněna" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Došlo k chybě" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Veřejná police s názvem '%(title)s' již existuje." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Osobní police s názvem ‘%(title)s’ již existuje." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Změnit pořadí Police: '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Police: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Chyba otevírání police. Police neexistuje nebo není přístupná" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Neočekávaná data při čtení informací o aktualizaci" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Aktualizace není k dispozici. Máte nainstalovanou nejnovější verzi" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Nová aktualizace k dispozici. Klepnutím na tlačítko níže aktualizujte na nejnovější verzi." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Nelze získat informace o aktualizaci" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Klepnutím na tlačítko níže aktualizujte na nejnovější stabilní verzi." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Nová aktualizace k dispozici. Klepnutím na tlačítko níže aktualizujte na verzi: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Nejsou k dispozici žádné informace o verzi" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Objevte (Náhodné knihy)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Žhavé knihy (Nejstahovanější)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Autoři: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Vydavatel: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Série: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Hodnocení: %(rating)s stars" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Soubor formátů: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Kategorie: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Jazyky: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Rozšířené hledání" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Hledat" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Stáhnutí" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Seznam hodnocení" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Seznam formátů" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Úlohy" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Vydáno po " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Vydáno před " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Hodnocení <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Hodnocení >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Kniha byla úspěšně zařazena do fronty pro odeslání na %(kindlemail)s" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Rozšířené hledání" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Zadána neplatná police" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Lituji, nejste oprávněni přidat knihu do police: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Kniha je již součástí police: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Kniha byla přidána do police: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Knihy jsou již součástí police: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Knihy byly přidány do police: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Nelze přidat knihy do police: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Kniha byla odebrána z police: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Vytvořit polici" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Lituji, nejste oprávněni odebrat knihu z této police: %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Upravit polici" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Kniha úspěšně smazána" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Změnit pořadí Police: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Police %(title)s vytvořena" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Police %(title)s změněna" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Došlo k chybě" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Veřejná police s názvem '%(title)s' již existuje." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Osobní police s názvem ‘%(title)s’ již existuje." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Police: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Chyba otevírání police. Police neexistuje nebo není přístupná" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Úlohy" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Čekám" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Selhalo" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Spuštěno" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Dokončeno" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Neznámý stav" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Neočekávaná data při čtení informací o aktualizaci" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Aktualizace není k dispozici. Máte nainstalovanou nejnovější verzi" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Nová aktualizace k dispozici. Klepnutím na tlačítko níže aktualizujte na nejnovější verzi." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Nelze získat informace o aktualizaci" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Klepnutím na tlačítko níže aktualizujte na nejnovější stabilní verzi." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Nová aktualizace k dispozici. Klepnutím na tlačítko níže aktualizujte na verzi: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Nejsou k dispozici žádné informace o verzi" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Objevte (Náhodné knihy)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Žhavé knihy (Nejstahovanější)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Autoři: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Vydavatel: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Série: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Hodnocení: %(rating)s stars" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Soubor formátů: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Kategorie: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Jazyky: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Stáhnutí" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Seznam hodnocení" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Seznam formátů" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Nejprve nakonfigurujte nastavení pošty SMTP..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Kniha byla úspěšně zařazena do fronty pro odeslání na %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "Při odesílání této knihy došlo k chybě: %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "Nejprve nakonfigurujte vaši kindle e-mailovou adresu.." -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "E-mailový server není nakonfigurován, kontaktujte svého správce!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Registrovat" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Váš e-mail nemá povolení k registraci" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Potvrzovací e-mail byl odeslán na váš účet." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "Nelze aktivovat ověření LDAP" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "Záložní přihlášení jako: ‘%(nickname)s’, server LDAP není dosažitelný nebo neznámý uživatel" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Nelze se přihlásit: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Špatné uživatelské jméno nebo heslo" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "Nové heslo bylo zasláno na vaši emailovou adresu" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Zadejte platné uživatelské jméno pro obnovení hesla" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Nyní jste přihlášeni jako: '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)s profil" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Profil aktualizován" +#: cps/web.py:1420 +#, fuzzy +msgid "Oops! An account already exists for this Email." +msgstr "Byl nalezen existující účet pro tuto e-mailovou adresu." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Poslat do Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "Calibre převaděč %(tool)s nenalezen" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Kepubify-převaděč selhal: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "Převedený soubor nebyl nalezen nebo více než jeden soubor ve složce %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Převaděč eknih selhal: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "upravit metadata" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Nahrávat" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Uživatelé" @@ -1344,14 +1521,15 @@ msgstr "Přezdívka" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "E-mail" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Poslat do Kindle e-mailová adresa" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Správce" @@ -1361,212 +1539,229 @@ msgstr "Správce" msgid "Password" msgstr "Heslo" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Nahrávat" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Stahovat" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Prohlížení knih" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Upravovat" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Smazat" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Veřejná police" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Přidat nového uživatele" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "Importovat LDAP uživatele" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "Nastavení e-mailového serveru SMTP" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "SMTP hostitel" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP port" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "Šifrování" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "SMTP přihlášení" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Z e-mailu" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Konfigurace" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Calibre DB adresář" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Úroveň logu" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Port" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Knihy na stránku" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Nahrávání" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Anonymní prohlížení" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Veřejná registrace" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Magic Link vzdálené přihlášení" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "Reverzní proxy přihlášení" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Název záhlaví reverzního proxy" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Upravit základní konfiguraci" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Upravit základní konfiguraci" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "Upravit konfiguraci uživatelského rozhraní" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Správa" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Zobrazit log" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Znovupřipojení ke Calibre databázi" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Restartovat" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Vypnout" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Aktualizovat" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Verze" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Detaily" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Současná verze" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Zkontrolovat aktualizace" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Provést aktualizaci" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Opravdu chcete restartovat?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "OK" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Zrušit" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Opravdu chcete vypnout?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Probíhá aktualizace, prosím nenačítejte stránku znovu" @@ -1578,119 +1773,118 @@ msgstr "přes" msgid "In Library" msgstr "V knihovně" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "redukovat" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Více od" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Smazat knihu" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Smazat formáty:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Převést formát knihy:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Převést z:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "vyberte možnost" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Převést do:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Převést knihu" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Název knihy" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Autor" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Popis" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "Identifikátory" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "Typy identifikátorů" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "Hodnota identifikátorů" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Odstranit" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "Přidat identifikátor" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Štítky" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "ID série" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Hodnocení" @@ -1702,82 +1896,83 @@ msgstr "Adresa URL obalu (jpg, obal je stažen a uložen v databázi, pole je po msgid "Upload Cover from Local Disk" msgstr "Nahrát obal z místní jednotky" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Datum vydání" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Vydavatel" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Jazyk" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Ano" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Ne" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Nahrát formát" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Zobrazit knihu po uložení" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Získat metadata" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Uložit" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Klíčové slovo" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr "Hledat klíčové slovo" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Kliknutím na obal načtěte metadata do formuláře" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Načítání..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Zavřít" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Zdroj" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Chyba vyhledávání!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Nebyly nalezeny žádné výsledky! Zadejte jiné klíčové slovo." @@ -1869,27 +2064,36 @@ msgstr "Zadejte jméno domény" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Identifikátory" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Jste si opravdu jisti?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "" @@ -1982,6 +2186,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Povolit nahrávání" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "Povolené nahrávání formátů souborů" @@ -1995,7 +2203,7 @@ msgid "Enable Public Registration" msgstr "Povolit veřejnou registraci" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "Použít e-mail jako přezdívku" #: cps/templates/config_edit.html:132 @@ -2062,11 +2270,6 @@ msgstr "LDAP Server Port" msgid "LDAP Encryption" msgstr "LDAP Šifrování" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Žádné" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2202,7 +2405,7 @@ msgstr "Počet náhodných knih k zobrazení" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Počet autorů k zobrazení před skrytím (0 = Zakázat skrytí)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Motiv" @@ -2234,138 +2437,141 @@ msgstr "Regulární výraz pro řazení názvů" msgid "Default Settings for New Users" msgstr "Výchozí nastavení pro nového uživatele" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Uživatel admin" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Povolit stahování" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Povolit prohlížeč knih" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Povolit nahrávání" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Povolit úpravy" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "Povolit mazání knih" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Povolit změnu hesla" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Povolit úpravy veřejných polic" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Vynechat jazyky" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Zobrazit knihy s jazykem" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Výchozí zobrazení pro nové uživatele" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Zobrazit náhodné knihy v podrobném zobrazení" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "Přidat povolené/zakázané štítky" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "Přidat povolené/zakázané hodnoty vlastních sloupců" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Číst v prohližeči" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Poslechnout v prohlížeči" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, fuzzy, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Publikováno" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Označit jako nepřečtené" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Označit jako přečtené" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Přečteno" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Obnovit z archivu" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Archívovat" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "Archivováno" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Popis:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Přidat do police" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Veřejné)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Upravit metadata" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "" +#, fuzzy +msgid "Gmail Account" +msgstr "Účet" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 @@ -2389,10 +2595,11 @@ msgid "Attachment Size Limit" msgstr "Limit velikosti souboru" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Uložit nastavení a odeslat zkušební e-mail" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Zpět" @@ -2418,46 +2625,63 @@ msgstr "Zadejte jméno domény" msgid "Denied Domains (Blacklist)" msgstr "Zakázané domény pro registraci" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Další" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "Otevřte soubor .kobo/Kobo eReader.conf v textovém editoru a vložte (nebo upravte):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Otevřte soubor .kobo/Kobo/Kobo eReader.conf v textovém editoru a vložte (nebo upravte):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Kobo Sync token" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 #, fuzzy msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "E-mailový server není nakonfigurován, kontaktujte svého správce!" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Vytvořit problém" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Zpět domů" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "" @@ -2521,7 +2745,7 @@ msgstr "Knihy řazené podle hodnocení" msgid "Books ordered by file formats" msgstr "Knihy seřazené podle souboru formátů" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Police" @@ -2530,63 +2754,67 @@ msgstr "Police" msgid "Books organized in shelves" msgstr "Knihy organizované v policích" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Domů" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Přepnout navigaci" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Hledat v knihovně" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Nahrávání..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Chyba" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Nahrávání hotovo, zpracovávám, čekejte prosím..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Nastavení" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Účet" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Odhlásit se" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Nahrávání..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Chyba" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Nahrávání hotovo, zpracovávám, čekejte prosím..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Nastavení" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Prosím neobnovujte stránku" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Procházet" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "O knihovně" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Předchozí" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Podrobnosti o knize" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Zapamatovat si" @@ -2595,7 +2823,7 @@ msgstr "Zapamatovat si" msgid "Forgot Password?" msgstr "Zapomenuté heslo?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Přihlásit se pomocí Magic Link" @@ -2691,7 +2919,7 @@ msgstr "" msgid "Select" msgstr "" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "Kniha" @@ -2705,128 +2933,141 @@ msgstr "Calibre-Web katalog eknih" msgid "epub Reader" msgstr "Čtečka PDF" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Světlý" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Tmavý" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Zpět" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Po otevření postranních panelů přeformátujte text." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "Čtečka PDF" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Klávesové zkratky" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Předchozí strana" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Následujicí strana" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Změnit měřítko na nejlepší" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Změnit měřítko na šířku" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Změnit měřítko na výšku" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Změnit měřítko na nativní" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Otočit doprava" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Otočit doleva" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Převrátit obrázek" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Světlý" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Tmavý" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Měřítko" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Nejlepší" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Šířka" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Výška" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Nativní" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Otočit" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Převrátit" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Vodorovně" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Svisle" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Směr" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Zleva doprava" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Zprava doleva" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "" @@ -2835,7 +3076,7 @@ msgstr "" msgid "DJVU Reader" msgstr "Čtečka PDF" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "Čtečka PDF" @@ -2854,7 +3095,7 @@ msgid "Choose a username" msgstr "Zvolte uživatelské jméno" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Vaše e-mailová adresa" #: cps/templates/remote_login.html:5 @@ -2873,15 +3114,19 @@ msgstr "Jakmile tak učiníte, budete automaticky přihlášeni na tomto zaříz msgid "This verification link will expire in 10 minutes." msgstr "Tento ověřovací odkaz vyprší za 10 minut." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Nenalezeny žádné výsledky" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Termín vyhledávání:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Výsledky pro:" @@ -2893,10 +3138,6 @@ msgstr "Datum vydání od" msgid "Published Date To" msgstr "Datum vydání do" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Vynechat štítky" @@ -2938,30 +3179,26 @@ msgstr "" msgid "To:" msgstr "" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Smazat tuto polici" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Police bude smazána pro všechny uživatele" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Sdílet se všemi" @@ -3003,8 +3240,8 @@ msgid "System Statistics" msgstr "" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Knihovna programu" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3030,9 +3267,17 @@ msgstr "Průběh" msgid "Run Time" msgstr "Doba spuštění" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Čas spuštění" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3062,19 +3307,23 @@ msgstr "Kobo Sync token" msgid "Create/View" msgstr "Vytvořit/Prohlížet" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "Přidat povolené/zakázané hodnoty vlastních sloupců" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Odstranit tohoto uživatele" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Vygenerovat URL pro Kobo Auth" @@ -3094,17 +3343,17 @@ msgstr "Zvolte uživatelské jméno" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "Vaše e-mailová adresa" +msgid "Enter Email" +msgstr "Zkušební e-mail" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Enter Kindle E-mail Address" +msgid "Enter eReader Email" msgstr "Poslat do Kindle e-mailová adresa" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Kindle E-mail" +msgid "eReader Email" msgstr "Zkušební e-mail" #: cps/templates/user_table.html:137 @@ -3174,10 +3423,6 @@ msgstr "" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Zobrazit výběr sérií" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Zobrazit náhodné knihy" - diff --git a/cps/translations/de/LC_MESSAGES/messages.mo b/cps/translations/de/LC_MESSAGES/messages.mo index 4ad26e6b2..0313f5e61 100644 Binary files a/cps/translations/de/LC_MESSAGES/messages.mo and b/cps/translations/de/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/de/LC_MESSAGES/messages.po b/cps/translations/de/LC_MESSAGES/messages.po index 823c2aa7c..6365a5f30 100644 --- a/cps/translations/de/LC_MESSAGES/messages.po +++ b/cps/translations/de/LC_MESSAGES/messages.po @@ -7,581 +7,631 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" -"PO-Revision-Date: 2021-08-01 17:24+0200\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" +"PO-Revision-Date: 2023-01-22 13:51+0100\n" "Last-Translator: Ozzie Isaacs\n" "Language: de\n" "Language-Team: \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "Nicht installiert" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "Installiert" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Statistiken" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" -msgstr "Server neu gestartet, Seite bitte neu laden" +#: cps/admin.py:143 +msgid "Server restarted, please reload page." +msgstr "Server neu gestartet, Seite bitte neu laden." -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" -msgstr "Server wird heruntergefahren, Fenster bitte schließen" +#: cps/admin.py:145 +msgid "Performing Server shutdown, please close window." +msgstr "Server wird heruntergefahren, Fenster bitte schließen." -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Erfolgreich neu verbunden" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "Datenbank wurde erneut verbunden" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Unbekannter Befehl" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +msgid "Success! Books queued for Metadata Backup" +msgstr "Bücher wurden erfolgreich für Metadaten Backup eingereiht" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Unbekannt" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Admin Seite" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Basiskonfiguration" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Benutzeroberflächenkonfiguration" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" msgstr "Benutzer bearbeiten" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Alle" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "Benutzer nicht gefunden" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "{} Benutzer erfolgreich gelöscht" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Zeige alle" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "Ungültige Anfrage" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "Guest Name kann nicht geändert werden" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "Guest Benutzer kann diese Rolle nicht haben" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "Kein Admin Benutzer verblieben Admin Berechtigung kann nicht entfernt werden" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "Wert muss true oder false sein" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "Ungültige Rolle" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "Guest Benutzer kann diese Sichtbarkeit nicht haben" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "Ungültige Sichtbarkeit" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "Guest Sprache wird automatisch bestimmt und kann nicht eingestellt werden" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "Keine gültige Sprache gewählt" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "Keine gültige Buchsprache gewählt" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "Parameter wurde nicht gefunden" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "Ungültige Lese Spalte" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "Ungültiger Spaltenname für Einschränkung" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Konfiguration von Calibre-Web wurde aktualisiert" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "Möchten Sie wirklich den Kobo Token löschen?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "Möchten Sie wirklich diese Domain löschen?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "Möchten Sie wirklich diesen Benutzer löschen?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Möchten Sie wirklich dieses Bücherregal löschen?" -#: cps/admin.py:580 +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Möchten Sie wirklich die Anzeigesprache der ausgewählten Benutzer ändern?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "Möchten Sie wirklich die Büchersprachen für die ausgewählten Benutzer ändern?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "Möchten Sie wirklich die ausgewählte Rolle für die ausgewählten Benutzer verändern?" -#: cps/admin.py:586 +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Möchten Sie wirklich die ausgewählten Sichtbarkeitsbeschränkungen der ausgewählten Benutzer ändern?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "Möchten Sie wirklich die Sichtbarkeiten für die ausgewählten Benutzer verändern?" -#: cps/admin.py:590 +#: cps/admin.py:622 msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Möchten Sie wirklich die Synchronisation von Bücherregalen für die ausgewählten Benutzer verändern?" -#: cps/admin.py:592 +#: cps/admin.py:624 msgid "Are you sure you want to change Calibre library location?" msgstr "Ort der Calibre Datenbank editieren?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "Tag nicht gefunden" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "Calibre-Web wird nach neuen Covern suchen und Cover Miniaturansichten aktualisieren, dies kann eine Weile dauern?" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "Ungültige Aktion" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Möchten Sie wirklich die Synchronisationsdatenbank von Calibre-Web löschen, um eine komplette Synchronisation zu erzwingen?" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Verbieten" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Erlauben" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{} Synchronisationseinträge gelöscht" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Tag nicht gefunden" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Ungültige Aktion" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json ist nicht für Web Anwendungen konfiguriert" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "Logdatei Pfad ist ungültig, bitte einen gültigen Pfad angeben" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "Zugriffs Logdatei Pfad ist ungültig, bitte einen gültigen Pfad angeben" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Bitte einen LDAP Server, Port, DN und Benutzer Objekt angeben" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "Bitte einen LDAP Service Account und Password eingeben" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "Bitte einen LDAP Service Account eingeben" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "LDAP Gruppen Objekt Filter benötigt genau eine \"%s\" Format Kennung" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "LDAP Gruppen Objekt Filter hat ungleiche Anzahl von Klammern" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "LDAP Benutzer Objekt Filter benötigt genau eine \"%s\" Format Kennung" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "LDAP Benutzer Objekt Filter hat ungleiche Anzahl von Klammern" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "Der LDAP Member User Filter benötigt genau eine \"%s\" Formatierungsmarkierung" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "LDAP Member User Filter hat eine ungleiche Anzahl von geöffneten und geschlossenen Klammern" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "LDAP CA-Zertifikat, Zertifikat oder Key Datei ist kein gültiger Pfad" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "Einstellungsdatenbank ist nicht schreibbar" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "DB Pfad ist nicht gültig, bitte einen gültigen Pfad angeben" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "Datenbank ist nicht schreibbar" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "Schlüsseldatei ist ungültig, bitte einen gültigen Pfad angeben" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "Zertifikatsdatei ist ungültig, bitte einen gültigen Pfad angeben" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Einstellungen des E-Mail-Servers aktualisiert" - -#: cps/admin.py:1324 -msgid "Database Configuration" -msgstr "Datenbank-Konfiguration" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Bitte alle Felder ausfüllen!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "E-Mail bezieht sich nicht auf eine gültige Domain" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "Neuen Benutzer hinzufügen" -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Benutzer '%(user)s' angelegt" - -#: cps/admin.py:1369 -msgid "Found an existing account for this e-mail address or name." -msgstr "Es existiert bereits ein Account für diese E-Mailadresse oder diesen Benutzernamen." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Benutzer '%(nick)s' gelöscht" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "Guest Benutzer kann nicht gelöscht werden" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Benutzer kann nicht gelöscht werden, es wäre kein Admin Benutzer übrig" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Benutzer %(nick)s bearbeiten" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Benutzer '%(nick)s' aktualisiert" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Es ist ein unbekannter Fehler aufgetreten. Bitte später erneut versuchen." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "SMTP-Einstellungen ändern" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "Gmail Account Verifikation erfolgreich" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "G-Mail Konto verifiziert." -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Datenbankfehler: %(error)s." + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "Test E-Mail an %(email)s wurde zum Senden in die Warteschlange eingereiht, für das Ergebnis bitte Aufgaben überprüfen" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Es trat ein Fehler beim Versenden der Test-E-Mail auf: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Bitte zuerst E-Mail Adresse konfigurieren..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Einstellungen des E-Mail-Servers aktualisiert" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "Einstellungen für Geplante Aufgaben" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "Ungültigen Startzeitpunkt für Aufgaben spezifiziert" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "Ungültige Laufzeit für Aufgaben spezifiziert" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "Einstellungen für Geplante Aufgaben aktualisiert" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Es ist ein unbekannter Fehler aufgetreten. Bitte später erneut versuchen." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "Einstellungsdatenbank ist nicht schreibbar" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Benutzer %(nick)s bearbeiten" + +#: cps/admin.py:1423 +#, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Passwort für Benutzer %(user)s wurde zurückgesetzt" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." -msgstr "Bitte zuerst die SMTP-Einstellung konfigurieren ..." +#: cps/admin.py:1429 +msgid "Oops! Please configure the SMTP mail settings." +msgstr "Bitte zuerst die SMTP-Einstellung konfigurieren." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Logdatei Anzeige" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Frage Update an" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Lade Update herunter" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Entpacke Update" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Ersetze Dateien" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Schließe Datenbankverbindungen" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Stoppe Server" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Update abgeschlossen, bitte okay drücken und Seite neu laden" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Update fehlgeschlagen:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTP Fehler" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Verbindungsfehler" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Timeout beim Verbindungsaufbau" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Allgemeiner Fehler" -#: cps/admin.py:1696 -#, fuzzy +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" msgstr "Updatedatei konnte nicht in Temporärem Ordner gespeichert werden" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" -msgstr "" +msgstr "Dateien konnten während des Updates nicht ausgetauscht werden" -#: cps/admin.py:1721 -#, fuzzy +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" -msgstr "Mindestens ein LDAP Benutzer konnte nicht erzeugt werden" +msgstr "Mindestens ein LDAP Benutzer konnte nicht extrahiert werden" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "Mindestens ein LDAP Benutzer konnte nicht erzeugt werden" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Fehler: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Fehler: Keine Benutzerinformationen von LDAP Server empfangen" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "Mindestens ein LDAP Benutzer wurde nicht in der Datenbank gefudnen" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} Benutzer erfolgreich importiert" -#: cps/converter.py:30 -msgid "not configured" -msgstr "Nicht konfiguriert" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "DB Pfad ist nicht gültig, bitte einen gültigen Pfad angeben" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "Datenbank ist nicht schreibbar" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "Schlüsseldatei ist ungültig, bitte einen gültigen Pfad angeben" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "Zertifikatsdatei ist ungültig, bitte einen gültigen Pfad angeben" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "Datenbankeinstellung aktualisiert" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "Datenbank-Konfiguration" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Bitte alle Felder ausfüllen." + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "E-Mail bezieht sich nicht auf eine gültige Domain" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Neuen Benutzer hinzufügen" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Benutzer '%(user)s' angelegt" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "Es existiert bereits ein Account für diese E-Mailadresse oder diesen Benutzernamen." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Benutzer '%(nick)s' gelöscht" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Guest Benutzer kann nicht gelöscht werden" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Benutzer kann nicht gelöscht werden, es wäre kein Admin Benutzer übrig" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "E-Mail kann nicht leer sein und muss gültig sein" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Benutzer '%(nick)s' aktualisiert" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "Nicht installiert" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Ausführeberechtigung fehlt" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "Benutzerdefinierte Spalte Nr. %(column)d ist nicht in Calibre Datenbank vorhanden" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Buch Format erfolgreich gelöscht" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Keine" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Buch erfolgreich gelöscht" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Öffnen des Buchs fehlgeschlagen. Datei existiert nicht oder ist nicht zugänglich" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "Metadaten editieren" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "Benutzer hat keine Berechtigung Cover hochzuladen" -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "%(seriesindex)s ist keine gültige Zahl, Eintrag wird ignoriert" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s ist keine gültige Sprache" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "Dateiendung '%(ext)s' kann nicht auf diesen Server hochgeladen werden" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Dateien müssen eine Erweiterung haben, um hochgeladen zu werden" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Fehler beim Erzeugen des Pfads %(path)s (Zugriff verweigert)" - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Fehler beim Speichern der Datei %(file)s." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Datenbankfehler: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Dateiformat %(ext)s zu %(book)s hinzugefügt" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "IDs unterscheiden nicht Groß-Kleinschreibung, alte ID wird überschrieben" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Metadaten wurden erfolgreich aktualisiert" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Fehler beim Editieren des Buchs, Details im Logfile" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "Fehler beim editieren des Buches: {}" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Das hochgeladene Buch existiert evtl. schon in der Bibliothek: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "Die Datei %(filename)s konnte nicht im temporären Ordner gespeichert werden" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Fehler beim Verschieben der Cover Datei %(file)s: %(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Datei %(file)s hochgeladen" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Quell- oder Zielformat für Konvertierung fehlt" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Buch wurde erfolgreich für die Konvertierung nach %(book_format)s eingereiht" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Es trat ein Fehler beim Konvertieren des Buches auf: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Das hochgeladene Buch existiert evtl. schon in der Bibliothek: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "'%(langname)s' ist keine gültige Sprache" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Dateiendung '%(ext)s' kann nicht auf diesen Server hochgeladen werden" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Dateien müssen eine Erweiterung haben, um hochgeladen zu werden" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Die Datei %(filename)s konnte nicht im temporären Ordner gespeichert werden" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Fehler beim Verschieben der Cover Datei %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Buch Format erfolgreich gelöscht" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Buch erfolgreich gelöscht" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "Keine Erlaubnis zum Bücher löschen" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "Metadaten editieren" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s ist keine gültige Zahl, Eintrag wird ignoriert" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "Benutzer hat kein Recht zusätzliche Dateiformate hochzuladen" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Fehler beim Erzeugen des Pfads %(path)s (Zugriff verweigert)" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Fehler beim Speichern der Datei %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Dateiformat %(ext)s zu %(book)s hinzugefügt" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Google Drive Setup is nicht komplett, bitte versuche Google Drive zu deaktivieren und aktiviere es anschließend erneut" @@ -595,165 +645,173 @@ msgstr "Callback Domain ist nicht verifiziert, bitte Domain in der Google Develo msgid "%(format)s format not found for book id: %(book)d" msgstr "%(format)s Format für Buch-ID %(book)d nicht gefunden" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s von Buch %(fn)s nicht auf Google Drive gefunden" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s nicht gefunden: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" -msgstr "An Kindle senden" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +msgid "Send to eReader" +msgstr "An E-Reader senden" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +msgid "This Email has been sent via Calibre-Web." msgstr "Diese E-Mail wurde durch Calibre-Web versendet." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +msgid "Calibre-Web Test Email" msgstr "Calibre-Web Test-E-Mail" -#: cps/helper.py:113 -msgid "Test e-mail" -msgstr "Test-E-Mail" +#: cps/helper.py:115 +msgid "Test Email" +msgstr "Test E-Mail" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Loslegen mit Calibre-Web" -#: cps/helper.py:135 +#: cps/helper.py:137 #, python-format -msgid "Registration e-mail for user: %(name)s" -msgstr "Registrierungs-E-Mail für Benutzer %(name)s" +msgid "Registration Email for user: %(name)s" +msgstr "Registrierungs-E-Mail für Benutzer: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 +#: cps/helper.py:148 cps/helper.py:154 #, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" -msgstr "Konvertiere %(orig)s nach %(format)s und sende an Kindle" +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "Konvertiere %(orig)s nach %(format)s und sende an E-Reader" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 #, python-format -msgid "Send %(format)s to Kindle" -msgstr "Sende %(format)s an Kindle" +msgid "Send %(format)s to eReader" +msgstr "Sende %(format)s an E-Reader" -#: cps/helper.py:219 cps/tasks/convert.py:90 -#, fuzzy, python-format -msgid "%(book)s send to Kindle" -msgstr "An Kindle senden" +#: cps/helper.py:225 +#, python-format +msgid "%(book)s send to eReader" +msgstr "%(book)s an E-Reader gesendet" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Die angeforderte Datei konnte nicht gelesen werden. Evtl. falsche Zugriffsrechte?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "Gelesenen Status konnte nicht aktualisiert werden: {}" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "Löschen des Ordners für Buch %(id)s ist fehlgeschlagen, der Pfad hat Unterordner: %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "Löschen von Buch %(id)s fehlgeschlagen: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "Lösche Buch %(id)s nur aus Datenbank, Pfad zum Buch in Datenbank ist nicht gültig: %(path)s" -#: cps/helper.py:388 +#: cps/helper.py:450 #, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Umbenennen des Titels '%(src)s' zu '%(dest)s' schlug fehl: %(error)s" +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Umbenennen des Autors '%(src)s' zu '%(dest)s' schlug fehl: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Umbenennen der Datei im Pfad '%(src)s' nach '%(dest)s' ist fehlgeschlagen: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Datei %(file)s wurde nicht auf Google Drive gefunden" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Umbenennen des Titels '%(src)s' zu '%(dest)s' schlug fehl: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "Fehler beim umbenennen der Datei im Pfad: {}" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Buchpfad %(path)s wurde nicht auf Google Drive gefunden" -#: cps/helper.py:507 cps/web.py:1654 -msgid "Found an existing account for this e-mail address" -msgstr "Es existiert bereits ein Benutzer für diese E-Mailadresse" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "Es existiert bereits ein Benutzerkonto für diese E-Mail Adresse" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Benutzername ist schon vorhanden" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "Ungültiges E-Mail Adressformat" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "Python Module 'advocate' ist nicht installiert, wird aber für das Cover hochladen benötigt" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Fehler beim Herunterladen des Covers" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "Coverdatei fehlerhaft" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "Keine Berechtigung Cover von Localhost oder dem lokalen Netzwerk hochzuladen" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Fehler beim Erzeugen des Ordners für die Coverdatei" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "Cover Datei ist keine gültige Bilddatei, kann nicht gespeichert werden" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "Nur jpg/jpeg/png/webp/bmp Dateien werden als Coverdatei unterstützt" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "Ungültiger Cover Dateiinhalt" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Es werden nur jpg/jpeg Dateien als Cover untertützt" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "UnRar Programm nicht gefunden" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" -msgstr "Fehler beim ausführen von UnRar" +#: cps/helper.py:947 +msgid "Error executing UnRar" +msgstr "Fehler beim Ausführen von UnRar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Wartend" +#: cps/helper.py:1040 +msgid "Cover" +msgstr "Titelbild" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Fehlgeschlagen" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "Alle Bücher für Metadaten Backup einreihen" -#: cps/helper.py:766 -msgid "Started" -msgstr "Gestartet" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Beendet" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Unbekannter Status" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Bitte nicht von \"localhost\" auf Calibre-Web zugreifen, um einen gültigen api_endpoint für Kobo Geräte zu erhalten" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Kobo Setup" @@ -762,9 +820,9 @@ msgstr "Kobo Setup" msgid "Register with %(provider)s" msgstr "Anmelden mit %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "Du bist nun eingeloggt als '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -823,505 +881,597 @@ msgstr "Google Oauth Fehler, bitte später erneut versuchen." msgid "Google Oauth error: {}" msgstr "Google Oauth Fehler: {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "{} Sterne" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Login" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Token wurde nicht gefunden" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Token ist abgelaufen" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Erfolg! Bitte zum Gerät zurückkehren" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Bücher" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Zeige kürzlich hinzugefügte Bücher" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Beliebte Bücher" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Zeige beliebte Bücher" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "Heruntergeladene Bücher" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "Zeige heruntergeladene Bücher" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Best bewertete Bücher" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Bestbewertete Bücher anzeigen" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Gelesene Bücher" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +msgid "Show Read and Unread" msgstr "Zeige gelesene/ungelesene Bücher" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Ungelesene Bücher" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Zeige Ungelesene" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Entdecke" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Zeige zufällige Bücher" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Kategorien" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +msgid "Show Category Section" msgstr "Zeige Kategorienauswahl" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Serien" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +msgid "Show Series Section" msgstr "Zeige Serienauswahl" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Autoren" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +msgid "Show Author Section" msgstr "Zeige Autorenauswahl" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Verleger" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +msgid "Show Publisher Section" msgstr "Zeige Verlegerauswahl" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Sprachen" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +msgid "Show Language Section" msgstr "Zeige Sprachauswahl" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Bewertungen" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +msgid "Show Ratings Section" msgstr "Zeige Bewertungsauswahl" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Dateiformate" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +msgid "Show File Formats Section" msgstr "Zeige Dateiformatauswahl" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Archivierte Bücher" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +msgid "Show Archived Books" msgstr "Zeige archivierte Bücher" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "Bücherliste" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "Zeige Bücherliste" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Ungültiges Bücherregal angegeben" - -#: cps/shelf.py:73 -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Du hast keine Berechtigung, ein Buch zu diesem Bücherregal hinzuzufügen" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Buch ist bereits Teil des Bücherregals %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Das Buch wurde dem Bücherregal %(sname)s hinzugefügt" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Dir ist es nicht erlaubt, ein Buch zum Bücherregal %(name)s hinzuzufügen" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Bücher sind bereits Teil des Bücherregals %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Bücher wurden zum Bücherregal %(sname)s hinzugefügt" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Bücher konnten nicht zum Bücherregal %(sname)s hinzugefügt werden" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Das Buch wurde aus dem Bücherregal: %(sname)s entfernt" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Dir ist es nicht erlaubt, Bücher aus dem Bücherregal %(sname)s zu entfernen" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Bücherregal erzeugen" - -#: cps/shelf.py:236 -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Dir ist es nicht erlaubt, dieses Bücherregal zu editieren" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Bücherregal editieren" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Bücherregal %(title)s erzeugt" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Bücherregal %(title)s verändert" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Es trat ein Fehler auf" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Es existiert bereit ein öffentliches Bücherregal mit dem Name '%(title)s'." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Es existiert bereit ein privates Bücherregal mit dem Name '%(title)s'." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Reihenfolge in Bücherregal '%(name)s' verändern" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Bücherregal: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Fehler beim Öffnen des Bücherregals. Bücherregal exisitert nicht oder ist nicht zugänglich" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Updateinformationen enthalten unbekannte Daten" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Kein Update verfügbar. Es ist bereits die aktuellste Version installiert" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Es sind Updates verfügbar. Klicke auf den Button unten, um auf die aktuellste Version zu aktualisieren." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Updateinformationen konnten nicht geladen werden" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Klicke auf den Button unten, um auf die letzte stabile Version zu aktualisieren." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Ein neues Update ist verfügbar. Klicke auf den Button unten, um auf Version: %(version)s zu aktualisieren" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Keine Releaseinformationen verfügbar" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Entdecke (Zufällige Bücher)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Beliebte Bücher (am meisten Downloads)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "Von %(user)s heruntergeladene Bücher" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Author: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Verleger: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Serie: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Bewertung: %(rating)s Sterne" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Dateiformat: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Kategorie: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Sprache: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Erweiterte Suche" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Suche" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Downloads" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Bewertungsliste" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Liste der Dateiformate" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Aufgaben" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Herausgegeben nach dem " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Herausgegeben vor dem " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Bewertung <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Bewertung >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "Lesestatus = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "Fehler bei der Suche nach eigenen Spalten, bitte Calibre-Web neustarten" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Buch erfolgreich zum Senden an %(kindlemail)s eingereiht" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Erweiterte Suche" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Ungültiges Bücherregal angegeben" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Du hast keine Berechtigung, ein Buch zu diesem Bücherregal hinzuzufügen" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Buch ist bereits Teil des Bücherregals %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Das Buch wurde dem Bücherregal %(sname)s hinzugefügt" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "Keine Erlaubnis Bücher zu diesem Bücherregal hinzuzufügen" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Bücher sind bereits Teil des Bücherregals %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Bücher wurden zum Bücherregal %(sname)s hinzugefügt" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Bücher konnten nicht zum Bücherregal %(sname)s hinzugefügt werden" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Das Buch wurde aus dem Bücherregal: %(sname)s entfernt" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "Sie haben keine Berechtigung um Bücher aus diesem Bücherregal zu löschen" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Bücherregal erzeugen" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Dir ist es nicht erlaubt, dieses Bücherregal zu editieren" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Bücherregal editieren" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "Fehler beim Löschen des Bücherregals" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "Bücherregal erfolgreich gelöscht" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Reihenfolge in Bücherregal '%(name)s' verändern" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "Sie haben keine Berechtigung um öffentliche Bücherregal zu erzeugen" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Bücherregal %(title)s erzeugt" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Bücherregal %(title)s verändert" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Es trat ein Fehler auf" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Es existiert bereit ein öffentliches Bücherregal mit dem Name '%(title)s'." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Es existiert bereit ein privates Bücherregal mit dem Name '%(title)s'." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Bücherregal: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Fehler beim Öffnen des Bücherregals. Bücherregal exisitert nicht oder ist nicht zugänglich" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Aufgaben" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Wartend" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Fehlgeschlagen" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Gestartet" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Beendet" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "Beendet" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "Abgebrochen" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Unbekannter Status" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Updateinformationen enthalten unbekannte Daten" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Kein Update verfügbar. Es ist bereits die aktuellste Version installiert" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Es sind Updates verfügbar. Klicke auf den Button unten, um auf die aktuellste Version zu aktualisieren." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Updateinformationen konnten nicht geladen werden" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Klicke auf den Button unten, um auf die letzte stabile Version zu aktualisieren." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Ein neues Update ist verfügbar. Klicke auf den Button unten, um auf Version: %(version)s zu aktualisieren" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Keine Releaseinformationen verfügbar" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Entdecke (Zufällige Bücher)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Beliebte Bücher (am meisten Downloads)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Von %(user)s heruntergeladene Bücher" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Author: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Verleger: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Serie: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "Bewertung: Keine" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Bewertung: %(rating)s Sterne" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Dateiformat: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Kategorie: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Sprache: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Downloads" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Bewertungsliste" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Liste der Dateiformate" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Bitte zuerst die SMTP-Einstellung konfigurieren ..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Buch erfolgreich zum Senden an %(eReadermail)s eingereiht" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "Beim Senden des Buchs trat ein Fehler auf: %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." -msgstr "Bitte zuerst die Kindle E-Mailadresse konfigurieren..." +#: cps/web.py:1213 +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "Bitte zuerst die E-Reader E-Mailadresse konfigurieren." -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" -msgstr "Der E-Mail Server ist nicht konfigurierte, bitte den Administrator kontaktieren!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "Der E-Mail Server ist nicht konfigurierte, bitte den Administrator kontaktieren." -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Registrieren" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" -msgstr "Diese E-Mail ist nicht für die Registrierung zugelassen" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." +msgstr "Diese E-Mail ist nicht für die Registrierung zugelassen." -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Eine Bestätigungs-E-Mail wurde an deinen E-Mail Account versendet." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "LDAP-Authentifizierung kann nicht aktiviert werden" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "Rückfall Login als: '%(nickname)s', LDAP Server ist nicht erreichbar, oder der Nutzer ist unbekannt" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Login nicht erfolgreich: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" -msgstr "Falscher Benutzername oder Passwort" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." +msgstr "Falscher Benutzername oder Passwort." -#: cps/web.py:1555 -msgid "New Password was send to your email address" -msgstr "Das neue Passwort wurde an die E-Mail Adresse verschickt" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." +msgstr "Das neue Passwort wurde an die E-Mail Adresse verschickt." -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Bitte einen gültigen Benutzernamen zum Zurücksetzen des Passworts angeben" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Eingeloggt als: '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)s's Profil" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +msgid "Success! Profile Updated" msgstr "Profil aktualisiert" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "Es existiert bereits ein Benutzer für diese E-Mailadresse." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "Keine gültige gmail.json Datei mit Oauth informationen gefunden" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s an E-Reader gesendet" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "Calibre E-Book Konverter %(tool)s nicht gefunden" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "%(format)s Format nicht gefunden" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "EBook Converter mit unbekanntem Fehler fehlgeschlagen" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Kepubify Konverter Aufruf fehlgeschlagen: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "Konvertierte Datei nicht gefunden, oder mehr als eine Datei im Pfad %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Fehler des EBook-Converters: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "Calibre fehlgeschlagen mit Fehler: %(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "Konvertiere" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "Calibre Datenbank wird neu verbunden" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "E-Mail" + +#: cps/tasks/metadata_backup.py:47 +msgid "Backing up Metadata" +msgstr "Metadaten Backup läuft" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "%(count)s Cover Miniaturansichten erzeugt" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "Cover Miniaturansichtern" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "{0} Serien Miniaturansichten erzeugt" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "Cover Miniaturansichten Cache wird gelöscht" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Upload" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Benutzerliste" @@ -1334,14 +1484,14 @@ msgstr "Benutzername" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "E-Mail" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" -msgstr "Kindle" +msgid "Send to eReader Email" +msgstr "An E-Reader E-Mail Adresse senden" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Admin" @@ -1351,211 +1501,228 @@ msgstr "Admin" msgid "Password" msgstr "Passwort" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Upload" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Download" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Bücher ansehen" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Editieren" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Löschen" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Öffentliches Bücherregal" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Neuen Benutzer hinzufügen" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "LDAP Benutzer importieren" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "Einstellungen des SMTP-Servers" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "SMTP-Hostname" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP Port" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "Verschlüsselung" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "SMTP-Login" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Absenderadresse" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "E-Mail Service" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "Gmail via Oauth2" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Konfiguration" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Ordner der Calibre-DB" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Loglevel" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Port" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "Externer Port" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Bücher pro Seite" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Hochladen" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Anonymes Durchsuchen" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Öffentliche Registrierung" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Remotelogin ('Magischer Link')" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "Reverse Proxy Login" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Reverse Proxy Header Name" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 msgid "Edit Calibre Database Configuration" msgstr "Calibre Datenbank Konfiguration editieren" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Basiskonfiguration" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "Benutzeroberflächenkonfiguration" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "Geplante Aufgabe" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "Zeitpunkt an dem die Aufgabe startet" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "Maximale Aufgabendauer" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "Buchcover Miniaturansichten erzeugen" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "Seriencover Miniaturansichten erzeugen" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "Mit Calibre Bibliothek neuverbinden" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "Cover Miniaturansichten aktualisieren" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Administration" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "Debug Daten herunterladen" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Logdateien ansehen" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Calibre-DB neu verbinden" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Neustart" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Calibre-Web beenden" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Update" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "Versionsinformation" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Version" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Details" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Aktuelle Version" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Nach Update suchen" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Update durchführen" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Calibre-Web wirklich neustarten?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "OK" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Abbruch" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Calibre-Web wirklich anhalten?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Updatevorgang, Seite bitte nicht neu laden" @@ -1567,119 +1734,118 @@ msgstr "via" msgid "In Library" msgstr "In Bibliothek" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "Sortiere nach Buchdatum, Neuestes zuerst" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "Sortiere nach Buchdatum, Aältestes zuerst" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "Sortiere Titel in alphabetischer Reihenfolge" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "Sortiere Titel in umgekehrt alphabetischer Reihenfolge" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "Sortiere nach Herausgabedatum, Neueste zuerst" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "Sortiere nach Herausgabedatum, Älteste zuerst" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "Reduzieren" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Mehr von" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Buch löschen" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Lösche Formate:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Konvertiere Buchformat:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Konvertiere von:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "Wähle eine Option" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Konvertiere nach:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Konvertiere Buch" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Buchtitel" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Autor" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Beschreibung" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "IDs" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "ID Typ" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "ID Wert" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Entfernen" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "ID hinzufügen" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Tags" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "Serien ID" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Bewertung" @@ -1691,82 +1857,82 @@ msgstr "Cover-URL (jpg, Cover wird heruntergeladen und in der Datenbank gespeich msgid "Upload Cover from Local Disk" msgstr "Coverdatei von Lokalem Laufwerk hochladen" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Herausgabedatum" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Herausgeber" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Sprache" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Ja" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Nein" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Format hochladen" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Buch nach Bearbeitung ansehen" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Metadaten laden" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Speichern" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Suchbegriff" -#: cps/templates/book_edit.html:237 -#, fuzzy +#: cps/templates/book_edit.html:234 msgid "Search keyword" -msgstr " Suchbegriff " +msgstr "Suche Schlüsselbegriff" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Klicke auf das Bild, um die Metadaten zu übertragen" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Lade..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Schließen" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Quelle" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Fehler bei der Suche!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Keine Ergebnisse gefunden! Bitte ein anderes Schlüsselwort benutzen." @@ -1850,35 +2016,42 @@ msgid "Enter Publishers" msgstr "Herausgeber eingeben" #: cps/templates/book_table.html:73 -#, fuzzy msgid "Enter comments" -msgstr "Domainnamen eingeben" +msgstr "Kommentare eingeben" #: cps/templates/book_table.html:73 msgid "Comments" -msgstr "" +msgstr "Kommentare" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 -#, fuzzy +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "Archivstatus" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Lesestatus" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 msgid "Enter " -msgstr "IDs" +msgstr "Eingeben " -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Sicher?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "Bücher werden zusammengeführt. Von Titel:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "In Buch mit Titel:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "Zusammenführen" @@ -1940,7 +2113,7 @@ msgstr "Nightly" #: cps/templates/config_edit.html:50 msgid "Trusted Hosts (Comma Separated)" -msgstr "" +msgstr "Trusted Hosts (Komma separiert)" #: cps/templates/config_edit.html:61 msgid "Logfile Configuration" @@ -1964,12 +2137,16 @@ msgstr "Feature-Konfiguration" #: cps/templates/config_edit.html:104 msgid "Convert non-English characters in title and author while saving to disk" -msgstr "" +msgstr "Nicht-englische Zeichen in Titel und Autor beim Speichern auf Festplatte ersetzen" #: cps/templates/config_edit.html:108 msgid "Enable Uploads" msgstr "Hochladen aktivieren" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(Bitte stellen Sie sicher das sie über die Upload Berechtigung verfügen)" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "Erlaubte Dateiformate zum Hochladen" @@ -1983,7 +2160,7 @@ msgid "Enable Public Registration" msgstr "Öffentliche Registrierung aktivieren" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "Benutze E-Mail als Benutzername" #: cps/templates/config_edit.html:132 @@ -2050,11 +2227,6 @@ msgstr "LDAP Server Port" msgid "LDAP Encryption" msgstr "LDAP Verschlüsselung" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Keine" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2190,7 +2362,7 @@ msgstr "Anzahl anzuzeigender zufälliger Bücher" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Anzahl in Übersicht anzuzeigender Autoren (0=alle werden angezeigt)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Theme" @@ -2222,139 +2394,139 @@ msgstr "Regulärer Ausdruck für Titelsortierung" msgid "Default Settings for New Users" msgstr "Standard-Einstellungen für neue Benutzer" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Administrator" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Downloads erlauben" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Anzeige von Büchern erlauben" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Hochladen erlauben" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Bearbeiten erlauben" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "Löschen von Büchern erlauben" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Ändern des Passworts erlauben" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Editieren öffentlicher Bücherregale erlauben" -#: cps/templates/config_view_edit.html:119 -#, fuzzy +#: cps/templates/config_view_edit.html:123 msgid "Default Language" -msgstr "Sprachen ausschließen" +msgstr "Default Sprache" -#: cps/templates/config_view_edit.html:127 -#, fuzzy +#: cps/templates/config_view_edit.html:131 msgid "Default Visible Language of Books" -msgstr "Zeige nur Bücher mit dieser Sprache" +msgstr "Defaulteinstellung sichtbare Büchersprache" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Standard-Sichtbarkeiten für neue Benutzer" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Zeige zufällige Bücher in der Detailansicht" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "Erlaubte/Verbotene Tags hinzufügen" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "Erlaubte/Verbotene Calibre Spalten hinzufügen" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Im Browser lesen" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Im Browser anhören" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "Buch %(index)s von %(range)s" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Herausgabedatum" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Als ungelesen markieren" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Als gelesen markieren" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Gelesen" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Vom Archiv wiederherstellen" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Zum Archiv hinzufügen" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "Archiviert" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Beschreibung:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Zu Bücherregal hinzufügen" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Öffentlich)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Metadaten bearbeiten" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "Wähle Server Typ" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "Benutze Standard E-Mail Account" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "Gmail Account mit Oauth2 Verification" +msgid "Gmail Account" +msgstr "G-Mail Konto" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" -msgstr "Gmail Account als E-Mail Server verwenden" +msgid "Setup Gmail Account" +msgstr "G-Mail Konto einrichten" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" @@ -2377,10 +2549,10 @@ msgid "Attachment Size Limit" msgstr "Anhangsgröße" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" -msgstr "Einstellungen speichern und Test-E-Mail versenden" +msgid "Save and Send Test Email" +msgstr "Einstellungen speichern und Test E-Mail versenden" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Zurück" @@ -2406,45 +2578,61 @@ msgstr "Domainnamen eingeben" msgid "Denied Domains (Blacklist)" msgstr "Verbotene Domains für eine Registrierung" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Nächste" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "Öffne die .kobo/Kobo eReader.conf Datei in einem Texteditor und füge hinzu (oder ersetze):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Öffne die .kobo/Kobo/Kobo eReader.conf Datei in einem Texteditor und füge hinzu (oder ersetze):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "Kobo Token:" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "Liste" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "Calibre-Web Instanz ist nicht konfiguriert, bitte den Administrator kontaktieren" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Issue erzeugen" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Zurück zur Hauptseite" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "Benutzer ausloggem" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "Aufsteigend nach Downloadzahlen sortieren" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "Absteigend nach Downloadzahlen sortieren" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "Sortiere Autoren in alphabetischer Reihenfolge" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "Sortiere Autoren in umgekehrt alphabetischer Reihenfolge" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "Sortiere Serienindex aufsteigend" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "Sortiere Serienindex absteigend" @@ -2508,7 +2696,7 @@ msgstr "Bücher nach Bewertungen sortiert" msgid "Books ordered by file formats" msgstr "Bücher nach Dateiformaten sortiert" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Bücherregale" @@ -2517,63 +2705,67 @@ msgstr "Bücherregale" msgid "Books organized in shelves" msgstr "Bücher in Bücherregalen organisiert" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Home" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Nagivation umschalten" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Bibiliothek durchsuchen" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Lade hoch..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Fehler" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Hochladen beendet, verarbeite Daten, bitte warten..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Einstellungen" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Account" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Logout" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Lade hoch..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Fehler" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Hochladen beendet, verarbeite Daten, bitte warten..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Einstellungen" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Bitte die Seite nicht neu laden" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Durchsuchen" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Über" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Vorheriger Eintrag" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Buchdetails" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "Raster" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Merken" @@ -2582,7 +2774,7 @@ msgstr "Merken" msgid "Forgot Password?" msgstr "Passwort vergessen?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Einloggen mit magischem Link" @@ -2678,7 +2870,7 @@ msgstr "Übergeordnetes Verzeichnis" msgid "Select" msgstr "Auswahl" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 msgid "Ok" msgstr "Ok" @@ -2690,127 +2882,139 @@ msgstr "Calibre-Web E-Book-Katalog" msgid "epub Reader" msgstr "epub-Leser" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Hell" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Dunkel" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "Sepia" + +#: cps/templates/read.html:84 +msgid "Black" +msgstr "Schwarz" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Text umbrechen, wenn Seitenleiste geöffnet ist." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "Schriftgröße" + #: cps/templates/readcbr.html:7 msgid "Comic Reader" msgstr "Comic-Leser" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Tastaturkürzel" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Vorherige Seite" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Nächste Seite" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Optimale Skalierung" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Skaliere auf Breite" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Skaliere auf Höhe" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Skaliere 1:1" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Rechts rotieren" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Links rotieren" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Bild umdrehen" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Hell" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Dunkel" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Skalierung" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Beste" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Breite" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Höhe" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "1:1" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Rotieren" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Umdrehen" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Horizontal" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Vertikal" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Leserichtung" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Links nach rechts" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Rechts nach links" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "Zurück nach oben" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "Position merken" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "Scrollleiste" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "Zeige" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "Verstecke" @@ -2818,7 +3022,7 @@ msgstr "Verstecke" msgid "DJVU Reader" msgstr "DJVU-Leser" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 msgid "PDF Reader" msgstr "PDF-Reader" @@ -2835,7 +3039,7 @@ msgid "Choose a username" msgstr "Wähle einen Benutzernamen" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Deine E-Mail-Adresse" #: cps/templates/remote_login.html:5 @@ -2854,15 +3058,19 @@ msgstr "Danach wirst du automatisch auf diesem Gerät eingeloggt sein." msgid "This verification link will expire in 10 minutes." msgstr "Dieser Link wird in 10 Minuten ablaufen." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "Thumbnails für Serien Cover erzeugen" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Keine Ergebnisse" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Suchbegriff:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Ergebnisse für:" @@ -2874,10 +3082,6 @@ msgstr "Herausgabedatum von" msgid "Published Date To" msgstr "Herausgabedatum bis" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "Lesestatus" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Tags ausschließen" @@ -2918,30 +3122,26 @@ msgstr "Von:" msgid "To:" msgstr "Bis:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Lösche dieses Bücherregal" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "Bücherregal Eigenschaften bearbeiten" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "Bücher manuell sortieren" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "Manuelles Sortieren deaktivieren" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "Manuelles Sortieren aktivieren" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Das Bücherregal wird für alle und für immer gelöscht" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Bücherregal mit anderen Benutzern teilen" @@ -2983,8 +3183,8 @@ msgid "System Statistics" msgstr "System Statistiken" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Programm Bibliothek" +msgid "Program" +msgstr "Programm" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3010,9 +3210,17 @@ msgstr "Fortschritt" msgid "Run Time" msgstr "Laufzeit" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Startzeitpunkt" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "Aktionen" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "Diese Aufgabe wird abgebrochen. Der Fortschritt wird gespeichert." + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "Dies ist eine geplante Aufgabe, sie wird zur geplanten Zeit erneut ausgeführt." #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3042,19 +3250,23 @@ msgstr "Kobo Sync Token" msgid "Create/View" msgstr "Erzeugen/Ansehen" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "Komplettsynchronisation Kobo erzwingen" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "Erlaubte/Verbotene Calibre Spalten hinzufügen" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "Nur Bücher aus ausgewählten Bücherregalen mit Kobo synchronisieren" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Benutzer löschen" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Kobo Auth URL erzeugen" @@ -3071,16 +3283,16 @@ msgid "Enter Username" msgstr "Benutzernamen eingeben" #: cps/templates/user_table.html:135 -msgid "Enter E-mail Address" -msgstr "E-Mail-Adresse eingeben" +msgid "Enter Email" +msgstr "E-Mailadresse eingeben" #: cps/templates/user_table.html:136 -msgid "Enter Kindle E-mail Address" -msgstr "Kindle E-mail Adresse eingeben" +msgid "Enter eReader Email" +msgstr "E-Reader E-Mail Adresse eingeben" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" -msgstr "Kindle E-Mail" +msgid "eReader Email" +msgstr "E-Reader E-Mail" #: cps/templates/user_table.html:137 msgid "Locale" @@ -3119,9 +3331,8 @@ msgid "Edit Denied Column Values" msgstr "Erlaubte/Verbotene Calibre Spalten bearbeiten" #: cps/templates/user_table.html:142 -#, fuzzy msgid "Denied Column Values" -msgstr "Verbotene Calibre Spalten" +msgstr "Verbotene Spaltennamen" #: cps/templates/user_table.html:144 msgid "Change Password" @@ -3136,15 +3347,10 @@ msgid "Edit Public Shelves" msgstr "Öffentliche Bücherregale bearbeiten" #: cps/templates/user_table.html:152 -#, fuzzy msgid "Sync selected Shelves with Kobo" msgstr "Ausgesuchte Bücherregale mit Kobo synchronisieren" #: cps/templates/user_table.html:156 -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Zeige Gelesen/Ungelesen Auswahl" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Zeige zufällige Bücher" - diff --git a/cps/translations/el/LC_MESSAGES/messages.mo b/cps/translations/el/LC_MESSAGES/messages.mo index fe3cf9566..b625f1ed6 100644 Binary files a/cps/translations/el/LC_MESSAGES/messages.mo and b/cps/translations/el/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/el/LC_MESSAGES/messages.po b/cps/translations/el/LC_MESSAGES/messages.po index fad7c698c..27c595928 100644 --- a/cps/translations/el/LC_MESSAGES/messages.po +++ b/cps/translations/el/LC_MESSAGES/messages.po @@ -6,589 +6,646 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Depountis Georgios\n" "Language: el\n" "Language-Team: \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "δεν εγκαταστάθηκε" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "εγκαταστάθηκε" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Στατιστικά" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Ο διακομιστής επανεκκίνησε, παρακαλούμε φόρτωσε ξανά τη σελίδα" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Πραγματοποιείται κλείσιμο του διακομιστή, παρακαλούμε κλείσε το παράθυρο" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Επιτυχής επανασύνδεση" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Άγνωστη εντολή" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Το βιβλίο έχει επιτυχώς μπει σε σειρά για αποστολή στο %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "ʼΑγνωστο" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Σελίδα διαχειριστή" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Βασική Διαμόρφωση" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "UI Διαμόρφωση" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" msgstr "Χρήστης Διαχειριστής" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Όλα" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "Δεν βρέθηκε χρήστης" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Προβολή Όλων" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "Δεν έχει απομείνει χρήστης διαχειριστής, δεν μπορεί να αφαιρεθεί ο ρόλος διαχειριστή" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Ενημερώθηκε η διαμόρφωση Calibre-Web" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "Θέλεις πραγματικά να διαγράψεις τη Μονάδα Kobo;" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Είσαι σίγουρος/η πως θέλεις να διαγράψεις αυτό το ράφι;" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Είσαι σίγουρος/η πως θέλεις να διαγράψεις αυτό το ράφι;" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Είσαι σίγουρος/η πως θέλεις να διαγράψεις αυτό το ράφι;" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Είσαι σίγουρος/η πως θέλεις να διαγράψεις αυτό το ράφι;" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "Είσαι σίγουρος/η πως θέλεις να κάνεις κλείσιμο;" -#: cps/admin.py:741 -msgid "Tag not found" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Απόρριψη" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Επιτρέπεται" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json Δεν Έχει Διαμορφωθεί Για Διαδικτυακή Εφαρμογή" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "Το Φύλλο Καταγραφής Τοποθεσίας δεν είναι Έγκυρο, Παρακαλούμε Συμπλήρωσε Τη Σωστή Πορεία" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "Η Πρόσβαση Φύλλου Καταγραφης Τοποθεσίας δεν είναι έγκυρη, Παρακαλούμε Συμπλήρωσε Τη Σωστή Πορεία" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Παρακαλούμε Συμπλήρωσε ένα Πάροχο LDAP, Θύρα, DN και Αντικείμενο Αναγνώρισης Χρήστη" -#: cps/admin.py:1102 +#: cps/admin.py:1191 #, fuzzy msgid "Please Enter a LDAP Service Account and Password" msgstr "Παρακαλούμε συμπλήρωσε ένα έγκυρο όνομα χρήστη για επαναφορά του κωδικού" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "Το Αντικείμενο Φίλτρου Ομάδας LDAP Πρέπει να Έχει Μια \"%s\" Αναγνώριση Μορφής" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "Το Αντικείμενο Φίλτρου Ομάδας LDAP Έχει Παρενθέσεις Που Δεν Ταιριάζουν" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "Το Αντικείμενο Φίλτρου Χρήστη LDAP πρέπει να Έχει Μια \"%s\" Αναγνώριση Μορφής" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "Το Αντικείμενο Φίλτρου Χρήστη LDAP Έχει Παρενθέσεις Που Δεν Ταιριάζουν" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "Οι ρυθμίσεις DB δεν μπορούν να Γραφτούν" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "Προσθήκη Νέου Χρήστη" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "Η Τοποθεσία DB δεν είναι Έγκυρη, Παρακαλούμε Συμπληρώστε Τη Σωστή Πορεία" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "Η DB δεν μπορεί να Γραφτεί" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "Το Αρχειο Κλειδί Τοποθεσίας δεν είναι Έγκυρο, Παρακαλούμε Συμπληρώστε Τη Σωστή Πορεία" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "Η Τοποθεσία Certfile δεν είναι Έγκυρη, Παρακαλούμε Συμπληρώστε Τη Σωστή Πορεία" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Ενημερώθηκαν οι ρυθμίσεις E-mail διακομιστή" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Διαμόρφωση Λειτουργίας" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Παρακαλούμε συμπλήρωσε όλα τα πεδία!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "Το E-mail δεν είναι από έγκυρο domain" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "Προσθήκη νέου χρήστη" - -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Χρήστης/ες '%(user)s' δημιουργήθηκαν" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Βρέθηκε ένας ήδη υπάρχον λογαριασμός για αυτή τη διεύθυνση e-mail ή όνομα χρήστη." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Χρήστης/ες '%(nick)s' διαγράφηκαν" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Δεν έχει απομείνει χρήστης διαχειριστής, δεν μπορεί να διαγραφεί ο χρήστης" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Επεξεργασία χρήστη %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Χρήστης/ες '%(nick)s' ενημερώθηκαν" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Προέκυψε ένα άγνωστο σφάλμα. Παρακαλούμε δοκίμασε ξανά αργότερα." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Επεξεργασία Ρυθμίσεων E-mail Διακομιστή" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Σφάλμα βάσης δεδομένων: %(error)s." + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Παρουσιάστηκε σφάλμα κατά την αποστολή του δοκιμαστικού e-mail:% (res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Παρακαλούμε ρύθμισε πρώτα τη διεύθυνση e-mail σου..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Ενημερώθηκαν οι ρυθμίσεις E-mail διακομιστή" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Προέκυψε ένα άγνωστο σφάλμα. Παρακαλούμε δοκίμασε ξανά αργότερα." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Επεξεργασία χρήστη %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Κωδικός για επαναφορά %(user) χρήστη/ών" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Παρακαλούμε διαμόρφωσε πρώτα τις ρυθμίσεις ταχυδρομείου SMTP..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Προβολέας αρχείου φύλλου καταγραφής" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Αίτημα πακέτου ενημέρωσης" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Κατεβάζει πακέτο ενημέρωσης" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Ανοίγει πακέτο ενημέρωσης" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Αντικατάσταση αρχείων" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Οι συνδέσεις βάσης δεδομένων είναι κλειστές" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Σταματάει το διακομιστή" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Η ενημέρωση τελειώσε, παρακαλούμε πιέστε το εντάξει και φορτώστε ξανά τη σελίδα" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Η ενημέρωση απέτυχε:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTP Σφάλμα" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Σφάλμα σύνδεσης" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Τελείωσε ο χρόνος κατά την προσπάθεια δημιουργίας σύνδεσης" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Γενικό σφάλμα" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "Το Αρχείο Ενημέρωσης Δεν Μπόρεσε Να Αποθηκευτεί σε" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 #, fuzzy msgid "Failed to extract at least One LDAP User" msgstr "Αποτυχία Δημιουργίας Τουλάχιστον Ενός Χρήστη LDAP" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "Αποτυχία Δημιουργίας Τουλάχιστον Ενός Χρήστη LDAP" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Σφάλμα: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Σφάλμα: Δεν επιστράφηκε χρήστης σε απάντηση του διακομιστή LDAP" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "Τουλάχιστον Ένας Χρήστης LDAP Δεν Βρέθηκε Στη Βάση Δεδομένων" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "" -#: cps/converter.py:30 -msgid "not configured" -msgstr "δεν διαμορφώθηκε" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "Η Τοποθεσία DB δεν είναι Έγκυρη, Παρακαλούμε Συμπληρώστε Τη Σωστή Πορεία" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "Η DB δεν μπορεί να Γραφτεί" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "Το Αρχειο Κλειδί Τοποθεσίας δεν είναι Έγκυρο, Παρακαλούμε Συμπληρώστε Τη Σωστή Πορεία" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "Η Τοποθεσία Certfile δεν είναι Έγκυρη, Παρακαλούμε Συμπληρώστε Τη Σωστή Πορεία" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "Ενημερώθηκαν οι ρυθμίσεις E-mail διακομιστή" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Διαμόρφωση Λειτουργίας" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Παρακαλούμε συμπλήρωσε όλα τα πεδία!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "Το E-mail δεν είναι από έγκυρο domain" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Προσθήκη νέου χρήστη" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Χρήστης/ες '%(user)s' δημιουργήθηκαν" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Βρέθηκε ένας ήδη υπάρχον λογαριασμός για αυτή τη διεύθυνση e-mail ή όνομα χρήστη." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Χρήστης/ες '%(nick)s' διαγράφηκαν" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Δεν έχει απομείνει χρήστης διαχειριστής, δεν μπορεί να διαγραφεί ο χρήστης" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Χρήστης/ες '%(nick)s' ενημερώθηκαν" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "δεν εγκαταστάθηκε" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Λείπουν άδειες εκτέλεσης" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 -#, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, fuzzy, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "Η ειδικά προσαρμοσμένη στήλη No.%(column)d δεν υπάρχει στο επίπεδο βάσης δεδομένων" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Η μορφή βιβλίου Διαγράφηκε Επιτυχώς" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Κανένα" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Το Βιβλίο Διαγράφηκε Επιτυχώς" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Oυπς! Ο επιλεγμένος τίτλος βιβλίου δεν είναι διαθέσιμος. Το αρχείο δεν υπάρχει ή δεν είναι προσβάσιμο" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "επεξεργασία μεταδεδομένων" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s δεν είναι μια έγκυρη γλώσσα" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "Η επέκταση αρχείου '%(ext)s' δεν επιτρέπεται να ανέβει σε αυτό το διακομιστή" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Το αρχείο προς ανέβασμα πρέπει να έχει μια επέκταση" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Αποτυχεία δημιουργίας πορείας %(path)s (Η άδεια απορρήφθηκε)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Αποτυχία αποθήκευσης αρχείου %(file)s." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Σφάλμα βάσης δεδομένων: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Μορφή αρχείου %(ext)s προστέθηκε σε %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "Τα αναγνωριστικά δεν έχουν Διάκριση Πεζών-Κεφαλαίων Γραμμάτων, Αντικατάσταση Παλιού Αναγνωριστικού" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Τα μεταδεδομένα ενημερώθηκαν επιτυχώς" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Σφάλμα επεξεργασίας βιβλίου, παρακαλούμε έλεγξε το φύλλο καταγραφής για λεπτομέρειες" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Το βιβλίο που ανέβηκε πιθανόν να υπάρχει στη βιβλιοθήκη, σκέψου να το αλλάξεις πριν ανεβάσεις νέο: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "Το αρχείο %(filename)s δεν μπόρεσε να αποθηκευτεί σε temp dir" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Αποτυχία Μετακίνησης Αρχείου Φόντου %(file)s: %(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Το αρχείο %(file)s ανέβηκε" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Η δομή πηγής ή προορισμού για μετατροπή λείπει" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Το βιβλίο είναι σε σειρά επιτυχώς για μετατροπή σε %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Υπήρξε ένα σφάλμα στη μετατροπή αυτού του βιβλίου: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Το βιβλίο που ανέβηκε πιθανόν να υπάρχει στη βιβλιοθήκη, σκέψου να το αλλάξεις πριν ανεβάσεις νέο: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s δεν είναι μια έγκυρη γλώσσα" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Η επέκταση αρχείου '%(ext)s' δεν επιτρέπεται να ανέβει σε αυτό το διακομιστή" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Το αρχείο προς ανέβασμα πρέπει να έχει μια επέκταση" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Το αρχείο %(filename)s δεν μπόρεσε να αποθηκευτεί σε temp dir" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Αποτυχία Μετακίνησης Αρχείου Φόντου %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Η μορφή βιβλίου Διαγράφηκε Επιτυχώς" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Το Βιβλίο Διαγράφηκε Επιτυχώς" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "επεξεργασία μεταδεδομένων" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Αποτυχεία δημιουργίας πορείας %(path)s (Η άδεια απορρήφθηκε)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Αποτυχία αποθήκευσης αρχείου %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Μορφή αρχείου %(ext)s προστέθηκε σε %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Η ρύθμιση του Google Drive δεν ολοκληρώθηκε, προσπάθησε να απενεργοποιήσεις και να ενεργοποιήσεις ξανά το Google Drive" @@ -602,166 +659,180 @@ msgstr "Η ανάκληση ονόματος δεν έχει επαληθευτ msgid "%(format)s format not found for book id: %(book)d" msgstr "%(format)s η δομή δεν βρέθηκε για την ταυτότητα βιβλίου: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s δεν βρέθηκε στο Google Drive: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s δεν βρέθηκε: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Αποστολή στο Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Αυτό το e-mail έχει σταλεί μέσω Calibre-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Calibre-Web δοκιμαστικό e-mail" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Δοκιμαστικό e-mail" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Ξεκινήστε με το Calibre-Web" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "e-mail εγγραφής για χρήστη: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "Μετατροπή %(orig)s σε %(format)s και αποστολή στο Kindle" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "Αποστολή %(format)s στο Kindle" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Αποστολή στο Kindle" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Το αρχείου που χητήθηκε δεν μπορεί να διαβαστεί. Μπορεί να υπάρχουν λαθασμένες άδειες;" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "Η διαγραφή φακέλου βιβλίου για το βιβλίο %(id)s απέτυχε, η πορεία έχει υπό-φακέλους: %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "Η διαγραφή βιβλίου %(id)s απέτυχε: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, fuzzy, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "Διαγραφή βιβλίου %(id)s, η πορεία βιβλίου δεν είναι έγκυρη: %(path)s" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "Η μετονομασία τίτλου από: '%(src)s' σε '%(dest)s' απέτυχε με σφάλμα: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Η μετονομασία αρχείου σε πορεία '%(src)s' σε '%(dest)s' απέτυχε με σφάλμα: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Το αρχείο %(file)s δεν βρέθηκε στο Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Η μετονομασία τίτλου από: '%(src)s' σε '%(dest)s' απέτυχε με σφάλμα: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Η πορεία βιβλίου %(path)s δεν βρέθηκε στο Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Βρέθηκε ένας ήδη υπάρχον λογαριασμός για αυτή τη διεύθυνση e-mail." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Αυτό το όνομα χρήστη έχει ήδη παρθεί" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Σφάλμα Κατεβάσματος Φόντου" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "Σφάλμα Μορφής Φόντου" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Αποτυχία δημιουργίας πορείας για φόντο" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "Το αρχείο φόντου δεν είναι ένα έγκυρο αρχείο εικόνας, ή δεν μπόρεσε να αποθηκευτεί" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Μόνο jpg/jpeg αρχεία υποστηρίζονται ως αρχεία φόντου" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "Δεν βρέθηκε δυαδικό αρχείο Unrar" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" msgstr "Σφάλμα εκτέλεσης UnRar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Αναμονή" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Ανακάλυψε" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Απέτυχε" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "Ξεκίνησε" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Τελείωσε" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "ʼΑγνωστη κατάσταση" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Παρακαλούμε λάβε πρόσβαση στο calibre-web από ένα μη τοπικό εξηπηρετητή για να λάβεις μια έγκυρη api_endpoint για συσκευή kobo" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Καθορισμός Kobo" @@ -770,9 +841,9 @@ msgstr "Καθορισμός Kobo" msgid "Register with %(provider)s" msgstr "Εγγραφή με %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "τώρα έχεις συνδεθεί ως: '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -831,507 +902,613 @@ msgstr "Google Oauth σφάλμα, παρακαλούμε δοκίμασε ξα msgid "Google Oauth error: {}" msgstr "" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Σύνδεση" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Η μάρκα δεν βρέθηκε" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Η μάρκα έχει λήξει" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Επιτυχία! Παρακαλούμε επέστρεψε στη συσκευή σου" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Βιβλία" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Προβολή πρόσφατων βιβλίων" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Βιβλία στη Μόδα" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Προβολή Βιβλίων στη Μόδα" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "Κατεβασμένα Βιβλία" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "Προβολή Κατεβασμένων Βιβλίων" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Βιβλία με Κορυφαία Αξιολόγηση" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Προβολή Βιβλίων με Κορυφαία Αξιολόγηση" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Βιβλία που Διαβάστηκαν" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Προβολή διαβασμένων και αδιάβαστων" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Βιβλία που δεν Διαβάστηκαν" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Προβολή αδιάβαστων" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Ανακάλυψε" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Προβολή Τυχαίων Βιβλίων" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Κατηγορίες" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Προβολή επιλογών κατηγορίας" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Σειρές" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Προβολή επιλογών σειράς" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Συγγραφείς" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Προβολή επιλογών συγγραφέα" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Εκδότες" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Προβολή επιλογών εκδότη" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Γλώσσες" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Προβολή επιλογών γλώσσας" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Αξιολογήσεις" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Προβολή επιλογών αξιολόγησης" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Μορφές αρχείου" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Προβολή επιλογών μορφής αρχείου" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Αρχειοθετημένα Βιβλία" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" msgstr "Προβολή αρχειοθετημένων βιβλίων" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "Λίστα Βιβλίων" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "Προβολή Λίστας Βιβλίων" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Διευκρινίστηκε μη έγκυρο ράφι" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Συγγνώμη δεν σου επιτρέπεται να προσθέσεις ένα βιβλίο στο ράφι: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Το βιβλίο είναι ήδη μέρος αυτού του ραφιού: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Το βιβλίο έχει προστεθεί στο ράφι: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Δεν σου επιτρέπεται να προσθέσεις ένα βιβλίο στο ράφι: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Τα βιβλία είναι ήδη μέρος του ραφιού: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Βιβλία είχαν προστεθεί στο ραφι: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Δεν μπόρεσε να γίνει η προσθήκη βιβλίων στο ράφι: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Το βιβλίο έχει αφαιρεθεί από το ράφι: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Συγγνώμη αλλά δεν σου επιτρέπεται η αφαίρεση ενός βιβλίου από αυτό το ράφι: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Δημιούργησε ένα Ράφι" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Συγγνώμη αλλά δεν σου επιτρέπεται η αφαίρεση ενός βιβλίου από αυτό το ράφι: %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Επεξεργασία ενός ραφιού" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Το ράφι %(title)s δημιουργήθηκε" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Το ράφι %(title)s άλλαξε" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Υπήρξε ένα σφάλμα" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Ένα δημόσιο ράφι με το όνομα '%(title)s' υπάρχει ήδη." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Ένα ιδιωτικό ράφι με το όνομα '%(title)s' υπάρχει ήδη." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Αλλαγή σειράς του Ραφιού: '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Ράφι: '%(name)s" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Σφάλμα κατά το άνοιγμα του ραφιού. Το ράφι δεν υπάρχει ή δεν είναι προσβάσιμο" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Απρόβλεπτα δεδομένα κατά την ανάγνωση των πληροφοριών ενημέρωσης" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Δεν υπάρχει διαθέσιμη ενημέρωση. Έχεις ήδη την τελευταία έκδοση εγκατεστημένη" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Μια νέα ενημέρωση είναι διαθέσιμη. Κάνε κλικ στο κουμπί πιο κάτω για να ενημερώσεις με την τελευταία έκδοση." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Δεν μπόρεσε να συγκεντρώσει τις πληροφορίες ενημέρωσης" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Κάνε κλικ στο κουμπί πιο κάτω για να ενημερώσεις με την τελευταία σταθερή έκδοση." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Μια νέα ενημέρωση είναι διαθέσιμη. Κάνε κλικ στο κουμπί πιο κάτω για ενημέρωση με την έκδοση: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Δεν υπάρχουν διαθέσιμες πληροφορίες αποδέσμευσης" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Ανακάλυψε (Τυχαία Βιβλία)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Βιβλία στη Μόδα (Με τα περισσότερα κατεβάσματα)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "Κατεβασμένα βιβλία από %(user)s" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Συγγραφέας: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Εκδότης: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Σειρές: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Αξιολόγηση: %(rating)s stars" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Μορφή αρχείου: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Κατηγορία: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Γλώσσα: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Προχωρημένη Αναζήτηση" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Αναζήτηση" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Κατεβασμένα" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Λίστα αξιολογήσεων" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Λίστα μορφών αρχείου" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Εργασίες" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Εκδόθηκε μετά" -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Εκδόθηκε πριν" -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Αξιολόγηση <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Αξιολόγηση >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Το βιβλίο έχει επιτυχώς μπει σε σειρά για αποστολή στο %(kindlemail)s" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Προχωρημένη Αναζήτηση" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Διευκρινίστηκε μη έγκυρο ράφι" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Συγγνώμη δεν σου επιτρέπεται να προσθέσεις ένα βιβλίο στο ράφι: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Το βιβλίο είναι ήδη μέρος αυτού του ραφιού: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Το βιβλίο έχει προστεθεί στο ράφι: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Τα βιβλία είναι ήδη μέρος του ραφιού: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Βιβλία είχαν προστεθεί στο ραφι: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Δεν μπόρεσε να γίνει η προσθήκη βιβλίων στο ράφι: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Το βιβλίο έχει αφαιρεθεί από το ράφι: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Δημιούργησε ένα Ράφι" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Συγγνώμη αλλά δεν σου επιτρέπεται η αφαίρεση ενός βιβλίου από αυτό το ράφι: %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Επεξεργασία ενός ραφιού" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Το Βιβλίο Διαγράφηκε Επιτυχώς" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Αλλαγή σειράς του Ραφιού: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Το ράφι %(title)s δημιουργήθηκε" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Το ράφι %(title)s άλλαξε" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Υπήρξε ένα σφάλμα" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Ένα δημόσιο ράφι με το όνομα '%(title)s' υπάρχει ήδη." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Ένα ιδιωτικό ράφι με το όνομα '%(title)s' υπάρχει ήδη." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Ράφι: '%(name)s" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Σφάλμα κατά το άνοιγμα του ραφιού. Το ράφι δεν υπάρχει ή δεν είναι προσβάσιμο" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Εργασίες" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Αναμονή" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Απέτυχε" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Ξεκίνησε" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Τελείωσε" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "ʼΑγνωστη κατάσταση" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Απρόβλεπτα δεδομένα κατά την ανάγνωση των πληροφοριών ενημέρωσης" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Δεν υπάρχει διαθέσιμη ενημέρωση. Έχεις ήδη την τελευταία έκδοση εγκατεστημένη" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Μια νέα ενημέρωση είναι διαθέσιμη. Κάνε κλικ στο κουμπί πιο κάτω για να ενημερώσεις με την τελευταία έκδοση." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Δεν μπόρεσε να συγκεντρώσει τις πληροφορίες ενημέρωσης" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Κάνε κλικ στο κουμπί πιο κάτω για να ενημερώσεις με την τελευταία σταθερή έκδοση." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Μια νέα ενημέρωση είναι διαθέσιμη. Κάνε κλικ στο κουμπί πιο κάτω για ενημέρωση με την έκδοση: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Δεν υπάρχουν διαθέσιμες πληροφορίες αποδέσμευσης" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Ανακάλυψε (Τυχαία Βιβλία)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Βιβλία στη Μόδα (Με τα περισσότερα κατεβάσματα)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Κατεβασμένα βιβλία από %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Συγγραφέας: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Εκδότης: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Σειρές: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Αξιολόγηση: %(rating)s stars" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Μορφή αρχείου: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Κατηγορία: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Γλώσσα: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Κατεβασμένα" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Λίστα αξιολογήσεων" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Λίστα μορφών αρχείου" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Παρακαλούμε διαμόρφωσε πρώτα τις ρυθμίσεις ταχυδρομείου SMTP..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Το βιβλίο έχει επιτυχώς μπει σε σειρά για αποστολή στο %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "Oυπς! Υπήρξε ένα σφάλμα κατά την αποστολή αυτού του βιβλίου: %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "Παρακαλούμε ενημέρωσε το προφίλ σου με μια έγκυρη Διεύθυνση E-mail Αποστολής στο Kindle." -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "Ο διακομιστής E-Mail δεν έχει διαμορφωθεί, παρακαλούμε επικοινώνησε με το διαχειριστή σου!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Εγγραφή" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Η διεύθυνση e-mail σου δεν επιτρέπεται να εγγραφεί" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Το e-mail επιβεβαίωσης έχει σταλεί στον e-mail λογαριασμό σου." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "Δεν μπόρεσε να ενεργοποιηθεί η επαλήθευση LDAP" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "Εναλλακτική Σύνδεση ως: '%(nickname)s', Ο Διακομιστής LDAP δεν είναι προσβάσιμος, ή ο χρήστης δεν είναι γνωστός" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Δεν μπόρεσε να συνδεθεί: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Λανθασμένο Όνομα Χρήστη ή Κωδικός" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "Ο Νέος Κωδικός έχει σταλεί στη διεύθυνση email σου" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Παρακαλούμε συμπλήρωσε ένα έγκυρο όνομα χρήστη για επαναφορά του κωδικού" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Έχεις συνδεθεί ως: '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)s's προφίλ" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Το προφίλ ενημερώθηκε" +#: cps/web.py:1420 +#, fuzzy +msgid "Oops! An account already exists for this Email." +msgstr "Βρέθηκε ένας ήδη υπάρχον λογαριασμός για αυτή τη διεύθυνση e-mail." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Αποστολή στο Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "Το εργαλείο μετατροπής Calibre ebook %(tool)s δεν βρέθηκε" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "%(format)s μορφή δεν βρέθηκε σε δίσκο" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "Ο μετατροπέας Ebook απέτυχε με άγνωστο σφάλμα" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Ο μετατροπέας Kepubify απέτυχε: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "Το τροποποιημένο αρχείο δεν βρέθηκε ή υπάρχουν περισσότερα από ένα αρχεία στο φάκελο %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Ο μετατροπέας Ebook απέτυχε: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "Το Calibre απέτυχε με σφάλμα: %(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "επεξεργασία μεταδεδομένων" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Ανέβασμα" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Χρήστες" @@ -1344,14 +1521,15 @@ msgstr "Όνομα Χρήστη" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "Διεύθυνση E-mail" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Διεύθυνση E-mail Αποστολής στο Kindle" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Διαχειριστής" @@ -1361,212 +1539,229 @@ msgstr "Διαχειριστής" msgid "Password" msgstr "Κωδικός" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Ανέβασμα" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Κατέβασμα" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Προβολή Βιβλίων" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Επεξεργασία" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Διαγραφή" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Δημόσιο Ράφι" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Προσθήκη Νέου Χρήστη" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "Εισαγωγή Χρηστών LDAP" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "Ρυθμίσεις E-mail Διακομιστή" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "Όνομα Εξυπηρετητή SMTP" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP Θύρα" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "Κρυπτογράφηση" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "Σύνδεση SMTP" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Από E-mail" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Διαμόρφωση" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Ευρετήριο Βάσης Δεδομένων Calibre" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Επίπεδο Φύλλου Καταγραφής" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Θύρα" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "Εξωτερική Θύρα" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Βιβλία ανά Σελίδα" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Ανεβάσμένα" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Ανώνυμη Περιήγηση" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Δημόσια Εγγραφή" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Μαγικός Σύνδεσμος Απομακρυσμένης Σύνδεσης" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "Αναστροφή Σύνδεσης Διακομιστή Μεσολάβησης" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Αναστροφή Proxy Όνομα Επικεφαλίδας" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Επεξεργασία Βασικής Διαμόρφωσης" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Επεξεργασία Βασικής Διαμόρφωσης" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "Επεξεργασία Διαμόρφωσης UI" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Διοίκηση" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Προβολή Φύλλων Καταγραφής" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Επανασύνδεση Βάσης Δεδομένων Calibre" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Επανεκκίνηση" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Κλείσιμο" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Ενημέρωση" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Έκδοση" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Λεπτομέρειες" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Τρέχουσα έκδοση" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Έλεγχος για Ενημέρωση" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Πραγματοποίηση Ενημέρωσης" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Είσαι σίγουρος/η πως θέλεις να κάνεις επανεκκίνηση" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "OK" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Ακύρωση" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Είσαι σίγουρος/η πως θέλεις να κάνεις κλείσιμο;" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Γίνεται ενημέρωση, παρακαλούμε μη φορτώσεις ξανά αυτή τη σελίδα" @@ -1578,119 +1773,118 @@ msgstr "μέσω" msgid "In Library" msgstr "Στη Βιβλιοθήκη" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "μείωση" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Περισσότερα από" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Διαγραφή Βιβλίου" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Διαγραφή μορφών:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Μετατροπή μορφής βιβλίου:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Μετατροπή από:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "διάλεξε μια επιλογή" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Μετατροπή σε:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Μετατροπή βιβλίου" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Τίτλος Βιβλίου" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Συγγραφέας" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Περιγραφή" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "Αναγνωριστικά" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "Είδος Αναγνωριστικού" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "Τιμή Αναγνωριστικού" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Αφαίρεση" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "Προσθήκη Αναγνωριστικού" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Ετικέτες" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "Ταυτότητα Σειράς" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Αξιολόγηση" @@ -1702,82 +1896,83 @@ msgstr "Συγκέντρωση Εξώφυλλου από URL (JPEG - Η εικό msgid "Upload Cover from Local Disk" msgstr "Ανέβασμα Εξώφυλλου από Τοπικό Δίσκο" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Ημερομηνία Έκδοσης" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Εκδότης" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Γλώσσα" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Ναι" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Όχι" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Μορφή Ανεβάσματος" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Προβολή Βιβλίου σε Αποθήκευση" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Συγκέντρωση Μεταδεδομένων" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Αποθήκευση" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Λέξη κλειδί" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr "Αναζήτηση λέξης κλειδιού" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Κάνε κλικ στο εξώφυλλο για φόρτωση μεταδεδομένων στη φόρμα" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Φόρτωση..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Κλείσιμο" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Πηγή" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Σφάλμα αναζήτησης!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Δεν βρέθηκε(αν) αποτέλεσμα(τα)! Παρακαλούμε δοκίμασε μια άλλη λέξη κλειδί." @@ -1869,27 +2064,36 @@ msgstr "Όνομα domain" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Αναγνωριστικά" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Είσαι πραγματικά σίγουρος/η;" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "Βιβλία με Τίτλους θα ενωθούν από:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "Μέσα σε Βιβλίο με Τίτλο:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "Συγχώνευση" @@ -1982,6 +2186,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Ενεργοποίηση Ανεβάσματος" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "Επιτρεπόμενες Μορφές Αρχείων για Ανέβασμα" @@ -1995,7 +2203,7 @@ msgid "Enable Public Registration" msgstr "Ενεργοποίηση Δημόσιας Εγγραφής" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "Χρήση E-Mail ως Όνομα Χρήστη" #: cps/templates/config_edit.html:132 @@ -2062,11 +2270,6 @@ msgstr "Θύρα Διακομιστή LDAP" msgid "LDAP Encryption" msgstr "LDAP Αποκρυπτογράφηση" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Κανένα" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2202,7 +2405,7 @@ msgstr "Αριθμός Τυχαίων Βιβλίων για Εμφάνιση" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Αριθμός Συγγραφέων για Εμφάνιση Πριν την Απόκρυψη (0=Απενεργοποίηση Απόκρυψης)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Θέμα" @@ -2234,138 +2437,141 @@ msgstr "Συνήθης Έκφραση για Ταξινόμηση Τίτλου" msgid "Default Settings for New Users" msgstr "Προκαθορισμένες Ρυθμίσεις για Νέους Χρήστες" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Χρήστης Διαχειριστής" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Να Επιτρέπεται το Κατέβασμα" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Να Επιτρέπεται η Προβολή eBook Viewer" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Να Επιτρέπεται το Ανέβασμα" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Να Επιτρέπεται η Επεξεργασία" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "Να Επιτρέπεται η Διαγραφή Βιβλίων" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Να Επιτρέπεται η Αλλαγή Κωδικού" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Να Επιτρέπεται η Επεξεργασία Δημόσιων Ραφιών" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Εξαίρεση Γλωσσών" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Γλώσσα Βιβλίων" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Προκαθορισμένες Ορατότηες για Νέους Χρήστες" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Προβολή Τυχαίων Βιβλίων σε Προβολή Λεπτομερειών" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "Προσθήκη ετικετών Επιτρέπεται/Απορρίπτεται" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "Προσθήκη τιμών ειδικά κατασκευασμένων στηλών Επιτρέπεται/Απορρίπτεται" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Διάβασε στο Πρόγραμμα Περιήγησης" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "ʼΑκουσε στο Πρόγραμμα Περιήγησης" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, fuzzy, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Εκδόθηκε" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Σήμανση ως Αδιάβαστο" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Σήμανση ως Διαβασμένο" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Διαβάστηκε" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Επαναφορά από το αρχείο" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Προσθήκη στο αρχείο" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "Αρχειοθετήθηκε" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Περιγραφή" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Προσθήκη στο ράφι" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Δημόσιο)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Επεξεργασία Μεταδεδομένων" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "" +#, fuzzy +msgid "Gmail Account" +msgstr "Λογαριασμός" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 @@ -2389,10 +2595,11 @@ msgid "Attachment Size Limit" msgstr "Όριο Μεγέθους Επισύναψης" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Αποθήκευση και Αποστολή E-mail Δοκιμής" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Πίσω" @@ -2418,46 +2625,63 @@ msgstr "Όνομα domain" msgid "Denied Domains (Blacklist)" msgstr "Domains που Απορρίφθηκαν (Μαύρη λίστα)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Επόμενο" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "ʼΑνοιξε το .kobo/Kobo eReader.conf αρχείο σε πρόγραμμα επεξεργασίας κειμένου και πρόσθεσε (ή κάνε επεξεργασία):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "ʼΑνοιξε το .kobo/Kobo/Kobo eReader.conf αρχείο σε πρόγραμμα επεξεργασίας κειμένου και πρόσθεσε (ή κάνε επεξεργασία):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Kobo Μονάδα Συγχρονισμού" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 #, fuzzy msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "Ο διακομιστής E-Mail δεν έχει διαμορφωθεί, παρακαλούμε επικοινώνησε με το διαχειριστή σου!" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Δημιουργία Θέματος" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Επιστροφή στην Κεντρική" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "" @@ -2521,7 +2745,7 @@ msgstr "Τα βιβλία ταξινομήθηκαν ανά Αξιολόγηση msgid "Books ordered by file formats" msgstr "Τα βιβλία ταξινομήθηκαν ανά μορφές αρχείου" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Ράφια" @@ -2530,63 +2754,67 @@ msgstr "Ράφια" msgid "Books organized in shelves" msgstr "Βιβλία οργανωμένα σε ράφια" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Κεντρική" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Αλλαγή Θέσης Περιήγησης" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Αναζήτηση Βιβλιοθήκης" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Φόρτωση..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Σφάλμα" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Το ανέβασμα έγινε, γίνεται επεξεργασία, παρακαλούμε περίμενε..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Ρυθμίσεις" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Λογαριασμός" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Αποσύνδεση" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Φόρτωση..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Σφάλμα" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Το ανέβασμα έγινε, γίνεται επεξεργασία, παρακαλούμε περίμενε..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Ρυθμίσεις" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Παρακαλούμε μην ανανεώσεις τη σελίδα" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Περιήγηση" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Σχετικά" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Προηγούμενο" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Λεπτομέρειες Βιβλίου" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Να με Θυμάσαι" @@ -2595,7 +2823,7 @@ msgstr "Να με Θυμάσαι" msgid "Forgot Password?" msgstr "Ξέχασες τον Κωδικό;" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Σύνδεση με το Μαγικό Σύνδεσμο" @@ -2691,7 +2919,7 @@ msgstr "" msgid "Select" msgstr "" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "Βιβλίο" @@ -2705,128 +2933,141 @@ msgstr "Calibre-Web Κατάλογος eBook" msgid "epub Reader" msgstr "PDF πρόγραμμα ανάγνωσης" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Φωτεινό" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Σκοτεινό" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Πίσω" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Επανάληψη ροής κειμένου όταν οι μπάρες στο πλάι είναι ανοιχτές." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "PDF πρόγραμμα ανάγνωσης" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Συντομεύσεις Πληκτρολογίου" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Προηγούμενη Σελίδα" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Επόμενη Σελίδα" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Κλιμάκωση στο Καλυτερο" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Κλιμάκωση σε Πλάτος" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Κλιμάκωση σε Ύψος" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Κλιμάκωση σε Τοπικό" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Περιστροφή Δεξιά" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Περιστροφή Αριστερά" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Γύρισμα Σελίδας" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Φωτεινό" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Σκοτεινό" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Κλίμακα" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Καλύτερο" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Πλάτος" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Ύψος" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Ντόπιο" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Περιστροφή" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Γύρισμα" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Οριζόντιο" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Κάθετο" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Κατεύθυνση" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Αριστερά προς Δεξιά" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Δεξιά προς Αριστερά" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "" @@ -2835,7 +3076,7 @@ msgstr "" msgid "DJVU Reader" msgstr "PDF πρόγραμμα ανάγνωσης" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "PDF πρόγραμμα ανάγνωσης" @@ -2854,7 +3095,7 @@ msgid "Choose a username" msgstr "Επιλογή ενός ονόματος χρήστη" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Η διεύθυνση email σου" #: cps/templates/remote_login.html:5 @@ -2873,15 +3114,19 @@ msgstr "Με την επαλήθευση, θα συνδεθείτε αυτόμα msgid "This verification link will expire in 10 minutes." msgstr "Αυτός ο σύνδεσμος επαλήθευσης θα λήξει σε 10 λεπτά." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Δεν Βρέθηκαν Αποτελέσματα" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Όρος Αναζήτησης:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Αποτελέσματα για:" @@ -2893,10 +3138,6 @@ msgstr "Ημερομηνία Έκδοσης Από" msgid "Published Date To" msgstr "Ημερομηνία Έκδοσης Μέχρι" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Εξαίρεση Ετικετών" @@ -2938,30 +3179,26 @@ msgstr "" msgid "To:" msgstr "" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Διαγραφή αυτού του Ραφιού" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Το ράφι θα διαγραφεί για όλους τουε χρήστες" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Κοινοποίηση με Όλους" @@ -3003,8 +3240,8 @@ msgid "System Statistics" msgstr "" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Πρόγραμμα Βιβλιοθήκης" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3030,9 +3267,17 @@ msgstr "Πρόοδος" msgid "Run Time" msgstr "Χρόνος Λειτουργίας" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Ώρα Έναρξης" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3062,19 +3307,23 @@ msgstr "Kobo Μονάδα Συγχρονισμού" msgid "Create/View" msgstr "Δημιουγία/Προβολή" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "Προσθήκη Τιμών Ειδικά Προσαρμοσμένης Στήλης επιτρέπεται/Απορρίπτεται" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Διαγραφή Χρήστη" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Δημιουργία Kobo Auth URL" @@ -3094,17 +3343,17 @@ msgstr "Επιλογή ενός ονόματος χρήστη" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "Η διεύθυνση email σου" +msgid "Enter Email" +msgstr "Δοκιμαστικό e-mail" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Enter Kindle E-mail Address" +msgid "Enter eReader Email" msgstr "Διεύθυνση E-mail Αποστολής στο Kindle" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Kindle E-mail" +msgid "eReader Email" msgstr "Δοκιμαστικό e-mail" #: cps/templates/user_table.html:137 @@ -3174,10 +3423,6 @@ msgstr "" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Προβολή επιλογών σειράς" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Προβολή τυχαίων βιβλίων" - diff --git a/cps/translations/es/LC_MESSAGES/messages.mo b/cps/translations/es/LC_MESSAGES/messages.mo index 99318bb33..51ff23b3b 100644 Binary files a/cps/translations/es/LC_MESSAGES/messages.mo and b/cps/translations/es/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/es/LC_MESSAGES/messages.po b/cps/translations/es/LC_MESSAGES/messages.po index a44d25736..aa2d8c57c 100644 --- a/cps/translations/es/LC_MESSAGES/messages.po +++ b/cps/translations/es/LC_MESSAGES/messages.po @@ -9,590 +9,647 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2020-05-25 17:22+0200\n" "Last-Translator: minakmostoles \n" "Language: es\n" "Language-Team: es \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" - -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "no instalado" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "instalado" +"Generated-By: Babel 2.10.3\n" # "Last-Translator: victorhck \n" -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Estadísticas" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Servidor reiniciado. Por favor, recargue la página" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "El servidor se está apagando. Por favor, cierre la ventana" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Reconexión correcta" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Comando desconocido" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Libro puesto en la cola de envío a %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Desconocido" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Página de administración" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Configuración básica" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Configuración de la interfaz de usuario" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" msgstr "Editar usuarios" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Todo" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "Usuario no encontrado" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "{} usuarios eliminados con éxito" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Mostrar todo" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "Petición mal formulada" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "El nombre de invitado no se puede cambiar" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "El invitado no puede tener ese rol" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "No queda ningún usuario administrador, no se puede eliminar al usuario" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "Valor tiene que ser verdadero o falso" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "Rol inválido" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "El invitado no puede tener esta vista" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "Vista no válida" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "El sitio del invitado se determina automáticamente y no puede ser cambiado" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "No hay un sitio válido" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "No se ha indicado un idioma válido para el libro" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "Parámetro no encontrado" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "Columna de lectura no válida" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "Columna restringida no válida" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Configuración de Calibre-Web actualizada" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "¿Realmente quieres borrar el Token de Kobo?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "¿Realmente deseas borrar este dominio?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "¿Realmente quieres borrar este usuario?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "¿Realmente quieres eliminar este estante?" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "¿Realmente quieres cambiar el idioma de los usuarios seleccionados?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "¿Realmente quieres cambiar los idiomas visibles del libro de los usuarios seleccionados?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "¿Realmente quieres cambiar el rol seleccionado de el usuario seleccionado?" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "¿Realmente quieres cambiar las restricciones de los usuarios seleccionados?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "¿Realmente quieres cambiar las restricciones de visibilidad de los usuarios seleccionados?" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "¿Realmente quieres cambiar el comportamiento de sincronización de estante del usuario seleccionado?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "¿Realmente quieres cambiar la ubicación de la biblioteca Calibre?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "Etiqueta no encontrada" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "Acción no válida" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Denegar" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Permitir" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Etiqueta no encontrada" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Acción no válida" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json no está configurado para la aplicación web" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "La ruta del Logfile no es válida. Por favor, Introduce la ruta correcta" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "La ruta del Access Logfile no es válida. Por favor, Introduce la ruta correcta" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Por favor, Introduce un proveedor LDAP, puerto, DN y el User Object Identifier" -#: cps/admin.py:1102 +#: cps/admin.py:1191 #, fuzzy msgid "Please Enter a LDAP Service Account and Password" msgstr "Por favor, introduce una cuenta de servicio LDAP y su contraseña" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "Por favor, introduce una cuenta de servicio LDAP" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "LDAP Group Object Filter necesita tener un identificador de formato \"%s\"" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "El LDAP Group Object Filter tiene un paréntesis diferente" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "LDAP Group Object Filter necesita tener un identificador de formato \"%s\"" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "El LDAP Group Object Filter tiene un paréntesis diferente" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "El filtro de usuarios LDAP necesita tener un identificador de formato \"%s\"" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "El filtro de LDAP \"Member User\" tiene paréntesis no coincidentes" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "Ubicaciones del certificado de la CA del LDAP, del certificado o de la clave no válidos. Por favor introduce la ruta correcta" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "La base de datos de configuración no es modificable" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "Añadir nuevo usuario" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "La ruta de la base de datos no es válida. Por favor, Introduce la ruta correcta" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "La base de datos no es modificable" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "La ruta del Keyfile no es válida, por favor, Introduce la ruta correcta" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "La ruta de Certfile no es válida, por favor, Introduce la ruta correcta" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Actualizados los ajustes del servidor de correo electrónico" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Configuración de la base de datos" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "¡Por favor, rellena todos los campos!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "El correo electrónico no tiene un dominio válido" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "Añadir un nuevo usuario" - -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Usuario '%(user)s' creado" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Encontrada una cuenta existente para este correo electrónico o nombre de usuario." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Usuario '%(nick)s' eliminado" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "No puedes borrar al Usuario Invitado" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "No queda ningún usuario administrador, no se puede borrar al usuario" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Editar Usuario %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Usuario '%(nick)s' actualizado" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Ha ocurrido un error desconocido. Por favor vuelva a intentarlo más tarde." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Cambiar parámetros de correo" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "Verificación de cuenta de Gmail exitosa" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Error en la base de datos: %(error)s." + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "Puesto en cola un correo electrónico de prueba enviado a %(email)s, por favor, comprueba el resultado en Tareas" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Ocurrió un error enviando el correo electrónico de prueba: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Por favor, configure su correo electrónico primero..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Actualizados los ajustes del servidor de correo electrónico" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Ha ocurrido un error desconocido. Por favor vuelva a intentarlo más tarde." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Editar Usuario %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Contraseña para el usuario %(user)s reinicializada" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Configura primero los parámetros del servidor SMTP..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Visor del fichero de log" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Solicitando paquete de actualización" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Descargando paquete de actualización" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Descomprimiendo paquete de actualización" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Remplazando archivos" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Los conexiones con la base datos están cerradas" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Parando el servidor" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Actualización finalizada. Por favor, pulse OK y recargue la página" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Falló la actualización:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "Error HTTP" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Error de conexión" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Tiempo agotado mientras se trataba de establecer la conexión" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Error general" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "La actualización del archivo no pudo guardarse en el directorio temporal (Temp Dir)" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 #, fuzzy msgid "Failed to extract at least One LDAP User" msgstr "Error al crear al menos un usuario LDAP" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "Error al crear al menos un usuario LDAP" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Error: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Error: el servidor LDAP no ha devuelto ningún usuario" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "Al menos, un usuario LDAP no se ha encontrado en la base de datos" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} Usuario importado con éxito" -#: cps/converter.py:30 -msgid "not configured" -msgstr "no configurado" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "La ruta de la base de datos no es válida. Por favor, Introduce la ruta correcta" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "La base de datos no es modificable" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "La ruta del Keyfile no es válida, por favor, Introduce la ruta correcta" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "La ruta de Certfile no es válida, por favor, Introduce la ruta correcta" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "Actualizados los ajustes del servidor de correo electrónico" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Configuración de la base de datos" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "¡Por favor, rellena todos los campos!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "El correo electrónico no tiene un dominio válido" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Añadir un nuevo usuario" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Usuario '%(user)s' creado" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Encontrada una cuenta existente para este correo electrónico o nombre de usuario." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Usuario '%(nick)s' eliminado" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "No puedes borrar al Usuario Invitado" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "No queda ningún usuario administrador, no se puede borrar al usuario" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Usuario '%(nick)s' actualizado" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "no instalado" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Faltan permisos de ejecución" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 -#, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, fuzzy, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "Columna personalizada No.%(column)d no existe en la base de datos calibre" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Formato de libro eliminado con éxito" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Ninguno" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Libro eliminado con éxito" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "oh, oh, el libro seleccionado no está disponible. El archivo no existe o no es accesible" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "editar metadatos" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "" -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "%(seriesindex) no es un número válido, saltando" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s no es un idioma válido" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "No se permite subir archivos con la extensión '%(ext)s' a este servidor" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "El archivo a subir debe tener una extensión" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Fallo al crear la ruta %(path)s (permiso denegado)" - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Fallo al guardar el archivo %(file)s." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Error en la base de datos: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Archivo con formato %(ext)s añadido a %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "Los identificadores no distinguen entre mayúsculas y minúsculas, sobrescribiendo el identificador antiguo" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Metadatos actualizados con éxito" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Error al editar el libro, por favor, compruebe el archivo de registro (logfile) para tener más detalles" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "El libro cargado probablemente existe en la biblioteca, considera cambiarlo antes de subirlo de nuevo: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "El archivo %(filename)s no pudo salvarse en el directorio temporal (Temp Dir)" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Fallo al mover el archivo de cubierta %(file)s: %(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "El fichero %(file)s ha sido subido" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Falta la fuente o el formato de destino para la conversión" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Libro puesto a la cola para su conversión a %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Ocurrió un error al convertir este libro: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "El libro cargado probablemente existe en la biblioteca, considera cambiarlo antes de subirlo de nuevo: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s no es un idioma válido" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "No se permite subir archivos con la extensión '%(ext)s' a este servidor" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "El archivo a subir debe tener una extensión" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "El archivo %(filename)s no pudo salvarse en el directorio temporal (Temp Dir)" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Fallo al mover el archivo de cubierta %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Formato de libro eliminado con éxito" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Libro eliminado con éxito" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "editar metadatos" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex) no es un número válido, saltando" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Fallo al crear la ruta %(path)s (permiso denegado)" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Fallo al guardar el archivo %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Archivo con formato %(ext)s añadido a %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "La configuración de Google Drive no se ha completado, intente desactivar y activar Google Drive nuevamente" @@ -606,166 +663,181 @@ msgstr "El dominio Callback no se ha verificado, siga los pasos para verificarlo msgid "%(format)s format not found for book id: %(book)d" msgstr "%(format)s formato no encontrado para el id del libro: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s no encontrado en Google Drive: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s no encontrado: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Enviar al Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Este correo electrónico ha sido enviado usando Calibre-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Correo de prueba de Calibre-Web" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Comprobar correo electrónico" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Primeros pasos con Calibre-Web" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Correo electrónico de registro para el usuario: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "Convertir %(orig)s a %(format)s y enviar al Kindle" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "Enviado %(format)s al Kindle" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Enviar al Kindle" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "El archivo solicitado no puede ser leído. ¿Quizás existen problemas con los permisos?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "Fallo al intentar borrar la carpeta del libro %(id)s, la ruta tiene subcarpetas: %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "El eliminado del libro %(id)s falló: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, fuzzy, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "Borrando el libro %(id)s, la ruta del libro es no válida: %(path)s" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "El renombrado del título de: '%(src)s' a '%(dest)s' falló con el error: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Ha fallado el cambio de nombre del archivo '%(src)s' a '%(dest)s' con el error: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Fichero %(file)s no encontrado en Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "El renombrado del título de: '%(src)s' a '%(dest)s' falló con el error: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "La ruta %(path)s del libro no fue encontrada en Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Encontrada una cuenta existente para esa dirección de correo electrónico" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Este nombre de usuario ya está en uso" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" msgstr "Dirección de correo no válida" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Error al descargar la cubierta" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "Error en el formato de la cubierta" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Error al crear una ruta para la cubierta" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "El archivo de cubierta no es una imágen válida" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "Sólo se admiten como portada los archivos jpg/jpeg/png/webp/bmp" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Sólo se admiten como portada los archivos jpg/jpeg" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "No se encuentra el archivo binario UnRar" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" msgstr "Error ejecutando UnRar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Esperando" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Descubrir" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Fallido" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "Comenzado" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Finalizado" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Estado desconocido" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Por favor, accede a calibre-web desde una ubicación que no sea localhost para obtener una api_endpoint válida para tu dispositivo Kobo" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Configuración de Kobo" @@ -774,9 +846,9 @@ msgstr "Configuración de Kobo" msgid "Register with %(provider)s" msgstr "Registrado con %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "has iniciado sesión como : '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -835,507 +907,613 @@ msgstr "Error en Google Oauth, por favor vuelva a intentarlo más tarde." msgid "Google Oauth error: {}" msgstr "Error Google Oauth {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "{} Estrellas" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Inicio de sesión" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Token no encontrado" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "El token ha expirado" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "¡Correcto! Por favor regrese a su dispositivo" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Libros" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Mostrar libros recientes" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Libros populares" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Mostrar libros populares" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "Libros Descargados" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "Mostrar Libros Descargados" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Libros mejor valorados" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Mostrar libros mejor valorados" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Libros leídos" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Mostrar leídos y no leídos" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Libros no leídos" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Mostrar no leído" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Descubrir" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Mostrar libros al azar" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Categorías" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Mostrar selección de categorías" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Series" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Mostrar selección de series" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Autores" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Mostrar selección de autores" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Editores" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Mostrar selección de editores" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Idiomas" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Mostrar selección de idiomas" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Calificaciones" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Mostrar selección de calificaciones" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Formatos de archivo" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Mostrar selección de formatos de archivo" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Libros archivados" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" msgstr "Mostrar libros archivados" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "Lista de Libros" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "Mostrar Lista de Libros" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Estantería especificada no válida" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Lo sentimos, no tiene permisos para agregar un libro al estante: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "El libro ya forma parte del estante: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "El libro fue agregado a el estante: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "No tiene permiso para añadir un libro a el estante: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Los libros ya forman parte del estante: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Los libros han sido añadidos al estante: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "No se pudieron agregar libros al estante: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "El libro fue eliminado del estante: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Lo siento, no tiene permiso para eliminar un libro del estante: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Crear un estante" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Lo siento, no tiene permiso para eliminar un libro del estante: %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Editar un estante" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Estante %(title)s creado" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Estante %(title)s cambiado" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Ha sucedido un error" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Ya existe un estante público con el nombre '%(title)s'." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Ya existe un estante privado con el nombre '%(title)s'." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Cambiar orden del estante: '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Estante: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Error al abrir un estante. El estante no existe o no es accesible" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Dato inesperado mientras se leía la información de actualización" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Actualización no disponible. Ya tienes instalada la versión más reciente" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Una nueva actualización está disponible. Haz clic en el botón inferior para actualizar a la versión más reciente." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "No se puede conseguir información sobre la actualización" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Haz clic en el botón de abajo para actualizar a la última versión estable." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Hay una nueva actualización disponible. Haz clic en el botón de abajo para actualizar a la versión: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "No hay información del lanzamiento disponible" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Descubrir (Libros al azar)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Libros populares (los más descargados)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "Libros descargados por %(user)s" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Autor/es: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Editor/es: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Series: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Calificación: %(rating)s estrellas" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Formato del archivo: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Categoría : %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Idioma: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Búsqueda avanzada" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Buscar" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Descargas" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Lista de calificaciones" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Lista de formatos" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Tareas" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Publicado después de " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Publicado antes de " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Calificación <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Calificación >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "Estado de lectura = $(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "Error en la búsqueda de columnas personalizadas, por favor reinicia Calibre-Web" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Libro puesto en la cola de envío a %(kindlemail)s" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Búsqueda avanzada" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Estantería especificada no válida" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Lo sentimos, no tiene permisos para agregar un libro al estante: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "El libro ya forma parte del estante: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "El libro fue agregado a el estante: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Los libros ya forman parte del estante: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Los libros han sido añadidos al estante: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "No se pudieron agregar libros al estante: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "El libro fue eliminado del estante: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Crear un estante" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Lo siento, no tiene permiso para eliminar un libro del estante: %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Editar un estante" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Libro eliminado con éxito" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Cambiar orden del estante: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Estante %(title)s creado" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Estante %(title)s cambiado" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Ha sucedido un error" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Ya existe un estante público con el nombre '%(title)s'." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Ya existe un estante privado con el nombre '%(title)s'." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Estante: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Error al abrir un estante. El estante no existe o no es accesible" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Tareas" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Esperando" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Fallido" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Comenzado" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Finalizado" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Estado desconocido" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Dato inesperado mientras se leía la información de actualización" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Actualización no disponible. Ya tienes instalada la versión más reciente" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Una nueva actualización está disponible. Haz clic en el botón inferior para actualizar a la versión más reciente." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "No se puede conseguir información sobre la actualización" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Haz clic en el botón de abajo para actualizar a la última versión estable." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Hay una nueva actualización disponible. Haz clic en el botón de abajo para actualizar a la versión: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "No hay información del lanzamiento disponible" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Descubrir (Libros al azar)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Libros populares (los más descargados)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Libros descargados por %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Autor/es: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Editor/es: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Series: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Calificación: %(rating)s estrellas" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Formato del archivo: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Categoría : %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Idioma: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Descargas" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Lista de calificaciones" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Lista de formatos" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Configura primero los parámetros del servidor SMTP..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Libro puesto en la cola de envío a %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "Ha sucedido un error en el envío del libro: %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "Por favor actualiza tu perfil con la dirección de correo de su kindle..." -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "El servidor de correo no está configurado, por favor, ¡avisa a tu administrador!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Registro" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Su correo electrónico no está permitido para registrarse" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Se ha enviado un correo electrónico de verificación a su cuenta de correo." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "No se puede activar la autenticación LDAP" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "Fallback login como: '%(nickname)s', no se puede acceder al servidor LDAP o usuario desconocido" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "No se pudo entrar: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Usuario o contraseña inválido" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "Una nueva contraseña se ha enviado a su cuenta de correo electrónico" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Por favor, introduce un usuario válido para restablecer la contraseña" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Ahora estás conectado como: '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "Perfil de %(name)s" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Perfil actualizado" +#: cps/web.py:1420 +#, fuzzy +msgid "Oops! An account already exists for this Email." +msgstr "Encontrada una cuenta existente para esa dirección de correo electrónico" + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "No se ha encontrado ningún archivo gmail.json válido con información OAuth" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Enviar al Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "Calibre ebook-convert %(tool)s no encontrado" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "%(format)s format no encontrado en disco" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "El conversor de Ebook falló con un error desconocido" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Kepubify-converter falló: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "Archivo convertido no encontrado, o más de un archivo en el directorio %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Falló Ebook-converter: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "Calibre falló con el error: %(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "editar metadatos" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Subir archivo" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Usuarios" @@ -1348,14 +1526,15 @@ msgstr "Nombre de usuario" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "Correo electrónico" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Enviar al correo de Kindle" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Admin" @@ -1365,212 +1544,230 @@ msgstr "Admin" msgid "Password" msgstr "Contraseña" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Subir archivo" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Descargar" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Ver libros" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Editar" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Borrar" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Estantería pública" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Añadir nuevo usuario" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "Importar usuarios LDAP" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "Ajustes del servidor de correo electrónico" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "Servidor SMTP" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "Puerto SMTP" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "Encriptado" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "Login SMTP" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Desde el correo" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" msgstr "Servicio de Correo" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "Gmail por Oauth2" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Configuración" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Directorio de la base de datos de Calibre" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Nivel de registro" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Puerto" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "Puerto externo" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Libros por página" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Subidas" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Navegación anónima" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Registro público" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Acceso remoto mediante enlace mágico" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "Acceso mediante Proxy inverso" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Nombre de cabecera de Proxy inverso" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Editar la configuración de la base de datos de Calibre" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Editar la configuración básica" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "Editar la configuración de la interfaz de usuario" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Administración" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "Descargar paquete de debug" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Ver archivos de registro" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Reconectar a la BD Calibre" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Reiniciar" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Apagar" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Actualizar" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Versión" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Detalles" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Versión actual" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Comprobar actualizaciones" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Realizar actualización" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "¿Realmente quieres reiniciar?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "Ok" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Cancelar" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "¿Realmente quiere detener?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Actualizando. Por favor, no recargue la página" @@ -1582,119 +1779,118 @@ msgstr "via" msgid "In Library" msgstr "En la Librería" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "Ordenar en base a fecha del libro, más reciente primero" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "Ordenar en base a fecha del libro, menos reciente primero" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "Ordenar en base al título en orden alfabético" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "Ordenar en base al título en orden alfabético invertido" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "Ordenar en base a fecha de publicación, más reciente primero" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "Ordenar en base a fecha de publicación, menos reciente primero" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "reducir" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Más de" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Borrar libro" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Borrar formatos:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Convertir formato de libro:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Convertir desde:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "seleccionar una opción" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Convertir a:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Convertir libro" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Título del libro" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Autor" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Descripción" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "Identificadores" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "Tipo de identificador" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "Valor de identificador" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Borrar" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "Añadir identificador" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Etiquetas" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "ID de serie" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Clasificación" @@ -1706,82 +1902,83 @@ msgstr "Obtener portada de URL (JPEG, la portada ser'a descargada y almacenada e msgid "Upload Cover from Local Disk" msgstr "Subir portada desde un disco local" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Fecha de publicación" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Editor" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Idioma" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Sí" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "No" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Subir formato" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Ver libro tras la edición" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Obtener metadatos" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Guardar" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Palabra clave" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " Buscar por palabras clave " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Haz clic en la portada para cargar los metadatos en el formulario" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Cargando..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Cerrar" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Origen" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "¡Error en la búsqueda!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "¡No se encontraron resultados! Por favor intenta con otra palabra clave." @@ -1873,27 +2070,36 @@ msgstr "Introducir nombre de dominio" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Leer estado" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Identificadores" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "¿Estás realmente seguro?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "Libros con título serán fusionados de:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "En el libro con el título:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "Fusionar" @@ -1986,6 +2192,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Permitir subidas" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "Formatos de archivo permitidos para subida" @@ -1999,7 +2209,7 @@ msgid "Enable Public Registration" msgstr "Permitir registro público" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "Utilizar eMail como nombre de usuario" #: cps/templates/config_edit.html:132 @@ -2066,11 +2276,6 @@ msgstr "Puerto del servidor LDAP" msgid "LDAP Encryption" msgstr "Encriptación LDAP" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Ninguno" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2206,7 +2411,7 @@ msgstr "Número de libros aleatorios a mostrar" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Número de autores para mostrar antes de ocultar (0 = desactivar la ocultación)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Tema" @@ -2238,139 +2443,143 @@ msgstr "Expresión regular para ordenar títulos" msgid "Default Settings for New Users" msgstr "Ajustes por defecto para nuevos usuarios" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Usuario administrador" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Permitir descargas" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Permitir visor de libros" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Permitir subidas de archivos" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Permitir editar" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "Permitir borrar libros" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Permitir cambiar la contraseña" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Permitir editar estantes públicos" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Excluir idiomas" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Mostrar libros con idioma" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Visibilidad predeterminada para nuevos usuarios" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Mostrar libros aleatorios en la vista detallada" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "Añadir etiquetas Permitidas/Denegados" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "Añadir valores personalizados Permitidos/Denegados" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Leer en el navegador" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Escuchar en el navegador" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, fuzzy, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Publicado" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Marcar como no leido" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Marcar como leido" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Leído" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Restarurar desde el archivo" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Añadir a archivación" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "Archivado" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Descripción:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Agregar al estante" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Público)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Editar metadatos" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "Elige tipo de servidor" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +#, fuzzy +msgid "Standard Email Account" msgstr "Usar cuenta de correo estándar" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "Verificación de cuenta Gmal con OAuth2" +#, fuzzy +msgid "Gmail Account" +msgstr "Elige tipo de servidor" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" -msgstr "Configurar cuenta de Gmail como servidor de correo" +msgid "Setup Gmail Account" +msgstr "" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" @@ -2393,10 +2602,11 @@ msgid "Attachment Size Limit" msgstr "Tamaño límite del archivo adjunto" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Guardar y enviar un correo electrónico de prueba" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Regresar" @@ -2422,46 +2632,63 @@ msgstr "Introducir nombre de dominio" msgid "Denied Domains (Blacklist)" msgstr "Dominios prohibidos (Blaclist)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Siguiente" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "Abre el archivo .kobo/Kobo eReader.conf en un editor de texto y añade (o edita):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Abre el archivo .kobo/Kobo/Kobo eReader.conf en un editor de texto y añade (o edita):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Token de sincronización de Kobo" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 #, fuzzy msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "El servidor de E-Mail no está configurado, por favor contacta a tu administrador" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Crear una incidencia" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Volver al inicio" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "Cerrar sesión" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "Ordenar autores en orden alfabético" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "Ordenar autores en orden alfabético inverso" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "Ordenar ascendientemente en base al índice de serie" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "Ordenar descendientemente en base al índice de serie" @@ -2525,7 +2752,7 @@ msgstr "Libros ordenados por puntuación" msgid "Books ordered by file formats" msgstr "Libros ordenados por formato de archivo" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Estanterías" @@ -2534,63 +2761,67 @@ msgstr "Estanterías" msgid "Books organized in shelves" msgstr "Libros organizados en estanterías" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Inicio" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Alternar navegación" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Buscar en la librería" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Cargando..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Error" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Carga hecha, procesando, por favor espere ..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Ajustes" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Cuenta" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Cerrar sesión" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Cargando..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Error" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Carga hecha, procesando, por favor espere ..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Ajustes" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Por favor, no actualice la página" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Navegar" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Acerca de" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Previo" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Detalles del libro" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Recordarme" @@ -2599,7 +2830,7 @@ msgstr "Recordarme" msgid "Forgot Password?" msgstr "¿Olvidó la contraseña?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Iniciar sesión con un enlace mágico" @@ -2695,7 +2926,7 @@ msgstr "Directorio padre" msgid "Select" msgstr "Seleccionar" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "Ok" @@ -2709,128 +2940,141 @@ msgstr "Catálogo de ebooks de Calibre-Web" msgid "epub Reader" msgstr "Lector PDF" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Claro" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Oscuro" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Regresar" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Redimensionar el texto cuando las barras laterales están abiertas." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "Lector PDF" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Atajos de teclado" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Página previa" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Página siguiente" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Escalar a mejor" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Escalar a la ancho" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Escalar a lo alto" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Escalado nativo" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Rotar hacia la derecha" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Rotar hacia la izquierda" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Voltear imagen" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Claro" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Oscuro" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Escalar" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Mejor" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Ancho" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Alto" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Nativo" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Rotar" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Voltear" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Horizontal" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Vertical" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Dirección" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "De izquierda a derecha" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "De derecha a izquierda" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "Volver al principio" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "Recordar posición" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "Barra de desplazamiento" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "Mostrar" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "Ocultar" @@ -2839,7 +3083,7 @@ msgstr "Ocultar" msgid "DJVU Reader" msgstr "Lector PDF" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "Lector PDF" @@ -2858,7 +3102,7 @@ msgid "Choose a username" msgstr "Escoger un nombre de usuario" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Tu dirección de correo" #: cps/templates/remote_login.html:5 @@ -2877,15 +3121,19 @@ msgstr "Una vez que lo realice, iniciará sesión automáticamente en ese dispos msgid "This verification link will expire in 10 minutes." msgstr "El enlace expirará después de 10 minutos." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "No se han encontrado resultados" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Término de búsqueda:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Resultados para:" @@ -2897,10 +3145,6 @@ msgstr "Fecha de publicación desde" msgid "Published Date To" msgstr "Fecha de publicación hasta" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "Leer estado" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Excluir etiquetas" @@ -2942,30 +3186,26 @@ msgstr "De:" msgid "To:" msgstr "Para:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Borrar este estante" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "Editar propiedades del estante" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "Ordenar libros manualmente" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "Deshabilitar cambio de orden" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "Habilitar cambio de orden" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "La estantería se eliminará para todos los usuarios" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Compartir con todos" @@ -3007,8 +3247,8 @@ msgid "System Statistics" msgstr "Estadísticas del sistema" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Biblioteca del programa" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3034,9 +3274,17 @@ msgstr "Progreso" msgid "Run Time" msgstr "Tiempo de ejecución" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Fecha de inicio" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3066,19 +3314,23 @@ msgstr "Token de sincronización de Kobo" msgid "Create/View" msgstr "Crear/Ver" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "Añadir columnas de valores propios de Permitidos/Denegados" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "Sincronizar con Kobo solo los libros de las estanterías seleccionadas" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Borrar usuario" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Generar Auth URL de Kobo" @@ -3098,18 +3350,18 @@ msgstr "Introduce el nombre de usuario" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "Introduce la dirección de correo electrónico" +msgid "Enter Email" +msgstr "Comprobar correo electrónico" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Enter Kindle E-mail Address" -msgstr "Introduce la dirección de correo electrónico Kindle" +msgid "Enter eReader Email" +msgstr "Enviar al correo de Kindle" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Kindle E-mail" -msgstr "Correo electrónico Kindle" +msgid "eReader Email" +msgstr "Comprobar correo electrónico" #: cps/templates/user_table.html:137 #, fuzzy @@ -3179,10 +3431,6 @@ msgstr "sincronizar estanterías seleccionadas con Kobo" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Mostrar selección leidos/no leidos" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Mostrar libros al azar" - diff --git a/cps/translations/fi/LC_MESSAGES/messages.mo b/cps/translations/fi/LC_MESSAGES/messages.mo index 1754e51a9..28bf47697 100644 Binary files a/cps/translations/fi/LC_MESSAGES/messages.mo and b/cps/translations/fi/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/fi/LC_MESSAGES/messages.po b/cps/translations/fi/LC_MESSAGES/messages.po index 58d169241..d6f9b7ba0 100644 --- a/cps/translations/fi/LC_MESSAGES/messages.po +++ b/cps/translations/fi/LC_MESSAGES/messages.po @@ -7,586 +7,643 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2020-01-12 13:56+0100\n" "Last-Translator: Samuli Valavuo \n" "Language: fi\n" "Language-Team: \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "ei asennettu" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "asennettu" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Tilastot" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Palvelin uudelleenkäynnistetty, ole hyvä ja päivitä sivu" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Palvelinta sammutetaan, ole hyvä ja sulje sivu" -#: cps/admin.py:154 -msgid "Reconnect successful" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Kirja lisätty onnistuneeksi lähetettäväksi osoitteeseen %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Tuntematon" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Ylläpitosivu" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Perusasetukset" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Käyttöliittymän asetukset" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" msgstr "Pääkäyttäjä" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Kaikki" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Näytä kaikki" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Calibre-Web asetukset päivitetty" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Oletko varma, että haluat poistaa hyllyn?" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Oletko varma, että haluat poistaa hyllyn?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Oletko varma, että haluat poistaa hyllyn?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Oletko varma, että haluat poistaa hyllyn?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "Haluatko varmasti pysäyttää Calibre-Webin?" -#: cps/admin.py:741 -msgid "Tag not found" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Sähköpostipalvelimen tiedot päivitetty" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Ominaisuuksien asetukset" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Ole hyvä ja täytä kaikki kentät!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "Sähköpostiosoite ei ole toimivasta domainista" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "Lisää uusi käyttäjä" - -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Käyttäjä '%(user)s' lisätty" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Tälle sähköpostiosoitteelle tai tunnukselle löytyi jo tili." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Käyttäjä '%(nick)s' poistettu" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Pääkäyttäjiä ei jää jäljelle, käyttäjää ei voi poistaa" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Muokkaa käyttäjää %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Käyttäjä '%(nick)s' päivitetty" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Tapahtui tuntematon virhe. Yritä myöhemmin uudelleen." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Muuta SMTP asetuksia" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "" + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Testisähköpostin lähetyksessä tapahtui virhe: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "" -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Sähköpostipalvelimen tiedot päivitetty" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Tapahtui tuntematon virhe. Yritä myöhemmin uudelleen." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Muokkaa käyttäjää %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Käyttäjän %(user)s salasana palautettu" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Ole hyvä ja aseta SMTP postiasetukset ensin..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Lokitiedoston katselin" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Haetaan päivitystiedostoa" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Ladataan päivitystiedostoa" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Puretaan päivitystiedostoa" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Korvataan tiedostoja" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Tietokantayhteydet on katkaistu" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Sammutetaan palvelin" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Päivitys valmistui, ole hyvä ja paina OK ja lataa sivu uudelleen" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Päivitys epäonnistui:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTP virhe" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Yhteysvirhe" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Aikakatkaisu yhteyttä luotaessa" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Yleinen virhe" -#: cps/admin.py:1696 +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" msgstr "" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" msgstr "" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "" -#: cps/converter.py:30 -msgid "not configured" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" msgstr "" +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "Sähköpostipalvelimen tiedot päivitetty" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Ominaisuuksien asetukset" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Ole hyvä ja täytä kaikki kentät!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "Sähköpostiosoite ei ole toimivasta domainista" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Lisää uusi käyttäjä" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Käyttäjä '%(user)s' lisätty" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Tälle sähköpostiosoitteelle tai tunnukselle löytyi jo tili." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Käyttäjä '%(nick)s' poistettu" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Pääkäyttäjiä ei jää jäljelle, käyttäjää ei voi poistaa" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Käyttäjä '%(nick)s' päivitetty" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "ei asennettu" + #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Ei mitään" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Virhe eKirjan avaamisessa. Tiedostoa ei ole tai se ei ole saatavilla:" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "muokkaa metadataa" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s ei ole kelvollinen kieli" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "Tiedostopääte '%(ext)s' ei ole sallittujen palvelimelle ladattavien listalla" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Ladattavalla tiedostolla on oltava tiedostopääte" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Polun %(path)s luonti epäonnistui (Ei oikeutta)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Tiedoston %(file)s tallennus epäonnistui." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Tiedostoformaatti %(ext)s lisätty %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Metadata päivitetty onnistuneesti" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Kirjan editoinnissa tapahtui virhe, tarkista virheilmoitus lokista" - -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " +#: cps/editbooks.py:234 +msgid "Error editing book: {}" msgstr "" -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Tiedosto %(file)s tallennettu" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Lähteen tai kohteen tiedostomuoto puuttuu" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Kirja lisätty muutosjonoon muotoon %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Kirjan muunnoksessa tapahtui virhe: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "" + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s ei ole kelvollinen kieli" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Tiedostopääte '%(ext)s' ei ole sallittujen palvelimelle ladattavien listalla" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Ladattavalla tiedostolla on oltava tiedostopääte" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "muokkaa metadataa" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Polun %(path)s luonti epäonnistui (Ei oikeutta)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Tiedoston %(file)s tallennus epäonnistui." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Tiedostoformaatti %(ext)s lisätty %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Google Drive asetukset ei ole valmiit. Koita poistaa Google Drive käytöstä ja ottaa se uudelleen käyttöön" @@ -600,166 +657,178 @@ msgstr "Paluuosoitteen domain ei ole varmistettu, seuraa ohjeita vamistaaksesi s msgid "%(format)s format not found for book id: %(book)d" msgstr "%(format)s tiedostomuotoa ei löytynyt kirjalle: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s ei löytynyt Google Drivesta: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s ei löydy: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Lähetä Kindleen" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Tämä sähköposti on lähetetty Calibre-Web:sta." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Calibre-Web testisähköposti" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Testi sähköposti" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Aloita Calibre-Web:in käyttö" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Rekiströintisähköposti käyttäjälle: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "Muunna %(orig)s muotoon %(format)s ja lähetä Kindleen" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "Lähetä %(format)s Kindleen" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Lähetä Kindleen" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Haettua tiedostoa ei pystytty lukemaan. Ehkä vaäärät oikeudet?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "Tiedon muuttaminen arvosta: '%(src)s' arvoon '%(dest)s' epäonnistui virheeseen: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Tiedoston nimeäminen polusta '%(src)s' polkuun '%(dest)s' epäonnistui virheeseen: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Tiedostoa %(file)s ei löytynyt Google Drivesta" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Tiedon muuttaminen arvosta: '%(src)s' arvoon '%(dest)s' epäonnistui virheeseen: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Kirjan polkua %(path)s ei löytynyt Google Drivesta" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Tälle sähköpostiosoitteelle läytyi jo käyttäjätunnus." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +msgid "Error executing UnRar" msgstr "" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Odottaa" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Löydä" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Epäonnistui" - -#: cps/helper.py:766 -msgid "Started" -msgstr "Aloitettu" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Valmistui" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Tuntematon tila" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" msgstr "" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "" + +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "" @@ -768,9 +837,9 @@ msgstr "" msgid "Register with %(provider)s" msgstr "Rekisteröi tuottajalle %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "olet nyt kirjautunut tunnuksella: \"%(nickname)s\"" #: cps/oauth_bb.py:148 @@ -829,507 +898,613 @@ msgstr "Google Oauth virhe, yritä myöhemmin uudelleen." msgid "Google Oauth error: {}" msgstr "" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Kirjaudu sisään" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Valtuutusta ei löytynyt" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Valtuutus vanhentunut" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Onnistui! Ole hyvä ja palaa laitteellesi" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Kirjat" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Näytä viimeisimmät kirjat" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Kuumat kirjat" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Näytä kuumat kirjat" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Parhaiten arvioidut kirjat" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Näytä parhaiten arvioidut kirjat" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Luetut kirjat" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Näytä luetut ja lukemattomat" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Lukemattomat kirjat" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Näyt lukemattomat" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Löydä" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Näytä satunnausia kirjoja" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Kategoriat" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Näytä kategoriavalinta" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Sarjat" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Näytä sarjavalinta" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Kirjailijat" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Näytä kirjailijavalinta" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Julkaisijat" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Näytä julkaisijavalinta" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Kielet" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Näytä keilivalinta" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Arvostelut" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Näytä arvosteluvalinta" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Tiedotomuodot" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Näytä tiedostomuotovalinta" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" -msgstr "" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "Näytä viimeisimmät kirjat" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Virheellinen hylly valittu" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Valitettavasti sinulla ei ole oikeutta lisätä kirjaa hyllyyn: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Kirja on jo hyllyssä: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Kirja on lisätty hyllyyn: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Sinulla ei ole oikeutta lisätä kirjaa hyllyyn: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Kirjat on jo osa hyllyssä: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Kirjat on lisätty hyllyyn: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Kirjojen lisäys hyllyyn: %(sname)s epäonnistui" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Kirja on poistettu hyllystä: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Valitettavsti sinulla ei ole oikeutta poistaa kirjaa hyllystä: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "luo hylly" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Valitettavsti sinulla ei ole oikeutta poistaa kirjaa hyllystä: %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Muokkaa hyllyä" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Hylly %(title)s luotu" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Hylly %(title)s muutettu" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Tapahtui virhe" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Muuta hyllyn: '%(name)s' järjestystä" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Hylly: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Virhe hyllyn avauksessa. Hyllyä ei ole tai se ei ole saatavilla" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Odottamatonta tietoa luettaessa päivitystietoa" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Ei päivitystä saatavilla. Sinulla on jo uusin versio" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Uusi päivitys saatavilla. Paina alla olevaa nappia päivittääksesi uusimpaan versioon." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Päivitystiedon hakeminen epäonnistui" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Paina alla olevaa nappia päivittääksesi uusimpaan vakaaseen versioon." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Uusi päivitys saatavilla. Paina alla olevaa nappia päivittääksesi versioon: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Ei päivitystietoa saatavilla" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Löydä (satunnaiset kirjat)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Kuumat kirjat (ladatuimmat)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Kirjailija: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Julkaisija: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Sarja: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Arvostelu: %(rating)s tähteä" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Tiedostomuoto: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Kategoria: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Kieli: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Edistynyt haku" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Hae" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "DLS" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Arvostelulistaus" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Tiedostomuotolistaus" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Tehtävät" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Julkaistu alkaen " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Julkaisut ennen " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Arvostelu <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Arvostelu >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Edistynyt haku" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Virheellinen hylly valittu" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Valitettavasti sinulla ei ole oikeutta lisätä kirjaa hyllyyn: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Kirja lisätty onnistuneeksi lähetettäväksi osoitteeseen %(kindlemail)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Kirja on jo hyllyssä: %(shelfname)s" -#: cps/web.py:1445 +#: cps/shelf.py:89 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" -msgstr "Kirjan: %(res)s lähettämisessa tapahtui virhe" +msgid "Book has been added to shelf: %(sname)s" +msgstr "Kirja on lisätty hyllyyn: %(sname)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." -msgstr "Ole hyvä ja aseta Kindle sähköpostiosoite ensin..." - -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" msgstr "" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Kirjat on jo osa hyllyssä: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Kirjat on lisätty hyllyyn: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Kirjojen lisäys hyllyyn: %(sname)s epäonnistui" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Kirja on poistettu hyllystä: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "luo hylly" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Valitettavsti sinulla ei ole oikeutta poistaa kirjaa hyllystä: %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Muokkaa hyllyä" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Metadata päivitetty onnistuneesti" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Muuta hyllyn: '%(name)s' järjestystä" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Hylly %(title)s luotu" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Hylly %(title)s muutettu" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Tapahtui virhe" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Hylly: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Virhe hyllyn avauksessa. Hyllyä ei ole tai se ei ole saatavilla" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Tehtävät" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Odottaa" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Epäonnistui" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Aloitettu" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Valmistui" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Tuntematon tila" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Odottamatonta tietoa luettaessa päivitystietoa" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Ei päivitystä saatavilla. Sinulla on jo uusin versio" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Uusi päivitys saatavilla. Paina alla olevaa nappia päivittääksesi uusimpaan versioon." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Päivitystiedon hakeminen epäonnistui" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Paina alla olevaa nappia päivittääksesi uusimpaan vakaaseen versioon." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Uusi päivitys saatavilla. Paina alla olevaa nappia päivittääksesi versioon: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Ei päivitystietoa saatavilla" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Löydä (satunnaiset kirjat)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Kuumat kirjat (ladatuimmat)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Kirjailija: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Julkaisija: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Sarja: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Arvostelu: %(rating)s tähteä" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Tiedostomuoto: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Kategoria: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Kieli: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "DLS" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Arvostelulistaus" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Tiedostomuotolistaus" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Ole hyvä ja aseta SMTP postiasetukset ensin..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Kirja lisätty onnistuneeksi lähetettäväksi osoitteeseen %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "Kirjan: %(res)s lähettämisessa tapahtui virhe" + +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "Ole hyvä ja aseta Kindle sähköpostiosoite ensin..." + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "" + +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Rekisteröi" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Sähköpostiosoitteellasi ei ole sallittua rekisteröityä" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Vahvistusviesti on lähetetty sähköpostiosoitteeseesi." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "LDAP autnetikoinnin aktivointi ei onnistu" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Väärä käyttäjätunnus tai salasana" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "olet kirjautunut tunnuksella: '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)sn profiili" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Profiili päivitetty" +#: cps/web.py:1420 +#, fuzzy +msgid "Oops! An account already exists for this Email." +msgstr "Tälle sähköpostiosoitteelle läytyi jo käyttäjätunnus." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Lähetä Kindleen" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "E-kirjan muunnos epäonnistui: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "muokkaa metadataa" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Lähetä" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Käyttäjälista" @@ -1342,14 +1517,15 @@ msgstr "Lempinimi" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "Sähköposti" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Kindle" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Ylläpito" @@ -1359,212 +1535,229 @@ msgstr "Ylläpito" msgid "Password" msgstr "Salasana" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Lähetä" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Lataa" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Näytä ekirjat" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Muokkaa" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Poista" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "SMTP sähköpostipalvelimen asetukset" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "SMTP palvein" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP portti" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "SSL" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "SMTP tunnus" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Lähettäjän sähköposti" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Asetukset" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Calibre DB hakemisto" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Lokitaso" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Portti" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Kirjaa sivulla" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Lähetetään" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Nimetön selaus" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Julkinen rekisteröinti" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Etäkirjautuminen" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Calibre DB hakemisto" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Ylläpito" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Katsele lokitiedostoja" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Uudelleenyhdistä Calibre DB" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Uudellenkäynnistä Calibre-Web" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Sammuta Calibre-Web" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Päivitä" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Versio" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Yksityiskohdat" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Nykyinen versio" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Tarkista päivitykset" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Päivitä" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Haluatko varmasti uudelleenkäynnistää Calibre-Webin?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "Ok" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Haluatko varmasti pysäyttää Calibre-Webin?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Päivitetään, älä päivitä sivua" @@ -1576,119 +1769,118 @@ msgstr "" msgid "In Library" msgstr "Kirjastossa" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "vähennä" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Enemmän" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Poista kirja" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Poista tiedostomuodot:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Muunna kirjan tiedostomuoto:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Muunna muodosta:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "valitse vaihtoehto" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Muunna muotoon:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Muunna kirja" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Kirjan otsikko" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Kirjailija" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Kuvaus" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Tunnisteet" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Arvostelu" @@ -1700,82 +1892,83 @@ msgstr "Kannen osoite (jpg, kuva ladataan ja tallennetaan tietokantaan, kenttä msgid "Upload Cover from Local Disk" msgstr "Lataa kuva paikalliselta levyltä" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Julkaisupäivä" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Julkaisija" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Kieli" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Kyllä" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Ei" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Lataa tiedostomuoto" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "katso kirjaa muokkauksen jälkeen" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Hae metadata" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Avainsana" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " Hae avainsanaa " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Klikkaa kantta ladataksesi metadata lomakkeelle" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Ladataan..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Sulje" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Lähde" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Hakuvirhe!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Ei osumia! Kokeile jotain tosita hakusanaa." @@ -1867,27 +2060,36 @@ msgstr "Syötä domainnimi" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Rekisteröi" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Oletko aivan varma?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "" @@ -1979,6 +2181,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Salli lähetys" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "" @@ -1992,7 +2198,7 @@ msgid "Enable Public Registration" msgstr "Salli julkinen rekisteröinti" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "" #: cps/templates/config_edit.html:132 @@ -2059,11 +2265,6 @@ msgstr "LDAP Palveimen portti" msgid "LDAP Encryption" msgstr "" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Ei mitään" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "" @@ -2199,7 +2400,7 @@ msgstr "Satunnaisten kirjojen näytön lukumäärä" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Kirjailijoiden lukumäärä ennen piilotusta (0=poista piilotus)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Teema" @@ -2231,138 +2432,141 @@ msgstr "Regular expression nimikkeiden järjestämiseen" msgid "Default Settings for New Users" msgstr "Uuden käyttäjän oletusasetukset" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Pääkäyttäjä" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Salli kirjojen lataukset" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Salli kirjojen luku" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Salli lisäykset" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Salli muutokset" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Salli sananan vaihto" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Salli julkisten hyllyjen editointi" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Poissulje kieli" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Näytä kirjat kielellä" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Oletusnäkymä uusille käyttäjille" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Näytä satunnaisia kirjoja näkymässä" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Lue selaimessa" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Kuuntele selaimessa" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Merkitse lukemattomaksi" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Merkitse luetuksi" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Luettu" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Kuvaus:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Lisää hyllyyn" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Muokkaa metadataa" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "" +#, fuzzy +msgid "Gmail Account" +msgstr "Tili" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 @@ -2386,10 +2590,11 @@ msgid "Attachment Size Limit" msgstr "" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Tallenna asetukset ja testaa sähköpostia" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Palaa" @@ -2415,45 +2620,61 @@ msgstr "Syötä domainnimi" msgid "Denied Domains (Blacklist)" msgstr "" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Seuraava" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" msgstr "" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Luo virheilmoitus" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Palaa kotiin" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "" @@ -2517,7 +2738,7 @@ msgstr "" msgid "Books ordered by file formats" msgstr "" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "" @@ -2526,63 +2747,67 @@ msgstr "" msgid "Books organized in shelves" msgstr "" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Koti" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Vaihda navigointi" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Ladataan..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Virhe" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Lataus tehty, prosessoidaan, ole hyvä ja odota..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Asetukset" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Tili" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Kirjaudu ulos" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Ladataan..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Virhe" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Lataus tehty, prosessoidaan, ole hyvä ja odota..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Asetukset" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Selaa" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Tietoja" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Edellinen" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Kirjan tiedot" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Muista minut" @@ -2591,7 +2816,7 @@ msgstr "Muista minut" msgid "Forgot Password?" msgstr "" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Kirjadu käyttäen magic link" @@ -2687,7 +2912,7 @@ msgstr "" msgid "Select" msgstr "" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "Kirja" @@ -2701,128 +2926,141 @@ msgstr "Calibre-Web e-kirjaluettelo" msgid "epub Reader" msgstr "PDF lukija" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Vaalea" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Tumma" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Palaa" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Uudelleenjärjestä teksti kun sivut on auki." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "PDF lukija" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Näppäimistöpikakomennot" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Edellinen sivu" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Seuraava sivu" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Skaalaa parhaaseen" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Skaalaa leveyteen" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Skaalaa korkeuteen" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Skaalaa alkuperäiseen" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Käännä oikealle" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Käännä vasemmalle" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Käännä kuva" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Vaalea" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Tumma" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Skaalaa" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Paras" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Leveys" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Korkeus" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Alkuperäinen" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Pyöritä" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Käännä" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Vaakasuunta" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Pystysuunta" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Suunta" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Vasemmalta oikealle" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Oikealta vasemmalle" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "" @@ -2831,7 +3069,7 @@ msgstr "" msgid "DJVU Reader" msgstr "PDF lukija" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "PDF lukija" @@ -2850,7 +3088,7 @@ msgid "Choose a username" msgstr "Valitse käyttäjänimi" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Sähköpostiosoitteesi" #: cps/templates/remote_login.html:5 @@ -2869,15 +3107,19 @@ msgstr "Kun teet näin, sinut kirjataan automaattisesti sisään tälle laitteel msgid "This verification link will expire in 10 minutes." msgstr "Linkki vanhenee 10 minuutissa." -#: cps/templates/search.html:5 -msgid "No Results Found" +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" msgstr "" #: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "" + +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Tulosket haulle:" @@ -2889,10 +3131,6 @@ msgstr "Julkaisupäivästä" msgid "Published Date To" msgstr "Julkaisupäivään" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Poissulje merkintä" @@ -2934,30 +3172,26 @@ msgstr "" msgid "To:" msgstr "" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Poista tämä hylly" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Hylly poistetaan kaikilta ja ikuisesti!" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "pitäisikö hyllyn olla julkinen?" @@ -2999,8 +3233,8 @@ msgid "System Statistics" msgstr "" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Ohjelmiston luokka" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3026,9 +3260,17 @@ msgstr "Edistyminen" msgid "Run Time" msgstr "Ajoaika" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Käynnistysaika" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3058,19 +3300,23 @@ msgstr "" msgid "Create/View" msgstr "" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Poista tämä käyttäjä" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "" @@ -3090,17 +3336,17 @@ msgstr "Valitse käyttäjänimi" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "Sähköpostiosoitteesi" +msgid "Enter Email" +msgstr "Testi sähköposti" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Enter Kindle E-mail Address" +msgid "Enter eReader Email" msgstr "Kindle" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Kindle E-mail" +msgid "eReader Email" msgstr "Testi sähköposti" #: cps/templates/user_table.html:137 @@ -3164,10 +3410,6 @@ msgstr "" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Näytä sarjavalinta" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Näytä satunnaisia kirjoja" - diff --git a/cps/translations/fr/LC_MESSAGES/messages.mo b/cps/translations/fr/LC_MESSAGES/messages.mo index df93858a2..4d21931f4 100644 Binary files a/cps/translations/fr/LC_MESSAGES/messages.mo and b/cps/translations/fr/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/fr/LC_MESSAGES/messages.po b/cps/translations/fr/LC_MESSAGES/messages.po index ad302c5ff..f839e7ba6 100644 --- a/cps/translations/fr/LC_MESSAGES/messages.po +++ b/cps/translations/fr/LC_MESSAGES/messages.po @@ -22,589 +22,646 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2020-06-07 06:47+0200\n" "Last-Translator: \n" "Language: fr\n" "Language-Team: \n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "non installé" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "installé" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Statistiques" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Serveur redémarré, merci de rafraîchir la page" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Arrêt du serveur en cours, merci de fermer la fenêtre" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Reconnecté avec succès" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Commande inconnue" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Le livre a été mis en file de traitement avec succès pour un envoi vers %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Inconnu" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Page admin" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Configuration principale" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Configuration de l’interface utilisateur" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" -msgstr "Utilisateur admin" +msgstr "Éditer les utilisateurs" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Tout" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "L'utilisateur n'a pas été trouvé" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "{} utilisateurs supprimés avec succès" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Montrer tout" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "Demande malformée" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "Le nom de l’invité ne peut pas être modifié" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "L’invité ne peut pas avoir ce rôle" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "Aucun utilisateur admin restant, impossible de supprimer le rôle admin" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "La valeur doit être vraie ou fausse" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "Rôle invalide" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "L’invité ne peut pas avoir cette vue" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "Vue invalide" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "Les paramètres régionaux de l’invité sont déterminés automatiquement et ne peuvent pas être définis" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "Aucun paramètre régional valide n’est donné" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "Aucune langue de livre valide donnée" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "Paramètre non trouvé" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "Colonne de lecture non valide" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "Colonne restreinte non valide" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Configuration de Calibre-Web mise à jour" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "Voulez-vous vraiment supprimer le jeton Kobo ?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "Voulez-vous vraiment supprimer ce domaine ?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "Voulez-vous vraiment supprimer cet utilisateur ?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Voulez-vous vraiment supprimer l’étagère ?" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Voulez-vous vraiment supprimer l’étagère ?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "Voulez-vous vraiment modifier les langues de livre visibles pour le ou les utilisateurs sélectionnés ?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "Voulez-vous vraiment modifier le rôle sélectionné pour le ou les utilisateurs sélectionnés ?" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Voulez-vous vraiment modifier les restrictions sélectionnées pour le ou les utilisateurs sélectionnés ?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "Voulez-vous vraiment modifier les restrictions de visibilité sélectionnées pour le ou les utilisateurs sélectionnés ?" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Voulez-vous vraiment supprimer l’étagère?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "Voulez-vous vraiment arrêter Calibre-Web ?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "Étiquette introuvable" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "Action invalide" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Êtes-vous certain de vouloir supprimer la base de données de synchronisation de Calibre-Web pour forcer une synchronisation complète avec votre liseuse Kobo ?" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Refuser" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Autoriser" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{} entrées de synchronisation supprimées" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Étiquette introuvable" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Action invalide" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json n'est pas configuré pour l'application Web" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "L'emplacement du fichier logfile est incorrect, veuillez saisir un chemin valide" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "L'emplacement du fichier Access Logfile est incorrect, veuillez saisir un chemin valide" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Veuillez saisir un fournisseur LDAP, Port, DN et l'identifiant objet de l'utilisateur" -#: cps/admin.py:1102 +#: cps/admin.py:1191 #, fuzzy msgid "Please Enter a LDAP Service Account and Password" msgstr "Veuillez entrer un nom d'utilisateur valide pour réinitialiser le mot de passe" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "Veuillez entrer un compte de service LDAP" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "Le filtre objet du groupe LDAP a besoin d'un identifiant de format \"%s\"" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "Le filtre objet du groupe LDAP a une parenthèse non gérée" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "Le filtre objet de l'utilisateur LDAP a besoin d'un identifiant de format \"%s\"" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "Le filtre objet de l'utilisateur LDAP a une parenthèse non gérée" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "Le filtre utilisateur des membres LDAP doit avoir un identificateur de format \"%s\\ »" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "Le filtre utilisateur de membre LDAP a des parenthèses non appariées" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "LDAP CACertificat, certificat ou emplacement de clé non valide, veuillez entrer le chemin correct" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "Les paramètres de la base de données ne sont pas accessibles en écriture" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "L'emplacement de la base de données est incorrect, veuillez saisir un chemin valide" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "La base de données n'est pas accessible en écriture" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "L'emplacement du fichier Keyfile est incorrect, veuillez saisir un chemin valide" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "L'emplacement du fichier Certfile est incorrect, veuillez saisir un chemin valide" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Les paramètres du serveur de courriels ont été mis à jour" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Configuration des options" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Veuillez compléter tous les champs !" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "Cette adresse de courriel n’appartient pas à un domaine valide" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "Ajouter un nouvel utilisateur" -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Utilisateur '%(user)s' créé" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Un compte existant a été trouvé pour cette adresse de courriel ou pour ce surnom." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Utilisateur '%(nick)s' supprimé" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "Impossible de supprimer l’utilisateur Invité" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Aucun utilisateur admin restant, impossible de supprimer l’utilisateur" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Éditer l'utilisateur %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Utilisateur '%(nick)s' mis à jour" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Une erreur inconnue est survenue. Veuillez réessayer plus tard." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Modifier les paramètres du serveur de courriels" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "La vérification du compte Gmail réussie" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Erreur de la base de données: %(error)s." + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "Teste les courriels en file d’attente pour l’envoi à %(email)s, veuillez vérifier le résultat des tâches" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Il y a eu une erreur pendant l’envoi du courriel de test : %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Veuillez d'abord configurer votre adresse de courriel..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Les paramètres du serveur de courriels ont été mis à jour" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Une erreur inconnue est survenue. Veuillez réessayer plus tard." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Éditer l'utilisateur %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Le mot de passe de l’utilisateur %(user)s a été réinitialisé" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Veuillez configurer les paramètres SMTP au préalable..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Visualiseur de fichier journal" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Demande de mise à jour" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Téléchargement de la mise à jour" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Décompression de la mise à jour" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Remplacement des fichiers" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Les connexions à la base de données ont été fermées" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Arrêt du serveur" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Mise à jour terminée, merci d’appuyer sur okay et de rafraîchir la page" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "La mise à jour a échoué :" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "Erreur HTTP" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Erreur de connexion" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Délai d'attente dépassé lors de l'établissement de connexion" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Erreur générale" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "Le fichier de mise à jour ne peut pas être sauvegardé dans le répertoire temporaire" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" -msgstr "" +msgstr "Les fichiers n’ont pas pu être remplacés pendant la mise à jour" -#: cps/admin.py:1721 +#: cps/admin.py:1542 #, fuzzy msgid "Failed to extract at least One LDAP User" msgstr "Impossible de créer au moins un utilisateur LDAP" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "Impossible de créer au moins un utilisateur LDAP" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Erreur : %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Erreur : Aucun utilisateur renvoyé dans la réponse LDAP du serveur" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "Au moins un utilisateur LDAP n'a pas été trouvé dans la base de données" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} utilisateur importé avec succès" -#: cps/converter.py:30 -msgid "not configured" -msgstr "non configuré" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "L'emplacement de la base de données est incorrect, veuillez saisir un chemin valide" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "La base de données n'est pas accessible en écriture" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "L'emplacement du fichier Keyfile est incorrect, veuillez saisir un chemin valide" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "L'emplacement du fichier Certfile est incorrect, veuillez saisir un chemin valide" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "Les paramètres du serveur de courriels ont été mis à jour" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Configuration des options" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Veuillez compléter tous les champs !" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "Cette adresse de courriel n’appartient pas à un domaine valide" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Ajouter un nouvel utilisateur" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Utilisateur '%(user)s' créé" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Un compte existant a été trouvé pour cette adresse de courriel ou pour ce surnom." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Utilisateur '%(nick)s' supprimé" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Impossible de supprimer l’utilisateur Invité" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Aucun utilisateur admin restant, impossible de supprimer l’utilisateur" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Utilisateur '%(nick)s' mis à jour" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "non installé" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Les permissions d'exécutions manquantes" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 -#, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, fuzzy, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "La colonne personnalisée No.%(column)d n'existe pas dans la base de données calibre" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Le format du livre a été supprimé avec succès" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Aucun" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Le livre a été supprimé avec succès" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Erreur d'ouverture du livre numérique. Le fichier n'existe pas ou n'est pas accessible" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "modifier les métadonnées" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "" -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "%(seriesindex)s n’est pas un nombre valide, ignoré" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s n'est pas une langue valide" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "L’extension de fichier '%(ext)s' n’est pas autorisée pour être déposée sur ce serveur" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Pour être déposé le fichier doit avoir une extension" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Impossible de créer le chemin %(path)s (Permission refusée)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Échec de la sauvegarde du fichier %(file)s." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Erreur de la base de données: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Le format de fichier %(ext)s a été ajouté à %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "Les identificateurs ne sont pas sensibles à la casse, écrasant l’ancien identificateur" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Les métadonnées ont bien été mises à jour" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Erreur d’édition du livre, veuillez consulter le journal (log) pour plus de détails" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Le fichier téléchargé existe probablement dans la librairie, veuillez le modifier avant de le télécharger de nouveau: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "Le fichier %(filename)s ne peut pas être sauvegardé dans le répertoire temporaire" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Impossible de déplacer le fichier de couverture %(file)s: %(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Le fichier %(file)s a été téléchargé" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Le format de conversion de la source ou de la destination est manquant" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Le livre a été mis avec succès en file de traitement pour conversion vers %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Une erreur est survenue au cours de la conversion du livre : %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Le fichier téléchargé existe probablement dans la librairie, veuillez le modifier avant de le télécharger de nouveau: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s n'est pas une langue valide" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "L’extension de fichier '%(ext)s' n’est pas autorisée pour être déposée sur ce serveur" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Pour être déposé le fichier doit avoir une extension" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Le fichier %(filename)s ne peut pas être sauvegardé dans le répertoire temporaire" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Impossible de déplacer le fichier de couverture %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Le format du livre a été supprimé avec succès" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Le livre a été supprimé avec succès" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "Vous n’avez par les permissions pour supprimer les livres" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "modifier les métadonnées" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s n’est pas un nombre valide, ignoré" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Impossible de créer le chemin %(path)s (Permission refusée)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Échec de la sauvegarde du fichier %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Le format de fichier %(ext)s a été ajouté à %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "La configuration de Google Drive n’est pas terminée, essayez de désactiver et d’activer à nouveau Google Drive" @@ -618,166 +675,181 @@ msgstr "Le domaine de retour d’appel (Callback domain) est non vérifié, veui msgid "%(format)s format not found for book id: %(book)d" msgstr "le format %(format)s est introuvable pour le livre : %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "le %(format)s est introuvable sur Google Drive : %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s introuvable : %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Envoyer vers Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Ce courriel a été envoyé depuis Calibre-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Courriel de test de Calibre-Web" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Courriel de test" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Bien démarrer avec Calibre-Web" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Courriel d’inscription pour l’utilisateur : %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "Convertir de %(orig)s vers %(format)s et envoyer au Kindle" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "Envoyer %(format)s vers le Kindle" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Envoyer vers Kindle" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Le fichier demandé n’a pu être lu. Problème de permission d’accès ?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "Échec de la suppression du dossier de livre pour le livre %(id)s, le chemin d’accès comporte des sous-dossiers : %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "La suppression du livre %(id)s a échoué: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, fuzzy, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "Suppression du livre %(id)s, le chemin du livre est invalide : %(path)s" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "Renommer le titre de : '%(src)s' à '%(dest)s' a échoué avec l’erreur : %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "La modification du nom de fichier du chemin : '%(src)s' vers '%(dest)s' a échoué avec l’erreur : %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Le fichier %(file)s n'a pas été trouvé dans Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Renommer le titre de : '%(src)s' à '%(dest)s' a échoué avec l’erreur : %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Le chemin du livre %(path)s n'a pas été trouvé dans Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Un compte existant a été trouvé pour cette adresse de courriel." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Cet utilisateur est déjà pris" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" msgstr "Format de l’adresse courriel invalide" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Erreur lors du téléchargement de la couverture" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "Erreur de format de couverture" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Impossible de créer le chemin pour la couverture" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "Le fichier couverture n'est pas un fichier image valide, ou ne peut pas être stocké" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "Seuls les fichiers jpg/jpeg/png/webp/bmp sont supportés comme fichier de couverture" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "Contenu du fichier de couverture invalide" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Seuls les fichiers jpg/jpeg sont supportés comme fichier de couverture" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "Fichier binaire Unrar non trouvé" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" msgstr "Une erreur est survenue lors de l'exécution d'UnRar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "En attente" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Découvrir" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Echoué" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "Débuté" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Terminé" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Statut inconnu" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Veuilllez ne pas accéder à calibre-web par localhost pour obtenir un api_endpoint valide pour un appareil kobo" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Configuration Kobo" @@ -786,9 +858,9 @@ msgstr "Configuration Kobo" msgid "Register with %(provider)s" msgstr "Enregistrer avec %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "vous êtes maintenant connecté comme : '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -847,507 +919,613 @@ msgstr "Erreur Oauth Google, veuillez réessayer plus tard." msgid "Google Oauth error: {}" msgstr "Erreur Oauth Google : {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "{} Étoiles" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Connexion" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Jeton non trouvé" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Jeton expiré" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Réussite! Merci de vous tourner vers votre appareil" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Livres" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Afficher les livres récents" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Livres populaires" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Montrer les livres populaires" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "Livres téléchargés" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "Montrer les livres téléchargés" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Livres les mieux notés" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Montrer les livres les mieux notés" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Livres lus" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Montrer lus et non-lus" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Livres non-lus" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Afficher non-lus" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Découvrir" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Montrer des livres au hasard" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Catégories" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Montrer la sélection par catégories" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Séries" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Montrer la sélection par séries" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Auteurs" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Montrer la sélection par auteur" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Éditeurs" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Montrer la sélection par éditeur" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Langues" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Montrer la sélection par langue" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Notes" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Afficher la sélection des évaluations" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Formats de fichier" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Afficher la sélection des formats de fichiers" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Livres archivés" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" msgstr "Afficher les livres archivés" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "Liste des livres" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "Montrer la liste des livres" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "L’étagère indiquée est invalide" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Désolé, vous n’êtes pas autorisé à ajouter un livre dans l’étagère: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Ce livre est déjà sur l’étagère : %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Le livre a bien été ajouté à l'étagère : %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Vous n’êtes pas autorisé à ajouter un livre dans l’étagère : %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Ces livres sont déjà sur l’étagère : %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Les livres ont été ajoutés à l’étagère : %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Impossible d’ajouter les livres à l’étagère : %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Le livre a été supprimé de l'étagère %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Désolé, vous n’êtes pas autorisé à enlever un livre de cette étagère : %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Créer une étagère" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Désolé, vous n’êtes pas autorisé à enlever un livre de cette étagère : %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Modifier une étagère" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Étagère %(title)s créée" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "L’étagère %(title)s a été modifiée" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Il y a eu une erreur" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Une étagère publique avec le nom '%(title)s' existe déjà." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Une étagère privée avec le nom '%(title)s' existe déjà." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Modifier l’arrangement de l’étagère : ‘%(name)s’" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Étagère : '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Erreur à l’ouverture de l’étagère. Elle n’existe plus ou n’est plus accessible" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Données inattendues lors de la lecture des informations de mise à jour" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Aucune mise à jour disponible. Vous avez déjà la dernière version installée" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Une nouvelle mise à jour est disponible. Cliquez sur le bouton ci-dessous pour charger la dernière version." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Impossible d'extraire les informations de mise à jour" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Téléchargez la dernière version en cliquant sur le bouton ci-dessous." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Une nouvelle mise à jour est disponible. Cliquez sur le bouton ci-dessous pour charger la version: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Aucune information concernant cette version n’est disponible" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Découvrir (Livres au hasard)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Livres populaires (les plus téléchargés)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "Livres téléchargés par %(user)s" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Auteur : %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Éditeur : '%(name)s'" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Séries : %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Évaluation : %(rating)s étoiles" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Format de fichier : %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Catégorie : %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Langue : %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Recherche avancée" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Chercher" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Téléchargements" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Liste des évaluations" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Liste de formats de fichiers" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Tâches" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Publié après le " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Publié avant le " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Évaluation <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Évaluation >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "Status de lecture = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "Erreur lors de la recherche de colonnes personnalisées, veuillez redémarrer Calibre-Web" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Le livre a été mis en file de traitement avec succès pour un envoi vers %(kindlemail)s" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Recherche avancée" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "L’étagère indiquée est invalide" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Désolé, vous n’êtes pas autorisé à ajouter un livre dans l’étagère: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Ce livre est déjà sur l’étagère : %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Le livre a bien été ajouté à l'étagère : %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "Vous n’êtes pas autorisé à ajouter un livre à l’étagère" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Ces livres sont déjà sur l’étagère : %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Les livres ont été ajoutés à l’étagère : %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Impossible d’ajouter les livres à l’étagère : %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Le livre a été supprimé de l'étagère %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "Désolé, vous n’êtes pas autorisé à supprimer un livre de cette étagère" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Créer une étagère" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Désolé, vous n’êtes pas autorisé à enlever un livre de cette étagère : %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Modifier une étagère" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Le livre a été supprimé avec succès" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Modifier l’arrangement de l’étagère : ‘%(name)s’" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "Désolé, vous n’êtes pas autorisé à créer une étagère publique" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Étagère %(title)s créée" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "L’étagère %(title)s a été modifiée" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Il y a eu une erreur" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Une étagère publique avec le nom '%(title)s' existe déjà." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Une étagère privée avec le nom '%(title)s' existe déjà." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Étagère : '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Erreur à l’ouverture de l’étagère. Elle n’existe plus ou n’est plus accessible" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Tâches" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "En attente" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Echoué" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Débuté" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Terminé" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Statut inconnu" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Données inattendues lors de la lecture des informations de mise à jour" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Aucune mise à jour disponible. Vous avez déjà la dernière version installée" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Une nouvelle mise à jour est disponible. Cliquez sur le bouton ci-dessous pour charger la dernière version." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Impossible d'extraire les informations de mise à jour" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Téléchargez la dernière version en cliquant sur le bouton ci-dessous." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Une nouvelle mise à jour est disponible. Cliquez sur le bouton ci-dessous pour charger la version: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Aucune information concernant cette version n’est disponible" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Découvrir (Livres au hasard)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Livres populaires (les plus téléchargés)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Livres téléchargés par %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Auteur : %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Éditeur : '%(name)s'" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Séries : %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Évaluation : %(rating)s étoiles" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Format de fichier : %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Catégorie : %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Langue : %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Téléchargements" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Liste des évaluations" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Liste de formats de fichiers" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Veuillez configurer les paramètres SMTP au préalable..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Le livre a été mis en file de traitement avec succès pour un envoi vers %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "Il y a eu une erreur en envoyant ce livre : %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "Veuillez mettre à jour votre profil avec une adresse de courriel Kindle valide." -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "Le serveur de courriel n'est pas configuré, veuillez contacter votre administrateur!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Créer un compte" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Votre adresse de courriel n’est pas autorisé pour une inscription" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Le courriel de confirmation a été envoyé à votre adresse." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "Impossible d’activer l’authentification LDAP" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "Connexion de secours comme: '%(nickname)s', le serveur LDAP est indisponible, ou l'utilisateur est inconnu" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Impossible de se connecter: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Mauvais nom d'utilisateur ou mot de passe" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "Le nouveau mot de passe a été envoyé vers votre adresse de courriel" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Veuillez entrer un nom d'utilisateur valide pour réinitialiser le mot de passe" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Vous êtes maintenant connecté en tant que : ‘%(nickname)s’" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "Profil de %(name)s" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Profil mis à jour" +#: cps/web.py:1420 +#, fuzzy +msgid "Oops! An account already exists for this Email." +msgstr "Un compte existant a été trouvé pour cette adresse de courriel." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "Aucun fichier gmail.json avec information OAuth valide trouvé" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Envoyer vers Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "ebook-convert calibre %(tool)s non trouvé" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "Format %(format)s non trouvé sur le disque" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "Le convertisseur Ebook a échoué avec une erreur inconnue" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "La commande Kepubify-converter a échouée : %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "Fichier converti non trouvé ou plus d'un fichier dans le chemin %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "La commande ebook-convert a échouée : %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "Calibre a échoué avec l’erreur : %(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "modifier les métadonnées" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Téléverser" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Liste des utilisateurs" @@ -1360,14 +1538,15 @@ msgstr "Nom d'utilisateur" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "Adresse de courriel" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Envoyer vers une adresse de courriel Kindle" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Administration" @@ -1377,212 +1556,230 @@ msgstr "Administration" msgid "Password" msgstr "Mot de passe" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Téléverser" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Télécharger" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Afficher les livres" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Éditer" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Supprimer" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Étagère publique" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Ajouter un nouvel utilisateur" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "Importer des utilisateurs LDAP" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "Paramètres du serveur de courriels" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "Nom d'hôte du serveur SMTP" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "Port du serveur SMTP" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "Chiffrement" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "Compte utilisateur SMTP" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Expéditeur des courriels" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" msgstr "Service courriel" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "Gmail via Oauth2" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Configuration" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Répertoire de la base de données Calibre" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Niveau de journalisation" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Port" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "Port exeterne" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Livres par page" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Téléversements" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Navigation anonyme" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Inscription publique" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Connexion à distance Magic Link" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "Compte du Reverse Proxy" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Nom de l'en-tête du Reverse Proxy" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" -msgstr "Éditer la configuration principale" +msgstr "Éditer la configuration de la base de données Calibre" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Éditer la configuration principale" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" -msgstr "Configuration de l’interface utilisateur" +msgstr "Éditer la configuration de l’interface utilisateur" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Administration" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "Télécharger le package de débogage" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Afficher les fichiers journaux" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Reconnecter la base de données Calibre" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Redémarrer Calibre-Web" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Arrêter Calibre-Web" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Mise à jour de Calibre-Web" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Version" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Détails" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Version actuelle" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Rechercher les mises à jour" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Effectuer la mise à jour" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Voulez-vous vraiment redémarrer Calibre-Web?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "OK" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Annuler" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Voulez-vous vraiment arrêter Calibre-Web?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Mise à jour en cours, ne pas rafraîchir la page" @@ -1594,119 +1791,118 @@ msgstr "via" msgid "In Library" msgstr "Dans la librairie" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "Trier en fonction de la date du livre, le plus récent en premier" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "Trier en fonction de la date du livre, le plus ancien en premier" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "Trier les titres dans l’ordre alphabétique" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "Trier le titre dans l’ordre alphabétique inverse" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "Trier en fonction de la date de publication, le plus récent en premier" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "Trier en fonction de la date de publication, le plus ancien en premier" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "réduire" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Plus de" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Supprimer le livre" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Supprimer les formats :" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Convertir le format du livre :" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Convertir depuis :" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "choisir une option" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Convertir vers :" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Convertir le livre" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Titre du livre" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Auteur" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Description" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "Identifiants" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "Type d'identifiant" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "Valeur d'identifiant" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Supprimer" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "Ajouter un identifiant" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Étiquettes" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "ID de séries" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Évaluation" @@ -1718,82 +1914,83 @@ msgstr "Obtenir la couverture à partir d'une URL (JPEG - l'image sera télécha msgid "Upload Cover from Local Disk" msgstr "Téléverser la couverture depuis un fichier en local" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Date de publication" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Éditeur" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Langue" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Oui" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Non" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Format du fichier téléversé" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Voir le livre lors de la sauvegarde" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Obtenir les métadonnées" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Sauvegarder" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Mot-clé" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " Rechercher le mot-clé " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Cliquer sur la couverture pour importer les métadonnées dans le formulaire" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Chargement..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Fermer" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Source" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Erreur lors de la recherche!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Aucun résultat. Veuillez essayer avec un nouveau mot clé." @@ -1883,29 +2080,38 @@ msgstr "Saisir le nom du domaine" #: cps/templates/book_table.html:73 msgid "Comments" +msgstr "Commentaires" + +#: cps/templates/book_table.html:75 +msgid "Archive Status" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Status de lecture" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Identifiants" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Êtes-vous vraiment sûr?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "Les livres avec titre vont être fusionnés depuis :" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "Dans le livre avec le titre :" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "Fusionner" @@ -1968,7 +2174,7 @@ msgstr "Nightly" #: cps/templates/config_edit.html:50 msgid "Trusted Hosts (Comma Separated)" -msgstr "" +msgstr "Hôtes de confiance (séparés par des virgules)" #: cps/templates/config_edit.html:61 msgid "Logfile Configuration" @@ -1992,12 +2198,16 @@ msgstr "Configuration des options" #: cps/templates/config_edit.html:104 msgid "Convert non-English characters in title and author while saving to disk" -msgstr "" +msgstr "Convertir les caractères non-anglais des titre et auteur lors de l’enregistrement sur le disque" #: cps/templates/config_edit.html:108 msgid "Enable Uploads" msgstr "Autoriser le téléversement de fichier" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(Svp, vérifiez que les utilisateurs ont aussi les droits de téléchargement vers le serveur)" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "Formats de fichiers à télécharger autorisés" @@ -2011,7 +2221,7 @@ msgid "Enable Public Registration" msgstr "Autoriser l’inscription publique" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "Utiliser l'e-mail comme nom d'utilisateur" #: cps/templates/config_edit.html:132 @@ -2078,11 +2288,6 @@ msgstr "Port du serveur LDAP" msgid "LDAP Encryption" msgstr "Chiffrement LDAP" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Aucun" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2157,7 +2362,7 @@ msgstr "Champ des membres de groupe LDAP" #: cps/templates/config_edit.html:278 msgid "LDAP Member User Filter Detection" -msgstr "" +msgstr "Filtre de détection des utilisateurs membres LDAP" #: cps/templates/config_edit.html:280 msgid "Autodetect" @@ -2218,7 +2423,7 @@ msgstr "Nombre de livres choisis au hasard à afficher" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Nombre d’auteurs à afficher avant de masquer (0=désactiver le masquage)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Thème" @@ -2250,139 +2455,143 @@ msgstr "Expression régulière à utiliser pour trier les titres" msgid "Default Settings for New Users" msgstr "Réglages par défaut pour les nouveaux utilisateurs" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Utilisateur admin" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Permettre les téléchargements" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Autoriser le visionneur de livres" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Permettre le téléversement de fichiers" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Permettre l'édition" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "Permettre la suppression de livres" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Permettre le changement de mot de passe" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Autoriser la modification d’étagères publiques" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Exclure les langues" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Montrer les livres dans la langue" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Mode de visualisation par défaut pour les nouveaux utilisateurs" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Montrer aléatoirement des livres dans la vue détaillée" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "Ajouter les étiquettes autorisées/refusées" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "Ajouter les valeurs de colonnes autorisées/refusées" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Lire dans le navigateur" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Écouter dans le navigateur" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, fuzzy, python-format msgid "Book %(index)s of %(range)s" -msgstr "" +msgstr "Livre %(index)s sur %(range)s" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Publié" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Marquer comme non lu" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Marquer comme lu" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Lu" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Restaurer à partir de l'archive" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Ajouter comme archive" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "Archivé" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Description :" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Ajouter à l'étagère" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Public)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Éditer les métadonnées" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "Choisissez le type de serveur" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +#, fuzzy +msgid "Standard Email Account" msgstr "Utilisez le compte courriel standard" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "Compte Gmail avec vérification OAuth2" +#, fuzzy +msgid "Gmail Account" +msgstr "Choisissez le type de serveur" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" -msgstr "Configuration du compte Gmail comme serveur courriel" +msgid "Setup Gmail Account" +msgstr "" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" @@ -2405,10 +2614,11 @@ msgid "Attachment Size Limit" msgstr "Limite de la taille de la pièce jointe" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Sauvegarder les réglages et tester l’envoi d’un courriel" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Retour" @@ -2434,46 +2644,63 @@ msgstr "Saisir le nom du domaine" msgid "Denied Domains (Blacklist)" msgstr "Domaines refusés (Liste noire)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Suivant" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "Ouvrir le fichier .kobo/Kobo eReader.conf dans un éditeur de texte et ajouter (ou éditer):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Ouvrir le fichier .kobo/Kobo/Kobo eReader.conf dans un éditeur de texte et ajouter (ou éditer):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Jeton de synchro Kobo" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 #, fuzzy msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "Le serveur de courriel n'est pas configuré, veuillez contacter votre administrateur!" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Signaler un problème" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Retour à l’accueil" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "Déconnecter l’utilisateur" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "Trier de manière ascendante selon le nombre de téléchargements" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "Trier de manière descendante selon le nombre de téléchargements" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "Trier les auteurs dans l’ordre alphabétique" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "Trier les auteurs dans l’ordre alphabétique inverse" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "Trier par ordre croissant en fonction de l’index de série" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "Trier par ordre décroissant en fonction de l’index de série" @@ -2537,7 +2764,7 @@ msgstr "Livres classés par évaluation" msgid "Books ordered by file formats" msgstr "Livres classés par formats de fichiers" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Etagères" @@ -2546,63 +2773,67 @@ msgstr "Etagères" msgid "Books organized in shelves" msgstr "Livres organisés par étagères" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Accueil" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Basculer la navigation" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Chercher dans librairie" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Téléversement en cours..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Erreur" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Téléversement terminé, traitement en cours, veuillez patienter…." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Paramètres" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Compte" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Déconnexion" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Téléversement en cours..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Erreur" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Téléversement terminé, traitement en cours, veuillez patienter…." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Paramètres" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Veuillez ne pas rafraîchir la page" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Explorer" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "À propos" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Précédent" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Détails du livre" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Se rappeler de moi" @@ -2611,7 +2842,7 @@ msgstr "Se rappeler de moi" msgid "Forgot Password?" msgstr "Mot de passe oublié ?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Se connecter avec Magic Link" @@ -2707,7 +2938,7 @@ msgstr "Répertoire parent" msgid "Select" msgstr "Sélectionner" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "Livre" @@ -2721,128 +2952,141 @@ msgstr "Catalogue de livres électroniques Calibre-Web" msgid "epub Reader" msgstr "Lecteur PDF" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Clair" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Sombre" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Retour" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Mettre à jour la mise en page du texte quand les bandeaux latéraux sont ouverts." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "Lecteur PDF" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Raccourcis clavier" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Page précédente" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Page suivante" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Mise à l’échelle optimale" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Mise à l’échelle sur la largeur" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Mise à l’échelle sur la hauteur" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Mise à l’échelle d’origine" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Rotation droite" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Rotation gauche" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Inverser l’image" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Clair" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Sombre" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Échelle" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Optimal" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Largeur" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Hauteur" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Origine" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Rotation" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Inverser" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Horizontal" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Vertical" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Direction" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "De gauche à droite" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "De droite à gauche" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "Réinitialiser en haut" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "Se rappeler de la position" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "Barre de défilement" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "Montrer" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "Cacher" @@ -2851,7 +3095,7 @@ msgstr "Cacher" msgid "DJVU Reader" msgstr "Lecteur PDF" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "Lecteur PDF" @@ -2870,7 +3114,7 @@ msgid "Choose a username" msgstr "Choisissez un nom d'utilisateur" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Votre adresse de courriel" #: cps/templates/remote_login.html:5 @@ -2889,15 +3133,19 @@ msgstr "Une fois fait, vous serez automatiquement connecté à cet appareil." msgid "This verification link will expire in 10 minutes." msgstr "Le lien expirera après 10 minutes." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Aucun résultat trouvé" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Chercher le terme:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Résultats pour :" @@ -2909,10 +3157,6 @@ msgstr "Date de publication (depuis)" msgid "Published Date To" msgstr "Date de publication (jusqu’à)" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "Status de lecture" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Exclure les étiquettes" @@ -2954,30 +3198,26 @@ msgstr "Depuis" msgid "To:" msgstr "Vers" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Supprimer cette étagère" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "Éditer les propriétés de l’étagère" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "Organiser les livres manuellement" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "Désactiver l’ordre de modification" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "Activer l’ordre de modification" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "L’étagère sera supprimée pour tous les utilisateus" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Partager avec tout le monde" @@ -3019,8 +3259,8 @@ msgid "System Statistics" msgstr "Statistiques système" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Bibliothèque logicielle" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3046,9 +3286,17 @@ msgstr "Avancement" msgid "Run Time" msgstr "Durée" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Démarrage" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3078,19 +3326,23 @@ msgstr "Jeton de synchro Kobo" msgid "Create/View" msgstr "Créer/visualiser" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "Forcer une synchronisation complète Kobo" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "Ajouter les valeurs de colonnes personnalisées autorisées/refusées" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "Synchroniser uniquement les livres dans les étagères sélectionnées avec Kobo" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Supprimer l'utilisateur" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Générer l'URL d'authentification Kobo" @@ -3101,7 +3353,7 @@ msgstr "Sélectionner..." #: cps/templates/user_table.html:131 #, fuzzy msgid "Edit User" -msgstr "Utilisateur admin" +msgstr "Éditer l’utilisateur" #: cps/templates/user_table.html:134 #, fuzzy @@ -3110,17 +3362,17 @@ msgstr "Choisissez un nom d'utilisateur" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "Votre adresse de courriel" +msgid "Enter Email" +msgstr "Courriel de test" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Enter Kindle E-mail Address" +msgid "Enter eReader Email" msgstr "Envoyer vers une adresse de courriel Kindle" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Kindle E-mail" +msgid "eReader Email" msgstr "Courriel de test" #: cps/templates/user_table.html:137 @@ -3191,10 +3443,6 @@ msgstr "Synchroniser les étagères sélectionnées avec Kobo" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Montrer la sélection par séries" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Montrer des livres au hasard" - diff --git a/cps/translations/gl/LC_MESSAGES/messages.mo b/cps/translations/gl/LC_MESSAGES/messages.mo new file mode 100644 index 000000000..119f8f197 Binary files /dev/null and b/cps/translations/gl/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/gl/LC_MESSAGES/messages.po b/cps/translations/gl/LC_MESSAGES/messages.po new file mode 100644 index 000000000..539467d14 --- /dev/null +++ b/cps/translations/gl/LC_MESSAGES/messages.po @@ -0,0 +1,3383 @@ +# Translation to Galician for Calibre-Web. +# pollitor , 2022. +# +msgid "" +msgstr "" +"Project-Id-Version: Calibre-Web\n" +"Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" +"PO-Revision-Date: 2022-08-11 16:46+0200\n" +"Last-Translator: pollitor \n" +"Language: gl\n" +"Language-Team: gl\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.10.3\n" + +#: cps/about.py:84 +msgid "Statistics" +msgstr "Estatísticas" + +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." +msgstr "Servidor reiniciado. Por favor, recargue a páxina" + +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." +msgstr "O servidor estase apagando. Por favor, peche a xanela" + +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" + +#: cps/admin.py:156 +msgid "Unknown command" +msgstr "Orde descoñecida" + +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Libro posto na cola de envío a %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 +msgid "Unknown" +msgstr "Descoñecido" + +#: cps/admin.py:225 +msgid "Admin page" +msgstr "Páxina de administración" + +#: cps/admin.py:245 +msgid "Basic Configuration" +msgstr "Configuración Básica" + +#: cps/admin.py:283 +msgid "UI Configuration" +msgstr "Configuración da Interface de Usuario" + +#: cps/admin.py:317 cps/templates/admin.html:51 +msgid "Edit Users" +msgstr "Editar Usuarios" + +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 +msgid "All" +msgstr "Todo" + +#: cps/admin.py:388 cps/admin.py:1392 +msgid "User not found" +msgstr "Usuario non atopado" + +#: cps/admin.py:402 +msgid "{} users deleted successfully" +msgstr "{} usuarios borrados con éxito" + +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 +#: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 +msgid "Show All" +msgstr "Mostrar Todo" + +#: cps/admin.py:446 cps/admin.py:452 +msgid "Malformed request" +msgstr "Petición mal formada" + +#: cps/admin.py:464 cps/admin.py:1993 +msgid "Guest Name can't be changed" +msgstr "O nome do convidado non se pode cambiar" + +#: cps/admin.py:476 +msgid "Guest can't have this role" +msgstr "O convidado non pode ter este rol" + +#: cps/admin.py:488 cps/admin.py:1948 +msgid "No admin user remaining, can't remove admin role" +msgstr "Non queda ningún usuario administrador, non se pode eliminar ao usuario" + +#: cps/admin.py:492 cps/admin.py:506 +msgid "Value has to be true or false" +msgstr "O Valor ten que ser verdadeiro ou falso" + +#: cps/admin.py:494 +msgid "Invalid role" +msgstr "Rol non válido" + +#: cps/admin.py:498 +msgid "Guest can't have this view" +msgstr "O convidado non pode ter esta vista" + +#: cps/admin.py:508 +msgid "Invalid view" +msgstr "Vista non válida" + +#: cps/admin.py:511 +msgid "Guest's Locale is determined automatically and can't be set" +msgstr "O sitio do convidado determínase automáticamente e non se pode cambiar" + +#: cps/admin.py:515 +msgid "No Valid Locale Given" +msgstr "Non hai unha localización válida" + +#: cps/admin.py:526 +msgid "No Valid Book Language Given" +msgstr "Non se indicou unha lingua válida para o libro" + +#: cps/admin.py:528 cps/editbooks.py:442 +msgid "Parameter not found" +msgstr "Parámetro non atopado" + +#: cps/admin.py:565 +msgid "Invalid Read Column" +msgstr "Columna de lectura non válida" + +#: cps/admin.py:571 +msgid "Invalid Restricted Column" +msgstr "Columna restrinxida non válida" + +#: cps/admin.py:591 cps/admin.py:1819 +msgid "Calibre-Web configuration updated" +msgstr "Configuración de Calibre-Web actualizada" + +#: cps/admin.py:603 +msgid "Do you really want to delete the Kobo Token?" +msgstr "De verdade queres borrar o Token de Kobo?" + +#: cps/admin.py:605 +msgid "Do you really want to delete this domain?" +msgstr "De verdade desexas borrar este dominio?" + +#: cps/admin.py:607 +msgid "Do you really want to delete this user?" +msgstr "De verdade queres borrar este usuario?" + +#: cps/admin.py:609 +msgid "Are you sure you want to delete this shelf?" +msgstr "De verdade queres eliminar este andel?" + +#: cps/admin.py:611 +msgid "Are you sure you want to change locales of selected user(s)?" +msgstr "De verdade queres cambiar a linguaxe dos usuarios seleccionados?" + +#: cps/admin.py:613 +msgid "Are you sure you want to change visible book languages for selected user(s)?" +msgstr "De verdade queres cambiar as linguas visibles do libro dos usuarios seleccionados?" + +#: cps/admin.py:615 +msgid "Are you sure you want to change the selected role for the selected user(s)?" +msgstr "De verdade queres cambiar o rol seleccionado do usuario seleccionado?" + +#: cps/admin.py:617 +msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" +msgstr "De verdade queres cambiar as restricións escollidas dos usuarios seleccionados?" + +#: cps/admin.py:619 +msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" +msgstr "De verdade queres cambiar as restricións de visibilidade dos usuarios seleccionados?" + +#: cps/admin.py:622 +msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" +msgstr "De verdade queres cambiar o comportamento da sincronización do andel para o usuario seleccionado?" + +#: cps/admin.py:624 +msgid "Are you sure you want to change Calibre library location?" +msgstr "De verdade queres cambiar a localización da biblioteca Calibre?" + +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "Calibre-web buscará cubertas actualizadas e miniaturas de cubertas actualizadas, isto pode levar un intre?" + +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Está seguro que quere borrar a base de datos de sincronización de Calibre-Web para forzar unha sincronización completa co seu lector Kobo?" + +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 +#: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 +#: cps/templates/user_table.html:58 +msgid "Deny" +msgstr "Denegar" + +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 +#: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 +#: cps/templates/user_table.html:61 +msgid "Allow" +msgstr "Permitir" + +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "Elimináronse {} entradas de sincronización" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Etiqueta non atopada" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Acción non válida" + +#: cps/admin.py:1104 +msgid "client_secrets.json Is Not Configured For Web Application" +msgstr "client_secrets.json non está configurado para a aplicación web" + +#: cps/admin.py:1149 +msgid "Logfile Location is not Valid, Please Enter Correct Path" +msgstr "A localización do arquivo de rexistro non é válida. Por favor, Introduce a ruta correcta" + +#: cps/admin.py:1155 +msgid "Access Logfile Location is not Valid, Please Enter Correct Path" +msgstr "A localización do rexistro de accesos non é válida. Por favor, Introduce a ruta correcta" + +#: cps/admin.py:1185 +msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" +msgstr "Por favor, Introduce un provedor LDAP, porto, DN e o User Object Identifier" + +#: cps/admin.py:1191 +msgid "Please Enter a LDAP Service Account and Password" +msgstr "Por favor, introduce unha conta de servizo LDAP e o seu contrasinal" + +#: cps/admin.py:1194 +msgid "Please Enter a LDAP Service Account" +msgstr "Por favor, introduce unha conta de servizo LDAP" + +#: cps/admin.py:1199 +#, python-format +msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" +msgstr "LDAP Group Object Filter necesita ter un identificador de formato \"%s\"" + +#: cps/admin.py:1201 +msgid "LDAP Group Object Filter Has Unmatched Parenthesis" +msgstr "O LDAP Group Object Filter ten parénteses que non casan" + +#: cps/admin.py:1205 +#, python-format +msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" +msgstr "LDAP Group Object Filter necesita ter un identificador de formato \"%s\"" + +#: cps/admin.py:1207 +msgid "LDAP User Object Filter Has Unmatched Parenthesis" +msgstr "O LDAP Group Object Filter ten parénteses que non casan" + +#: cps/admin.py:1214 +#, python-format +msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" +msgstr "O filtro de usuarios LDAP necesita ter un identificador de formato \"%s\"" + +#: cps/admin.py:1216 +msgid "LDAP Member User Filter Has Unmatched Parenthesis" +msgstr "O filtro de LDAP \"Member User\" ten parénteses que non casan" + +#: cps/admin.py:1223 +msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" +msgstr "As localizacións do certificado da CA do LDAP, do certificado ou da chave non válidos. Por favor introduce a ruta correcta" + +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "Engadir novo usuario" + +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" +msgstr "Cambiar os parámetros do correo" + +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" + +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Error na base de datos: %(error)s." + +#: cps/admin.py:1311 +#, python-format +msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" +msgstr "Posto en cola un correo electrónico de proba enviado a %(email)s, por favor, comproba o resultado nas Tarefas" + +#: cps/admin.py:1314 +#, python-format +msgid "There was an error sending the Test e-mail: %(res)s" +msgstr "Ocurreu un error enviando o correo electrónico de proba: %(res)s" + +#: cps/admin.py:1316 +msgid "Please configure your e-mail address first..." +msgstr "Por favor, configure o seu correo electrónico primeiro..." + +#: cps/admin.py:1318 +msgid "Email Server Settings updated" +msgstr "Actualizáronse os axustes do servidor de correo electrónico" + +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "Editar a Configuración das Tarefas Programadas" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "Indicada unha hora incorrecta de comezo de tarefa" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "Indicada unha duracción incorrecta para a tarefa" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "Actualizouse a configuración das tarefas programadas" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Sucedeu un erro descoñecido. Por favor volva a intentalo máis tarde." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "A configuración da DB non se pode escribir" + +#: cps/admin.py:1411 cps/admin.py:2009 +#, python-format +msgid "Edit User %(nick)s" +msgstr "Editar o Usuario %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" +msgstr "Reiniciada a contrasinal para o usuario %(user)s" + +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." +msgstr "Configura primeiro os parámetros do servidor SMTP..." + +#: cps/admin.py:1440 +msgid "Logfile viewer" +msgstr "Visor do ficheiro de rexistro" + +#: cps/admin.py:1506 +msgid "Requesting update package" +msgstr "Solicitando paquete de actualización" + +#: cps/admin.py:1507 +msgid "Downloading update package" +msgstr "Descargando paquete de actualización" + +#: cps/admin.py:1508 +msgid "Unzipping update package" +msgstr "Descomprimendo paquete de actualización" + +#: cps/admin.py:1509 +msgid "Replacing files" +msgstr "Remplazando archivos" + +#: cps/admin.py:1510 +msgid "Database connections are closed" +msgstr "As conexións coa base datos están pechadas" + +#: cps/admin.py:1511 +msgid "Stopping server" +msgstr "Detendo o servidor" + +#: cps/admin.py:1512 +msgid "Update finished, please press okay and reload page" +msgstr "Actualización finalizada. Por favor, prema OK e recargue a páxina" + +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 +msgid "Update failed:" +msgstr "A actualización fallou:" + +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 +msgid "HTTP Error" +msgstr "Erro HTTP" + +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 +msgid "Connection error" +msgstr "Erro de conexión" + +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 +msgid "Timeout while establishing connection" +msgstr "Tempo esgotado mentras se trataba de establecer a conexión" + +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 +msgid "General error" +msgstr "Erro xeral" + +#: cps/admin.py:1517 +msgid "Update file could not be saved in temp dir" +msgstr "A actualización do arquivo non se puido gardar no directorio temporal (Temp Dir)" + +#: cps/admin.py:1518 +msgid "Files could not be replaced during update" +msgstr "Non se puideron substituír os ficheiros durante a actualización" + +#: cps/admin.py:1542 +msgid "Failed to extract at least One LDAP User" +msgstr "Erro ao extraer polo menos un usuario LDAP" + +#: cps/admin.py:1587 +msgid "Failed to Create at Least One LDAP User" +msgstr "Erro ao crear polo menos un usuario LDAP" + +#: cps/admin.py:1600 +#, python-format +msgid "Error: %(ldaperror)s" +msgstr "Erro: %(ldaperror)s" + +#: cps/admin.py:1604 +msgid "Error: No user returned in response of LDAP server" +msgstr "Erro: o servidor LDAP non devolveu ningún usuario" + +#: cps/admin.py:1637 +msgid "At Least One LDAP User Not Found in Database" +msgstr "Polo menos, un usuario LDAP non se atopou na base de datos" + +#: cps/admin.py:1639 +msgid "{} User Successfully Imported" +msgstr "Usuario {} importado con éxito" + +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "A localización da base de datos non é válida. Por favor, Introduce a ruta correcta" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "A base de datos non é modificable" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "A localización do Keyfile non é válida, por favor, Introduce a ruta correcta" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "A localización do Certfile non é válida, por favor, Introduce a ruta correcta" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "Actualizados os axustes da base de datos" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "Configuración da base de datos" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Por favor, cubra todos os campos!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "O correo electrónico non ven dun dominio válido" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Engadir un usuario novo" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Usuario '%(user)s' creado" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "Atopada unha conta existente para este correo electrónico ou nome de usuario." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Usuario '%(nick)s' eliminado" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Non se pode borrar ao Usuario Invitado" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Non queda ningún usuario administrador, non se pode borrar ao usuario" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Usuario '%(nick)s' actualizado" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "non instalado" + +#: cps/converter.py:32 +msgid "Execution permissions missing" +msgstr "Faltan permisos de execución" + +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" +msgstr "Columna personalizada No.%(column)d non existe na base de datos calibre" + +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Ningún" + +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" +msgstr "oh, oh, o libro seleccionado non está disponible. O arquivo non existe ou non está accesible" + +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "O usuario non ten permisos para subir a cuberta" + +#: cps/editbooks.py:174 cps/editbooks.py:716 +msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" +msgstr "Os identificadores non distinguen entre maiúsculas e minúsculas, sobrescribindo o identificador antigo" + +#: cps/editbooks.py:216 +msgid "Metadata successfully updated" +msgstr "Metadatos actualizados con éxito" + +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "Erro editando libro: {}" + +#: cps/editbooks.py:291 +#, python-format +msgid "File %(file)s uploaded" +msgstr "O ficheiro %(file)s subiuse" + +#: cps/editbooks.py:318 +msgid "Source or destination format for conversion missing" +msgstr "Falta a fonte ou o formato de destino para a conversión" + +#: cps/editbooks.py:326 +#, python-format +msgid "Book successfully queued for converting to %(book_format)s" +msgstr "Libro posto na cola para a súa conversión a %(book_format)s" + +#: cps/editbooks.py:330 +#, python-format +msgid "There was an error converting this book: %(res)s" +msgstr "Houbo un erro ao convertir este libro: %(res)s" + +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "O libro cargado probablemente existe na biblioteca, considera cambialo antes de subilo outra vez: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s non é unha lingua válida" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Non se permite subir arquivos coa extensión '%(ext)s' a este servidor" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "O arquivo que se vai cargar debe ter unha extensión" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "El archivo %(filename)s non puido gravarse no directorio temporal (Temp Dir)" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Fallo ao mover o arquivo de cuberta %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Formato de libro eliminado con éxito" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Libro eliminado con éxito" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "Vostede non ten permisos para borrar libros" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "editar metadatos" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s non é un número válido, saltando" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "O usuario non ten permisos para cargar formatos de ficheiro adicionais" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Fallo ao crear a ruta %(path)s (permiso denegado)" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Fallo ao gardar o arquivo %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Arquivo con formato %(ext)s engadido a %(book)s" + +#: cps/gdrive.py:58 +msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" +msgstr "A configuración de Google Drive non se completou, intente desactivar e activar Google Drive outra vez" + +#: cps/gdrive.py:95 +msgid "Callback domain is not verified, please follow steps to verify domain in google developer console" +msgstr "O dominio Callback non se comprobou, siga os pasos para comprobalo na consola de desenvolvedor de Google" + +#: cps/helper.py:80 +#, python-format +msgid "%(format)s format not found for book id: %(book)d" +msgstr "%(format)s formato non atopado para o id do libro: %(book)d" + +#: cps/helper.py:87 cps/tasks/convert.py:75 +#, python-format +msgid "%(format)s not found on Google Drive: %(fn)s" +msgstr "%(format)s non atopado en Google Drive: %(fn)s" + +#: cps/helper.py:92 +#, python-format +msgid "%(format)s not found: %(fn)s" +msgstr "%(format)s non atopado: %(fn)s" + +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +msgid "Send to eReader" +msgstr "Enviar ao Kindle" + +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." +msgstr "Este correo electrónico enviouse empregando Calibre-Web." + +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" +msgstr "Correo de proba de Calibre-Web" + +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" +msgstr "Comprobar correo electrónico" + +#: cps/helper.py:132 +msgid "Get Started with Calibre-Web" +msgstr "Primeiros pasos con Calibre-Web" + +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" +msgstr "Correo electrónico de rexistro para o usuario: %(name)s" + +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "Convertir %(orig)s a %(format)s e enviar ao Kindle" + +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" +msgstr "Enviado %(format)s ao Kindle" + +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" +msgstr "Enviar ao Kindle %(book)s" + +#: cps/helper.py:230 +msgid "The requested file could not be read. Maybe wrong permissions?" +msgstr "O arquivo solicitado non pode lerse. Quizais existen problemas cos permisos?" + +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "O estado de lectura non pode fixarse: {}" + +#: cps/helper.py:368 +#, python-format +msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" +msgstr "Fallo ao intentar borrar a carpeta do libro %(id)s, a ruta ten subcarpetas: %(path)s" + +#: cps/helper.py:374 +#, python-format +msgid "Deleting book %(id)s failed: %(message)s" +msgstr "O borrado do libro %(id)s fallou: %(message)s" + +#: cps/helper.py:385 +#, python-format +msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" +msgstr "Borrando o libro %(id)s, a ruta de libro non é válida: %(path)s" + +#: cps/helper.py:450 +#, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "O renomeado do título de: '%(src)s' a '%(dest)s' fallou co erro: %(error)s" + +#: cps/helper.py:522 cps/helper.py:531 +#, python-format +msgid "File %(file)s not found on Google Drive" +msgstr "Ficheiro %(file)s non atopado en Google Drive" + +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "O renomeado do título de: '%(src)s' a '%(dest)s' fallou co erro: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "Erro ao renomear o ficheiro na ruta: {}" + +#: cps/helper.py:603 +#, python-format +msgid "Book path %(path)s not found on Google Drive" +msgstr "A ruta %(path)s do libro non se atopou en Google Drive" + +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" + +#: cps/helper.py:652 +msgid "This username is already taken" +msgstr "Este nome de usuario xa está en uso" + +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" +msgstr "Enderezo de correo non válido" + +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "O módulo Python 'advocate' non está instalado pero se necesita para as cargas de cubertas" + +#: cps/helper.py:825 +msgid "Error Downloading Cover" +msgstr "Erro ao descargar a cuberta" + +#: cps/helper.py:828 +msgid "Cover Format Error" +msgstr "Erro no formato da cuberta" + +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "Non ten permiso para acceder a localhost ou á rede local para as cargas de cubertas" + +#: cps/helper.py:841 +msgid "Failed to create path for cover" +msgstr "Erro ao crear unha ruta para a cuberta" + +#: cps/helper.py:857 +msgid "Cover-file is not a valid image file, or could not be stored" +msgstr "O arquivo de cuberta non é unha imaxe válida" + +#: cps/helper.py:868 +msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" +msgstr "Soamente se admiten como cuberta os arquivos jpg/jpeg/png/webp/bmp" + +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "Contido do arquivo de cuberta non válido" + +#: cps/helper.py:884 +msgid "Only jpg/jpeg files are supported as coverfile" +msgstr "Soamente se admiten como cuberta os arquivos jpg/jpeg" + +#: cps/helper.py:936 +msgid "Unrar binary file not found" +msgstr "Non se atopa o arquivo binario de UnRar" + +#: cps/helper.py:947 +msgid "Error executing UnRar" +msgstr "Erro executando UnRar" + +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Descubrir" + +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" + +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "Por favor, accede a calibre-web dende unha ubicación que non sexa localhost para obter unha api_endpoint válida para o teu dispositivo Kobo" + +#: cps/kobo_auth.py:115 +msgid "Kobo Setup" +msgstr "Configuración de Kobo" + +#: cps/oauth_bb.py:77 +#, python-format +msgid "Register with %(provider)s" +msgstr "Rexistrado con %(provider)s" + +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 +#, python-format +msgid "Success! You are now logged in as: %(nickname)s" +msgstr "Iniciou sesión como : '%(nickname)s'" + +#: cps/oauth_bb.py:148 +#, python-format +msgid "Link to %(oauth)s Succeeded" +msgstr "O enlace a %(oauth)s realizouse con éxito" + +#: cps/oauth_bb.py:155 +msgid "Login failed, No User Linked With OAuth Account" +msgstr "Acceso errado, ningún usuario enlazado coa conta OAuth" + +#: cps/oauth_bb.py:197 +#, python-format +msgid "Unlink to %(oauth)s Succeeded" +msgstr "%(oauth)s desenlazado con éxito" + +#: cps/oauth_bb.py:202 +#, python-format +msgid "Unlink to %(oauth)s Failed" +msgstr "Erro ao desenlazar %(oauth)s" + +#: cps/oauth_bb.py:205 +#, python-format +msgid "Not Linked to %(oauth)s" +msgstr "Non vinculado con %(oauth)s" + +#: cps/oauth_bb.py:261 +msgid "Failed to log in with GitHub." +msgstr "Erro ao iniciar sesión con GitHub." + +#: cps/oauth_bb.py:267 +msgid "Failed to fetch user info from GitHub." +msgstr "Erro ao obter a información do usuario de GitHub." + +#: cps/oauth_bb.py:279 +msgid "Failed to log in with Google." +msgstr "Erro ao iniciar sesión con Google." + +#: cps/oauth_bb.py:285 +msgid "Failed to fetch user info from Google." +msgstr "Erro ao obter información do usuario de Google." + +#: cps/oauth_bb.py:332 +msgid "GitHub Oauth error, please retry later." +msgstr "Erro en GitHub Oauth, por favor, volva a intentalo máis tarde." + +#: cps/oauth_bb.py:335 +msgid "GitHub Oauth error: {}" +msgstr "Erro GitHub Oauth {}" + +#: cps/oauth_bb.py:356 +msgid "Google Oauth error, please retry later." +msgstr "Erro en Google Oauth, por favor volva a intentalo máis tarde." + +#: cps/oauth_bb.py:359 +msgid "Google Oauth error: {}" +msgstr "Erro Google Oauth {}" + +#: cps/opds.py:273 +msgid "{} Stars" +msgstr "{} Estrelas" + +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 +msgid "Login" +msgstr "Inicio de sesión" + +#: cps/remotelogin.py:74 cps/remotelogin.py:108 +msgid "Token not found" +msgstr "Token non atopado" + +#: cps/remotelogin.py:83 cps/remotelogin.py:116 +msgid "Token has expired" +msgstr "O token expirou" + +#: cps/remotelogin.py:92 +msgid "Success! Please return to your device" +msgstr "Correcto! Por favor volte ao seu dispositivo" + +#: cps/render_template.py:42 cps/web.py:410 +msgid "Books" +msgstr "Libros" + +#: cps/render_template.py:44 +msgid "Show recent books" +msgstr "Mostrar libros recentes" + +#: cps/render_template.py:45 cps/templates/index.xml:25 +msgid "Hot Books" +msgstr "Libros populares" + +#: cps/render_template.py:47 +msgid "Show Hot Books" +msgstr "Mostrar libros populares" + +#: cps/render_template.py:49 cps/render_template.py:54 +msgid "Downloaded Books" +msgstr "Libros descargados" + +#: cps/render_template.py:51 cps/render_template.py:56 +#: cps/templates/user_table.html:167 +msgid "Show Downloaded Books" +msgstr "Mostrar libros descargados" + +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 +msgid "Top Rated Books" +msgstr "Libros mellor valorados" + +#: cps/render_template.py:61 cps/templates/user_table.html:161 +msgid "Show Top Rated Books" +msgstr "Mostrar libros mellor valorados" + +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 +msgid "Read Books" +msgstr "Libros lidos" + +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" +msgstr "Mostrar lidos e non lidos" + +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 +msgid "Unread Books" +msgstr "Libros non lidos" + +#: cps/render_template.py:68 +msgid "Show unread" +msgstr "Mostrar non lidos" + +#: cps/render_template.py:69 +msgid "Discover" +msgstr "Descubrir" + +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 +msgid "Show Random Books" +msgstr "Mostrar libros ao chou" + +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 +msgid "Categories" +msgstr "Categorías" + +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" +msgstr "Mostrar selección de categorías" + +#: cps/render_template.py:75 cps/templates/book_edit.html:91 +#: cps/templates/book_table.html:68 cps/templates/index.xml:90 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 +msgid "Series" +msgstr "Series" + +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" +msgstr "Mostrar selección de series" + +#: cps/render_template.py:78 cps/templates/book_table.html:66 +#: cps/templates/index.xml:69 +msgid "Authors" +msgstr "Autores" + +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" +msgstr "Mostrar selección de autores" + +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 +msgid "Publishers" +msgstr "Editores" + +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" +msgstr "Mostrar selección de editores" + +#: cps/render_template.py:85 cps/templates/book_table.html:70 +#: cps/templates/index.xml:97 cps/templates/search_form.html:107 +#: cps/web.py:1078 +msgid "Languages" +msgstr "Linguas" + +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" +msgstr "Mostrar selección de linguas" + +#: cps/render_template.py:89 cps/templates/index.xml:104 +msgid "Ratings" +msgstr "Valoracións" + +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "Mostrar selección de valoracións" + +#: cps/render_template.py:92 cps/templates/index.xml:112 +msgid "File formats" +msgstr "Formatos de arquivo" + +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" +msgstr "Mostrar selección de formatos de arquivo" + +#: cps/render_template.py:96 cps/web.py:772 +msgid "Archived Books" +msgstr "Libros arquivados" + +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "Mostrar libros arquivados" + +#: cps/render_template.py:101 cps/web.py:803 +msgid "Books List" +msgstr "Lista de libros" + +#: cps/render_template.py:103 cps/templates/user_table.html:168 +msgid "Show Books List" +msgstr "Mostrar lista de libros" + +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 +msgid "Search" +msgstr "Buscar" + +#: cps/search.py:189 +msgid "Published after " +msgstr "Publicado despóis de " + +#: cps/search.py:196 +msgid "Published before " +msgstr "Publicado antes de " + +#: cps/search.py:218 +#, python-format +msgid "Rating <= %(rating)s" +msgstr "Valoración <= %(rating)s" + +#: cps/search.py:220 +#, python-format +msgid "Rating >= %(rating)s" +msgstr "Valoración >= %(rating)s" + +#: cps/search.py:222 +#, python-format +msgid "Read Status = %(status)s" +msgstr "Estado de lectura = %(status)s" + +#: cps/search.py:324 +msgid "Error on search for custom columns, please restart Calibre-Web" +msgstr "Erro na busca de columnas personalizadas, por favor reinicia Calibre-Web" + +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Búsqueda avanzada" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Andel especificado non válido" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Sentímolo, non ten permisos para engdir un libro ao andel: %(shelfname)s" + +#: cps/shelf.py:64 +#, python-format +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "O libro xa forma parte do andel: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "O libro engadiuse ao andel: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "Non ten permiso para engadir un libro ao andel" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Os libros xa forman parte do andel: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Os libros engadíronse ao andel: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Non se pudideron engadir libros ao andel: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "O libro eliminouse do andel: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "Síntoo, non ten permiso para quitar un libro do andel" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Crear un andel" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Síntoo, non ten permiso para editar o andel: %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Editar un andel" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "Erro borrando o estante" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "Andel eliminado con éxito" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Cambiar a orde do andel: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "Síntoo, non ten permiso para crear un andel público" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Andel %(title)s creado" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Andel %(title)s cambiado" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Ocorreu un erro" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Xa existe un andel público co nome '%(title)s'." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Xa existe un andel privado co nome '%(title)s'." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Andel: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Erro ao abrir un andel. O andel non existe ou non se pode acceder" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Tarefas" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Esperando" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Fallou" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Comezado" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Rematado" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "Rematado" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "Cancelado" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Estado descoñecido" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Dato inesperado mentres líase a información de actualización" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Actualización non dispoñiible. Xa tes instalada a versión máis recente" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Unha nova actualización está dispoñible. Preme no botón inferior para actualizar á versión máis reciente." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Non se pode conseguir información sobre a actualización" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Preme no botón de abaixo para actualizar á última versión estable." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Hai unha nova actualización dispoñible. Preme no botón de abaixo para actualizar á versión: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Non hai información do lanzamento dispoñible" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Descubrir (Libros ao chou)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Libros populares (os máis descargados)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Libros descargados por %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Autor/es: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Editor/es: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Series: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "Valoración: Ningunha" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Valoración: %(rating)s estrelas" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Formato do arquivo: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Categoría: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Lingua: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Descargas" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Lista de valoracións" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Lista de formatos" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Configura primeiro os parámetros do servidor SMTP..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Libro posto na cola de envío a %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "Oh, oh! Houbo un erro no envío do libro: %(res)s" + +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "Por favor actualiza o teu perfil co enderezo de correo do teu kindle..." + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "O servidor de correo non está configurado, por favor, avisa ao teu administrador!" + +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 +msgid "Register" +msgstr "Rexistro" + +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." +msgstr "O seu correo electrónico non está permitido para rexistrarse" + +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." +msgstr "Mandouse un correo electrónico de verificación á súa conta de correo." + +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" +msgstr "Non se pode activar a autenticación LDAP" + +#: cps/web.py:1303 +#, python-format +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" +msgstr "Fallback login como: '%(nickname)s', non se pode acceder ao servidor LDAP ou usuario descoñecido" + +#: cps/web.py:1309 +#, python-format +msgid "Oops! Login Failed: %(message)s" +msgstr "Non se puido entrar: %(message)s" + +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." +msgstr "Usuario ou contrasinal no válido" + +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." +msgstr "Unha nova contrasinal enviouse ao seu enderezo de correo electrónico" + +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" +msgstr "Por favor, introduce un usuario válido para restablecer a contrasinal" + +#: cps/web.py:1400 cps/web.py:1449 +#, python-format +msgid "%(name)s's Profile" +msgstr "Perfil de %(name)s" + +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" +msgstr "Perfil actualizado" + +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "Atopada unha conta existente para ese enderezo de correo electrónico" + +#: cps/services/gmail.py:58 +msgid "Found no valid gmail.json file with OAuth information" +msgstr "Non se atopou ningún arquivo gmail.json válido con información OAuth" + +#: cps/tasks/convert.py:92 +#, python-format +msgid "%(book)s send to E-Reader" +msgstr "Enviar ao Kindle %(book)s" + +#: cps/tasks/convert.py:153 +#, python-format +msgid "Calibre ebook-convert %(tool)s not found" +msgstr "Non se atopou Calibre ebook-convert %(tool)s" + +#: cps/tasks/convert.py:186 +#, python-format +msgid "%(format)s format not found on disk" +msgstr "O formato %(format)s non se atopou no disco" + +#: cps/tasks/convert.py:190 +msgid "Ebook converter failed with unknown error" +msgstr "O conversor de Ebook fallou cun erro descoñecido" + +#: cps/tasks/convert.py:202 +#, python-format +msgid "Kepubify-converter failed: %(error)s" +msgstr "Kepubify-converter fallou: %(error)s" + +#: cps/tasks/convert.py:224 +#, python-format +msgid "Converted file not found or more than one file in folder %(folder)s" +msgstr "Arquivo convertido non atopado, ou máis dun arquivo no directorio %(folder)s" + +#: cps/tasks/convert.py:247 +#, python-format +msgid "Ebook-converter failed: %(error)s" +msgstr "Fallou Ebook-converter: %(error)s" + +#: cps/tasks/convert.py:270 +#, python-format +msgid "Calibre failed with error: %(error)s" +msgstr "Calibre fallou co erro: %(error)s" + +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "Convertir" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "Reconectando a base de datos de Calibre" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "Correo electrónico" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "editar metadatos" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "Xeradas %(count)s miniaturas de cubertas" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "Miniaturas de cubertas" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "Xeradas {0} miniaturas de series" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "Limpando caché de miniaturas de cubertas" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Subir arquivo" + +#: cps/templates/admin.html:9 +msgid "Users" +msgstr "Usuarios" + +#: cps/templates/admin.html:13 cps/templates/login.html:9 +#: cps/templates/login.html:10 cps/templates/register.html:9 +#: cps/templates/user_edit.html:10 cps/templates/user_table.html:134 +msgid "Username" +msgstr "Nome de usuario" + +#: cps/templates/admin.html:14 cps/templates/register.html:14 +#: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 +msgid "Email" +msgstr "Enderezo de correo electrónico" + +#: cps/templates/admin.html:15 cps/templates/user_edit.html:28 +msgid "Send to eReader Email" +msgstr "Enviar ao enderezo de correo electrónico do Kindle" + +#: cps/templates/admin.html:17 cps/templates/layout.html:92 +#: cps/templates/user_table.html:143 +msgid "Admin" +msgstr "Administrador" + +#: cps/templates/admin.html:18 cps/templates/login.html:13 +#: cps/templates/login.html:14 cps/templates/user_edit.html:23 +msgid "Password" +msgstr "Contrasinal" + +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 +#: cps/templates/user_table.html:146 +msgid "Download" +msgstr "Descargar" + +#: cps/templates/admin.html:23 +msgid "View Books" +msgstr "Ver libros" + +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 +#: cps/templates/user_table.html:148 +msgid "Edit" +msgstr "Editar" + +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 +#: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 +#: cps/templates/user_table.html:149 +msgid "Delete" +msgstr "Borrar" + +#: cps/templates/admin.html:26 +msgid "Public Shelf" +msgstr "Andel público" + +#: cps/templates/admin.html:55 +msgid "Import LDAP Users" +msgstr "Importar usuarios LDAP" + +#: cps/templates/admin.html:62 +msgid "Email Server Settings" +msgstr "Axustes do servidor de correo electrónico" + +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 +msgid "SMTP Hostname" +msgstr "Servidor SMTP" + +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 +msgid "SMTP Port" +msgstr "Porto SMTP" + +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 +msgid "Encryption" +msgstr "Cifraxe" + +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 +msgid "SMTP Login" +msgstr "Login SMTP" + +#: cps/templates/admin.html:83 cps/templates/admin.html:94 +#: cps/templates/email_edit.html:55 +msgid "From Email" +msgstr "Dende o correo electrónico" + +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" +msgstr "Servizo de correo electrónico" + +#: cps/templates/admin.html:91 +msgid "Gmail via Oauth2" +msgstr "Gmail por Oauth2" + +#: cps/templates/admin.html:106 +msgid "Configuration" +msgstr "Configuración" + +#: cps/templates/admin.html:109 +msgid "Calibre Database Directory" +msgstr "Directorio da base de datos de Calibre" + +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 +msgid "Log Level" +msgstr "Nivel de rexistro" + +#: cps/templates/admin.html:117 +msgid "Port" +msgstr "Porto" + +#: cps/templates/admin.html:122 +msgid "External Port" +msgstr "Porto externo" + +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 +msgid "Books per Page" +msgstr "Libros por páxina" + +#: cps/templates/admin.html:133 +msgid "Uploads" +msgstr "Cargas" + +#: cps/templates/admin.html:137 +msgid "Anonymous Browsing" +msgstr "Navegación anónima" + +#: cps/templates/admin.html:141 +msgid "Public Registration" +msgstr "Rexistro público" + +#: cps/templates/admin.html:145 +msgid "Magic Link Remote Login" +msgstr "Acceso remoto mediante enlace máxico" + +#: cps/templates/admin.html:149 +msgid "Reverse Proxy Login" +msgstr "Acceso mediante Proxy inverso" + +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 +msgid "Reverse Proxy Header Name" +msgstr "Nome de cabeceira do Proxy inverso" + +#: cps/templates/admin.html:159 +msgid "Edit Calibre Database Configuration" +msgstr "Editar a configuración da base de datos de Calibre" + +#: cps/templates/admin.html:160 +msgid "Edit Basic Configuration" +msgstr "Editar a configuración básica" + +#: cps/templates/admin.html:161 +msgid "Edit UI Configuration" +msgstr "Editar a configuración da interfaz de usuario" + +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "Tarefas programadas" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "Hora de comezo das tarefas" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "Duración máxima das tarefas" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "Xerar as miniaturas das cubertas dos libros" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "Xerar as miniaturas das cubertas das series" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "Reconectar á librería de Calibre" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "Refrescar a caché de miniaturas das cubertas" + +#: cps/templates/admin.html:199 +msgid "Administration" +msgstr "Administración" + +#: cps/templates/admin.html:200 +msgid "Download Debug Package" +msgstr "Descargar o paquete de depuración" + +#: cps/templates/admin.html:201 +msgid "View Logs" +msgstr "Ver arquivos de rexistro" + +#: cps/templates/admin.html:207 +msgid "Restart" +msgstr "Reiniciar" + +#: cps/templates/admin.html:208 +msgid "Shutdown" +msgstr "Apagar" + +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "Información de versión" + +#: cps/templates/admin.html:220 +msgid "Version" +msgstr "Versión" + +#: cps/templates/admin.html:221 +msgid "Details" +msgstr "Detalles" + +#: cps/templates/admin.html:227 +msgid "Current Version" +msgstr "Versión actual" + +#: cps/templates/admin.html:234 +msgid "Check for Update" +msgstr "Comprobar actualizacións" + +#: cps/templates/admin.html:235 +msgid "Perform Update" +msgstr "Realizar actualización" + +#: cps/templates/admin.html:248 +msgid "Are you sure you want to restart?" +msgstr "De verdade queres reiniciar?" + +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 +msgid "OK" +msgstr "Vale" + +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 +#: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 +#: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 +msgid "Cancel" +msgstr "Cancelar" + +#: cps/templates/admin.html:266 +msgid "Are you sure you want to shutdown?" +msgstr "De verdade quere deter?" + +#: cps/templates/admin.html:278 +msgid "Updating, please do not reload this page" +msgstr "Actualizando. Por favor, non recargue a páxina" + +#: cps/templates/author.html:15 +msgid "via" +msgstr "via" + +#: cps/templates/author.html:23 +msgid "In Library" +msgstr "Na Librería" + +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 +msgid "Sort according to book date, newest first" +msgstr "Ordear pola data do libro, máis recente primeiro" + +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 +msgid "Sort according to book date, oldest first" +msgstr "Ordear pola data do libro, máis antigo primeiro" + +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 +msgid "Sort title in alphabetical order" +msgstr "Ordear polo título en orden alfabético" + +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 +msgid "Sort title in reverse alphabetical order" +msgstr "Ordear polo título en orde alfabético invertido" + +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 +msgid "Sort according to publishing date, newest first" +msgstr "Ordear pola data de publicación, máis recente primeiro" + +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 +msgid "Sort according to publishing date, oldest first" +msgstr "Ordear pola data de publicación, máis antigo primeiro" + +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 +msgid "reduce" +msgstr "reducir" + +#: cps/templates/author.html:99 +msgid "More by" +msgstr "Máis de" + +#: cps/templates/book_edit.html:11 +msgid "Delete Book" +msgstr "Borrar libro" + +#: cps/templates/book_edit.html:14 +msgid "Delete formats:" +msgstr "Borrar formatos:" + +#: cps/templates/book_edit.html:25 +msgid "Convert book format:" +msgstr "Convertir formato de libro:" + +#: cps/templates/book_edit.html:30 +msgid "Convert from:" +msgstr "Convertir dende:" + +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 +msgid "select an option" +msgstr "seleccionar unha opción" + +#: cps/templates/book_edit.html:37 +msgid "Convert to:" +msgstr "Convertir a:" + +#: cps/templates/book_edit.html:46 +msgid "Convert book" +msgstr "Convertir libro" + +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 +msgid "Book Title" +msgstr "Título do libro" + +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 +msgid "Author" +msgstr "Autor" + +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 +msgid "Description" +msgstr "Descrición" + +#: cps/templates/book_edit.html:73 +msgid "Identifiers" +msgstr "Identificadores" + +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 +msgid "Identifier Type" +msgstr "Tipo de identificador" + +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 +msgid "Identifier Value" +msgstr "Valor de identificador" + +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 +#: cps/templates/user_table.html:24 +msgid "Remove" +msgstr "Borrar" + +#: cps/templates/book_edit.html:83 +msgid "Add Identifier" +msgstr "Engadir identificador" + +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 +msgid "Tags" +msgstr "Etiquetas" + +#: cps/templates/book_edit.html:95 +msgid "Series ID" +msgstr "ID de serie" + +#: cps/templates/book_edit.html:99 +msgid "Rating" +msgstr "Valoración" + +#: cps/templates/book_edit.html:104 +msgid "Fetch Cover from URL (JPEG - Image will be downloaded and stored in database)" +msgstr "Obter portada de URL (JPEG, a portada descargarase e almacenarase na base de datos)" + +#: cps/templates/book_edit.html:108 +msgid "Upload Cover from Local Disk" +msgstr "Cargar portada dende un disco local" + +#: cps/templates/book_edit.html:113 +msgid "Published Date" +msgstr "Data de publicación" + +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 +msgid "Publisher" +msgstr "Editor" + +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 +msgid "Language" +msgstr "Lingua" + +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 +#: cps/templates/search_form.html:164 +msgid "Yes" +msgstr "Sí" + +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 +#: cps/templates/search_form.html:165 +msgid "No" +msgstr "Non" + +#: cps/templates/book_edit.html:201 +msgid "Upload Format" +msgstr "Cargar formato" + +#: cps/templates/book_edit.html:209 +msgid "View Book on Save" +msgstr "Ver libro ao gardar" + +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 +msgid "Fetch Metadata" +msgstr "Obter metadatos" + +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 +msgid "Save" +msgstr "Gardar" + +#: cps/templates/book_edit.html:233 +msgid "Keyword" +msgstr "Palabra chave" + +#: cps/templates/book_edit.html:234 +msgid "Search keyword" +msgstr "Buscar por palabras chave " + +#: cps/templates/book_edit.html:240 +msgid "Click the cover to load metadata to the form" +msgstr "Premer na portada para cargar los metadatos no formulario" + +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 +msgid "Loading..." +msgstr "Cargando..." + +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 +msgid "Close" +msgstr "Pechar" + +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 +msgid "Source" +msgstr "Orixe" + +#: cps/templates/book_edit.html:287 +msgid "Search error!" +msgstr "Erro na busca!" + +#: cps/templates/book_edit.html:288 +msgid "No Result(s) found! Please try another keyword." +msgstr "Non se atoparon resultados! Por favor intenta con outra palabra chave." + +#: cps/templates/book_table.html:12 cps/templates/book_table.html:69 +#: cps/templates/user_table.html:14 cps/templates/user_table.html:77 +#: cps/templates/user_table.html:100 +msgid "This Field is Required" +msgstr "Este campo é necesario" + +#: cps/templates/book_table.html:37 +msgid "Merge selected books" +msgstr "Unir libros seleccionados" + +#: cps/templates/book_table.html:38 cps/templates/user_table.html:124 +msgid "Remove Selections" +msgstr "Eliminar selección" + +#: cps/templates/book_table.html:41 +msgid "Exchange author and title" +msgstr "Intercambiar autor e título" + +#: cps/templates/book_table.html:47 +msgid "Update Title Sort automatically" +msgstr "Actualizar orde do título automáticamente" + +#: cps/templates/book_table.html:51 +msgid "Update Author Sort automatically" +msgstr "Actualizar orde do autor automáticamente" + +#: cps/templates/book_table.html:63 cps/templates/book_table.html:69 +msgid "Enter Title" +msgstr "Introduce título" + +#: cps/templates/book_table.html:63 cps/templates/config_view_edit.html:24 +#: cps/templates/shelf_edit.html:8 +msgid "Title" +msgstr "Título" + +#: cps/templates/book_table.html:64 +msgid "Enter Title Sort" +msgstr "Introduce a orde do título" + +#: cps/templates/book_table.html:64 +msgid "Title Sort" +msgstr "Orde do título" + +#: cps/templates/book_table.html:65 +msgid "Enter Author Sort" +msgstr "Introduce orde do autor" + +#: cps/templates/book_table.html:65 +msgid "Author Sort" +msgstr "Orde do autor" + +#: cps/templates/book_table.html:66 +msgid "Enter Authors" +msgstr "Introduce os autores" + +#: cps/templates/book_table.html:67 +msgid "Enter Categories" +msgstr "Introduce as categorías" + +#: cps/templates/book_table.html:68 +msgid "Enter Series" +msgstr "Introduce as series" + +#: cps/templates/book_table.html:69 +msgid "Series Index" +msgstr "Índice da serie" + +#: cps/templates/book_table.html:70 +msgid "Enter Languages" +msgstr "Introduce as linguas" + +#: cps/templates/book_table.html:71 +msgid "Publishing Date" +msgstr "Data de publicación" + +#: cps/templates/book_table.html:72 +msgid "Enter Publishers" +msgstr "Introduce os Editores" + +#: cps/templates/book_table.html:73 +msgid "Enter comments" +msgstr "Introducir os comentarios" + +#: cps/templates/book_table.html:73 +msgid "Comments" +msgstr "Comentarios" + +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "Estado do arquivo" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Leer estado" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 +msgid "Enter " +msgstr "Introduce " + +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 +msgid "Are you really sure?" +msgstr "De verdade estás seguro?" + +#: cps/templates/book_table.html:117 +msgid "Books with Title will be merged from:" +msgstr "Libros co título uniranse de:" + +#: cps/templates/book_table.html:121 +msgid "Into Book with Title:" +msgstr "No libro co título:" + +#: cps/templates/book_table.html:126 +msgid "Merge" +msgstr "Unir" + +#: cps/templates/config_db.html:12 +msgid "Location of Calibre Database" +msgstr "Localización da base de datos Calibre" + +#: cps/templates/config_db.html:22 +msgid "Use Google Drive?" +msgstr "Usar Google Drive?" + +#: cps/templates/config_db.html:27 +msgid "Authenticate Google Drive" +msgstr "Autenticar Google Drive" + +#: cps/templates/config_db.html:32 +msgid "Google Drive Calibre folder" +msgstr "Carpeta de Google Drive para Calibre" + +#: cps/templates/config_db.html:40 +msgid "Metadata Watch Channel ID" +msgstr "Metadata Watch Channel ID" + +#: cps/templates/config_db.html:43 +msgid "Revoke" +msgstr "Revogar" + +#: cps/templates/config_db.html:68 +msgid "New db location is invalid, please enter valid path" +msgstr "A localización da base de datos non é válida. Por favor, Introduce a ruta correcta" + +#: cps/templates/config_edit.html:18 +msgid "Server Configuration" +msgstr "Configuración do servidor" + +#: cps/templates/config_edit.html:25 +msgid "Server Port" +msgstr "Porto do servidor" + +#: cps/templates/config_edit.html:28 +msgid "SSL certfile location (leave it empty for non-SSL Servers)" +msgstr "Localización do arquivo de certificado SSL (deixar en branco se non hai un servidor SSL)" + +#: cps/templates/config_edit.html:35 +msgid "SSL Keyfile location (leave it empty for non-SSL Servers)" +msgstr "Localización do arquivo clave SSL (dejar en blanco si no hay un servidor SSL)" + +#: cps/templates/config_edit.html:43 +msgid "Update Channel" +msgstr "Canle de actualización" + +#: cps/templates/config_edit.html:45 +msgid "Stable" +msgstr "Estable" + +#: cps/templates/config_edit.html:46 +msgid "Nightly" +msgstr "Nocturno" + +#: cps/templates/config_edit.html:50 +msgid "Trusted Hosts (Comma Separated)" +msgstr "Anfitrións de confianza (Separados por comas)" + +#: cps/templates/config_edit.html:61 +msgid "Logfile Configuration" +msgstr "Configuración do arquivo de rexistro" + +#: cps/templates/config_edit.html:77 +msgid "Location and name of logfile (calibre-web.log for no entry)" +msgstr "Localización e nome do arquivo de rexistro (se non se especifica será calibre-web.log)" + +#: cps/templates/config_edit.html:82 +msgid "Enable Access Log" +msgstr "Habilitar rexistro de acceso" + +#: cps/templates/config_edit.html:85 +msgid "Location and name of access logfile (access.log for no entry)" +msgstr "Localización e nombre do archivo de rexistro de acceso (access.log non ten ningunha entrada)" + +#: cps/templates/config_edit.html:96 +msgid "Feature Configuration" +msgstr "Configuración de características" + +#: cps/templates/config_edit.html:104 +msgid "Convert non-English characters in title and author while saving to disk" +msgstr "Convertir caracteres non ingleses no título e no autor mentres se graba no disco" + +#: cps/templates/config_edit.html:108 +msgid "Enable Uploads" +msgstr "Permitir cargas" + +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(Por favor asegúrese que os usuarios teñen permisos de carga)" + +#: cps/templates/config_edit.html:112 +msgid "Allowed Upload Fileformats" +msgstr "Formatos de arquivo permitidos para carga" + +#: cps/templates/config_edit.html:118 +msgid "Enable Anonymous Browsing" +msgstr "Permitir navegación anónima" + +#: cps/templates/config_edit.html:122 +msgid "Enable Public Registration" +msgstr "Permitir rexistro público" + +#: cps/templates/config_edit.html:127 +msgid "Use Email as Username" +msgstr "Utilizar correo electrónico como nome de usuario" + +#: cps/templates/config_edit.html:132 +msgid "Enable Magic Link Remote Login" +msgstr "Permitir inicio de sesión remoto (\"magic link\")" + +#: cps/templates/config_edit.html:137 +msgid "Enable Kobo sync" +msgstr "Activar a sincronización con Kobo" + +#: cps/templates/config_edit.html:142 +msgid "Proxy unknown requests to Kobo Store" +msgstr "Peticións proxy á tenda Kobo descoñecidas" + +#: cps/templates/config_edit.html:145 +msgid "Server External Port (for port forwarded API calls)" +msgstr "Porto externo do servidor (para peticións API)" + +#: cps/templates/config_edit.html:153 +msgid "Use Goodreads" +msgstr "Usar Goodreads" + +#: cps/templates/config_edit.html:154 +msgid "Create an API Key" +msgstr "Obter unha API Key" + +#: cps/templates/config_edit.html:158 +msgid "Goodreads API Key" +msgstr "Goodreads API Key" + +#: cps/templates/config_edit.html:162 +msgid "Goodreads API Secret" +msgstr "Goodreads API Secret" + +#: cps/templates/config_edit.html:169 +msgid "Allow Reverse Proxy Authentication" +msgstr "Permitir Autenticación Proxy Inversa" + +#: cps/templates/config_edit.html:180 +msgid "Login type" +msgstr "Tipo de inicio de sesión" + +#: cps/templates/config_edit.html:182 +msgid "Use Standard Authentication" +msgstr "Usar autenticación estándar" + +#: cps/templates/config_edit.html:184 +msgid "Use LDAP Authentication" +msgstr "Usar autenticación LDAP" + +#: cps/templates/config_edit.html:187 +msgid "Use OAuth" +msgstr "Usar OAuth" + +#: cps/templates/config_edit.html:194 +msgid "LDAP Server Host Name or IP Address" +msgstr "Nome de anfitrión ou enderezo IP do servidor LDAP" + +#: cps/templates/config_edit.html:198 +msgid "LDAP Server Port" +msgstr "Porto do servidor LDAP" + +#: cps/templates/config_edit.html:202 +msgid "LDAP Encryption" +msgstr "Cifrado LDAP" + +#: cps/templates/config_edit.html:205 +msgid "TLS" +msgstr "TLS" + +#: cps/templates/config_edit.html:206 +msgid "SSL" +msgstr "SSL" + +#: cps/templates/config_edit.html:210 +msgid "LDAP CACertificate Path (Only needed for Client Certificate Authentication)" +msgstr "Ruta LDAP CACertificate (So necesaria para certificado de autenticación de cliente)" + +#: cps/templates/config_edit.html:217 +msgid "LDAP Certificate Path (Only needed for Client Certificate Authentication)" +msgstr "Ruta LDAP Certificate (So necesaria para certificado de autenticación de cliente)" + +#: cps/templates/config_edit.html:224 +msgid "LDAP Keyfile Path (Only needed for Client Certificate Authentication)" +msgstr "Ruta LDAP Keyfile (So necesaria para certificado de autenticación de cliente)" + +#: cps/templates/config_edit.html:233 +msgid "LDAP Authentication" +msgstr "Autenticación LDAP" + +#: cps/templates/config_edit.html:235 +msgid "Anonymous" +msgstr "Anónimo" + +#: cps/templates/config_edit.html:236 +msgid "Unauthenticated" +msgstr "Non autenticado" + +#: cps/templates/config_edit.html:237 +msgid "Simple" +msgstr "Simple" + +#: cps/templates/config_edit.html:242 +msgid "LDAP Administrator Username" +msgstr "Nome de usuario de administrador LDAP" + +#: cps/templates/config_edit.html:248 +msgid "LDAP Administrator Password" +msgstr "Contrasinal de administrador LDAP" + +#: cps/templates/config_edit.html:253 +msgid "LDAP Distinguished Name (DN)" +msgstr "Nome distinguido LDAP (DN)" + +#: cps/templates/config_edit.html:257 +msgid "LDAP User Object Filter" +msgstr "Filtro de obxectos de usuario LDAP" + +#: cps/templates/config_edit.html:262 +msgid "LDAP Server is OpenLDAP?" +msgstr "O servidor LDAP é OpenLDAP?" + +#: cps/templates/config_edit.html:264 +msgid "Following Settings are Needed For User Import" +msgstr "As seguintes configuracións son necesarias para a importación de usuarios" + +#: cps/templates/config_edit.html:266 +msgid "LDAP Group Object Filter" +msgstr "Filtro de obxectos de grupo LDAP" + +#: cps/templates/config_edit.html:270 +msgid "LDAP Group Name" +msgstr "Nome de grupo LDAP" + +#: cps/templates/config_edit.html:274 +msgid "LDAP Group Members Field" +msgstr "Campo de membros de grupo LDAP" + +#: cps/templates/config_edit.html:278 +msgid "LDAP Member User Filter Detection" +msgstr "Filtro de detección LDAP Member User" + +#: cps/templates/config_edit.html:280 +msgid "Autodetect" +msgstr "Auto detectar" + +#: cps/templates/config_edit.html:281 +msgid "Custom Filter" +msgstr "Filtro personalizado" + +#: cps/templates/config_edit.html:286 +msgid "LDAP Member User Filter" +msgstr "Filtro LDAP Member User" + +#: cps/templates/config_edit.html:297 +#, python-format +msgid "Obtain %(provider)s OAuth Credential" +msgstr "Obter a Credencial OAuth de %(provider)s" + +#: cps/templates/config_edit.html:300 +#, python-format +msgid "%(provider)s OAuth Client Id" +msgstr "Id de cliente de OAuth de %(provider)s" + +#: cps/templates/config_edit.html:304 +#, python-format +msgid "%(provider)s OAuth Client Secret" +msgstr "Secreto OAuth de Cliente de %(provider)s" + +#: cps/templates/config_edit.html:320 +msgid "External binaries" +msgstr "Binarios externos" + +#: cps/templates/config_edit.html:326 +msgid "Path to Calibre E-Book Converter" +msgstr "Ruta para Calibre E-Book Converter" + +#: cps/templates/config_edit.html:334 +msgid "Calibre E-Book Converter Settings" +msgstr "Axustes de Calibre E-Book Converter" + +#: cps/templates/config_edit.html:337 +msgid "Path to Kepubify E-Book Converter" +msgstr "Ruta para Kepubify E-Book Converter" + +#: cps/templates/config_edit.html:345 +msgid "Location of Unrar binary" +msgstr "Localización do binario de Unrar" + +#: cps/templates/config_view_edit.html:17 +msgid "View Configuration" +msgstr "Ver configuración" + +#: cps/templates/config_view_edit.html:32 +msgid "No. of Random Books to Display" +msgstr "Número de libros aleatorios a mostrar" + +#: cps/templates/config_view_edit.html:36 +msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" +msgstr "Número de autores para mostrar antes de agochar (0 = desactivar o agochamento)" + +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 +msgid "Theme" +msgstr "Tema" + +#: cps/templates/config_view_edit.html:42 +msgid "Standard Theme" +msgstr "Tema estándar" + +#: cps/templates/config_view_edit.html:43 +msgid "caliBlur! Dark Theme" +msgstr "caliBlur! Tema Escuro" + +#: cps/templates/config_view_edit.html:47 +msgid "Regular Expression for Ignoring Columns" +msgstr "Expresión regular para ignorar columnas" + +#: cps/templates/config_view_edit.html:51 +msgid "Link Read/Unread Status to Calibre Column" +msgstr "Enlazar á columna de Calibre de lido/sen ler" + +#: cps/templates/config_view_edit.html:60 +msgid "View Restrictions based on Calibre column" +msgstr "Ver restricións baseadas na columna de Calibre" + +#: cps/templates/config_view_edit.html:69 +msgid "Regular Expression for Title Sorting" +msgstr "Expresión regular para ordear títulos" + +#: cps/templates/config_view_edit.html:80 +msgid "Default Settings for New Users" +msgstr "Axustes por defecto para novos usuarios" + +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 +msgid "Admin User" +msgstr "Usuario administrador" + +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 +msgid "Allow Downloads" +msgstr "Permitir descargas" + +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 +msgid "Allow eBook Viewer" +msgstr "Permitir visor de libros" + +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 +msgid "Allow Uploads" +msgstr "Permitir cargas de arquivos" + +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 +msgid "Allow Edit" +msgstr "Permitir editar" + +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 +msgid "Allow Delete Books" +msgstr "Permitir borrar libros" + +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 +msgid "Allow Changing Password" +msgstr "Permitir cambiar a contrasinal" + +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 +msgid "Allow Editing Public Shelves" +msgstr "Permitir editar andeis públicos" + +#: cps/templates/config_view_edit.html:123 +msgid "Default Language" +msgstr "Lingua predeterminada" + +#: cps/templates/config_view_edit.html:131 +msgid "Default Visible Language of Books" +msgstr "Lingua visible predeterminada dos libros" + +#: cps/templates/config_view_edit.html:147 +msgid "Default Visibilities for New Users" +msgstr "Visibilidade predeterminada para novos usuarios" + +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 +#: cps/templates/user_table.html:154 +msgid "Show Random Books in Detail View" +msgstr "Mostrar libros aleatorios na vista detallada" + +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 +msgid "Add Allowed/Denied Tags" +msgstr "Engadir etiquetas Permitidas/denegados" + +#: cps/templates/config_view_edit.html:167 +msgid "Add Allowed/Denied custom column values" +msgstr "Engadir valores personalizados Permitidos/denegados" + +#: cps/templates/detail.html:62 cps/templates/detail.html:71 +msgid "Read in Browser" +msgstr "Ler no navegador" + +#: cps/templates/detail.html:79 cps/templates/detail.html:96 +msgid "Listen in Browser" +msgstr "Escoitar no navegador" + +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 +#, python-format +msgid "Book %(index)s of %(range)s" +msgstr "Libro %(index)s de %(range)s" + +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 +msgid "Published" +msgstr "Publicado" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Unread" +msgstr "Marcar como non lido" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Read" +msgstr "Marcar como lido" + +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 +msgid "Read" +msgstr "Lido" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Restore from archive" +msgstr "Restaurar dende o arquivo" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Add to archive" +msgstr "Engadir a arquivo" + +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 +msgid "Archived" +msgstr "Arquivado" + +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 +msgid "Description:" +msgstr "Descrición:" + +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 +msgid "Add to shelf" +msgstr "Engadir ao andel" + +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 +msgid "(Public)" +msgstr "(Público)" + +#: cps/templates/detail.html:300 +msgid "Edit Metadata" +msgstr "Editar metadatos" + +#: cps/templates/email_edit.html:13 +msgid "Email Account Type" +msgstr "Escolle tipo de servidor" + +#: cps/templates/email_edit.html:15 +#, fuzzy +msgid "Standard Email Account" +msgstr "Usar conta de correo electrónico estándar" + +#: cps/templates/email_edit.html:16 +#, fuzzy +msgid "Gmail Account" +msgstr "Escolle tipo de servidor" + +#: cps/templates/email_edit.html:22 +msgid "Setup Gmail Account" +msgstr "" + +#: cps/templates/email_edit.html:24 +msgid "Revoke Gmail Access" +msgstr "Revogar acceso a Gmail" + +#: cps/templates/email_edit.html:42 +msgid "STARTTLS" +msgstr "STARTTLS" + +#: cps/templates/email_edit.html:43 +msgid "SSL/TLS" +msgstr "SSL/TLS" + +#: cps/templates/email_edit.html:51 +msgid "SMTP Password" +msgstr "Contrasinal SMTP" + +#: cps/templates/email_edit.html:58 +msgid "Attachment Size Limit" +msgstr "Tamaño límite do arquivo achegado" + +#: cps/templates/email_edit.html:66 +#, fuzzy +msgid "Save and Send Test Email" +msgstr "Gardar e enviar un correo electrónico de proba" + +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 +#: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 +msgid "Back" +msgstr "Voltar" + +#: cps/templates/email_edit.html:74 +msgid "Allowed Domains (Whitelist)" +msgstr "Dominios permitidos para rexistrarse" + +#: cps/templates/email_edit.html:78 cps/templates/email_edit.html:105 +msgid "Add Domain" +msgstr "Engadir dominio" + +#: cps/templates/email_edit.html:81 cps/templates/email_edit.html:108 +#: cps/templates/user_table.html:27 +msgid "Add" +msgstr "Engadir" + +#: cps/templates/email_edit.html:86 cps/templates/email_edit.html:96 +msgid "Enter domainname" +msgstr "Introducir nome de dominio" + +#: cps/templates/email_edit.html:92 +msgid "Denied Domains (Blacklist)" +msgstr "Dominios prohibidos (Blaclist)" + +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 +msgid "Next" +msgstr "Seguinte" + +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Abre o arquivo .kobo/Kobo/Kobo eReader.conf nun editor de texto e engade (ou edita):" + +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "Token de sincronización de Kobo" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "Lista" + +#: cps/templates/http_error.html:34 +msgid "Calibre-Web Instance is unconfigured, please contact your administrator" +msgstr "A instancia de Calibre-Web non está configurada, por favor contacta co teu administrador" + +#: cps/templates/http_error.html:44 +msgid "Create Issue" +msgstr "Crear una incidencia" + +#: cps/templates/http_error.html:51 +msgid "Return to Home" +msgstr "Voltar ao inicio" + +#: cps/templates/http_error.html:53 +msgid "Logout User" +msgstr "Pechar sesión" + +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "Ordear carra arriba segundo a conta de descargas" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "Ordear cara abaixo segundo a conta de descargas" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 +msgid "Sort authors in alphabetical order" +msgstr "Ordenar autores en orde alfabética" + +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 +msgid "Sort authors in reverse alphabetical order" +msgstr "Ordenar autores en orde alfabética reversa" + +#: cps/templates/index.html:83 +msgid "Sort ascending according to series index" +msgstr "Ordear cara arriba segundo ao índice de serie" + +#: cps/templates/index.html:84 +msgid "Sort descending according to series index" +msgstr "Ordear cara abaixo segundo ao índice de serie" + +#: cps/templates/index.xml:6 +msgid "Start" +msgstr "Comezar" + +#: cps/templates/index.xml:18 +msgid "Alphabetical Books" +msgstr "Libros alfabéticos" + +#: cps/templates/index.xml:22 +msgid "Books sorted alphabetically" +msgstr "Libros ordeados alfabéticamente" + +#: cps/templates/index.xml:29 +msgid "Popular publications from this catalog based on Downloads." +msgstr "Publicacións populares do catálogo baseadas nas descargas." + +#: cps/templates/index.xml:36 +msgid "Popular publications from this catalog based on Rating." +msgstr "Publicacións populares do catálogo baseadas na valoración." + +#: cps/templates/index.xml:39 +msgid "Recently added Books" +msgstr "Libros engadidos recentemente" + +#: cps/templates/index.xml:43 +msgid "The latest Books" +msgstr "Últimos libros" + +#: cps/templates/index.xml:46 +msgid "Random Books" +msgstr "Libros ao chou" + +#: cps/templates/index.xml:73 +msgid "Books ordered by Author" +msgstr "Libros ordeados por autor" + +#: cps/templates/index.xml:80 +msgid "Books ordered by publisher" +msgstr "Libros ordeados por editor" + +#: cps/templates/index.xml:87 +msgid "Books ordered by category" +msgstr "Libros ordeados por categorías" + +#: cps/templates/index.xml:94 +msgid "Books ordered by series" +msgstr "Libros ordeados por series" + +#: cps/templates/index.xml:101 +msgid "Books ordered by Languages" +msgstr "Libros ordeados por lingua" + +#: cps/templates/index.xml:108 +msgid "Books ordered by Rating" +msgstr "Libros ordeados por valoración" + +#: cps/templates/index.xml:116 +msgid "Books ordered by file formats" +msgstr "Libros ordeados por formato de arquivo" + +#: cps/templates/index.xml:119 cps/templates/layout.html:153 +#: cps/templates/search_form.html:87 +msgid "Shelves" +msgstr "Andeis" + +#: cps/templates/index.xml:123 +msgid "Books organized in shelves" +msgstr "Libros organizados en andeis" + +#: cps/templates/layout.html:26 cps/templates/login.html:30 +msgid "Home" +msgstr "Inicio" + +#: cps/templates/layout.html:32 +msgid "Toggle Navigation" +msgstr "Alternar navegación" + +#: cps/templates/layout.html:48 +msgid "Search Library" +msgstr "Buscar na librería" + +#: cps/templates/layout.html:66 cps/templates/layout.html:95 +msgid "Account" +msgstr "Conta" + +#: cps/templates/layout.html:72 cps/templates/layout.html:97 +msgid "Logout" +msgstr "Pechar sesión" + +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Cargando..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Erro" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Carga feita, procesando, por favor agarde..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Axustes" + +#: cps/templates/layout.html:136 +msgid "Please do not refresh the page" +msgstr "Por favor, non actualice a páxina" + +#: cps/templates/layout.html:146 +msgid "Browse" +msgstr "Navegar" + +#: cps/templates/layout.html:159 cps/templates/stats.html:3 +msgid "About" +msgstr "Acerca de" + +#: cps/templates/layout.html:173 +msgid "Previous" +msgstr "Previo" + +#: cps/templates/layout.html:200 +msgid "Book Details" +msgstr "Detalles do libro" + +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "Reixa" + +#: cps/templates/login.html:18 +msgid "Remember Me" +msgstr "Lembrarme" + +#: cps/templates/login.html:23 +msgid "Forgot Password?" +msgstr "Esqueceu a contrasinal?" + +#: cps/templates/login.html:34 +msgid "Log in with Magic Link" +msgstr "Iniciar sesión cun enlace máxico" + +#: cps/templates/logviewer.html:6 +msgid "Show Calibre-Web Log: " +msgstr "Mostrar o rexistro de Calibre-Web: " + +#: cps/templates/logviewer.html:8 +msgid "Calibre-Web Log: " +msgstr "Rexistro de Calibre-Web: " + +#: cps/templates/logviewer.html:8 +msgid "Stream output, can't be displayed" +msgstr "A saída do fluxo non se pode mostrar" + +#: cps/templates/logviewer.html:12 +msgid "Show Access Log: " +msgstr "Mostrar rexistro de acceso:" + +#: cps/templates/logviewer.html:18 +msgid "Download Calibre-Web Log" +msgstr "Descargar o rexistro de Calibre-Web" + +#: cps/templates/logviewer.html:21 +msgid "Download Access Log" +msgstr "Descargar o rexistro de acceso" + +#: cps/templates/modal_dialogs.html:6 +msgid "Select Allowed/Denied Tags" +msgstr "Seleccionar etiquetas Permitidas/Negadas" + +#: cps/templates/modal_dialogs.html:7 +msgid "Select Allowed/Denied Custom Column Values" +msgstr "Seleccionar valores propios de columnas Permitidas/Denegadas" + +#: cps/templates/modal_dialogs.html:8 +msgid "Select Allowed/Denied Tags of User" +msgstr "Seleccionar etiquetas de usuario Permitido/Denegado" + +#: cps/templates/modal_dialogs.html:9 +msgid "Select Allowed/Denied Custom Column Values of User" +msgstr "Seleccionar columnas personalizadas de usuario Permitido/Denegado" + +#: cps/templates/modal_dialogs.html:15 +msgid "Enter Tag" +msgstr "Introduce a etiqueta" + +#: cps/templates/modal_dialogs.html:24 +msgid "Add View Restriction" +msgstr "Engadir restricción de vista" + +#: cps/templates/modal_dialogs.html:50 +msgid "This book format will be permanently erased from database" +msgstr "Este formato de libro borrarase permanentemente da base de datos" + +#: cps/templates/modal_dialogs.html:51 +msgid "This book will be permanently erased from database" +msgstr "O libro borrarase permanentemente da base de datos" + +#: cps/templates/modal_dialogs.html:52 +msgid "and hard disk" +msgstr "e do disco duro" + +#: cps/templates/modal_dialogs.html:56 +msgid "Important Kobo Note: deleted books will remain on any paired Kobo device." +msgstr "Nota de Kobo importante: os libros eliminados permanecerán nos dispositivos Kobo emparellados." + +#: cps/templates/modal_dialogs.html:57 +msgid "Books must first be archived and the device synced before a book can safely be deleted." +msgstr "Antes de que un libro poida eliminarse con seguridade debe arquivarse e sincronizarse co dispositivo." + +#: cps/templates/modal_dialogs.html:76 +msgid "Choose File Location" +msgstr "Escolla a localización do arquivo" + +#: cps/templates/modal_dialogs.html:82 +msgid "type" +msgstr "tipo" + +#: cps/templates/modal_dialogs.html:83 +msgid "name" +msgstr "nome" + +#: cps/templates/modal_dialogs.html:84 +msgid "size" +msgstr "tamaño" + +#: cps/templates/modal_dialogs.html:90 +msgid "Parent Directory" +msgstr "Directorio pai" + +#: cps/templates/modal_dialogs.html:98 +msgid "Select" +msgstr "Seleccionar" + +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 +msgid "Ok" +msgstr "Vale" + +#: cps/templates/osd.xml:5 +msgid "Calibre-Web eBook Catalog" +msgstr "Catálogo de libros electrónicos de Calibre-Web" + +#: cps/templates/read.html:6 +msgid "epub Reader" +msgstr "Lector epub" + +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Claro" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Oscuro" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "Sepia" + +#: cps/templates/read.html:84 +msgid "Black" +msgstr "Negro" + +#: cps/templates/read.html:88 +msgid "Reflow text when sidebars are open." +msgstr "Refluxo do texto cando as barras laterais están abertas." + +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + +#: cps/templates/readcbr.html:7 +msgid "Comic Reader" +msgstr "Lector de Cómics" + +#: cps/templates/readcbr.html:92 +msgid "Keyboard Shortcuts" +msgstr "Atallos de teclado" + +#: cps/templates/readcbr.html:95 +msgid "Previous Page" +msgstr "Páxina anterior" + +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 +msgid "Next Page" +msgstr "Páxina seguinte" + +#: cps/templates/readcbr.html:97 +msgid "Scale to Best" +msgstr "Escalar ao mellor" + +#: cps/templates/readcbr.html:98 +msgid "Scale to Width" +msgstr "Escalar ao ancho" + +#: cps/templates/readcbr.html:99 +msgid "Scale to Height" +msgstr "Escalar ao alto" + +#: cps/templates/readcbr.html:100 +msgid "Scale to Native" +msgstr "Escalado nativo" + +#: cps/templates/readcbr.html:101 +msgid "Rotate Right" +msgstr "Xirar cara a dereita" + +#: cps/templates/readcbr.html:102 +msgid "Rotate Left" +msgstr "Xirar cara a esquerda" + +#: cps/templates/readcbr.html:103 +msgid "Flip Image" +msgstr "Voltear a imaxe" + +#: cps/templates/readcbr.html:125 +msgid "Scale" +msgstr "Escalar" + +#: cps/templates/readcbr.html:128 +msgid "Best" +msgstr "Mellor" + +#: cps/templates/readcbr.html:129 +msgid "Width" +msgstr "Ancho" + +#: cps/templates/readcbr.html:130 +msgid "Height" +msgstr "Alto" + +#: cps/templates/readcbr.html:131 +msgid "Native" +msgstr "Nativo" + +#: cps/templates/readcbr.html:136 +msgid "Rotate" +msgstr "Rotar" + +#: cps/templates/readcbr.html:147 +msgid "Flip" +msgstr "Voltear" + +#: cps/templates/readcbr.html:150 +msgid "Horizontal" +msgstr "Horizontal" + +#: cps/templates/readcbr.html:151 +msgid "Vertical" +msgstr "Vertical" + +#: cps/templates/readcbr.html:156 +msgid "Direction" +msgstr "Dirección" + +#: cps/templates/readcbr.html:159 +msgid "Left to Right" +msgstr "De esquerda a dereita" + +#: cps/templates/readcbr.html:160 +msgid "Right to Left" +msgstr "De dereita a esquerda" + +#: cps/templates/readcbr.html:168 +msgid "Reset to Top" +msgstr "Voltar ao comezo" + +#: cps/templates/readcbr.html:169 +msgid "Remember Position" +msgstr "Lembrar posición" + +#: cps/templates/readcbr.html:174 +msgid "Scrollbar" +msgstr "Barra de desprazamento" + +#: cps/templates/readcbr.html:177 +msgid "Show" +msgstr "Mostrar" + +#: cps/templates/readcbr.html:178 +msgid "Hide" +msgstr "Agochar" + +#: cps/templates/readdjvu.html:5 +msgid "DJVU Reader" +msgstr "Lector DJVU" + +#: cps/templates/readpdf.html:32 +msgid "PDF Reader" +msgstr "Lector PDF" + +#: cps/templates/readtxt.html:6 +msgid "txt Reader" +msgstr "Lector txt" + +#: cps/templates/register.html:4 +msgid "Register New Account" +msgstr "Rexistre unha conta nova" + +#: cps/templates/register.html:10 +msgid "Choose a username" +msgstr "Escolla un nome de usuario" + +#: cps/templates/register.html:15 +msgid "Your Email" +msgstr "O teu enderezo de correo" + +#: cps/templates/remote_login.html:5 +msgid "Magic Link - Authorise New Device" +msgstr "Enlace Máxico - Autorizar un novo dispositivo" + +#: cps/templates/remote_login.html:7 +msgid "On another device, login and visit:" +msgstr "Utiliza otro dispositivo, inicia sesión e visita:" + +#: cps/templates/remote_login.html:11 +msgid "Once verified, you will automatically be logged in on this device." +msgstr "Unha vez verificado, iniciará sesión automáticamente neste dispositivo." + +#: cps/templates/remote_login.html:14 +msgid "This verification link will expire in 10 minutes." +msgstr "O enlace de verificación caducará despois de 10 minutos." + +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "Xerar miniaturas de cubertas de series" + +#: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "Non se atoparon resultados" + +#: cps/templates/search.html:7 +msgid "Search Term:" +msgstr "Termo de busca:" + +#: cps/templates/search.html:9 +msgid "Results for:" +msgstr "Resultados para:" + +#: cps/templates/search_form.html:21 +msgid "Published Date From" +msgstr "Data de publicación dende" + +#: cps/templates/search_form.html:31 +msgid "Published Date To" +msgstr "Data de publicación ata" + +#: cps/templates/search_form.html:59 +msgid "Exclude Tags" +msgstr "Excluir etiquetas" + +#: cps/templates/search_form.html:77 +msgid "Exclude Series" +msgstr "Excluir series" + +#: cps/templates/search_form.html:95 +msgid "Exclude Shelves" +msgstr "Excluir andeis" + +#: cps/templates/search_form.html:115 +msgid "Exclude Languages" +msgstr "Excluir linguas" + +#: cps/templates/search_form.html:126 +msgid "Extensions" +msgstr "Extensións" + +#: cps/templates/search_form.html:134 +msgid "Exclude Extensions" +msgstr "Excluir extensións" + +#: cps/templates/search_form.html:144 +msgid "Rating Above" +msgstr "Valoración superior a" + +#: cps/templates/search_form.html:148 +msgid "Rating Below" +msgstr "Valoración inferior a" + +#: cps/templates/search_form.html:180 +msgid "From:" +msgstr "De:" + +#: cps/templates/search_form.html:190 +msgid "To:" +msgstr "Para:" + +#: cps/templates/shelf.html:13 +msgid "Delete this Shelf" +msgstr "Borrar este andel" + +#: cps/templates/shelf.html:14 +msgid "Edit Shelf Properties" +msgstr "Editar propiedades do andel" + +#: cps/templates/shelf.html:17 +msgid "Arrange books manually" +msgstr "Ordear libros manualmente" + +#: cps/templates/shelf.html:18 +msgid "Disable Change order" +msgstr "Desactivar o cambio de orde" + +#: cps/templates/shelf.html:18 +msgid "Enable Change order" +msgstr "Activar o cambio de orde" + +#: cps/templates/shelf_edit.html:14 +msgid "Share with Everyone" +msgstr "Compartir con todos" + +#: cps/templates/shelf_edit.html:21 +msgid "Sync this shelf with Kobo device" +msgstr "Sincronizar este andel cun dispositivo Kobo" + +#: cps/templates/shelf_order.html:5 +msgid "Drag to Rearrange Order" +msgstr "Arrastra para reorganizar a orde" + +#: cps/templates/shelf_order.html:33 +msgid "Hidden Book" +msgstr "Libro agochado" + +#: cps/templates/stats.html:7 +msgid "Library Statistics" +msgstr "Estatísticas da Biblioteca" + +#: cps/templates/stats.html:12 +msgid "Books in this Library" +msgstr "Libros nesta biblioteca" + +#: cps/templates/stats.html:16 +msgid "Authors in this Library" +msgstr "Autores nesta biblioteca" + +#: cps/templates/stats.html:20 +msgid "Categories in this Library" +msgstr "Categorías nesta biblioteca" + +#: cps/templates/stats.html:24 +msgid "Series in this Library" +msgstr "Series nesta biblioteca" + +#: cps/templates/stats.html:29 +msgid "System Statistics" +msgstr "Estadísticas do sistema" + +#: cps/templates/stats.html:33 +msgid "Program" +msgstr "Programa" + +#: cps/templates/stats.html:34 +msgid "Installed Version" +msgstr "Versión instalada" + +#: cps/templates/tasks.html:12 +msgid "User" +msgstr "Usuario" + +#: cps/templates/tasks.html:14 +msgid "Task" +msgstr "Tarefa" + +#: cps/templates/tasks.html:15 +msgid "Status" +msgstr "Estado" + +#: cps/templates/tasks.html:16 +msgid "Progress" +msgstr "Progreso" + +#: cps/templates/tasks.html:17 +msgid "Run Time" +msgstr "Tempo de execución" + +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "Accións" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "Esta tarefa cancelarase. Non se gardará ningún progreso feito por esta tarefa." + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "Se esta é unha tarefa programada, volverá a lanzarse na próxima hora programada." + +#: cps/templates/user_edit.html:20 +msgid "Reset user Password" +msgstr "Restablecer contrasinal de usuario" + +#: cps/templates/user_edit.html:43 +msgid "Language of Books" +msgstr "Linguaxe de libros" + +#: cps/templates/user_edit.html:54 +msgid "OAuth Settings" +msgstr "Axustes OAuth" + +#: cps/templates/user_edit.html:56 +msgid "Link" +msgstr "Ligar" + +#: cps/templates/user_edit.html:58 +msgid "Unlink" +msgstr "Desligar" + +#: cps/templates/user_edit.html:64 +msgid "Kobo Sync Token" +msgstr "Token de sincronización de Kobo" + +#: cps/templates/user_edit.html:66 +msgid "Create/View" +msgstr "Crear/Ver" + +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "Forzar sincronización completa de kobo" + +#: cps/templates/user_edit.html:88 +msgid "Add allowed/Denied Custom Column Values" +msgstr "Engadir columnas de valores propios de Permitidos/Denegados" + +#: cps/templates/user_edit.html:137 +msgid "Sync only books in selected shelves with Kobo" +msgstr "Sincronizar con Kobo soamente os libros dos andeis seleccionados" + +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 +msgid "Delete User" +msgstr "Borrar usuario" + +#: cps/templates/user_edit.html:159 +msgid "Generate Kobo Auth URL" +msgstr "Xerar Auth URL de Kobo" + +#: cps/templates/user_table.html:80 cps/templates/user_table.html:103 +msgid "Select..." +msgstr "Selección..." + +#: cps/templates/user_table.html:131 +msgid "Edit User" +msgstr "Editar usuario" + +#: cps/templates/user_table.html:134 +msgid "Enter Username" +msgstr "Introduce o nome do usuario" + +#: cps/templates/user_table.html:135 +#, fuzzy +msgid "Enter Email" +msgstr "Comprobar correo electrónico" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "Enter eReader Email" +msgstr "Enviar ao enderezo de correo electrónico do Kindle" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "eReader Email" +msgstr "Comprobar o correo electrónico" + +#: cps/templates/user_table.html:137 +msgid "Locale" +msgstr "Lingua" + +#: cps/templates/user_table.html:138 +msgid "Visible Book Languages" +msgstr "Linguas de libros visibles" + +#: cps/templates/user_table.html:139 +msgid "Edit Allowed Tags" +msgstr "Editar etiquetas Permitidas" + +#: cps/templates/user_table.html:139 +msgid "Allowed Tags" +msgstr "Etiquetas Permitidas" + +#: cps/templates/user_table.html:140 +msgid "Edit Denied Tags" +msgstr "Editar Etiquetas Denegadas" + +#: cps/templates/user_table.html:140 +msgid "Denied Tags" +msgstr "Etiquetas Denegadas" + +#: cps/templates/user_table.html:141 +msgid "Edit Allowed Column Values" +msgstr "Editar valores permitidos para a columna" + +#: cps/templates/user_table.html:141 +msgid "Allowed Column Values" +msgstr "Valores permitidos da columna" + +#: cps/templates/user_table.html:142 +msgid "Edit Denied Column Values" +msgstr "Editar valores non permitidos para a columna" + +#: cps/templates/user_table.html:142 +msgid "Denied Column Values" +msgstr "Valores non permitidos dea columna" + +#: cps/templates/user_table.html:144 +msgid "Change Password" +msgstr "Cambiar a contrasinal" + +#: cps/templates/user_table.html:147 +msgid "View" +msgstr "Vista" + +#: cps/templates/user_table.html:150 +msgid "Edit Public Shelves" +msgstr "Editar andeis públicos" + +#: cps/templates/user_table.html:152 +msgid "Sync selected Shelves with Kobo" +msgstr "sincronizar andeis seleccionados con Kobo" + +#: cps/templates/user_table.html:156 +#, fuzzy +msgid "Show Read/Unread Section" +msgstr "Mostrar selección lidos/non lidos" + diff --git a/cps/translations/hu/LC_MESSAGES/messages.mo b/cps/translations/hu/LC_MESSAGES/messages.mo index cd2790bb2..f951d0ffd 100644 Binary files a/cps/translations/hu/LC_MESSAGES/messages.mo and b/cps/translations/hu/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/hu/LC_MESSAGES/messages.po b/cps/translations/hu/LC_MESSAGES/messages.po index a91824ee0..52b7cb0e8 100644 --- a/cps/translations/hu/LC_MESSAGES/messages.po +++ b/cps/translations/hu/LC_MESSAGES/messages.po @@ -7,586 +7,643 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2019-04-06 23:36+0200\n" "Last-Translator: \n" "Language: hu\n" "Language-Team: \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "nincs telepítve" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Statisztika" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "A kiszolgáló újraindult, tölts be újra az oldalt!" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "A kiszolgáló leállítása folyamatban, zárd be ezt az ablakot" -#: cps/admin.py:154 -msgid "Reconnect successful" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Ismeretlen" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Rendszergazda oldala" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Alapvető beállítások" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Felhasználói felület beállításai" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" msgstr "Rendszergazda felhasználó" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Mindent mutass" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "A Calibre-Web konfigurációja frissítve." -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Valóban törölni akarod a polcot?" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Valóban törölni akarod a polcot?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Valóban törölni akarod a polcot?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Valóban törölni akarod a polcot?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "Valóban le akarod állítani a Calibre-Web-et?" -#: cps/admin.py:741 -msgid "Tag not found" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Az e-mail kiszolgáló beállításai frissítve." - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Funkciók beállítása" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Az összes mezőt ki kell tölteni!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "Az e-mail tartománya nem érvényes." - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "Új felhasználó hozzáadása" - -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "A következő felhasználó létrehozva: %(user)s" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Már létezik felhasználó ehhez az e-mail címhez vagy felhasználói névhez." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "A felhasználó törölve: %(nick)s" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr " A felhasználó szerkesztése: %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "A felhasználó frissítve: %(nick)s" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Ismeretlen hiba történt. Próbáld újra később!" - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "SMTP beállítások változtatása" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "" + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Hiba történt a teszt levél küldése során: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "" -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Az e-mail kiszolgáló beállításai frissítve." -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Ismeretlen hiba történt. Próbáld újra később!" + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr " A felhasználó szerkesztése: %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "A(z) %(user)s felhasználó jelszavának alaphelyzetbe állítása" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Először be kell állítani az SMTP levelező beállításokat..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Frissítési csomag kérése" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Frissítési csomag letöltése" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Frissítési csomag kitömörítése" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Fájlok cserélése" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Adatbázis kapcsolatok lezárva" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Szerver leállítása" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "A frissítés települt, kattints az OK-ra és újra tölt az oldal" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "A frissítés nem sikerült:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTP hiba" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Kapcsolódási hiba" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Időtúllépés a kapcsolódás során" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Általános hiba" -#: cps/admin.py:1696 +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" msgstr "" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" msgstr "" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "" -#: cps/converter.py:30 -msgid "not configured" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" msgstr "" +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "Az e-mail kiszolgáló beállításai frissítve." + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Funkciók beállítása" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Az összes mezőt ki kell tölteni!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "Az e-mail tartománya nem érvényes." + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Új felhasználó hozzáadása" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "A következő felhasználó létrehozva: %(user)s" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Már létezik felhasználó ehhez az e-mail címhez vagy felhasználói névhez." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "A felhasználó törölve: %(nick)s" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "A felhasználó frissítve: %(nick)s" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "nincs telepítve" + #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Nincs" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Hiba történt az e-könyv megnyitásakor. A fájl nem létezik vagy nem érhető el:" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "Metaadatok szerkesztése" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "A(z) %(langname)s nem érvényes nyelv" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "A(z) \"%(ext)s\" kiterjesztésű fájlok feltöltése nincs engedélyezve ezen a szerveren." - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "A feltöltendő fájlnak kiterjesztéssel kell rendelkeznie!" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Nem sikerült létrehozni az elérési utat (engedély megtagadva): %(path)s." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Nem sikerült elmenteni a %(file)s fájlt." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "A(z) %(ext)s fájlformátum hozzáadva a könyvhez: %(book)s." - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "A metaadatok sikeresen frissültek" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Hiba a könyv szerkesztése során, további részletek a naplófájlban." - -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " +#: cps/editbooks.py:234 +msgid "Error editing book: {}" msgstr "" -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Az átalakításhoz hiányzik a forrás- vagy a célformátum!" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "A könyv sikeresen átalakításra lett jelölve a következő formátumra: %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Hiba történt a könyv átalakításakor: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "" + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "A(z) %(langname)s nem érvényes nyelv" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "A(z) \"%(ext)s\" kiterjesztésű fájlok feltöltése nincs engedélyezve ezen a szerveren." + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "A feltöltendő fájlnak kiterjesztéssel kell rendelkeznie!" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "Metaadatok szerkesztése" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Nem sikerült létrehozni az elérési utat (engedély megtagadva): %(path)s." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Nem sikerült elmenteni a %(file)s fájlt." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "A(z) %(ext)s fájlformátum hozzáadva a könyvhez: %(book)s." + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "A Google Drive beállítása nem fejeződött be, próbáld kikapcsolni és újra aktíválni a Google Drive-ot." @@ -600,166 +657,178 @@ msgstr "A visszahívási tartomány nem ellenőrzött, kövesd az alábbi lépé msgid "%(format)s format not found for book id: %(book)d" msgstr "A(z) %(format)s formátum nem található a következő könyvhöz: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s nem található a Google Drive-on: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s nem található: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Küldés Kindle-re" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Ez az e-mail a Calibre-Web-en keresztül lett küldve." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Calibre-Web teszt e-mail" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Teszt e-mail" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Kezdő lépések a Calibre-Web-bel" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Regisztrációs e-mail a következő felhasználóhoz: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "%(orig)s konvertálása %(format)s-ra és küldés Kindle-re" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "%(format)s küldése Kindle-re" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Küldés Kindle-re" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "A kért fájl nem olvasható. Esetleg jogosultsági probléma lenne?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "A cím átnevezése \"%(src)s\"-ról \"%(dest)s\"-ra nem sikerült a következő hiba miatt: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "\"%(src)s\" fájl átnevezése \"%(dest)s\"-re nem sikerült a következő hiba miatt: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "A \"%(file)s\" fájl nem található a Google Drive-on" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "A cím átnevezése \"%(src)s\"-ról \"%(dest)s\"-ra nem sikerült a következő hiba miatt: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "A könyv elérési útja (\"%(path)s\") nem található a Google Drive-on" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Már létezik felhasználó ehhez az e-mail címhez." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +msgid "Error executing UnRar" msgstr "" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Várakozás" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Felfedezés" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Nem sikerült" - -#: cps/helper.py:766 -msgid "Started" -msgstr "Elindítva" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Végrehajtva" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Ismeretlen állapot" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" msgstr "" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "" + +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "" @@ -768,9 +837,9 @@ msgstr "" msgid "Register with %(provider)s" msgstr "" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "Be vagy jelentkezve mint: %(nickname)s" #: cps/oauth_bb.py:148 @@ -829,507 +898,613 @@ msgstr "" msgid "Google Oauth error: {}" msgstr "" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Belépés" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "A token nem található." -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "A token érvényessége lejárt." -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Sikerült! Újra használható az eszköz." -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Legutóbbi könyvek mutatása" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Kelendő könyvek" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Kelendő könyvek mutatása" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Legjobb könyvek" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Legjobbra értékelt könyvek mutatása" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Olvasott könyvek" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Mutassa az olvasva/olvasatlan állapotot" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Olvasatlan könyvek" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Felfedezés" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Mutass könyveket találomra" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Címkék" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Címke választó mutatása" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Sorozatok" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Sorozat választó mutatása" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Szerzők" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Szerző választó mutatása" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Kiadók" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Kiadó választó mutatása" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Nyelvek" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Nyelv választó mutatása" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" -msgstr "" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "Sorozat választó mutatása" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" -msgstr "" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" +msgstr "Sorozat választó mutatása" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" -msgstr "" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "Legutóbbi könyvek mutatása" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "A megadott polc érvénytelen!" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Elnézést, nem vagy jogosult hozzáadni a könyvet a következő polcra: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "A könyv már a következő polcon van: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "A könyv hozzá lett adva a következő polchoz: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Nincs jogosultságod könyvet tenni a következő polcra: %(name)s." - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "A könyvek már a következő polcon vannak: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "A könyvek hozzá lettek adva a következő polchoz: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Nem sikerült hozzáadni a könyveket a polchoz: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "A könyv el lett távolítva a polcról: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Sajnálom, nincs jogosultságot eltávolítani könyvet erről a polcról: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Polc készítése" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Sajnálom, nincs jogosultságot eltávolítani könyvet erről a polcról: %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Polc szerkesztése" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "A következő polc létre lett hozva: %(title)s" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "A következő polc megváltoztatva: %(title)s" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Hiba történt" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "A következő polc átrendezése: %(name)s" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Polc: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Hiba a polc megnyitásakor. A polc nem létezik vagy nem elérhető." - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Ismeretlen adat a frissítési információk olvasásakor" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Nem érhető el újabb frissítés. Már a legújabb verzió van telepítve." - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Egy új frissítés érhető el. Kattints a lenti gombra a legújabb verzió frissítésére" - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Nem lehetett begyűjteni a frissítési információkat" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "" - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Új frissítés érhető el. Kattints az alábbi gombra a frissítéshez a következő verzióra: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Nincs információ a kiadásról." - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Felfedezés (könyvek találomra)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Kelendő könyvek (legtöbbet letöltöttek)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Kiadó: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Sorozat: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Címke: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Nyelv: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Részletes keresés" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Keresés" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Letöltések" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Feladatok" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Kiadva ezután: " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Kiadva ezelőtt: " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Értékelés <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Értékelés <= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Részletes keresés" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "A megadott polc érvénytelen!" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Elnézést, nem vagy jogosult hozzáadni a könyvet a következő polcra: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "A könyv sikeresen küldésre lett jelölve a következő címre: %(kindlemail)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "A könyv már a következő polcon van: %(shelfname)s" -#: cps/web.py:1445 +#: cps/shelf.py:89 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" -msgstr "Hiba történt a könyv küldésekor: %(res)s" +msgid "Book has been added to shelf: %(sname)s" +msgstr "A könyv hozzá lett adva a következő polchoz: %(sname)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." -msgstr "Először be kell állítani a kindle e-mail címet..." - -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" msgstr "" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "A könyvek már a következő polcon vannak: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "A könyvek hozzá lettek adva a következő polchoz: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Nem sikerült hozzáadni a könyveket a polchoz: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "A könyv el lett távolítva a polcról: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Polc készítése" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Sajnálom, nincs jogosultságot eltávolítani könyvet erről a polcról: %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Polc szerkesztése" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "A metaadatok sikeresen frissültek" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "A következő polc átrendezése: %(name)s" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "A következő polc létre lett hozva: %(title)s" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "A következő polc megváltoztatva: %(title)s" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Hiba történt" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Polc: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Hiba a polc megnyitásakor. A polc nem létezik vagy nem elérhető." + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Feladatok" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Várakozás" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Nem sikerült" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Elindítva" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Végrehajtva" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Ismeretlen állapot" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Ismeretlen adat a frissítési információk olvasásakor" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Nem érhető el újabb frissítés. Már a legújabb verzió van telepítve." + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Egy új frissítés érhető el. Kattints a lenti gombra a legújabb verzió frissítésére" + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Nem lehetett begyűjteni a frissítési információkat" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "" + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Új frissítés érhető el. Kattints az alábbi gombra a frissítéshez a következő verzióra: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Nincs információ a kiadásról." + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Felfedezés (könyvek találomra)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Kelendő könyvek (legtöbbet letöltöttek)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Kiadó: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Sorozat: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Címke: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Nyelv: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Letöltések" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Először be kell állítani az SMTP levelező beállításokat..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "A könyv sikeresen küldésre lett jelölve a következő címre: %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "Hiba történt a könyv küldésekor: %(res)s" + +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "Először be kell állítani a kindle e-mail címet..." + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "" + +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Regisztrálás" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Nem engedélyezett a megadott e-mail cím bejegyzése" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Jóváhagyó levél elküldve az email címedre." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Rossz felhasználó név vagy jelszó!" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)s profilja" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "A profil frissítve." +#: cps/web.py:1420 +#, fuzzy +msgid "Oops! An account already exists for this Email." +msgstr "Már létezik felhasználó ehhez az e-mail címhez." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Küldés Kindle-re" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Az e-könyv átalakítás nem sikerült: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "Metaadatok szerkesztése" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Feltöltés" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Felhasználók listája" @@ -1342,14 +1517,15 @@ msgstr "Felhasználói név" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "E-mail" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Kindle" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Rendszergazda" @@ -1359,212 +1535,229 @@ msgstr "Rendszergazda" msgid "Password" msgstr "Jelszó" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Feltöltés" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Letöltés" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Szerkesztés" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Törlés" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "SMTP e-mail kiszolgáló beállítások" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "SMTP szervernév" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP port" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "SSL" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "SMTP felhasználó" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Küldő e-mail cím" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Konfiguráció" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Calibre adatbázis mappája:" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Naplózás szintje:" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Port:" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Könyvek oldalanként:" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Feltöltés:" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Böngészés bejelentkezés nélkül:" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Nyílvános regisztráció:" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Távoli belépés:" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Calibre adatbázis mappája:" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Adminisztráció" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Újracsatlakozás a Calibre adatbázishoz" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "A Calibre adatbázis újraindítása" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "A Calibre adatbázis leállítása" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Frissítés" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Verzió" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Részletek" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Jelenlegi verzió" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Frissítés keresése" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Frissítés elkezdése" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Valóban újra akarod indítani a Calibre-Web-et?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "OK" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Valóban le akarod állítani a Calibre-Web-et?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Frissítés folyamatban, ne töltsd újra az oldalt" @@ -1576,119 +1769,118 @@ msgstr "keresztül" msgid "In Library" msgstr "Könyvtárban" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "csökkentsd" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Több eszerint:" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Könyv törlése" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Formátumok törlése:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Könyvformátum átalakítása:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Konvertálás erről:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "Válassz egy lehetőséget" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Konvertálás erre:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Könyv konvertálása" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Könyv címe" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Szerző" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Leírás" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Címkék" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Értékelés" @@ -1700,82 +1892,83 @@ msgstr "Borító URL (jpg, borító letöltve és elmentve az adatbázisban, a m msgid "Upload Cover from Local Disk" msgstr "Borító feltöltése helyi meghajtóról" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Kiadás éve" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Kiadó" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Nyelv" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Igen" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Nem" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Feltöltés formátuma" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Könyv megnézése szerkesztés után" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Metaadatok beszerzése" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Kulcsszó" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " Keresési kulcsszó " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Kattints a borítóra a metadatok betöltésére" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Betöltés..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Bezárás" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Forrás" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Keresési hiba!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Nincs találat! Próbálj másik kulcsszót." @@ -1867,27 +2060,36 @@ msgstr "Tartomány megadása" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Regisztrálás" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Biztosan?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "" @@ -1979,6 +2181,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Feltöltés engedélyezése" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "" @@ -1992,7 +2198,7 @@ msgid "Enable Public Registration" msgstr "Nyilvános regisztráció engedélyezése" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "" #: cps/templates/config_edit.html:132 @@ -2059,11 +2265,6 @@ msgstr "" msgid "LDAP Encryption" msgstr "" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Nincs" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "" @@ -2199,7 +2400,7 @@ msgstr "Találomra mutatott könyvek száma" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Mutatott szerzők száma (0=elrejtés kikapcsolása)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Téma" @@ -2231,138 +2432,141 @@ msgstr "Reguláris kifejezés címek sorbarendezéséhez" msgid "Default Settings for New Users" msgstr "Új felhasználók alapértelmezett beállításai" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Rendszergazda felhasználó" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Letöltés engedélyezése" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Feltöltés engedélyezése" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Szerkesztés engedélyezése" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Jelszó változtatásának engedélyezése" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Nyilvános polcok szerkesztésének engedélyezése" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Nyelvek kizárása" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Mutasd a könyveket a következő nyelvvel" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Új felhasználók alapértelmezett látható elemei" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Mutasson könyveket találomra a részletes nézetben" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Olvasás böngészőben" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Legyen olvasatlan" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Legyen olvasott" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Olvasva" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Ismertető:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Hozzáadás polchoz" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Metaadatok szerkesztése" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "" +#, fuzzy +msgid "Gmail Account" +msgstr "Felhasználói fiók" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 @@ -2386,10 +2590,11 @@ msgid "Attachment Size Limit" msgstr "" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Beállítások mentése és teszt e-mail küldése" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Vissza" @@ -2415,45 +2620,61 @@ msgstr "Tartomány megadása" msgid "Denied Domains (Blacklist)" msgstr "" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Következő" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" msgstr "" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Vissza a kezdőlapra" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "" @@ -2517,7 +2738,7 @@ msgstr "" msgid "Books ordered by file formats" msgstr "" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "" @@ -2526,63 +2747,67 @@ msgstr "" msgid "Books organized in shelves" msgstr "" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Kezdőlap" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Navigáció átkapcsolása" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Feltöltés..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Hiba" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Feltöltés kész, feldolgozás alatt, kérlek várj..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Beállítások" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Felhasználói fiók" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Kilépés" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Feltöltés..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Hiba" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Feltöltés kész, feldolgozás alatt, kérlek várj..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Beállítások" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Böngészés" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Névjegy" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Előző" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Könyv részletei" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Emlékezz rám" @@ -2591,7 +2816,7 @@ msgstr "Emlékezz rám" msgid "Forgot Password?" msgstr "" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Belépés varázshivatkozással" @@ -2687,7 +2912,7 @@ msgstr "" msgid "Select" msgstr "" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr " " @@ -2700,127 +2925,140 @@ msgstr "Calibre-Web e-könyv katalógus" msgid "epub Reader" msgstr "" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Világos" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Sötét" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Vissza" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Szöveg újratördelése amikor az oldalsávok nyitva vannak" +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 msgid "Comic Reader" msgstr "" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Gyorsbillentyűk" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Előző oldal" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Következő oldal" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Méretezés a legjobbra" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Méretezés a szélességre" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Méretezés a magasságra" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Méretezés a natívra" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Forgatás balra" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Forgatás jobbra" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Kép tükrözése" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Világos" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Sötét" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Méretezés" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Legjobb" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Szélesség" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Magasság" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Natív" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Forgatás" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Tökrözés" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Vízszintes" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Függőleges" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "" @@ -2828,7 +3066,7 @@ msgstr "" msgid "DJVU Reader" msgstr "" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 msgid "PDF Reader" msgstr "" @@ -2846,7 +3084,7 @@ msgid "Choose a username" msgstr "Válassz egy felhasználónevet" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Az e-mail címed" #: cps/templates/remote_login.html:5 @@ -2865,15 +3103,19 @@ msgstr "Az első belépés után automatikusan be leszel léptetve ezen az eszk msgid "This verification link will expire in 10 minutes." msgstr "" -#: cps/templates/search.html:5 -msgid "No Results Found" +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" msgstr "" #: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "" + +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Találatok a következőhöz:" @@ -2885,10 +3127,6 @@ msgstr "Kiadás éve ettől: " msgid "Published Date To" msgstr "Kiadás éve eddig: " -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Cimkék kizárása" @@ -2930,30 +3168,26 @@ msgstr "" msgid "To:" msgstr "" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Polc törlése" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "A polc el fog tűnni mindenki számára és örökké!" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Nyilvános polc" @@ -2995,8 +3229,8 @@ msgid "System Statistics" msgstr "" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Alkalmazás könyvtár" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3022,9 +3256,17 @@ msgstr "Állapot" msgid "Run Time" msgstr "Futásidő" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Indítás ideje" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3054,19 +3296,23 @@ msgstr "" msgid "Create/View" msgstr "" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "A felhasználó törlése" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "" @@ -3086,17 +3332,17 @@ msgstr "Válassz egy felhasználónevet" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "Az e-mail címed" +msgid "Enter Email" +msgstr "Teszt e-mail" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Enter Kindle E-mail Address" +msgid "Enter eReader Email" msgstr "Kindle" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Kindle E-mail" +msgid "eReader Email" msgstr "Teszt e-mail" #: cps/templates/user_table.html:137 @@ -3160,10 +3406,6 @@ msgstr "" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Sorozat választó mutatása" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Könyvek találomra mutatása" - diff --git a/cps/translations/id/LC_MESSAGES/messages.mo b/cps/translations/id/LC_MESSAGES/messages.mo new file mode 100644 index 000000000..6da595cbf Binary files /dev/null and b/cps/translations/id/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/id/LC_MESSAGES/messages.po b/cps/translations/id/LC_MESSAGES/messages.po new file mode 100644 index 000000000..fa79da8fe --- /dev/null +++ b/cps/translations/id/LC_MESSAGES/messages.po @@ -0,0 +1,3386 @@ +# Indonesian translations for Calibre-Web. +# Copyright (C) 2017 Calibre-Web +# This file is distributed under the same license as the Calibre-Web +# project. +# FIRST AUTHOR Arief Hidayat, 2021-2023. +msgid "" +msgstr "" +"Project-Id-Version: Calibre-Web\n" +"Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" +"PO-Revision-Date: 2023-01-21 10:00+0700\n" +"Last-Translator: Arief Hidayat\n" +"Language: id\n" +"Language-Team: Arief Hidayat \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.10.3\n" + +#: cps/about.py:84 +msgid "Statistics" +msgstr "Statistik" + +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." +msgstr "Server dimulai ulang, harap muat ulang halaman" + +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." +msgstr "Mematikan server, silakan tutup jendela" + +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" + +#: cps/admin.py:156 +msgid "Unknown command" +msgstr "Perintah tidak diketahui" + +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Buku berhasil diantrekan untuk Pencadangan Metadata" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 +msgid "Unknown" +msgstr "Tidak diketahui" + +#: cps/admin.py:225 +msgid "Admin page" +msgstr "Halaman Admin" + +#: cps/admin.py:245 +msgid "Basic Configuration" +msgstr "Pengaturan Dasar" + +#: cps/admin.py:283 +msgid "UI Configuration" +msgstr "Pengaturan Antarmuka" + +#: cps/admin.py:317 cps/templates/admin.html:51 +msgid "Edit Users" +msgstr "Edit pengguna" + +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 +msgid "All" +msgstr "Semua" + +#: cps/admin.py:388 cps/admin.py:1392 +msgid "User not found" +msgstr "Pengguna tidak ditemukan" + +#: cps/admin.py:402 +msgid "{} users deleted successfully" +msgstr "{} pengguna berhasil dihapus" + +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 +#: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 +msgid "Show All" +msgstr "Tampilkan semua" + +#: cps/admin.py:446 cps/admin.py:452 +msgid "Malformed request" +msgstr "Permintaan salah" + +#: cps/admin.py:464 cps/admin.py:1993 +msgid "Guest Name can't be changed" +msgstr "Nama Tamu tidak dapat diganti" + +#: cps/admin.py:476 +msgid "Guest can't have this role" +msgstr "Tamu tidak dapat memiliki peran ini" + +#: cps/admin.py:488 cps/admin.py:1948 +msgid "No admin user remaining, can't remove admin role" +msgstr "Tidak ada pengguna admin yang tersisa, tidak dapat menghapus peran admin" + +#: cps/admin.py:492 cps/admin.py:506 +msgid "Value has to be true or false" +msgstr "Nilai harus benar atau salah" + +#: cps/admin.py:494 +msgid "Invalid role" +msgstr "Peran tidak valid" + +#: cps/admin.py:498 +msgid "Guest can't have this view" +msgstr " Tamu tidak dapat mengakses tampilan ini" + +#: cps/admin.py:508 +msgid "Invalid view" +msgstr " Tampilan tidak valid" + +#: cps/admin.py:511 +msgid "Guest's Locale is determined automatically and can't be set" +msgstr "Lokal Tamu ditentukan secara otomatis dan tidak dapat disetel" + +#: cps/admin.py:515 +msgid "No Valid Locale Given" +msgstr "Tidak Ada Lokal yang Valid Diberikan" + +#: cps/admin.py:526 +msgid "No Valid Book Language Given" +msgstr "Tidak Ada Bahasa Buku yang Valid Diberikan" + +#: cps/admin.py:528 cps/editbooks.py:442 +msgid "Parameter not found" +msgstr "Parameter tidak ditemukan" + +#: cps/admin.py:565 +msgid "Invalid Read Column" +msgstr "Kolom Baca Tidak Valid" + +#: cps/admin.py:571 +msgid "Invalid Restricted Column" +msgstr "Kolom Dibatasi Tidak Valid" + +#: cps/admin.py:591 cps/admin.py:1819 +msgid "Calibre-Web configuration updated" +msgstr "Pengaturan Calibre-Web telah diperbarui" + +#: cps/admin.py:603 +msgid "Do you really want to delete the Kobo Token?" +msgstr "Apakah Anda yakin ingin menghapus Token Kobo?" + +#: cps/admin.py:605 +msgid "Do you really want to delete this domain?" +msgstr "Apakah Anda yakin ingin menghapus domain ini?" + +#: cps/admin.py:607 +msgid "Do you really want to delete this user?" +msgstr "Apakah Anda yakin ingin menghapus pengguna ini?" + +#: cps/admin.py:609 +msgid "Are you sure you want to delete this shelf?" +msgstr "Apakah Anda yakin ingin menghapus rak ini?" + +#: cps/admin.py:611 +msgid "Are you sure you want to change locales of selected user(s)?" +msgstr "Apakah Anda yakin ingin merubah lokalisasi untuk pengguna yang dipilih?" + +#: cps/admin.py:613 +msgid "Are you sure you want to change visible book languages for selected user(s)?" +msgstr "Apakah Anda yakin ingin merubah bahasa buku yang terlihat untuk pengguna yang dipilih?" + +#: cps/admin.py:615 +msgid "Are you sure you want to change the selected role for the selected user(s)?" +msgstr "Apakah Anda yakin ingin merubah peran untuk pengguna yang dipilih?" + +#: cps/admin.py:617 +msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" +msgstr "Apakah Anda yakin ingin mengubah batasan yang dipilih untuk pengguna yang dipilih?" + +#: cps/admin.py:619 +msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" +msgstr "Apakah Anda yakin ingin merubah batasan visibilitas untuk pengguna yang dipilih?" + +#: cps/admin.py:622 +msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" +msgstr "Apakah Anda yakin ingin mengubah perilaku sinkronisasi rak untuk pengguna yang dipilih?" + +#: cps/admin.py:624 +msgid "Are you sure you want to change Calibre library location?" +msgstr "Apakah Anda yakin ingin mengubah lokasi perpustakaan Calibre?" + +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "Calibre-Web akan mencari Sampul yang diperbarui dan memperbarui Thumbnail Sampul, ini mungkin memakan waktu cukup lama?" + +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Apakah Anda yakin ingin menghapus database sinkronisasi Calibre-Web untuk memaksakan sinkronisasi penuh dengan Kobo Reader Anda?" + +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 +#: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 +#: cps/templates/user_table.html:58 +msgid "Deny" +msgstr "Tolak" + +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 +#: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 +#: cps/templates/user_table.html:61 +msgid "Allow" +msgstr "Izinkan" + +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{} entri sinkronisasi dihapus" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Tag tidak ditemukan" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Tindakan Tidak Valid" + +#: cps/admin.py:1104 +msgid "client_secrets.json Is Not Configured For Web Application" +msgstr "client_secrets.json Tidak Diatur Untuk Aplikasi Web" + +#: cps/admin.py:1149 +msgid "Logfile Location is not Valid, Please Enter Correct Path" +msgstr "Lokasi Logfile tidak Valid, Harap Masukkan Jalur yang Benar" + +#: cps/admin.py:1155 +msgid "Access Logfile Location is not Valid, Please Enter Correct Path" +msgstr "Akses Logfile Catatan tidak Valid, Harap Masukkan Jalur yang Benar" + +#: cps/admin.py:1185 +msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" +msgstr "Harap Masukkan Provider LDAP, Port, DN dan User Obect Identifier" + +#: cps/admin.py:1191 +msgid "Please Enter a LDAP Service Account and Password" +msgstr "Masukkan Akun Layanan LDAP dan Kata Sandi" + +#: cps/admin.py:1194 +msgid "Please Enter a LDAP Service Account" +msgstr "Masukkan Akun Layanan LDAP" + +#: cps/admin.py:1199 +#, python-format +msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" +msgstr "Filter Objek Grup LDAP Harus Memiliki Satu Pengidentifikasi Format \"%s\"" + +#: cps/admin.py:1201 +msgid "LDAP Group Object Filter Has Unmatched Parenthesis" +msgstr "Filter Objek Grup LDAP Memiliki Tanda kurung yang Tak Berpasangan" + +#: cps/admin.py:1205 +#, python-format +msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" +msgstr "Filter Objek Pengguna LDAP harus Memiliki Satu Pengidentifikasi Format \"%s\"" + +#: cps/admin.py:1207 +msgid "LDAP User Object Filter Has Unmatched Parenthesis" +msgstr "Filter Objek Pengguna LDAP Memiliki Tanda kurung yang Tak Berpasangan" + +#: cps/admin.py:1214 +#, python-format +msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" +msgstr "Filter Pengguna Anggota LDAP harus Memiliki Satu Pengenal Format \"%s\"" + +#: cps/admin.py:1216 +msgid "LDAP Member User Filter Has Unmatched Parenthesis" +msgstr "Filter Pengguna Anggota LDAP Memiliki Tanda Kurung yang Tak Berpasangan" + +#: cps/admin.py:1223 +msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" +msgstr "Lokasi LDAP Sertifikat CA, Sertifikat, atau Kunci tidak Valid, Harap Masukkan Jalur yang Benar " + +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "Tambah Pengguna Baru" + +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" +msgstr "Edit Pengaturan Server Email" + +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" + +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Kesalahan basis data: %(error)s" + +#: cps/admin.py:1311 +#, python-format +msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" +msgstr "Uji email diantrean untuk dikirim ke %(email), harap periksa Tasks untuk hasilnya" + +#: cps/admin.py:1314 +#, python-format +msgid "There was an error sending the Test e-mail: %(res)s" +msgstr "Terjadi kesalahan saat mengirim email tes: %(res)s" + +#: cps/admin.py:1316 +msgid "Please configure your e-mail address first..." +msgstr "Harap atur alamat email Anda terlebih dahulu.." + +#: cps/admin.py:1318 +msgid "Email Server Settings updated" +msgstr "Setelan server email diperbarui" + +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "Edit Pengaturan Tugas Terjadwal" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "Waktu mulai tidak valid untuk tugas yang ditentukan" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "Durasi tidak valid untuk tugas yang ditentukan" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "Pengaturan tugas terjadwal diperbarui" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Terjadi kesalahan yang tidak diketahui. Coba lagi nanti." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "Pengaturan DB tidak dapat ditulisi" + +#: cps/admin.py:1411 cps/admin.py:2009 +#, python-format +msgid "Edit User %(nick)s" +msgstr "Edit pengguna %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" +msgstr "Kata sandi untuk pengaturan ulang pengguna %(user) " + +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." +msgstr "Harap atur pengaturan email SMTP terlebih dahulu..." + +#: cps/admin.py:1440 +msgid "Logfile viewer" +msgstr "Penampil berkas log" + +#: cps/admin.py:1506 +msgid "Requesting update package" +msgstr "Meminta paket pembaruan" + +#: cps/admin.py:1507 +msgid "Downloading update package" +msgstr "Mengunduh paket pembaruan" + +#: cps/admin.py:1508 +msgid "Unzipping update package" +msgstr "Mengekstrak paket pembaruan" + +#: cps/admin.py:1509 +msgid "Replacing files" +msgstr "Mengganti berkas" + +#: cps/admin.py:1510 +msgid "Database connections are closed" +msgstr "Koneksi basis data ditutup" + +#: cps/admin.py:1511 +msgid "Stopping server" +msgstr "Menghentikan server" + +#: cps/admin.py:1512 +msgid "Update finished, please press okay and reload page" +msgstr "Pembaruan selesai, silakan tekan OK dan muat ulang halaman" + +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 +msgid "Update failed:" +msgstr "Pembaruan gagal:" + +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 +msgid "HTTP Error" +msgstr "Kesalahan HTTP" + +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 +msgid "Connection error" +msgstr "Kesalahan koneksi" + +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 +msgid "Timeout while establishing connection" +msgstr "Batas waktu saat membuat koneksi" + +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 +msgid "General error" +msgstr "Kesalahan umum" + +#: cps/admin.py:1517 +msgid "Update file could not be saved in temp dir" +msgstr "Berkas pembaruan tidak dapat disimpan di direktori temp" + +#: cps/admin.py:1518 +msgid "Files could not be replaced during update" +msgstr "Berkas tidak dapat diganti selama pembaruan" + +#: cps/admin.py:1542 +msgid "Failed to extract at least One LDAP User" +msgstr "Gagal mengekstrak setidaknya Satu Pengguna LDAP" + +#: cps/admin.py:1587 +msgid "Failed to Create at Least One LDAP User" +msgstr "Gagal Membuat Sedikitnya Satu Pengguna LDAP" + +#: cps/admin.py:1600 +#, python-format +msgid "Error: %(ldaperror)s" +msgstr "Kesalahan: %(ldaperror)s" + +#: cps/admin.py:1604 +msgid "Error: No user returned in response of LDAP server" +msgstr "Error: Tidak ada pengguna yang dikembalikan sebagai respons dari server LDAP" + +#: cps/admin.py:1637 +msgid "At Least One LDAP User Not Found in Database" +msgstr "Setidaknya Satu Pengguna LDAP Tidak Ditemukan di Basis Data" + +#: cps/admin.py:1639 +msgid "{} User Successfully Imported" +msgstr "{} Pengguna Berhasil Diimpor" + +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "Lokasi Basis Data tidak Valid, Harap Masukkan Jalur yang Benar" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "Basis Data tidak dapat ditulisi" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "Lokasi keyfile tidak Valid, Harap Masukkan Jalur yang Benar " + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "Lokasi Sertifikat tidak Valid, Harap Masukkan Jalur yang Benar " + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "Pengaturan Basis Data diperbarui" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "Pengaturan Basis Data" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Harap masukkan seluruh isian!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "Email bukan dari domain yang valid" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Tambahkan pengguna baru" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Pengguna '%(user)s' telah dibuat" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "Ditemukan akun yang ada untuk alamat email atau nama ini." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Pengguna '%(nick)s' telah dihapus" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Tidak dapat menghapus Pengguna Tamu" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Tidak ada pengguna admin tersisa, tidak dapat menghapus pengguna" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "Alamat email tidak boleh kosong dan harus berupa email yang valid" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Pengguna '%(nick)s' diperbarui" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "belum dipasang" + +#: cps/converter.py:32 +msgid "Execution permissions missing" +msgstr "Izin eksekusi hilang" + +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" +msgstr "Kolom Kustom No.%(column)d tidak ada di basis data kaliber" + +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Tidak ada" + +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" +msgstr "Ups! Judul buku yang dipilih tidak tersedia. Berkas tidak ada atau tidak dapat diakses" + +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "Pengguna tidak berhak mengganti sampul" + +#: cps/editbooks.py:174 cps/editbooks.py:716 +msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" +msgstr "IDは大文字小文字を区別しません。元のIDを上書きします" + +#: cps/editbooks.py:216 +msgid "Metadata successfully updated" +msgstr "Metadata berhasil diperbarui" + +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "Kesalahan pengeditan buku: {}" + +#: cps/editbooks.py:291 +#, python-format +msgid "File %(file)s uploaded" +msgstr "Berkas %(file)s telah diunggah" + +#: cps/editbooks.py:318 +msgid "Source or destination format for conversion missing" +msgstr "Format sumber atau tujuan untuk konversi tidak ada" + +#: cps/editbooks.py:326 +#, python-format +msgid "Book successfully queued for converting to %(book_format)s" +msgstr "Buku berhasil diantrekan untuk dikonversi ke %(book_format)s" + +#: cps/editbooks.py:330 +#, python-format +msgid "There was an error converting this book: %(res)s" +msgstr "Terjadi kesalahan saat mengonversi buku ini: %(res)s" + +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Buku yang diunggah mungkin ada di perpustakaan, pertimbangkan untuk mengubahnya sebelum mengunggah yang baru: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "'%(langname)s' bukan bahasa yang valid" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Ekstensi berkas '%(ext)s' tidak diizinkan untuk diunggah ke server ini" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Berkas yang akan diunggah harus memiliki ekstensi" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Berkas %(filename)s tidak dapat disimpan ke direktori temp" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Gagal Memindahkan Berkas Sampul %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Format Buku Berhasil Dihapus" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Buku Berhasil Dihapus" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "Anda tidak memiliki izin untuk menghapus buku" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "edit metadata" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s dilewati karena bukan angka yang valid" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "Pengguna tidak memiliki izin untuk mengunggah format berkas tambahan" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Gagal membuat jalur %(path)s (Izin ditolak)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Gagal menyimpan berkas %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Format berkas %(ext)s ditambahkan ke %(book)s" + +#: cps/gdrive.py:58 +msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" +msgstr "Pengaturan Google Drive belum selesai, coba nonaktifkan dan aktifkan kembali Google Drive" + +#: cps/gdrive.py:95 +msgid "Callback domain is not verified, please follow steps to verify domain in google developer console" +msgstr "Domain panggilan balik tidak diverifikasi, ikuti langkah-langkah untuk memverifikasi domain di konsol pengembang google" + +#: cps/helper.py:80 +#, python-format +msgid "%(format)s format not found for book id: %(book)d" +msgstr "%(format)s format tidak ditemukan untuk id buku: %(book)d" + +#: cps/helper.py:87 cps/tasks/convert.py:75 +#, python-format +msgid "%(format)s not found on Google Drive: %(fn)s" +msgstr "%(format)s tidak ditemukan di Google Drive: %(fn)s" + +#: cps/helper.py:92 +#, python-format +msgid "%(format)s not found: %(fn)s" +msgstr "%(format)s tidak ditemukan: %(fn)s" + +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +msgid "Send to eReader" +msgstr "Kirim ke E-Reader" + +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." +msgstr "Email ini telah dikirim melalui Calibre-Web." + +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" +msgstr "Email tes Calibre-Web" + +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" +msgstr "Email tes" + +#: cps/helper.py:132 +msgid "Get Started with Calibre-Web" +msgstr "Memulai dengan Calibre-Web" + +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" +msgstr "Email pendaftaran untuk pengguna: %(name)s" + +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "Ubah %(orig)s menjadi %(format)s dan kirim ke E-Reader" + +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" +msgstr "Kirim %(format)s ke E-Reader" + +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" +msgstr "%%(buku)s telah dikirim ke E-Reader" + +#: cps/helper.py:230 +msgid "The requested file could not be read. Maybe wrong permissions?" +msgstr "Berkas yang diminta tidak dapat dibaca. Mungkin izinnya salah?" + +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "Status baca tidak bisa disetel: {}" + +#: cps/helper.py:368 +#, python-format +msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" +msgstr "Menghapus folder buku untuk buku %(id)s gagal, jalur memiliki subfolder: %(path)s" + +#: cps/helper.py:374 +#, python-format +msgid "Deleting book %(id)s failed: %(message)s" +msgstr "Gagal menghapus buku %(id)s: %(message)s" + +#: cps/helper.py:385 +#, python-format +msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" +msgstr "Menghapus buku %(id)s hanya dari basis data, jalur buku di basis data tidak valid: %(path)s" + +#: cps/helper.py:450 +#, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Ganti nama pengarang dari: '%(src)s' menjadi '%(dest)s' gagal dengan kesalahan: %(error)s" + +#: cps/helper.py:522 cps/helper.py:531 +#, python-format +msgid "File %(file)s not found on Google Drive" +msgstr "Berkas %(file)s tidak ditemukan di Google Drive" + +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Ganti nama judul dari: '%(src)s' menjadi '%(dest)s' gagal dengan kesalahan: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "Kesalahan dalam mengganti nama berkas di jalur: {}" + +#: cps/helper.py:603 +#, python-format +msgid "Book path %(path)s not found on Google Drive" +msgstr "Jalur buku %(path)s tidak ditemukan di Google Drive" + +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" + +#: cps/helper.py:652 +msgid "This username is already taken" +msgstr "Nama pengguna ini sudah digunakan" + +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" +msgstr "Format alamat email tidak valid" + +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "Modul 'advocate' Python tidak diinstal tetapi diperlukan untuk unggahan sampul" + +#: cps/helper.py:825 +msgid "Error Downloading Cover" +msgstr "Kesalahan Mengunduh Sampul" + +#: cps/helper.py:828 +msgid "Cover Format Error" +msgstr "Kesalahan Format Sampul" + +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "Anda tidak diizinkan mengakses localhost atau jaringan lokal untuk unggahan sampul" + +#: cps/helper.py:841 +msgid "Failed to create path for cover" +msgstr "Gagal membuat jalur untuk sampul" + +#: cps/helper.py:857 +msgid "Cover-file is not a valid image file, or could not be stored" +msgstr "Berkas sampul bukan berkas gambar yang valid, atau tidak dapat disimpan" + +#: cps/helper.py:868 +msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" +msgstr "Hanya berkas jpg/jpeg/png/webp/bmp yang didukung sebagai berkas sampul" + +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "Konten berkas sampul tidak valid" + +#: cps/helper.py:884 +msgid "Only jpg/jpeg files are supported as coverfile" +msgstr "Hanya berkas jpg/jpeg yang didukung sebagai berkas sampul" + +#: cps/helper.py:936 +msgid "Unrar binary file not found" +msgstr "Berkas biner unrar tidak ditemukan" + +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" +msgstr "Kesalahan saat menjalankan UnRar" + +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Sampul" + +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "Antrian semua buku untuk cadangan metadata" + +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "Mohon akses calibre-web dari non localhost untuk mendapatkan api_endpoint yang valid untuk perangkat kobo" + +#: cps/kobo_auth.py:115 +msgid "Kobo Setup" +msgstr "Pengaturan Kobo" + +#: cps/oauth_bb.py:77 +#, python-format +msgid "Register with %(provider)s" +msgstr "Daftar dengan %(provider)s" + +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 +#, python-format +msgid "Success! You are now logged in as: %(nickname)s" +msgstr "Anda sekarang login sebagai: %(nickname)s" + +#: cps/oauth_bb.py:148 +#, python-format +msgid "Link to %(oauth)s Succeeded" +msgstr "Tautan ke %(oauth)s Berhasil" + +#: cps/oauth_bb.py:155 +msgid "Login failed, No User Linked With OAuth Account" +msgstr "Login gagal, Tidak Ada Pengguna yang Tertaut Dengan Akun OAuth" + +#: cps/oauth_bb.py:197 +#, python-format +msgid "Unlink to %(oauth)s Succeeded" +msgstr "Membatalkan tautan ke %(oauth)s Berhasil" + +#: cps/oauth_bb.py:202 +#, python-format +msgid "Unlink to %(oauth)s Failed" +msgstr "Membatalkan tautan ke %(oauth)s Gagal" + +#: cps/oauth_bb.py:205 +#, python-format +msgid "Not Linked to %(oauth)s" +msgstr "Tidak Tertaut ke %(oauth)s" + +#: cps/oauth_bb.py:261 +msgid "Failed to log in with GitHub." +msgstr "Gagal masuk dengan GitHub." + +#: cps/oauth_bb.py:267 +msgid "Failed to fetch user info from GitHub." +msgstr "Gagal mengambil info pengguna dari GitHub." + +#: cps/oauth_bb.py:279 +msgid "Failed to log in with Google." +msgstr "Gagal masuk dengan Google." + +#: cps/oauth_bb.py:285 +msgid "Failed to fetch user info from Google." +msgstr "Gagal mengambil info pengguna dari Google." + +#: cps/oauth_bb.py:332 +msgid "GitHub Oauth error, please retry later." +msgstr "Kesalahan GitHub Oauth, silakan coba lagi nanti." + +#: cps/oauth_bb.py:335 +msgid "GitHub Oauth error: {}" +msgstr "Kesalahan GitHub OAuth: {}" + +#: cps/oauth_bb.py:356 +msgid "Google Oauth error, please retry later." +msgstr "Kesalahan Google Oauth, harap coba lagi nanti." + +#: cps/oauth_bb.py:359 +msgid "Google Oauth error: {}" +msgstr "Kesalahan Google OAuth: {}" + +#: cps/opds.py:273 +msgid "{} Stars" +msgstr "{}★" + +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 +msgid "Login" +msgstr "Masuk" + +#: cps/remotelogin.py:74 cps/remotelogin.py:108 +msgid "Token not found" +msgstr "Token tidak ditemukan" + +#: cps/remotelogin.py:83 cps/remotelogin.py:116 +msgid "Token has expired" +msgstr "Token telah kedaluwarsa" + +#: cps/remotelogin.py:92 +msgid "Success! Please return to your device" +msgstr "Berhasil! Silakan kembali ke perangkat Anda" + +#: cps/render_template.py:42 cps/web.py:410 +msgid "Books" +msgstr "Buku" + +#: cps/render_template.py:44 +msgid "Show recent books" +msgstr "Tampilkan buku terbaru" + +#: cps/render_template.py:45 cps/templates/index.xml:25 +msgid "Hot Books" +msgstr "Buku Populer" + +#: cps/render_template.py:47 +msgid "Show Hot Books" +msgstr "Tampilkan Buku Populer" + +#: cps/render_template.py:49 cps/render_template.py:54 +msgid "Downloaded Books" +msgstr "Buku yang Diunduh" + +#: cps/render_template.py:51 cps/render_template.py:56 +#: cps/templates/user_table.html:167 +msgid "Show Downloaded Books" +msgstr "Tampilkan Buku yang Diunduh" + +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 +msgid "Top Rated Books" +msgstr "Buku Berperingkat Teratas" + +#: cps/render_template.py:61 cps/templates/user_table.html:161 +msgid "Show Top Rated Books" +msgstr "Tampilkan Buku Berperingkat Teratas" + +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 +msgid "Read Books" +msgstr "Buku Telah Dibaca" + +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" +msgstr "Tampilkan sudah dibaca dan belum dibaca" + +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 +msgid "Unread Books" +msgstr "Buku yang Belum Dibaca" + +#: cps/render_template.py:68 +msgid "Show unread" +msgstr "Tampilkan belum dibaca" + +#: cps/render_template.py:69 +msgid "Discover" +msgstr "Temukan" + +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 +msgid "Show Random Books" +msgstr "Tampilkan Buku Acak" + +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 +msgid "Categories" +msgstr "Kategori" + +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" +msgstr "Tampilkan pilihan kategori" + +#: cps/render_template.py:75 cps/templates/book_edit.html:91 +#: cps/templates/book_table.html:68 cps/templates/index.xml:90 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 +msgid "Series" +msgstr "Seri" + +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" +msgstr "Tampilkan pilihan seri" + +#: cps/render_template.py:78 cps/templates/book_table.html:66 +#: cps/templates/index.xml:69 +msgid "Authors" +msgstr "Penulis" + +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" +msgstr "Tampilkan pilihan penulis" + +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 +msgid "Publishers" +msgstr "Penerbit" + +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" +msgstr "Tampilkan pilihan penerbit" + +#: cps/render_template.py:85 cps/templates/book_table.html:70 +#: cps/templates/index.xml:97 cps/templates/search_form.html:107 +#: cps/web.py:1078 +msgid "Languages" +msgstr "Bahasa" + +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" +msgstr "Tampilkan pilihan bahasa" + +#: cps/render_template.py:89 cps/templates/index.xml:104 +msgid "Ratings" +msgstr "Peringkat" + +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "Tampilkan pilihan peringkat" + +#: cps/render_template.py:92 cps/templates/index.xml:112 +msgid "File formats" +msgstr "Format berkas" + +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" +msgstr "Tampilkan pilihan format berkas" + +#: cps/render_template.py:96 cps/web.py:772 +msgid "Archived Books" +msgstr "Buku yang Diarsipkan" + +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "Tampilkan buku yang diarsipkan" + +#: cps/render_template.py:101 cps/web.py:803 +msgid "Books List" +msgstr "Daftar Buku" + +#: cps/render_template.py:103 cps/templates/user_table.html:168 +msgid "Show Books List" +msgstr "Tampilkan Daftar Buku" + +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 +msgid "Search" +msgstr "Telusuri" + +#: cps/search.py:189 +msgid "Published after " +msgstr "Terbit setelah " + +#: cps/search.py:196 +msgid "Published before " +msgstr "Terbit sebelum " + +#: cps/search.py:218 +#, python-format +msgid "Rating <= %(rating)s" +msgstr "Peringkat ≤ %(rating)s" + +#: cps/search.py:220 +#, python-format +msgid "Rating >= %(rating)s" +msgstr "Peringkat ≥ %(rating)s" + +#: cps/search.py:222 +#, python-format +msgid "Read Status = %(status)s" +msgstr "Status Baca = %(status)s" + +#: cps/search.py:324 +msgid "Error on search for custom columns, please restart Calibre-Web" +msgstr "Terjadi kesalahan saat mencari kolom khusus, harap mulai ulang Calibre-Web" + +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Penelusuran Lanjutan" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Rak yang ditentukan tidak valid" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Maaf Anda tidak diperbolehkan menambahkan buku ke rak: %(shelfname)s" + +#: cps/shelf.py:64 +#, python-format +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Buku sudah menjadi bagian dari rak: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Buku telah ditambahkan ke rak: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "Anda tidak diperbolehkan menambahkan buku ke rak: %(name)s" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Buku sudah menjadi bagian dari rak: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Buku telah ditambahkan ke rak: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Tidak dapat menambahkan buku ke rak: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Buku telah dihapus dari rak: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "Maaf Anda tidak diizinkan untuk menghapus buku dari rak ini: %(sname)s" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Buat Rak" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Maaf, Anda tidak diizinkan mengedit rak ini" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Edit Rak" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "Kesalahan menghapus Rak" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "Rak berhasil dihapus" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Ubah urutan Rak: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "Maaf, Anda tidak diizinkan membuat rak publik" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Rak %(title)s dibuat" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Rak %(title)s diubah" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Ada kesalahan" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Rak publik dengan nama '%(title)s' sudah ada." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Rak pribadi dengan nama '%(title)s' sudah ada." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Rak: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Terjadi kesalahan saat membuka rak. Rak tidak ada atau tidak dapat diakses" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Tugas" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Menunggu" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Gagal" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Dimulai" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Selesai" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "Berakhir" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "Dibatalkan" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Status Tidak Diketahui" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Data tak terduga saat membaca informasi pembaruan" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Tidak ada pembaruan yang tersedia. Anda telah memasang versi terbaru" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Pembaruan tersedia. Klik tombol di bawah untuk memperbarui ke versi terbaru." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Tidak dapat mengambil informasi pembaruan" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Klik tombol di bawah untuk memperbarui ke versi stabil terbaru." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Pembaruan tersedia. Klik tombol di bawah untuk memperbarui ke versi: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Tidak ada informasi rilis yang tersedia" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Temukan (Buku Acak)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Buku Populer (Paling Banyak Diunduh)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Buku telah diunduh oleh %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Penulis: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Penerbit: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Seri: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "Peringkat: Tidak ada" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Peringkat: %(rating)s★" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Format berkas: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Kategori: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Bahasa: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Unduhan" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Daftar peringkat" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Daftar format berkas" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Harap atur pengaturan email SMTP terlebih dahulu..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Buku telah diantrikan untuk dikirim ke %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "Oops! Terjadi kesalahan saat mengirim buku: %(res)s" + +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "Harap perbarui profil Anda dengan alamat e-mail Kirim ke Kindle yang valid." + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "Server email belum diatur, silakan hubungi administrator!" + +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 +msgid "Register" +msgstr "Daftar" + +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." +msgstr "Alamat email Anda tidak diizinkan untuk mendaftar" + +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." +msgstr "E-mail konfirmasi telah dikirimkan ke alamat email Anda." + +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" +msgstr "Tidak dapat mengaktifkan autentikasi LDAP." + +#: cps/web.py:1303 +#, python-format +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" +msgstr "Login Pengganti sebagai: '%(nickname)s', Server LDAP tidak dapat dijangkau, atau pengguna tidak diketahui." + +#: cps/web.py:1309 +#, python-format +msgid "Oops! Login Failed: %(message)s" +msgstr "Tidak dapat login: %(message)s" + +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." +msgstr "Pengguna atau Kata Sandi salah" + +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." +msgstr "Kata Sandi baru telah dikirimkan ke alamat email Anda" + +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" +msgstr "Harap masukkan pengguna valid untuk mengatur ulang kata sandi" + +#: cps/web.py:1400 cps/web.py:1449 +#, python-format +msgid "%(name)s's Profile" +msgstr "Profil %(name)s" + +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" +msgstr "Profil diperbarui" + +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "Ditemukan akun yang ada untuk alamat email ini" + +#: cps/services/gmail.py:58 +msgid "Found no valid gmail.json file with OAuth information" +msgstr "Tidak ditemukan berkas gmail.json yang valid dengan informasi OAuth" + +#: cps/tasks/convert.py:92 +#, python-format +msgid "%(book)s send to E-Reader" +msgstr "%%(buku)s telah dikirim ke E-Reader" + +#: cps/tasks/convert.py:153 +#, python-format +msgid "Calibre ebook-convert %(tool)s not found" +msgstr "Calibre ebook-convert %(tool)s tidak ditemukan" + +#: cps/tasks/convert.py:186 +#, python-format +msgid "%(format)s format not found on disk" +msgstr "%(format)s format tidak ditemukan dalam disk" + +#: cps/tasks/convert.py:190 +msgid "Ebook converter failed with unknown error" +msgstr "Konverter ebook gagal dengan kesalahan yang tidak diketahui." + +#: cps/tasks/convert.py:202 +#, python-format +msgid "Kepubify-converter failed: %(error)s" +msgstr "Kebupify-converter gagal: %(error)s" + +#: cps/tasks/convert.py:224 +#, python-format +msgid "Converted file not found or more than one file in folder %(folder)s" +msgstr "Berkas yang telah dikonversi tidak ditemukan atau terdapat duplikat dalam folder %(folder)s" + +#: cps/tasks/convert.py:247 +#, python-format +msgid "Ebook-converter failed: %(error)s" +msgstr "Ebook-converter gagal: %(error)s" + +#: cps/tasks/convert.py:270 +#, python-format +msgid "Calibre failed with error: %(error)s" +msgstr "Calibre gagal dengan kesalahan: %(error)s" + +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "Konversi" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "Menghubungkan kembali basis data Calibre" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "Email" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "Mencadangkan Metadata" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "%(count)s thumbnail sampul dibuat" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "Thumbnail Sampul" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "{0} thumbnail seri dihasilkan" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "Menghapus cache thumbnail sampul" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Unggah" + +#: cps/templates/admin.html:9 +msgid "Users" +msgstr "Pengguna" + +#: cps/templates/admin.html:13 cps/templates/login.html:9 +#: cps/templates/login.html:10 cps/templates/register.html:9 +#: cps/templates/user_edit.html:10 cps/templates/user_table.html:134 +msgid "Username" +msgstr "Nama Pengguna" + +#: cps/templates/admin.html:14 cps/templates/register.html:14 +#: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 +msgid "Email" +msgstr "Alamat Email" + +#: cps/templates/admin.html:15 cps/templates/user_edit.html:28 +msgid "Send to eReader Email" +msgstr "Alamat E-mail untuk Kirim ke E-Reader" + +#: cps/templates/admin.html:17 cps/templates/layout.html:92 +#: cps/templates/user_table.html:143 +msgid "Admin" +msgstr "Admin" + +#: cps/templates/admin.html:18 cps/templates/login.html:13 +#: cps/templates/login.html:14 cps/templates/user_edit.html:23 +msgid "Password" +msgstr "Kata Sandi" + +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 +#: cps/templates/user_table.html:146 +msgid "Download" +msgstr "Unduh" + +#: cps/templates/admin.html:23 +msgid "View Books" +msgstr "Lihat Buku" + +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 +#: cps/templates/user_table.html:148 +msgid "Edit" +msgstr "Edit" + +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 +#: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 +#: cps/templates/user_table.html:149 +msgid "Delete" +msgstr "Hapus" + +#: cps/templates/admin.html:26 +msgid "Public Shelf" +msgstr "Rak Publik" + +#: cps/templates/admin.html:55 +msgid "Import LDAP Users" +msgstr "Impor Pengguna LDAP" + +#: cps/templates/admin.html:62 +msgid "Email Server Settings" +msgstr "Pengaturan Server Email" + +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 +msgid "SMTP Hostname" +msgstr "Hostname SMTP" + +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 +msgid "SMTP Port" +msgstr "Port SMTP" + +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 +msgid "Encryption" +msgstr "Enkripsi" + +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 +msgid "SMTP Login" +msgstr "Login SMTP" + +#: cps/templates/admin.html:83 cps/templates/admin.html:94 +#: cps/templates/email_edit.html:55 +msgid "From Email" +msgstr "Dari Email" + +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" +msgstr "Layanan Email" + +#: cps/templates/admin.html:91 +msgid "Gmail via Oauth2" +msgstr "Gmail via Oauth2" + +#: cps/templates/admin.html:106 +msgid "Configuration" +msgstr "Pengaturan" + +#: cps/templates/admin.html:109 +msgid "Calibre Database Directory" +msgstr "Jalur Database Calibre" + +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 +msgid "Log Level" +msgstr "Log Level" + +#: cps/templates/admin.html:117 +msgid "Port" +msgstr "Port" + +#: cps/templates/admin.html:122 +msgid "External Port" +msgstr "Port Eksternal" + +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 +msgid "Books per Page" +msgstr "Buku per halaman" + +#: cps/templates/admin.html:133 +msgid "Uploads" +msgstr "Unggah" + +#: cps/templates/admin.html:137 +msgid "Anonymous Browsing" +msgstr "Penjelajahan Anonim" + +#: cps/templates/admin.html:141 +msgid "Public Registration" +msgstr "Registrasi Publik" + +#: cps/templates/admin.html:145 +msgid "Magic Link Remote Login" +msgstr "Login Jarak Jauh dengan Magic Link" + +#: cps/templates/admin.html:149 +msgid "Reverse Proxy Login" +msgstr "Login Reverse Proxy" + +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 +msgid "Reverse Proxy Header Name" +msgstr "Nama Header Reverse Proxy" + +#: cps/templates/admin.html:159 +msgid "Edit Calibre Database Configuration" +msgstr "Edit Pengaturan Basis Data Caliber" + +#: cps/templates/admin.html:160 +msgid "Edit Basic Configuration" +msgstr "Edit Pengaturan Dasar" + +#: cps/templates/admin.html:161 +msgid "Edit UI Configuration" +msgstr "Edit Pengaturan Antarmuka" + +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "Tugas Terjadwal" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "Waktu saat tugas mulai dijalankan" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "Durasi tugas maksimum" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "Buat thumbnail sampul buku" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "Buat thumbnail sampul seri" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "Sambungkan kembali ke Perpustakaan Caliber" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "Segarkan Cache Thumbnail Sampul" + +#: cps/templates/admin.html:199 +msgid "Administration" +msgstr "Administrasi" + +#: cps/templates/admin.html:200 +msgid "Download Debug Package" +msgstr "Unduh Paket Debug" + +#: cps/templates/admin.html:201 +msgid "View Logs" +msgstr "Tampilkan Log" + +#: cps/templates/admin.html:207 +msgid "Restart" +msgstr "Mulai Ulang" + +#: cps/templates/admin.html:208 +msgid "Shutdown" +msgstr "Matikan" + +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "Informasi Versi" + +#: cps/templates/admin.html:220 +msgid "Version" +msgstr "Versi" + +#: cps/templates/admin.html:221 +msgid "Details" +msgstr "Detail" + +#: cps/templates/admin.html:227 +msgid "Current Version" +msgstr "Versi saat ini" + +#: cps/templates/admin.html:234 +msgid "Check for Update" +msgstr "Periksa Pembaruan" + +#: cps/templates/admin.html:235 +msgid "Perform Update" +msgstr "Lakukan Pembaruan" + +#: cps/templates/admin.html:248 +msgid "Are you sure you want to restart?" +msgstr "Apa Anda yakin untuk memulai ulang?" + +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 +msgid "OK" +msgstr "OK" + +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 +#: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 +#: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 +msgid "Cancel" +msgstr "Batal" + +#: cps/templates/admin.html:266 +msgid "Are you sure you want to shutdown?" +msgstr "Apa Anda yakin untuk mematikan layanan?" + +#: cps/templates/admin.html:278 +msgid "Updating, please do not reload this page" +msgstr "Memperbarui, jangan memuat ulang halaman ini" + +#: cps/templates/author.html:15 +msgid "via" +msgstr "melalui" + +#: cps/templates/author.html:23 +msgid "In Library" +msgstr "Dalam Pustaka" + +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 +msgid "Sort according to book date, newest first" +msgstr "Urutkan menurut tanggal buku, terbaru dulu" + +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 +msgid "Sort according to book date, oldest first" +msgstr "Urutkan menurut tanggal buku, terlama dulu" + +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 +msgid "Sort title in alphabetical order" +msgstr "Urutkan judul dalam urutan abjad" + +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 +msgid "Sort title in reverse alphabetical order" +msgstr "Urutkan judul dalam urutan abjad terbalik" + +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 +msgid "Sort according to publishing date, newest first" +msgstr "Urutkan menurut tanggal penerbitan, yang terbaru dulu" + +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 +msgid "Sort according to publishing date, oldest first" +msgstr "Urutkan menurut tanggal penerbitan, yang terlama dulu" + +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 +msgid "reduce" +msgstr "kurangi" + +#: cps/templates/author.html:99 +msgid "More by" +msgstr "Lainnya oleh" + +#: cps/templates/book_edit.html:11 +msgid "Delete Book" +msgstr "Hapus" + +#: cps/templates/book_edit.html:14 +msgid "Delete formats:" +msgstr "Hapus format:" + +#: cps/templates/book_edit.html:25 +msgid "Convert book format:" +msgstr "KOnversi format buku:" + +#: cps/templates/book_edit.html:30 +msgid "Convert from:" +msgstr "Konversi dari:" + +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 +msgid "select an option" +msgstr "pilih opsi" + +#: cps/templates/book_edit.html:37 +msgid "Convert to:" +msgstr "Konversi ke:" + +#: cps/templates/book_edit.html:46 +msgid "Convert book" +msgstr "Konversi buku" + +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 +msgid "Book Title" +msgstr "Judul Buku" + +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 +msgid "Author" +msgstr "Penulis" + +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 +msgid "Description" +msgstr "Deskripsi" + +#: cps/templates/book_edit.html:73 +msgid "Identifiers" +msgstr "Pengidentifikasi" + +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 +msgid "Identifier Type" +msgstr "Tipe Pengidentifikasi" + +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 +msgid "Identifier Value" +msgstr "Nilai Pengidentifikasi" + +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 +#: cps/templates/user_table.html:24 +msgid "Remove" +msgstr "Hapus" + +#: cps/templates/book_edit.html:83 +msgid "Add Identifier" +msgstr "Tambah Pengidentifikasi" + +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 +msgid "Tags" +msgstr "Tag" + +#: cps/templates/book_edit.html:95 +msgid "Series ID" +msgstr "ID Seri" + +#: cps/templates/book_edit.html:99 +msgid "Rating" +msgstr "Rating" + +#: cps/templates/book_edit.html:104 +msgid "Fetch Cover from URL (JPEG - Image will be downloaded and stored in database)" +msgstr "Ambil Sampul dari URL (JPEG - Gambar akan diunduh dan disimpan dalam basis data)" + +#: cps/templates/book_edit.html:108 +msgid "Upload Cover from Local Disk" +msgstr "Unggah Sampul dari disk lokal" + +#: cps/templates/book_edit.html:113 +msgid "Published Date" +msgstr "Tanggal Terbit" + +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 +msgid "Publisher" +msgstr "Penerbit" + +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 +msgid "Language" +msgstr "Bahasa" + +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 +#: cps/templates/search_form.html:164 +msgid "Yes" +msgstr "Ya" + +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 +#: cps/templates/search_form.html:165 +msgid "No" +msgstr "Tidak" + +#: cps/templates/book_edit.html:201 +msgid "Upload Format" +msgstr "Format Unggahan" + +#: cps/templates/book_edit.html:209 +msgid "View Book on Save" +msgstr "Tampilkan Buku setelah Disimpan" + +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 +msgid "Fetch Metadata" +msgstr "Ambil Metadata" + +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 +msgid "Save" +msgstr "Simpan" + +#: cps/templates/book_edit.html:233 +msgid "Keyword" +msgstr "Kata Kunci" + +#: cps/templates/book_edit.html:234 +msgid "Search keyword" +msgstr "Cari Kata kunci" + +#: cps/templates/book_edit.html:240 +msgid "Click the cover to load metadata to the form" +msgstr "Klik sampul untuk memuat metadata ke formulir" + +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 +msgid "Loading..." +msgstr "Memuat..." + +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 +msgid "Close" +msgstr "Tutup" + +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 +msgid "Source" +msgstr "Sumber" + +#: cps/templates/book_edit.html:287 +msgid "Search error!" +msgstr "Kesalahan pencarian!" + +#: cps/templates/book_edit.html:288 +msgid "No Result(s) found! Please try another keyword." +msgstr "Tidak ada hasil yang ditemukan! Silakan coba kata kunci lain." + +#: cps/templates/book_table.html:12 cps/templates/book_table.html:69 +#: cps/templates/user_table.html:14 cps/templates/user_table.html:77 +#: cps/templates/user_table.html:100 +msgid "This Field is Required" +msgstr "Isian Ini Diperlukan" + +#: cps/templates/book_table.html:37 +msgid "Merge selected books" +msgstr "Gabungkan buku terpiih" + +#: cps/templates/book_table.html:38 cps/templates/user_table.html:124 +msgid "Remove Selections" +msgstr "Hapus Pilihan" + +#: cps/templates/book_table.html:41 +msgid "Exchange author and title" +msgstr "Tukar penulis dan judul" + +#: cps/templates/book_table.html:47 +msgid "Update Title Sort automatically" +msgstr "Perbarui Pengurutan Judul secara otomatis" + +#: cps/templates/book_table.html:51 +msgid "Update Author Sort automatically" +msgstr "Perbarui Pengurutan Penulis secara otomatis" + +#: cps/templates/book_table.html:63 cps/templates/book_table.html:69 +msgid "Enter Title" +msgstr "Masukkan Judul" + +#: cps/templates/book_table.html:63 cps/templates/config_view_edit.html:24 +#: cps/templates/shelf_edit.html:8 +msgid "Title" +msgstr "Judul" + +#: cps/templates/book_table.html:64 +msgid "Enter Title Sort" +msgstr "Masukkan Urutan Judul" + +#: cps/templates/book_table.html:64 +msgid "Title Sort" +msgstr "Urutan Judul" + +#: cps/templates/book_table.html:65 +msgid "Enter Author Sort" +msgstr "Masukkan Urutan Penulis" + +#: cps/templates/book_table.html:65 +msgid "Author Sort" +msgstr "Urutan Penulis" + +#: cps/templates/book_table.html:66 +msgid "Enter Authors" +msgstr "Masukkan Penulis" + +#: cps/templates/book_table.html:67 +msgid "Enter Categories" +msgstr "Masukkan Kategori" + +#: cps/templates/book_table.html:68 +msgid "Enter Series" +msgstr "Masukkan Seri" + +#: cps/templates/book_table.html:69 +msgid "Series Index" +msgstr "Indeks Pencarian" + +#: cps/templates/book_table.html:70 +msgid "Enter Languages" +msgstr "Masukkan Bahasa" + +#: cps/templates/book_table.html:71 +msgid "Publishing Date" +msgstr "Tanggal Terbit" + +#: cps/templates/book_table.html:72 +msgid "Enter Publishers" +msgstr "Masukkan Penerbit" + +#: cps/templates/book_table.html:73 +msgid "Enter comments" +msgstr "Masukkan komentar" + +#: cps/templates/book_table.html:73 +msgid "Comments" +msgstr "Komentar" + +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "Status Arsip" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Status Baca" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 +msgid "Enter " +msgstr "入力: " + +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 +msgid "Are you really sure?" +msgstr "Apakah Anda yakin?" + +#: cps/templates/book_table.html:117 +msgid "Books with Title will be merged from:" +msgstr "Buku dengan Judul akan digabungkan dari:" + +#: cps/templates/book_table.html:121 +msgid "Into Book with Title:" +msgstr "Ke dalam Buku dengan Judul:" + +#: cps/templates/book_table.html:126 +msgid "Merge" +msgstr "Gabungkan" + +#: cps/templates/config_db.html:12 +msgid "Location of Calibre Database" +msgstr "Lokasi Database Calibre" + +#: cps/templates/config_db.html:22 +msgid "Use Google Drive?" +msgstr "Gunakan Google Drive?" + +#: cps/templates/config_db.html:27 +msgid "Authenticate Google Drive" +msgstr "Autentikasi Google Drive" + +#: cps/templates/config_db.html:32 +msgid "Google Drive Calibre folder" +msgstr "Silakan tekan simpan untuk melanjutkan penyiapan" + +#: cps/templates/config_db.html:40 +msgid "Metadata Watch Channel ID" +msgstr "ID Saluran Metadata Watch" + +#: cps/templates/config_db.html:43 +msgid "Revoke" +msgstr "Tarik Kembali" + +#: cps/templates/config_db.html:68 +msgid "New db location is invalid, please enter valid path" +msgstr "Lokasi basis data baru tidak valid, harap masukkan jalur yang valid" + +#: cps/templates/config_edit.html:18 +msgid "Server Configuration" +msgstr "Pengaturan Server" + +#: cps/templates/config_edit.html:25 +msgid "Server Port" +msgstr "Port Server" + +#: cps/templates/config_edit.html:28 +msgid "SSL certfile location (leave it empty for non-SSL Servers)" +msgstr "Lokasi berkas sertifikat SSL (biarkan kosong untuk Server non-SSL)" + +#: cps/templates/config_edit.html:35 +msgid "SSL Keyfile location (leave it empty for non-SSL Servers)" +msgstr "Lokasi SSL Keyfile (biarkan kosong untuk Server non-SSL)" + +#: cps/templates/config_edit.html:43 +msgid "Update Channel" +msgstr "Saluran Pembaruan" + +#: cps/templates/config_edit.html:45 +msgid "Stable" +msgstr "Stabil" + +#: cps/templates/config_edit.html:46 +msgid "Nightly" +msgstr "Nightly" + +#: cps/templates/config_edit.html:50 +msgid "Trusted Hosts (Comma Separated)" +msgstr "Host Tepercaya (Pisahkan dengan Koma)" + +#: cps/templates/config_edit.html:61 +msgid "Logfile Configuration" +msgstr "Pengaturan Logfile" + +#: cps/templates/config_edit.html:77 +msgid "Location and name of logfile (calibre-web.log for no entry)" +msgstr "Lokasi dan nama logfile (caliber-web.log jika tanpa entri)" + +#: cps/templates/config_edit.html:82 +msgid "Enable Access Log" +msgstr "Aktifkan Log Akses" + +#: cps/templates/config_edit.html:85 +msgid "Location and name of access logfile (access.log for no entry)" +msgstr "Lokasi dan nama access logfile (access.log jika tanpa entri)" + +#: cps/templates/config_edit.html:96 +msgid "Feature Configuration" +msgstr "Pengaturan Fitur" + +#: cps/templates/config_edit.html:104 +msgid "Convert non-English characters in title and author while saving to disk" +msgstr "Konversikan karakter non-Inggris dalam judul dan penulis saat menyimpan ke disk" + +#: cps/templates/config_edit.html:108 +msgid "Enable Uploads" +msgstr "Izinkan Unggahan" + +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(Harap pastikan pengguna juga memiliki hak mengunggah)" + +#: cps/templates/config_edit.html:112 +msgid "Allowed Upload Fileformats" +msgstr "Format Berkas Unggahan yang Diizinkan" + +#: cps/templates/config_edit.html:118 +msgid "Enable Anonymous Browsing" +msgstr "Izinkan Penjelajahan Anonim" + +#: cps/templates/config_edit.html:122 +msgid "Enable Public Registration" +msgstr "Izinkan Registrasi Publik" + +#: cps/templates/config_edit.html:127 +msgid "Use Email as Username" +msgstr "Gunakan Email sebagai Nama Pengguna" + +#: cps/templates/config_edit.html:132 +msgid "Enable Magic Link Remote Login" +msgstr "Izinkan Login Jarak Jauh dengan Magic Link" + +#: cps/templates/config_edit.html:137 +msgid "Enable Kobo sync" +msgstr "Aktifkan sinkronisasi Kobo" + +#: cps/templates/config_edit.html:142 +msgid "Proxy unknown requests to Kobo Store" +msgstr "Proxy permintaan tidak dikenal ke Kobo Store" + +#: cps/templates/config_edit.html:145 +msgid "Server External Port (for port forwarded API calls)" +msgstr "Port Eksternal Server (untuk panggilan API melalui port forward)" + +#: cps/templates/config_edit.html:153 +msgid "Use Goodreads" +msgstr "Gunakan Goodreads" + +#: cps/templates/config_edit.html:154 +msgid "Create an API Key" +msgstr "Buat Kunci API" + +#: cps/templates/config_edit.html:158 +msgid "Goodreads API Key" +msgstr "Kunci API Goodreads" + +#: cps/templates/config_edit.html:162 +msgid "Goodreads API Secret" +msgstr "Goodreads API Secret" + +#: cps/templates/config_edit.html:169 +msgid "Allow Reverse Proxy Authentication" +msgstr "Izinkan Reverse Proxy Authentication" + +#: cps/templates/config_edit.html:180 +msgid "Login type" +msgstr "Tipe Login" + +#: cps/templates/config_edit.html:182 +msgid "Use Standard Authentication" +msgstr "Gunakan Otentikasi Standar" + +#: cps/templates/config_edit.html:184 +msgid "Use LDAP Authentication" +msgstr "Gunakan Otentikasi LDAP" + +#: cps/templates/config_edit.html:187 +msgid "Use OAuth" +msgstr "Gunakan Oauth" + +#: cps/templates/config_edit.html:194 +msgid "LDAP Server Host Name or IP Address" +msgstr "Nama Host Server atau Alamat IP LDAP" + +#: cps/templates/config_edit.html:198 +msgid "LDAP Server Port" +msgstr "Port Server LDAP" + +#: cps/templates/config_edit.html:202 +msgid "LDAP Encryption" +msgstr "Enkripsi LDAP" + +#: cps/templates/config_edit.html:205 +msgid "TLS" +msgstr "TLS" + +#: cps/templates/config_edit.html:206 +msgid "SSL" +msgstr "SSL" + +#: cps/templates/config_edit.html:210 +msgid "LDAP CACertificate Path (Only needed for Client Certificate Authentication)" +msgstr "Jalur CACertificate LDAP (Hanya diperlukan untuk Autentikasi Sertifikat Klien)" + +#: cps/templates/config_edit.html:217 +msgid "LDAP Certificate Path (Only needed for Client Certificate Authentication)" +msgstr "Jalur Sertifikat LDAP (Hanya diperlukan untuk Otentikasi Sertifikat Klien)" + +#: cps/templates/config_edit.html:224 +msgid "LDAP Keyfile Path (Only needed for Client Certificate Authentication)" +msgstr "Jalur Keyfile LDAP (Hanya diperlukan untuk Otentikasi Sertifikat Klien)" + +#: cps/templates/config_edit.html:233 +msgid "LDAP Authentication" +msgstr "Otentikasi LDAP" + +#: cps/templates/config_edit.html:235 +msgid "Anonymous" +msgstr "Anonim" + +#: cps/templates/config_edit.html:236 +msgid "Unauthenticated" +msgstr "Tidak diautentikasi" + +#: cps/templates/config_edit.html:237 +msgid "Simple" +msgstr "Sederhana" + +#: cps/templates/config_edit.html:242 +msgid "LDAP Administrator Username" +msgstr "Nama Pengguna Administrator LDAP" + +#: cps/templates/config_edit.html:248 +msgid "LDAP Administrator Password" +msgstr "Kata Sandi Administrator LDAP" + +#: cps/templates/config_edit.html:253 +msgid "LDAP Distinguished Name (DN)" +msgstr "Distinguished Name (DN) LDAP" + +#: cps/templates/config_edit.html:257 +msgid "LDAP User Object Filter" +msgstr "Filter Objek Pengguna LDAP" + +#: cps/templates/config_edit.html:262 +msgid "LDAP Server is OpenLDAP?" +msgstr "Server LDAP adalah OpenLDAP?" + +#: cps/templates/config_edit.html:264 +msgid "Following Settings are Needed For User Import" +msgstr "Pengaturan Berikut Diperlukan Untuk Impor Pengguna" + +#: cps/templates/config_edit.html:266 +msgid "LDAP Group Object Filter" +msgstr "Filter Objek Grup LDAP" + +#: cps/templates/config_edit.html:270 +msgid "LDAP Group Name" +msgstr "Nama Grup LDAP" + +#: cps/templates/config_edit.html:274 +msgid "LDAP Group Members Field" +msgstr "Bidang Group Members LDAP" + +#: cps/templates/config_edit.html:278 +msgid "LDAP Member User Filter Detection" +msgstr "Deteksi Filter Pengguna Anggota LDAP" + +#: cps/templates/config_edit.html:280 +msgid "Autodetect" +msgstr "Deteksi otomatis" + +#: cps/templates/config_edit.html:281 +msgid "Custom Filter" +msgstr "Filter Kustom" + +#: cps/templates/config_edit.html:286 +msgid "LDAP Member User Filter" +msgstr "Filter Pengguna Anggota LDAP" + +#: cps/templates/config_edit.html:297 +#, python-format +msgid "Obtain %(provider)s OAuth Credential" +msgstr "Dapatkan %(provider)s Kredensial OAuth" + +#: cps/templates/config_edit.html:300 +#, python-format +msgid "%(provider)s OAuth Client Id" +msgstr "ID Klien %(provider)s OAuth" + +#: cps/templates/config_edit.html:304 +#, python-format +msgid "%(provider)s OAuth Client Secret" +msgstr "Client Secret %(provider)s OAuth" + +#: cps/templates/config_edit.html:320 +msgid "External binaries" +msgstr "Binari Eksternal" + +#: cps/templates/config_edit.html:326 +msgid "Path to Calibre E-Book Converter" +msgstr "Jalur ke Konverter E-Book Calibre" + +#: cps/templates/config_edit.html:334 +msgid "Calibre E-Book Converter Settings" +msgstr "Pengaturan Konverter E-Book Caliber" + +#: cps/templates/config_edit.html:337 +msgid "Path to Kepubify E-Book Converter" +msgstr "Jalur ke Konverter E-Book Kepubify" + +#: cps/templates/config_edit.html:345 +msgid "Location of Unrar binary" +msgstr "Lokasi binari Unrar" + +#: cps/templates/config_view_edit.html:17 +msgid "View Configuration" +msgstr "Pengaturan Tampilan" + +#: cps/templates/config_view_edit.html:32 +msgid "No. of Random Books to Display" +msgstr "Jumlah Buku Acak untuk Ditampilkan" + +#: cps/templates/config_view_edit.html:36 +msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" +msgstr "Jumlah Penulis untuk Ditampilkan Sebelum Disembunyikan (0=Nonaktifkan Penyembunyian)" + +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 +msgid "Theme" +msgstr "Tema" + +#: cps/templates/config_view_edit.html:42 +msgid "Standard Theme" +msgstr "Tema Standar" + +#: cps/templates/config_view_edit.html:43 +msgid "caliBlur! Dark Theme" +msgstr "Tema Gelap caliBlur!" + +#: cps/templates/config_view_edit.html:47 +msgid "Regular Expression for Ignoring Columns" +msgstr "Ekspresi Reguler untuk Mengabaikan Kolom" + +#: cps/templates/config_view_edit.html:51 +msgid "Link Read/Unread Status to Calibre Column" +msgstr "Tautkan Status Baca/Belum Dibaca ke Kolom Kaliber" + +#: cps/templates/config_view_edit.html:60 +msgid "View Restrictions based on Calibre column" +msgstr "Lihat Batasan berdasarkan kolom Caliber" + +#: cps/templates/config_view_edit.html:69 +msgid "Regular Expression for Title Sorting" +msgstr "Ekspresi Reguler untuk Penyortiran Judul" + +#: cps/templates/config_view_edit.html:80 +msgid "Default Settings for New Users" +msgstr "Pengaturan Default untuk Pengguna Baru" + +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 +msgid "Admin User" +msgstr "Pengguna Admin" + +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 +msgid "Allow Downloads" +msgstr "Izinkan Unduhan" + +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 +msgid "Allow eBook Viewer" +msgstr "Izinkan Penampil eBook" + +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 +msgid "Allow Uploads" +msgstr "Izinkan Unggahan" + +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 +msgid "Allow Edit" +msgstr "Izinkan Edit" + +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 +msgid "Allow Delete Books" +msgstr "Izinkan Menghapus Buku" + +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 +msgid "Allow Changing Password" +msgstr "Izinkan Mengganti Kata Sandi" + +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 +msgid "Allow Editing Public Shelves" +msgstr "Izinkan Mengedit Rak Publik" + +#: cps/templates/config_view_edit.html:123 +msgid "Default Language" +msgstr "Bahasa Bawaan" + +#: cps/templates/config_view_edit.html:131 +msgid "Default Visible Language of Books" +msgstr "Bahasa Buku Bawaan yang Terlihat" + +#: cps/templates/config_view_edit.html:147 +msgid "Default Visibilities for New Users" +msgstr "Visibilitas Default untuk Pengguna Baru" + +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 +#: cps/templates/user_table.html:154 +msgid "Show Random Books in Detail View" +msgstr "Tampilkan Buku Acak dalam Tampilan Detail" + +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 +msgid "Add Allowed/Denied Tags" +msgstr "Tambahkan Tag yang Diizinkan/Ditolak" + +#: cps/templates/config_view_edit.html:167 +msgid "Add Allowed/Denied custom column values" +msgstr "Tambahkan nilai kolom khusus yang Diizinkan/Ditolak" + +#: cps/templates/detail.html:62 cps/templates/detail.html:71 +msgid "Read in Browser" +msgstr "Baca di Peramban" + +#: cps/templates/detail.html:79 cps/templates/detail.html:96 +msgid "Listen in Browser" +msgstr "Dengarkan di Browser" + +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 +#, python-format +msgid "Book %(index)s of %(range)s" +msgstr "Buku" + +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 +msgid "Published" +msgstr "Diterbitkan" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Unread" +msgstr "Tandai sebagai Belum dibaca" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Read" +msgstr "Tandai sebagai dibaca" + +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 +msgid "Read" +msgstr "Baca" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Restore from archive" +msgstr "Pulihkan dari arsip" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Add to archive" +msgstr "Tambahkan ke Arsip" + +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 +msgid "Archived" +msgstr "Diarsipkan" + +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 +msgid "Description:" +msgstr "Deskripsi:" + +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 +msgid "Add to shelf" +msgstr "Tambah ke rak" + +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 +msgid "(Public)" +msgstr "(Publik)" + +#: cps/templates/detail.html:300 +msgid "Edit Metadata" +msgstr "Edit Metadata" + +#: cps/templates/email_edit.html:13 +msgid "Email Account Type" +msgstr "Pilih Jenis Server" + +#: cps/templates/email_edit.html:15 +#, fuzzy +msgid "Standard Email Account" +msgstr "Gunakan Akun Email Standar" + +#: cps/templates/email_edit.html:16 +#, fuzzy +msgid "Gmail Account" +msgstr "Pilih Jenis Server" + +#: cps/templates/email_edit.html:22 +msgid "Setup Gmail Account" +msgstr "" + +#: cps/templates/email_edit.html:24 +msgid "Revoke Gmail Access" +msgstr "Cabut Akses G-Mail" + +#: cps/templates/email_edit.html:42 +msgid "STARTTLS" +msgstr "STARTTLS" + +#: cps/templates/email_edit.html:43 +msgid "SSL/TLS" +msgstr "SSL/TLS" + +#: cps/templates/email_edit.html:51 +msgid "SMTP Password" +msgstr "Kata Sandi SMTP" + +#: cps/templates/email_edit.html:58 +msgid "Attachment Size Limit" +msgstr "Batas Ukuran Lampiran" + +#: cps/templates/email_edit.html:66 +#, fuzzy +msgid "Save and Send Test Email" +msgstr "Simpan dan Kirim Email Percobaan" + +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 +#: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 +msgid "Back" +msgstr "Kembali" + +#: cps/templates/email_edit.html:74 +msgid "Allowed Domains (Whitelist)" +msgstr "Domain yang Diizinkan (Daftar Putih)" + +#: cps/templates/email_edit.html:78 cps/templates/email_edit.html:105 +msgid "Add Domain" +msgstr "Tambahkan Domain" + +#: cps/templates/email_edit.html:81 cps/templates/email_edit.html:108 +#: cps/templates/user_table.html:27 +msgid "Add" +msgstr "Tambah" + +#: cps/templates/email_edit.html:86 cps/templates/email_edit.html:96 +msgid "Enter domainname" +msgstr "Masukkan Nama Domain" + +#: cps/templates/email_edit.html:92 +msgid "Denied Domains (Blacklist)" +msgstr "Domain yang Ditolak (Daftar Hitam)" + +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 +msgid "Next" +msgstr "Selanjutnya" + +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Buka berkas .kobo/Kobo/Kobo eReader.conf di editor teks dan tambahkan (atau edit):" + +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "Token Kobo:" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "Daftar" + +#: cps/templates/http_error.html:34 +msgid "Calibre-Web Instance is unconfigured, please contact your administrator" +msgstr "Instans Calibre-Web belum diatur, harap hubungi administrator Anda" + +#: cps/templates/http_error.html:44 +msgid "Create Issue" +msgstr "Buat Isu" + +#: cps/templates/http_error.html:51 +msgid "Return to Home" +msgstr "Kembali ke Beranda" + +#: cps/templates/http_error.html:53 +msgid "Logout User" +msgstr "Keluar Pengguna" + +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "Urutkan naik menurut jumlah unduhan" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "Urutkan turun menurut jumlah unduhan" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 +msgid "Sort authors in alphabetical order" +msgstr "Urutkan penulis dalam urutan abjad" + +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 +msgid "Sort authors in reverse alphabetical order" +msgstr "Urutkan penulis dalam urutan abjad terbalik" + +#: cps/templates/index.html:83 +msgid "Sort ascending according to series index" +msgstr "Urutkan naik menurut indeks seri" + +#: cps/templates/index.html:84 +msgid "Sort descending according to series index" +msgstr "Urutkan menurun menurut indeks seri" + +#: cps/templates/index.xml:6 +msgid "Start" +msgstr "Mulai" + +#: cps/templates/index.xml:18 +msgid "Alphabetical Books" +msgstr "Buku Abjad" + +#: cps/templates/index.xml:22 +msgid "Books sorted alphabetically" +msgstr "Buku diurutkan menurut abjad" + +#: cps/templates/index.xml:29 +msgid "Popular publications from this catalog based on Downloads." +msgstr "Publikasi populer dari katalog ini berdasarkan Unduhan." + +#: cps/templates/index.xml:36 +msgid "Popular publications from this catalog based on Rating." +msgstr "Publikasi populer dari katalog ini berdasarkan Rating." + +#: cps/templates/index.xml:39 +msgid "Recently added Books" +msgstr "Buku yang baru ditambahkan" + +#: cps/templates/index.xml:43 +msgid "The latest Books" +msgstr "Buku-buku terbaru" + +#: cps/templates/index.xml:46 +msgid "Random Books" +msgstr "Buku Acak" + +#: cps/templates/index.xml:73 +msgid "Books ordered by Author" +msgstr "Buku yang diurutkan menurut Penulis" + +#: cps/templates/index.xml:80 +msgid "Books ordered by publisher" +msgstr "Buku yang diurutkan menurut Penerbit" + +#: cps/templates/index.xml:87 +msgid "Books ordered by category" +msgstr "Buku yang diurutkan menurut Kategori" + +#: cps/templates/index.xml:94 +msgid "Books ordered by series" +msgstr "Buku yang diurutkan menurut Seri" + +#: cps/templates/index.xml:101 +msgid "Books ordered by Languages" +msgstr "Buku yang diurutkan menurut Bahasa" + +#: cps/templates/index.xml:108 +msgid "Books ordered by Rating" +msgstr "Buku yang diurutkan menurut Peringkat" + +#: cps/templates/index.xml:116 +msgid "Books ordered by file formats" +msgstr "Buku yang diurutkan menurut format berkas" + +#: cps/templates/index.xml:119 cps/templates/layout.html:153 +#: cps/templates/search_form.html:87 +msgid "Shelves" +msgstr "Rak" + +#: cps/templates/index.xml:123 +msgid "Books organized in shelves" +msgstr "本棚に整理された本" + +#: cps/templates/layout.html:26 cps/templates/login.html:30 +msgid "Home" +msgstr "Beranda" + +#: cps/templates/layout.html:32 +msgid "Toggle Navigation" +msgstr "Alihkan Navigasi" + +#: cps/templates/layout.html:48 +msgid "Search Library" +msgstr "Cari di Pustaka" + +#: cps/templates/layout.html:66 cps/templates/layout.html:95 +msgid "Account" +msgstr "Akun" + +#: cps/templates/layout.html:72 cps/templates/layout.html:97 +msgid "Logout" +msgstr "Keluar" + +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Mengunggah..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Terjadi Kesalahan" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Unggahan selesai, harap tunggu, data sedang diproses..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Pengaturan" + +#: cps/templates/layout.html:136 +msgid "Please do not refresh the page" +msgstr "Harap jangan segarkan halaman" + +#: cps/templates/layout.html:146 +msgid "Browse" +msgstr "Jelajahi" + +#: cps/templates/layout.html:159 cps/templates/stats.html:3 +msgid "About" +msgstr "Tentang" + +#: cps/templates/layout.html:173 +msgid "Previous" +msgstr "Sebelumnya" + +#: cps/templates/layout.html:200 +msgid "Book Details" +msgstr "Detail Buku" + +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "Terjadi Kesalahan" + +#: cps/templates/login.html:18 +msgid "Remember Me" +msgstr "Ingat saya" + +#: cps/templates/login.html:23 +msgid "Forgot Password?" +msgstr "Lupa Kata Sandi?" + +#: cps/templates/login.html:34 +msgid "Log in with Magic Link" +msgstr "Masuk dengan Magic Link" + +#: cps/templates/logviewer.html:6 +msgid "Show Calibre-Web Log: " +msgstr "Tampilkan Log Caliber-Web:" + +#: cps/templates/logviewer.html:8 +msgid "Calibre-Web Log: " +msgstr "Log Calibre-Web: " + +#: cps/templates/logviewer.html:8 +msgid "Stream output, can't be displayed" +msgstr "Output aliran, tidak dapat ditampilkan" + +#: cps/templates/logviewer.html:12 +msgid "Show Access Log: " +msgstr "Tampilkan Log Akses:" + +#: cps/templates/logviewer.html:18 +msgid "Download Calibre-Web Log" +msgstr "Unduh Calibre-Web Log" + +#: cps/templates/logviewer.html:21 +msgid "Download Access Log" +msgstr "Unduh Log Akses" + +#: cps/templates/modal_dialogs.html:6 +msgid "Select Allowed/Denied Tags" +msgstr "Pilih Tag yang Diizinkan/Ditolak" + +#: cps/templates/modal_dialogs.html:7 +msgid "Select Allowed/Denied Custom Column Values" +msgstr "Pilih Nilai Kolom Kustom yang Diizinkan/Ditolak" + +#: cps/templates/modal_dialogs.html:8 +msgid "Select Allowed/Denied Tags of User" +msgstr "Pilih Tag Pengguna yang Diizinkan/Ditolak" + +#: cps/templates/modal_dialogs.html:9 +msgid "Select Allowed/Denied Custom Column Values of User" +msgstr "Pilih Nilai Kolom Pengguna yang Diizinkan/Ditolak" + +#: cps/templates/modal_dialogs.html:15 +msgid "Enter Tag" +msgstr "Masukkan Tag" + +#: cps/templates/modal_dialogs.html:24 +msgid "Add View Restriction" +msgstr "Tambahkan Batasan Tampilan" + +#: cps/templates/modal_dialogs.html:50 +msgid "This book format will be permanently erased from database" +msgstr "Format buku ini akan dihapus secara permanen dari database" + +#: cps/templates/modal_dialogs.html:51 +msgid "This book will be permanently erased from database" +msgstr "Buku ini akan dihapus secara permanen dari basis data" + +#: cps/templates/modal_dialogs.html:52 +msgid "and hard disk" +msgstr "dan harddisk" + +#: cps/templates/modal_dialogs.html:56 +msgid "Important Kobo Note: deleted books will remain on any paired Kobo device." +msgstr "Catatan Penting Kobo: buku yang dihapus akan tetap ada di perangkat Kobo yang telah dipasangkan." + +#: cps/templates/modal_dialogs.html:57 +msgid "Books must first be archived and the device synced before a book can safely be deleted." +msgstr "Buku harus diarsipkan terlebih dahulu dan perangkat disinkronkan sebelum buku dapat dihapus dengan aman." + +#: cps/templates/modal_dialogs.html:76 +msgid "Choose File Location" +msgstr "Pilih Lokasi Berkas" + +#: cps/templates/modal_dialogs.html:82 +msgid "type" +msgstr "tipe" + +#: cps/templates/modal_dialogs.html:83 +msgid "name" +msgstr "nama" + +#: cps/templates/modal_dialogs.html:84 +msgid "size" +msgstr "ukuran" + +#: cps/templates/modal_dialogs.html:90 +msgid "Parent Directory" +msgstr "Direktori Induk" + +#: cps/templates/modal_dialogs.html:98 +msgid "Select" +msgstr "Pilih" + +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 +msgid "Ok" +msgstr "Ok" + +#: cps/templates/osd.xml:5 +msgid "Calibre-Web eBook Catalog" +msgstr "Katalog eBook Calibre-Web" + +#: cps/templates/read.html:6 +msgid "epub Reader" +msgstr "Pembaca EPUB" + +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Terang" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Gelap" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "Sepia" + +#: cps/templates/read.html:84 +msgid "Black" +msgstr "Hitam" + +#: cps/templates/read.html:88 +msgid "Reflow text when sidebars are open." +msgstr "Reflow teks saat sidebar terbuka." + +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + +#: cps/templates/readcbr.html:7 +msgid "Comic Reader" +msgstr "Pembaca Komik" + +#: cps/templates/readcbr.html:92 +msgid "Keyboard Shortcuts" +msgstr "Pintasan Keyboard" + +#: cps/templates/readcbr.html:95 +msgid "Previous Page" +msgstr "Halaman Sebelumnya" + +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 +msgid "Next Page" +msgstr "Halaman Selanjutnya" + +#: cps/templates/readcbr.html:97 +msgid "Scale to Best" +msgstr "Skala ke Terbaik" + +#: cps/templates/readcbr.html:98 +msgid "Scale to Width" +msgstr "Skala ke Lebar" + +#: cps/templates/readcbr.html:99 +msgid "Scale to Height" +msgstr "Skala ke Tinggi" + +#: cps/templates/readcbr.html:100 +msgid "Scale to Native" +msgstr "Skalakan ke Asli" + +#: cps/templates/readcbr.html:101 +msgid "Rotate Right" +msgstr "Putar ke Kanan" + +#: cps/templates/readcbr.html:102 +msgid "Rotate Left" +msgstr "Putar ke Kiri" + +#: cps/templates/readcbr.html:103 +msgid "Flip Image" +msgstr "Balikkan Gambar" + +#: cps/templates/readcbr.html:125 +msgid "Scale" +msgstr "Skala" + +#: cps/templates/readcbr.html:128 +msgid "Best" +msgstr "Terbaik" + +#: cps/templates/readcbr.html:129 +msgid "Width" +msgstr "Lebar" + +#: cps/templates/readcbr.html:130 +msgid "Height" +msgstr "Tinggi" + +#: cps/templates/readcbr.html:131 +msgid "Native" +msgstr "Asli" + +#: cps/templates/readcbr.html:136 +msgid "Rotate" +msgstr "Putar" + +#: cps/templates/readcbr.html:147 +msgid "Flip" +msgstr "Balik" + +#: cps/templates/readcbr.html:150 +msgid "Horizontal" +msgstr "Horizontal" + +#: cps/templates/readcbr.html:151 +msgid "Vertical" +msgstr "Vertical" + +#: cps/templates/readcbr.html:156 +msgid "Direction" +msgstr "Arah Baca" + +#: cps/templates/readcbr.html:159 +msgid "Left to Right" +msgstr "Kiri ke Kanan" + +#: cps/templates/readcbr.html:160 +msgid "Right to Left" +msgstr "Kanan ke Kiri" + +#: cps/templates/readcbr.html:168 +msgid "Reset to Top" +msgstr "Atur Ulang ke Atas" + +#: cps/templates/readcbr.html:169 +msgid "Remember Position" +msgstr "Ingat Posisi" + +#: cps/templates/readcbr.html:174 +msgid "Scrollbar" +msgstr "Scrollbar" + +#: cps/templates/readcbr.html:177 +msgid "Show" +msgstr "Tampilkan" + +#: cps/templates/readcbr.html:178 +msgid "Hide" +msgstr "Sembunyikan" + +#: cps/templates/readdjvu.html:5 +msgid "DJVU Reader" +msgstr "Pembaca DJVU" + +#: cps/templates/readpdf.html:32 +msgid "PDF Reader" +msgstr "Pembaca PDF" + +#: cps/templates/readtxt.html:6 +msgid "txt Reader" +msgstr "Pembaca txt" + +#: cps/templates/register.html:4 +msgid "Register New Account" +msgstr "Daftar Akun Baru" + +#: cps/templates/register.html:10 +msgid "Choose a username" +msgstr "Pilih nama pengguna" + +#: cps/templates/register.html:15 +msgid "Your Email" +msgstr "Alamat email Anda" + +#: cps/templates/remote_login.html:5 +msgid "Magic Link - Authorise New Device" +msgstr "Magic Link - Otorisasi Perangkat Baru" + +#: cps/templates/remote_login.html:7 +msgid "On another device, login and visit:" +msgstr "Di perangkat lain, masuk dan kunjungi:" + +#: cps/templates/remote_login.html:11 +msgid "Once verified, you will automatically be logged in on this device." +msgstr "Setelah diverifikasi, Anda akan secara otomatis masuk ke perangkat ini." + +#: cps/templates/remote_login.html:14 +msgid "This verification link will expire in 10 minutes." +msgstr "Tautan verifikasi ini akan kedaluwarsa dalam 10 menit." + +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "Hasilkan Thumbnail Sampul Seri" + +#: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "Tidak ada hasil yang ditemukan" + +#: cps/templates/search.html:7 +msgid "Search Term:" +msgstr "Istilah Penelusuran:" + +#: cps/templates/search.html:9 +msgid "Results for:" +msgstr "Hasil untuk:" + +#: cps/templates/search_form.html:21 +msgid "Published Date From" +msgstr "Tanggal Diterbitkan Dari" + +#: cps/templates/search_form.html:31 +msgid "Published Date To" +msgstr "Tanggal Diterbitkan Hingga" + +#: cps/templates/search_form.html:59 +msgid "Exclude Tags" +msgstr "Kecualikan Tag" + +#: cps/templates/search_form.html:77 +msgid "Exclude Series" +msgstr "Kecualikan Seri" + +#: cps/templates/search_form.html:95 +msgid "Exclude Shelves" +msgstr "Kecualikan Rak" + +#: cps/templates/search_form.html:115 +msgid "Exclude Languages" +msgstr "Kecualikan Bahasa" + +#: cps/templates/search_form.html:126 +msgid "Extensions" +msgstr "Ekstensi" + +#: cps/templates/search_form.html:134 +msgid "Exclude Extensions" +msgstr "Kecualikan Ekstensi" + +#: cps/templates/search_form.html:144 +msgid "Rating Above" +msgstr "Peringkat Diatas" + +#: cps/templates/search_form.html:148 +msgid "Rating Below" +msgstr "Peringkat Dibawah" + +#: cps/templates/search_form.html:180 +msgid "From:" +msgstr "Dari:" + +#: cps/templates/search_form.html:190 +msgid "To:" +msgstr "Hingga:" + +#: cps/templates/shelf.html:13 +msgid "Delete this Shelf" +msgstr "Hapus rak ini" + +#: cps/templates/shelf.html:14 +msgid "Edit Shelf Properties" +msgstr "Edit Properti Rak" + +#: cps/templates/shelf.html:17 +msgid "Arrange books manually" +msgstr "Atur buku secara manual" + +#: cps/templates/shelf.html:18 +msgid "Disable Change order" +msgstr "Nonaktifkan Ubah urutan" + +#: cps/templates/shelf.html:18 +msgid "Enable Change order" +msgstr "Aktifkan Ubah urutan" + +#: cps/templates/shelf_edit.html:14 +msgid "Share with Everyone" +msgstr "Bagikan dengan Semua Orang" + +#: cps/templates/shelf_edit.html:21 +msgid "Sync this shelf with Kobo device" +msgstr "Sinkronkan rak ini dengan perangkat Kobo" + +#: cps/templates/shelf_order.html:5 +msgid "Drag to Rearrange Order" +msgstr "Seret untuk Mengatur Ulang Urutan" + +#: cps/templates/shelf_order.html:33 +msgid "Hidden Book" +msgstr "Buku Tersembunyi" + +#: cps/templates/stats.html:7 +msgid "Library Statistics" +msgstr "Statistik Pustaka" + +#: cps/templates/stats.html:12 +msgid "Books in this Library" +msgstr "Buku dalam Pustaka Ini" + +#: cps/templates/stats.html:16 +msgid "Authors in this Library" +msgstr "Penulis dalam Pustaka Ini" + +#: cps/templates/stats.html:20 +msgid "Categories in this Library" +msgstr "Kategori dalam Pustaka Ini" + +#: cps/templates/stats.html:24 +msgid "Series in this Library" +msgstr "Seri dalam Pustaka Ini" + +#: cps/templates/stats.html:29 +msgid "System Statistics" +msgstr "Statistik Sistem" + +#: cps/templates/stats.html:33 +msgid "Program" +msgstr "Pustaka Program" + +#: cps/templates/stats.html:34 +msgid "Installed Version" +msgstr "Versi Terpasang" + +#: cps/templates/tasks.html:12 +msgid "User" +msgstr "Pengguna" + +#: cps/templates/tasks.html:14 +msgid "Task" +msgstr "Tugas" + +#: cps/templates/tasks.html:15 +msgid "Status" +msgstr "Status" + +#: cps/templates/tasks.html:16 +msgid "Progress" +msgstr "Kemajuan" + +#: cps/templates/tasks.html:17 +msgid "Run Time" +msgstr "Waktu Jalan" + +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "Tindakan" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "Tugas ini akan dibatalkan. Setiap kemajuan yang dibuat oleh tugas ini akan disimpan." + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "Jika ini adalah tugas terjadwal, ini akan dijalankan ulang selama waktu terjadwal berikutnya." + +#: cps/templates/user_edit.html:20 +msgid "Reset user Password" +msgstr "Atur ulang kata sandi pengguna" + +#: cps/templates/user_edit.html:43 +msgid "Language of Books" +msgstr "Bahasa Buku" + +#: cps/templates/user_edit.html:54 +msgid "OAuth Settings" +msgstr "Pengaturan OAuth" + +#: cps/templates/user_edit.html:56 +msgid "Link" +msgstr "Tautan" + +#: cps/templates/user_edit.html:58 +msgid "Unlink" +msgstr "Batalkan tautan" + +#: cps/templates/user_edit.html:64 +msgid "Kobo Sync Token" +msgstr "Token Kobo Sync" + +#: cps/templates/user_edit.html:66 +msgid "Create/View" +msgstr "Buat/Lihat" + +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "Paksa sinkronisasi kobo penuh" + +#: cps/templates/user_edit.html:88 +msgid "Add allowed/Denied Custom Column Values" +msgstr "Tambahkan Nilai Kolom Kustom yang Diizinkan/Ditolak" + +#: cps/templates/user_edit.html:137 +msgid "Sync only books in selected shelves with Kobo" +msgstr "Sinkronkan hanya buku di rak yang dipilih dengan Kobo" + +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 +msgid "Delete User" +msgstr "Hapus Pengguna" + +#: cps/templates/user_edit.html:159 +msgid "Generate Kobo Auth URL" +msgstr "Hasilkan URL Autentikasi Kobo" + +#: cps/templates/user_table.html:80 cps/templates/user_table.html:103 +msgid "Select..." +msgstr "Pilih..." + +#: cps/templates/user_table.html:131 +msgid "Edit User" +msgstr "Edit Pengguna" + +#: cps/templates/user_table.html:134 +msgid "Enter Username" +msgstr "Masukkan Nama Pengguna" + +#: cps/templates/user_table.html:135 +#, fuzzy +msgid "Enter Email" +msgstr "Email tes" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "Enter eReader Email" +msgstr "Alamat E-mail untuk Kirim ke E-Reader" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "eReader Email" +msgstr "Email E-Reader" + +#: cps/templates/user_table.html:137 +msgid "Locale" +msgstr "Lokal" + +#: cps/templates/user_table.html:138 +msgid "Visible Book Languages" +msgstr "Bahasa Buku Terlihat" + +#: cps/templates/user_table.html:139 +msgid "Edit Allowed Tags" +msgstr "Edit Tag yang Diizinkan" + +#: cps/templates/user_table.html:139 +msgid "Allowed Tags" +msgstr "Tag yang Diizinkan" + +#: cps/templates/user_table.html:140 +msgid "Edit Denied Tags" +msgstr "Edit Tag yang Ditolak" + +#: cps/templates/user_table.html:140 +msgid "Denied Tags" +msgstr "Tag yang Ditolak" + +#: cps/templates/user_table.html:141 +msgid "Edit Allowed Column Values" +msgstr "Edit Nilai Kolom yang Diizinkan" + +#: cps/templates/user_table.html:141 +msgid "Allowed Column Values" +msgstr "Nilai Kolom yang Diizinkan" + +#: cps/templates/user_table.html:142 +msgid "Edit Denied Column Values" +msgstr "Edit Nilai Kolom yang Ditolak" + +#: cps/templates/user_table.html:142 +msgid "Denied Column Values" +msgstr "Nilai Kolom yang Ditolak" + +#: cps/templates/user_table.html:144 +msgid "Change Password" +msgstr "Ubah Kata Sandi" + +#: cps/templates/user_table.html:147 +msgid "View" +msgstr "Tampilan" + +#: cps/templates/user_table.html:150 +msgid "Edit Public Shelves" +msgstr "Edit Rak Publik" + +#: cps/templates/user_table.html:152 +msgid "Sync selected Shelves with Kobo" +msgstr "Sinkronkan Rak yang dipilih dengan Kob" + +#: cps/templates/user_table.html:156 +#, fuzzy +msgid "Show Read/Unread Section" +msgstr "Tampilkan pilihan baca/belum dibaca" + diff --git a/cps/translations/it/LC_MESSAGES/messages.mo b/cps/translations/it/LC_MESSAGES/messages.mo index 0fc468d18..30e4d595e 100644 Binary files a/cps/translations/it/LC_MESSAGES/messages.mo and b/cps/translations/it/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/it/LC_MESSAGES/messages.po b/cps/translations/it/LC_MESSAGES/messages.po index 879a4cba1..738002da0 100644 --- a/cps/translations/it/LC_MESSAGES/messages.po +++ b/cps/translations/it/LC_MESSAGES/messages.po @@ -2,755 +2,816 @@ # Copyright (C) 2016 Smart Cities Community # This file is distributed under the same license as the Calibre-Web # Juan F. Villa , 2016. +# Massimo Pissarello , 2023. msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" -"PO-Revision-Date: 2017-04-04 15:09+0200\n" -"Last-Translator: ElQuimm \n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" +"PO-Revision-Date: 2023-02-04 20:25+0100\n" +"Last-Translator: Massimo Pissarello \n" "Language: it\n" -"Language-Team: \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Language-Team: Italian <>\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "non installato" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "installato" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Statistiche" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +msgid "Server restarted, please reload page." msgstr "Server riavviato, per favore ricarica la pagina" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +msgid "Performing Server shutdown, please close window." msgstr "Eseguo l'arresto del server, per favore chiudi la finestra" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Ricollegato con successo" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "OK! Database riconnesso" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Comando sconosciuto" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +msgid "Success! Books queued for Metadata Backup" +msgstr "OK! Libri in coda per il backup dei metadati" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Sconosciuto" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Pagina di amministrazione" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Configurazione di base" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Configurazione dell'interfaccia utente" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" msgstr "Modifica gli utenti" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Tutti" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "Utente non trovato" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" -msgstr "{} utente eliminato con successo" +msgstr "{} utenti eliminati con successo" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" -msgstr "tutte le lingue presenti" +msgstr "Mostra tutto" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "Richiesta non formulata correttamente" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "Il nome dell'utente Guest (ospite) non può essere modificato" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "L'utente Guest (ospite) non può avere questo ruolo" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "Non rimarrebbe nessun utente amministratore, non posso rimuovere il ruolo di amministratore" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" -msgstr "Il valore deve essere o vero o flaso" +msgstr "Il valore deve essere o vero o falso" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "Ruolo non valido" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" -msgstr "L'utente Guest (ospite) non può avere questa schermata" +msgstr "L'utente Guest (ospite) non può visualizzare questa schermata" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" -msgstr "Visualizzazione invalida" +msgstr "Visualizzazione non valida" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "Le impostazioni locali dell'utente Guest (ospite) sono determinate automaticamente e non possono essere configurate" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "Nessuna lingua valida indicata" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "Nessuna lingua valida per il libro" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "Parametro non trovato" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "Colonna di lettura non valida" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "Colonna con restrizioni non valida" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "La configurazione di Calibre-Web è stata aggiornata" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "Vuoi veramente eliminare il token di Kobo?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "Vuoi veramente eliminare questo dominio?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "Vuoi veramente eliminare questo utente?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Vuoi veramente eliminare questo scaffale?" -#: cps/admin.py:580 +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" -msgstr "Sei sicuro di voler modificare le impostazioni locali dell'/degli utente/i selezionato/i?" +msgstr "Sei sicuro di voler modificare le impostazioni locali del/degli utente/i selezionato/i?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" -msgstr "Sei sicuro di voler modificare le impostazioni delle lingue visualizzabili dell'/degli utente/i selezionato/i?" +msgstr "Sei sicuro di voler modificare le impostazioni delle lingue visualizzabili dall'/dagli utente/i selezionato/i?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" -msgstr "Sei sicuro di voler modificare il ruolo evidenziato dell'/degli utente/i selezionato/i?" +msgstr "Sei sicuro di voler modificare il ruolo evidenziato del/degli utente/i selezionato/i?" -#: cps/admin.py:586 -#, fuzzy +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" -msgstr "Sei sicuro di voler modificare le impostazioni delle restrizioni di visualizzazione dell'/degli utente/i selezionato/i?" +msgstr "Sei sicuro di voler modificare le restrizioni selezionate del/degli utente/i selezionato/i?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" -msgstr "Sei sicuro di voler modificare le impostazioni delle restrizioni di visualizzazione dell'/degli utente/i selezionato/i?" +msgstr "Sei sicuro di voler modificare le restrizioni di visibilità selezionate per l'utente(i) selezionato(i)?" -#: cps/admin.py:590 +#: cps/admin.py:622 msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Sei sicuro di voler modificare il comportamento di sincronizzazione dello scaffale per l'/gli utente/i selezionato/i?" -#: cps/admin.py:592 +#: cps/admin.py:624 msgid "Are you sure you want to change Calibre library location?" msgstr "Sei sicuro di voler modificare la posizione della libreria di Calibre?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "Etichetta non trovata" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "Calibre-Web cercherà le copertine aggiornate e aggiornerà le miniature delle copertine, questo richiederà un po' di tempo." -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "Azione non valida" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Sei sicuro di voler eliminare il database sincronizzato di Calibre-Web e forzare una sincronizzazione completa con il tuo lettore Kobo?" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Nega" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Permetti" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{} voci di sincronizzazione eliminate" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Etichetta non trovata" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Azione non valida" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json non è configurato per Web Application" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" -msgstr "La posizione del Logfile non è valida, per favore indica il percorso corretto" +msgstr "La posizione del file di log non è valida, per favore indica il percorso corretto" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" -msgstr "La posizione dell'Access Logfile non è valida, per favore indica il percorso corretto" +msgstr "La posizione del file di log di accesso non è valida, per favore indica il percorso corretto" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Per favore digita un Provider LDAP, porta, DN e User Object Identifier" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "Per favore digita nome di utente e password del servizio LDAP" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "Per favore indica un account di servizio LDAP" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "LDAP Group Object Filter deve avere un \"%s\" Format Identifier" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" -msgstr "LDAP Group Object Filter contiene una parentesi senza la corrispettiva" +msgstr "LDAP Group Object Filter contiene una parentesi senza la corrispondenza" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "LDAP User Object Filter deve avere un \"%s\" Format Identifier" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" -msgstr "LDAP User Object Filter contiene una parentesi senza la corrispettiva" +msgstr "LDAP User Object Filter contiene una parentesi senza la corrispondenza" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "LDAP Member User Filter deve avere un \"%s\" Format Identifier" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" -msgstr "LDAP Member User Filter contiene una parentesi senza la corrispettiva" +msgstr "LDAP Member User Filter contiene una parentesi senza la corrispondenza" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "LDAP CACertificate, il certificato o la posizione della chiave non sono corretti, per favore indica il percorso corretto" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "I parametri del DB non sono scrivibili" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "La posizione del DB non è valida, per favore indica il percorso corretto" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "Il DB non è scrivibile" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "La posizione del Keyfile non è valida, per favore indica il percorso corretto" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "La posizione del Certfile non è valida, per favore indica il percorso corretto" - -#: cps/admin.py:1316 -msgid "Database Settings updated" -msgstr "Configurazione del Database aggiornata" - -#: cps/admin.py:1324 -msgid "Database Configuration" -msgstr "Configurazione del Database" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Per favore compila tutti i campi!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "L'e-mail non proviene da un dominio valido" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "Aggiungi un nuovo utente" -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "L'utente '%(user)s' è stato creato" - -#: cps/admin.py:1369 -msgid "Found an existing account for this e-mail address or name." -msgstr "Trovato un account esistente con questo e-mail o nome di utente" - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "L'utente '%(nick)s' è stato eliminato" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "Non posso eliminare l'utente Guest (ospite)" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Non rimarrebbe nessun utente amministratore, non posso eliminare l'utente" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Modifica l'utente %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "L'utente '%(nick)s' è stato aggiornato" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Si è verificato un errore sconosciuto: per favore riprova." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Modifica le impostazioni del server e-mail" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "L'account Gmail è stato verificato con successo" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "OK! Account Gmail verificato." -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Errore nel database: %(error)s." + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" -msgstr "L'e-mail di test è stato accodato con successo per essere spedito a %(email)s, per favore verifica tramite il pulsante 'Compito' il risultato" +msgstr "L'e-mail di test è stato accodata con successo per essere spedita a %(email)s, per favore verifica tramite il pulsante 'Attività' il risultato" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Si è verificato un errore nell'invio dell'e-mail di test: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Per favore prima configura il tuo indirizzo e-mail..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" -msgstr "Configurazione del server e-mail aggiornata" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" +msgstr "Le impostazioni del server e-mail sono state aggiornate" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "Modifica le impostazioni delle attività pianificate" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "Ora di inizio non valida per l'attività specificata" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "Durata non valida per l'attività specificata" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "Impostazioni delle attività pianificate aggiornate" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Si è verificato un errore sconosciuto: per favore riprova." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "Il DB delle impostazioni non è scrivibile" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" -msgstr "La password dell'utente %(user)s è stata resettata" +msgid "Edit User %(nick)s" +msgstr "Modifica l'utente %(nick)s" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." -msgstr "Configura dapprima le impostazioni del server SMTP..." +#: cps/admin.py:1423 +#, python-format +msgid "Success! Password for user %(user)s reset" +msgstr "OK! Reimpostazione della password per l'utente %(user)s" -#: cps/admin.py:1619 +#: cps/admin.py:1429 +msgid "Oops! Please configure the SMTP mail settings." +msgstr "Configura prima le impostazioni del server SMTP." + +#: cps/admin.py:1440 msgid "Logfile viewer" -msgstr "Visualizzatore del Logfile" +msgstr "Visualizzatore del file di log" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" -msgstr "Richiedo il pacchetto di aggiornamento" +msgstr "Richiesta del pacchetto di aggiornamento" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" -msgstr "Scarico il pacchetto di aggiornamento" +msgstr "Download del pacchetto di aggiornamento" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" -msgstr "Decomprimo il pacchetto di aggiornamento" +msgstr "Decompressione del pacchetto di aggiornamento" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" -msgstr "Sostituisco i file" +msgstr "Sostituzione dei file" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Le connessioni al database sono chiuse" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" -msgstr "Arresto il server" +msgstr "Arresto del server" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Aggiornamento completato, per favore premi ok e ricarica la pagina" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Aggiornamento non riuscito:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "Errore HTTP" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Errore di connessione" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Tempo scaduto nello stabilire la connessione" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Errore generale" -#: cps/admin.py:1696 +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" msgstr "Il file di aggiornamento non può essere salvato nella cartella temporanea" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "Durante l'aggiornamento non è stato possibile sostituire alcuni file" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" -msgstr "Fallita l'estrazione di almeno un utente LDAP" +msgstr "Impossibile estrarre almeno un utente LDAP" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" -msgstr "Fallita la creazione di almeno un utente LDAP" +msgstr "Impossibile creare almeno un utente LDAP" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Errore: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Errore: nessun utente restituito in risposta dal server LDAP" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" -msgstr "Almeno un utente LDAP non è stato trovato nel database" +msgstr "Non è stato trovato nessun utente LDAP nel database" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} utente importato con successo" -#: cps/converter.py:30 -msgid "not configured" -msgstr "non configurato" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "La posizione del DB non è valida, per favore indica il percorso corretto" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "Il DB non è scrivibile" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "La posizione del Keyfile non è valida, per favore indica il percorso corretto" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "La posizione del Certfile non è valida, per favore indica il percorso corretto" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "Impostazioni database aggiornate" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "Configurazione del database" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Per favore compila tutti i campi!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "L'e-mail non proviene da un dominio valido" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Aggiungi un nuovo utente" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "L'utente '%(user)s' è stato creato" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "Trovato un account esistente con questa e-mail o nome utente" + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "L'utente '%(nick)s' è stato eliminato" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Non posso eliminare l'utente Guest (ospite)" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Non rimarrebbe nessun utente amministratore, non posso eliminare l'utente" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "L'indirizzo e-mail non può essere vuoto e deve essere un recapito valido" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "L'utente '%(nick)s' è stato aggiornato" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "non installato" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Mancano i permessi di esecuzione" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" -msgstr "La colonna personale no.%(column)d non esiste nel database di Calibre" +msgid "Custom Column No.%(column)d does not exist in calibre database" +msgstr "La colonna personalizzata no.%(column)d non esiste nel database di Calibre" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Il formato del libro è stato eliminato con successo" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Nessuna" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Il libro é stato eliminato con successo" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" +msgstr "Il libro selezionato non è disponibile. Il file non esiste o non è accessibile" -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" -msgstr "Errore durante l'apertura del libro selezionato. Il file non esiste o il file non è accessibile" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "L'utente non ha i permessi per caricare le copertine" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "modifica i metadati" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "%(seriesindex)s non è un numero valido, proseguo" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s non è una lingua valida" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "Non è consentito caricare file con l'estensione '%(ext)s' su questo server" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Il file da caricare deve avere un'estensione" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Impossibile creare la cartella %(path)s (autorizzazione negata)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Il salvataggio del file %(file)s non è riuscito." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Errore nel database: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Ho aggiunto il formato %(ext)s al libro %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" -msgstr "Gli identificatori non tengono conto delle lettere maiuscole o minuscole, sovrascrivo l'identificatore precedente" +msgstr "Gli identificatori non fanno distinzione tra maiuscole e minuscole, sovrascrivendo il vecchio identificatore" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "I metadati sono stati aggiornati con successo" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Errore nella modifica del libro. Per favore verifica i dettagli nel file di registro (logfile)" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "Errore durante la modifica del libro: {}" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Probabilmente il libro caricato esiste già nella libreria; considera di cambiare prima di sottoporlo nuovamente: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "Il file %(filename)s non può essere salvato nella cartella temporanea" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Impossibile spostare il file della copertina %(file)s: %(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Il file %(file)s è stato caricato" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Mancano o il formato sorgente o quello di destinazione, entrambi necessari alla conversione" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Libro accodato con successo per essere convertito in %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Si è verificato un errore durante la conversione del libro: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Probabilmente il libro caricato esiste già nella libreria, cambialo prima di caricarlo nuovamente:" + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s non è una lingua valida" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Non è consentito caricare file con l'estensione '%(ext)s' su questo server" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Il file da caricare deve avere un'estensione" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Il file %(filename)s non può essere salvato nella cartella temporanea" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Impossibile spostare il file della copertina %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Il formato del libro è stato eliminato con successo" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Il libro è stato eliminato con successo" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "Mancano le autorizzazioni per eliminare i libri" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "modifica i metadati" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s non è un numero valido, lo salto" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "L'utente non ha i permessi per caricare formati di file aggiuntivi" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Impossibile creare il percorso %(path)s (autorizzazione negata)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Il salvataggio del file %(file)s non è riuscito." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Ho aggiunto il formato %(ext)s al libro %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "La configurazione di Google Drive non è stata completata correttamente. Prova a disattivare e riattivare nuovamente Google Drive" #: cps/gdrive.py:95 msgid "Callback domain is not verified, please follow steps to verify domain in google developer console" -msgstr "Callback domain non è stato verificato. Per favore intraprendi il necessario per verificare il dominio nella developer console di Google" +msgstr "Il dominio di callback non è stato verificato. Per favore segui i passaggi per verificare il dominio nella console per sviluppatori di Google" #: cps/helper.py:80 #, python-format msgid "%(format)s format not found for book id: %(book)d" msgstr "Formato %(format)s non trovato per il libro: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s non trovato su Google Drive: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s non trovato: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" -msgstr "Invia a Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +msgid "Send to eReader" +msgstr "Invia all'eReader" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." -msgstr "Questo e-mail è stato spedito tramite Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +msgid "This Email has been sent via Calibre-Web." +msgstr "Questa e-mail è stata inviata tramite Calibre-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" -msgstr "E-mail di test da Calibre-Web" +#: cps/helper.py:114 +msgid "Calibre-Web Test Email" +msgstr "E-mail di prova di Calibre-Web" -#: cps/helper.py:113 -msgid "Test e-mail" -msgstr "E-mail di test" +#: cps/helper.py:115 +msgid "Test Email" +msgstr "E-mail di prova" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Inizia con Calibre-Web" -#: cps/helper.py:135 +#: cps/helper.py:137 #, python-format -msgid "Registration e-mail for user: %(name)s" -msgstr "E-mail di registrazione dell'utente: %(name)s" +msgid "Registration Email for user: %(name)s" +msgstr "E-mail di registrazione per l'utente: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 +#: cps/helper.py:148 cps/helper.py:154 #, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" -msgstr "Converti %(orig)s in %(format)s e spedisci a Kindle" +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "Converti %(orig)s in %(format)s e invia all'eReader" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 #, python-format -msgid "Send %(format)s to Kindle" -msgstr "Invia %(format)s a Kindle" +msgid "Send %(format)s to eReader" +msgstr "Invia %(format)s all'eReader" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, python-format -msgid "%(book)s send to Kindle" -msgstr "%(book)s inviato a Kindle" +msgid "%(book)s send to eReader" +msgstr "%(book)s inviato all'eReader" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Il file richiesto non può essere letto. I permessi sono corretti?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "Impossibile impostare lo stato di lettura: {}" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" -msgstr "L'eliminazione della cartella del libro %(id)s non è riuscita, il percorso ha sottocartelle: %(path)s" +msgstr "L'eliminazione della cartella del libro %(id)s non è riuscita, il percorso ha delle sottocartelle: %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "L'eliminazione del libro %(id)s non è riuscita: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "Eliminazione del libro %(id)s unicamente dal database. Il percorso del libro nel database non è valido: %(path)s" -#: cps/helper.py:388 +#: cps/helper.py:450 #, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "La modifica del titolo da '%(src)s' a '%(dest)s' è terminata con l'errore: %(error)s" +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "La modifica dell'autore da '%(src)s' a '%(dest)s' è terminata con l'errore: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "La modifica del file nella cartella da '%(src)s' a '%(dest)s' è terminata con l'errore: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "File %(file)s non trovato su Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "La modifica del titolo da '%(src)s' a '%(dest)s' è terminata con l'errore: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "Errore nel rinominare il file nel percorso: {}" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" -msgstr "Non ho trovato la cartella %(path)s del libro su Google Drive" +msgstr "Percorso del libro %(path)s non trovato su Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -msgid "Found an existing account for this e-mail address" -msgstr "Ho trovato un account creato in precedenza con questo indirizzo e-mail." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "Trovato un account esistente per questo indirizzo e-mail" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Questo nome di utente è già utilizzato" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" -msgstr "L'e-mail non è scritto in un formato valido" +#: cps/helper.py:664 +msgid "Invalid Email address format" +msgstr "Formato dell'indirizzo e-mail non valido" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "Il modulo Python 'advocate' non è installato, ma è necessario per caricare le copertine" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Errore nello scaricare la copertina" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" -msgstr "Errore di formato della copertina" +msgstr "Errore nel formato della copertina" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "Non sei autorizzato ad accedere a localhost o alla rete locale per caricare le copertine" + +#: cps/helper.py:841 msgid "Failed to create path for cover" -msgstr "Errore nel creare la cartella per la copertina" +msgstr "Errore nel creare il percorso per la copertina" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "Il file della copertina non è in un formato immagine valido o non può essere salvato" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "Solamente i file nei formati jpg/jpeg/png/webp/bmp sono supportati per le copertine" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "Contenuto del file di copertina non valido" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Solamente i file nei formati jpg/jpeg sono supportati per le copertine" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "Non ho trovato il file binario di UnRar" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +msgid "Error executing UnRar" msgstr "Errore nell'eseguire UnRar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Attendi" +#: cps/helper.py:1040 +msgid "Cover" +msgstr "Copertina" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Non riuscito" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "Metti in coda tutti i libri per il backup dei metadati" -#: cps/helper.py:766 -msgid "Started" -msgstr "Avviato" +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "Per favore accedi a Calibe-Web non da localhost per ottenere un api-endpoint valido per il lettore kobo" -#: cps/helper.py:768 -msgid "Finished" -msgstr "Terminato" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Stato sconosciuto" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" -msgstr "Per favore accedi a calibe-web non da localhost per ottenere un api-endpoint valido per il lettore kobo" - -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Configurazione di Kobo" @@ -759,10 +820,10 @@ msgstr "Configurazione di Kobo" msgid "Register with %(provider)s" msgstr "Registra con %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" -msgstr "ora sei connesso come: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" +msgstr "OK! Ora sei connesso come: %(nickname)s" #: cps/oauth_bb.py:148 #, python-format @@ -771,17 +832,17 @@ msgstr "Collegamento a %(oauth)s avvenuto con successo" #: cps/oauth_bb.py:155 msgid "Login failed, No User Linked With OAuth Account" -msgstr "Accesso non riuscito, non c'è un utente collegato all'account OAuth" +msgstr "Accesso non riuscito, non c'è nessun utente collegato all'account OAuth" #: cps/oauth_bb.py:197 #, python-format msgid "Unlink to %(oauth)s Succeeded" -msgstr "Scollegamento da %(oauth)s avvenuto con successo" +msgstr "Scollegamento da %(oauth)s riuscito" #: cps/oauth_bb.py:202 #, python-format msgid "Unlink to %(oauth)s Failed" -msgstr "Scollegamento da %(oauth)s non riuscito" +msgstr "Scollegamento da %(oauth)s non riuscito" #: cps/oauth_bb.py:205 #, python-format @@ -790,19 +851,19 @@ msgstr "Non collegato a %(oauth)s" #: cps/oauth_bb.py:261 msgid "Failed to log in with GitHub." -msgstr "Accesso con GitHub non è riuscito." +msgstr "Impossibile accedere con GitHub." #: cps/oauth_bb.py:267 msgid "Failed to fetch user info from GitHub." -msgstr "Il recupero delle informazioni dell'utente da GitHub non è riuscito." +msgstr "Impossibile recuperare le informazioni utente da GitHub." #: cps/oauth_bb.py:279 msgid "Failed to log in with Google." -msgstr "L'accesso con Google non è riuscito." +msgstr "Impossibile accedere con Google." #: cps/oauth_bb.py:285 msgid "Failed to fetch user info from Google." -msgstr "Il recupero delle informazioni dell'utente da Google non è riuscito." +msgstr "Impossibile recuperare le informazioni utente da Google." #: cps/oauth_bb.py:332 msgid "GitHub Oauth error, please retry later." @@ -820,740 +881,848 @@ msgstr "Google, errore Oauth: per favore riprova più tardi." msgid "Google Oauth error: {}" msgstr "Google, errore Oauth: {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "{} Stelle" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Accesso" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Token non trovato" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Il token è scaduto" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" -msgstr "Riuscito! Torna al tuo dispositivo" +msgstr "OK! Torna al tuo dispositivo" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Libri" -#: cps/render_template.py:41 -msgid "Show recent books" -msgstr "Mostra l'opzione per la selezione dei libri più recenti" - -#: cps/render_template.py:42 cps/templates/index.xml:25 -msgid "Hot Books" -msgstr "Libri popolari" - #: cps/render_template.py:44 -msgid "Show Hot Books" -msgstr "Mostra l'opzione per la selezione dei libri più popolari" +msgid "Show recent books" +msgstr "Mostra i libri recenti" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:45 cps/templates/index.xml:25 +msgid "Hot Books" +msgstr "Libri hot" + +#: cps/render_template.py:47 +msgid "Show Hot Books" +msgstr "Mostra i libri hot" + +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "Libri scaricati" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" -msgstr "Mostra l'opzione per la visualizzazione dei libri scaricati" +msgstr "Mostra i libri scaricati" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" -msgstr "Libri meglio valutati" +msgstr "Libri più votati" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" -msgstr "Mostra l'opzione per la selezione dei libri meglio valutati" +msgstr "Mostra i libri più votati" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Libri letti" -#: cps/render_template.py:61 -msgid "Show read and unread" -msgstr "Mostra l'opzione per la selezione letto e non letto" +#: cps/render_template.py:64 +msgid "Show Read and Unread" +msgstr "Mostra i libri letti e da leggere" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" -msgstr "Libri non letti" +msgstr "Libri da leggere" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" -msgstr "Mostra l'opzione per la selezione dei libri non letti" +msgstr "Mostra da leggere" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" -msgstr "Per scoprire" +msgstr "Da scoprire" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" -msgstr "Mostra libri casualmente" +msgstr "Mostra i libri casualmente" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Categorie" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" -msgstr "Mostra l'opzione per la selezione delle categorie" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +msgid "Show Category Section" +msgstr "Mostra la sezione delle categorie" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Serie" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" -msgstr "Mostra l'opzione per la selezione delle serie" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +msgid "Show Series Section" +msgstr "Mostra la sezione delle serie" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Autori" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" -msgstr "Mostra l'opzione per la selezione degli autori" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +msgid "Show Author Section" +msgstr "Mostra la sezione degli autori" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Editori" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" -msgstr "Mostra l'opzione per la selezione degli editori" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +msgid "Show Publisher Section" +msgstr "Mostra la sezione degli editori" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Lingue" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" -msgstr "Mostra l'opzione per la selezione delle lingue" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +msgid "Show Language Section" +msgstr "Mostra la sezione delle lingue" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Valutazioni" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" -msgstr "Mostra l'opzione per la selezione delle valutazioni" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +msgid "Show Ratings Section" +msgstr "Mostra la sezione delle valutazioni" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Formati file" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" -msgstr "Mostra l'opzione per la selezione del formato dei file" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +msgid "Show File Formats Section" +msgstr "Mostra la sezione dei formati dei file" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Libri archiviati" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" -msgstr "Mostra l'opzione per la selezione dei libri archiviati" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +msgid "Show Archived Books" +msgstr "Mostra i libri archiviati" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "Elenco libri" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" -msgstr "Mostra l'opzione per visualizzare i libri sottoforma di elenco" +msgstr "Mostra l'elenco dei libri" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Lo scaffale specificato non è valido" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Mi spiace, ma non sei autorizzato ad aggiungere libri allo scaffale: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Il libro è gia presente nello scaffale: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Il libro è stato aggiunto allo scaffale: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Non sei autorizzato ad aggiungere libri allo scaffale: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "I libri sono già presenti nello scaffale: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "I libri sono stati aggiunti allo scaffale: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Non posso aggiungere libri allo scaffale: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Il libro è stato rimosso dallo scaffale: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Spiacente, non sei autorizzato a togliere libri dallo scaffale: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Crea uno scaffale" - -#: cps/shelf.py:236 -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Spiacente, non sei autorizzato a modificare questo scaffale" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Modifica uno scaffale" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Lo scaffale %(title)s è stato creato" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Lo scaffale %(title)s è stato modificato" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "C'era un errore" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Esiste già uno scaffale pubblico denominato '%(title)s'." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Esiste già uno scaffale privato denominato '%(title)s'." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Modifica l'ordine dello scaffale: '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Scaffale: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Errore durante l'apertura dello scaffale. Lo scaffale non esiste o non è accessibile" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Dati inattesi durante il processo di aggiornamento" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Nessun aggiornamento disponibile. Hai già installata l'ultima versione" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Nuovo aggiornamento disponibile. Clicca sul pulsante sottostante per aggiornare all'ultima versione." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Impossibile recuperare le informazioni di aggiornamento" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Clicca sul pulsante per aggiornare all'ultima versione stabile." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Nuovo aggiornamento disponibile. Clicca sul pulsante sottostante per aggiornare alla versione: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Non sono disponibili informazioni sulla versione" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Scopri (libri casuali)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "I libri più richiesti" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "I libri scaricati da %(user)s" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Autore: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Editore: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Serie: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Valutazione: %(rating)s stelle" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Formato del file: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Categoria: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Lingua: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Ricerca avanzata" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Cerca" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Downloads" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Elenco delle valutazioni" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Elenco dei formati" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Compito" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Pubblicato dopo il " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Pubblicato prima del " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Valutazione <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Valutazione >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "Stato di lettura = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "Errore di ricerca nelle colonne personalizzate. Per favore riavvia Calibre-Web" -#: cps/web.py:1441 +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Ricerca avanzata" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Lo scaffale specificato non è valido" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Mi spiace, ma non sei autorizzato ad aggiungere libri a questo scaffale" + +#: cps/shelf.py:64 #, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Libro accodato con successo per essere spedito a %(kindlemail)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Il libro è gia presente nello scaffale: %(shelfname)s" -#: cps/web.py:1445 +#: cps/shelf.py:89 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" -msgstr "Oops! Si è verificato un errore durante l'invio di questo libro: %(res)s" +msgid "Book has been added to shelf: %(sname)s" +msgstr "Il libro è stato aggiunto allo scaffale: %(sname)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." -msgstr "Per favore aggiorna il tuo profilo con un indirizzo e-mail Kindle a cui inviare i libri." +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "Non sei autorizzato ad aggiungere libri allo scaffale" -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "I libri sono già presenti nello scaffale: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "I libri sono stati aggiunti allo scaffale: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Non posso aggiungere libri allo scaffale: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Il libro è stato rimosso dallo scaffale: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "Spiacente, ma non sei autorizzato a rimuovere libri da questo scaffale" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Crea uno scaffale" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Spiacente, ma non sei autorizzato a modificare questo scaffale" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Modifica uno scaffale" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "Errore nell'eliminare lo scaffale" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "Lo scaffale è stato eliminato con successo" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Modifica l'ordine dello scaffale: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "Spiacente, ma non sei autorizzato a creare scaffali pubblici" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Lo scaffale %(title)s è stato creato" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Lo scaffale %(title)s è stato modificato" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "C'è stato un errore" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Esiste già uno scaffale pubblico con il nome '%(title)s'." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Esiste già uno scaffale privato con il nome '%(title)s'." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Scaffale: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Errore durante l'apertura dello scaffale. Lo scaffale non esiste o non è accessibile" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Attività" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Attendi" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Non riuscito" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Avviato" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Finito" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "Terminato" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "Annullato" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Stato sconosciuto" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Dati imprevisti durante la lettura delle informazioni di aggiornamento" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Nessun aggiornamento disponibile. Hai già l'ultima versione installata" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "È disponibile un nuovo aggiornamento. Fare clic sul pulsante in basso per aggiornare all'ultima versione" + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Impossibile recuperare le informazioni sull'aggiornamento" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Fare clic sul pulsante in basso per eseguire l'aggiornamento all'ultima versione stabile." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "È disponibile un nuovo aggiornamento. Fare clic sul pulsante in basso per aggiornare alla versione:%(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Nessuna informazione disponibile sulla versione" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Scopri (libri casuali)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Libri hot (i più scaricati)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Libri scaricati da %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Autore: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Editore: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Serie: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "Valutazione: nessuna" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Valutazione: %(rating)s stelle" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Formato del file: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Categoria: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Lingua: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Scaricati" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Elenco delle valutazioni" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Elenco dei formati" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Configura prima le impostazioni del server SMTP." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "OK! Libro in coda per l'invio a %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "Si è verificato un errore durante l'invio del libro: %(res)s" + +#: cps/web.py:1213 +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "Per favore aggiorna il tuo profilo con un'e-mail eReader valida." + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "Il server e-mail non è configurato, per favore contatta l'amministratore" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" -msgstr "Registra" +msgstr "Registrati" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" -msgstr "Il tuo e-mail non è autorizzato alla registrazione" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." +msgstr "La tua e-mail non è consentita." -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." -msgstr "Un messaggio di conferma è stato inviato al tuo recapito e-mail." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." +msgstr "OK! L'e-mail di conferma è stata inviata." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "Non posso attivare l'autenticazione LDAP" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" -msgstr "Fallback login come: '%(nickname)s', il server LDAP non è raggiungibile o l'utente è sconosciuto" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" +msgstr "Accesso di riserva come: '%(nickname)s', il server LDAP non è raggiungibile o l'utente è sconosciuto" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Non posso accedere: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" -msgstr "Nome utente o password errati" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." +msgstr "Nome utente o password errati." -#: cps/web.py:1555 -msgid "New Password was send to your email address" -msgstr "Una nuova password è stata inviata al tuo recapito e-mail" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." +msgstr "OK! La nuova password è stata inviata alla tua e-mail." -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" -msgstr "Per favore digita un nome di utente valido per resettare la password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" +msgstr "Inserisci un nome utente valido per reimpostare la password" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Ora sei connesso come '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "Profilo di %(name)s" -#: cps/web.py:1650 -msgid "Profile updated" -msgstr "Profilo aggiornato" +#: cps/web.py:1416 +msgid "Success! Profile Updated" +msgstr "OK! Profilo aggiornato" + +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "Esiste già un account per questa e-mail." #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "Ho trovato un gmail.json file senza informazione OAuth" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s inviato all'E-Reader" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "Non ho trovato il convertitore %(tool)s di libri di Calibre" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "Non ho trovato il formato %(format)s nel disco" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "La conversione del libro è terminata con un errore sconosciuto" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Si è verificato un errore con il convertitore Kepubify: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" -msgstr "Non ho trovato il file convertito o ci sono più di un file nella cartella %(folder)s" +msgstr "Non ho trovato il file convertito o c'è più di un file nella cartella %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Errore nel convertitore: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "Si è verificato un errore con Calibre: %(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "Convertire" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "Riconessione al database di Calibre" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "E-mail" + +#: cps/tasks/metadata_backup.py:47 +msgid "Backing up Metadata" +msgstr "Backup dei metadati" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "Sono state generate %(count)s miniature delle copertine" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "Miniature delle copertine" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "Sono state generate {0} miniature delle serie" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "Cancellazione della cache delle miniature delle copertine" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Caricamento" + #: cps/templates/admin.html:9 msgid "Users" -msgstr "Elenco utenti" +msgstr "Utenti" #: cps/templates/admin.html:13 cps/templates/login.html:9 #: cps/templates/login.html:10 cps/templates/register.html:9 #: cps/templates/user_edit.html:10 cps/templates/user_table.html:134 msgid "Username" -msgstr "Utente" +msgstr "Nome utente" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" -msgstr "Indirizzo e-mail" +msgid "Email" +msgstr "E-mail" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" -msgstr "Invia all'indirizzo e-mail di Kindle" +msgid "Send to eReader Email" +msgstr "E-mail dell'eReader" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" -msgstr "Amministrazione" +msgstr "Amministratore" #: cps/templates/admin.html:18 cps/templates/login.html:13 #: cps/templates/login.html:14 cps/templates/user_edit.html:23 msgid "Password" msgstr "Password" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Upload" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Download" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" -msgstr "Vedi libri" +msgstr "Visualizza libri" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Modifica" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Elimina" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Scaffale pubblico" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Aggiungi un nuovo utente" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "Importa gli utenti LDAP" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" -msgstr "Configurazione server e-mail" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" +msgstr "Impostazioni server e-mail" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "Indirizzo server SMTP" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "Porta SMTP" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "Crittografia" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" -msgstr "Login SMTP" +msgstr "Accesso SMTP" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "E-mail da" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "Servizio e-mail" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "Gmail via Oauth2" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Configurazione" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Cartella del database di Calibre" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Livello di log" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Porta" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "Porta esterna" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Libri per pagina" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" -msgstr "Uploads" +msgstr "Caricamenti" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Navigazione anonima" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Registrazione pubblica" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" -msgstr "Magic Link Login remoto" +msgstr "Accesso remoto con Magic Link" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" -msgstr "Login reverse proxy" +msgstr "Accesso reverse proxy" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" -msgstr "Nome dell'intestazione Reverse Proxy" +msgstr "Nome dell'intestazione reverse proxy" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 msgid "Edit Calibre Database Configuration" -msgstr "Modifica la configurazione del Database di Calibre" +msgstr "Modifica la configurazione del database di Calibre" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Modifica la configurazione di base" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "Modifica la configurazione dell'interfaccia utente" -#: cps/templates/admin.html:160 -msgid "Administration" -msgstr "Amministrazione" +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "Attività pianificate" -#: cps/templates/admin.html:161 -msgid "Download Debug Package" -msgstr "Scarica Debug Package" +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "Ora di inizio" -#: cps/templates/admin.html:162 -msgid "View Logs" -msgstr "Visualizza Logfile" +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "Durata massima" -#: cps/templates/admin.html:165 +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "Genera miniature" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "Genera miniature delle copertine delle serie" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 msgid "Reconnect Calibre Database" msgstr "Ricollega il database di Calibre" -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "Aggiorna la cache delle miniature" + +#: cps/templates/admin.html:199 +msgid "Administration" +msgstr "Amministrazione" + +#: cps/templates/admin.html:200 +msgid "Download Debug Package" +msgstr "Scarica il pacchetto di debug" + +#: cps/templates/admin.html:201 +msgid "View Logs" +msgstr "Visualizza log" + +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Riavvia Calibre-Web" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Arresta Calibre-Web" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Aggiornamento" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "Informazioni sulla versione" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Versione" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Dettagli" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Versione attuale" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Ricerca aggiornamenti" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Esegui l'aggiornamento" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Vuoi veramente riavviare Calibre-Web?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" -msgstr "Ok" +msgstr "OK" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Annulla" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Vuoi veramente arrestare Calibre-Web?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Aggiornamento, non ricaricare la pagina." @@ -1565,119 +1734,118 @@ msgstr "via" msgid "In Library" msgstr "Nella libreria" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "Ordina secondo la data dei libri, prima i più recenti" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "Ordina secondo la data dei libri, prima i più vecchi" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "Ordina i titoli in ordine alfabetico" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "Ordina i titoli in ordine alfabetico inverso" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "Ordina secondo la data di pubblicazione, prima i più recenti" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "Ordina secondo la data di pubblicazione, prima i più vecchi" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "riduci" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" -msgstr "Altro da" +msgstr "Altri di" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Elimina libro" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Elimina i formati:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Converti il libro nel formato:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Converti da:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" -msgstr "seleziona un formato" +msgstr "seleziona un'opzione" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Converti in:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Converti libro" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Titolo del libro" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Autore" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Descrizione" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "Identificatori" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "Tipo di identificatore" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "Valore dell'identificatore" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Rimuovi" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "Aggiungi un identificatore" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" -msgstr "Categorie" +msgstr "Etichetta" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "ID della serie" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Valutazione" @@ -1689,83 +1857,84 @@ msgstr "Carica la copertina da URL (jpeg - l'immagine della copertina viene scar msgid "Upload Cover from Local Disk" msgstr "Carica la copertina dal disco locale" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Data di pubblicazione" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Editore" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Lingua" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Sì" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "No" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Carica formato" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" -msgstr "Visualizza il libro dopo la modifica" +msgstr "Visualizza il libro dopo averlo salvato" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" -msgstr "Ottieni metadati" +msgstr "Recupera i metadati" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Salva" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Parola chiave" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 msgid "Search keyword" msgstr "Cerca parola chiave" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Fai clic sulla copertina per caricare i metadati nel modulo" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Caricamento in corso..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Chiudi" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Fonte" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Errore nella ricerca!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." -msgstr "Nessun risultato! Prova con un altro criterio di ricerca." +msgstr "Nessun risultato trovato! Prova con un'altra parola chiave." #: cps/templates/book_table.html:12 cps/templates/book_table.html:69 #: cps/templates/user_table.html:14 cps/templates/user_table.html:77 @@ -1783,19 +1952,19 @@ msgstr "Rimuovi le selezioni" #: cps/templates/book_table.html:41 msgid "Exchange author and title" -msgstr "Scambia autore e titolo" +msgstr "Inverti autore e titolo" #: cps/templates/book_table.html:47 msgid "Update Title Sort automatically" -msgstr "Aggiorna automaticamente l'ordinamento dei titoli" +msgstr "Aggiorna automaticamente l'ordinamento per titolo" #: cps/templates/book_table.html:51 msgid "Update Author Sort automatically" -msgstr "Aggiorna automaticamente l'ordinamento degli autori" +msgstr "Aggiorna automaticamente l'ordinamento per autore" #: cps/templates/book_table.html:63 cps/templates/book_table.html:69 msgid "Enter Title" -msgstr "Indica il titolo" +msgstr "Inserisci il titolo" #: cps/templates/book_table.html:63 cps/templates/config_view_edit.html:24 #: cps/templates/shelf_edit.html:8 @@ -1804,23 +1973,23 @@ msgstr "Titolo" #: cps/templates/book_table.html:64 msgid "Enter Title Sort" -msgstr "Indica l'ordinamento del titolo" +msgstr "Inserisci l'ordinamento per titolo" #: cps/templates/book_table.html:64 msgid "Title Sort" -msgstr "Ordinamento del titolo" +msgstr "Ordina per titolo" #: cps/templates/book_table.html:65 msgid "Enter Author Sort" -msgstr "Indica l'ordinamento dell'autore" +msgstr "Inserisci l'ordinamento per autore" #: cps/templates/book_table.html:65 msgid "Author Sort" -msgstr "Ordinamento dell'autore" +msgstr "Ordina per autore" #: cps/templates/book_table.html:66 msgid "Enter Authors" -msgstr "Indica gli autori" +msgstr "Inserisci gli autori" #: cps/templates/book_table.html:67 msgid "Enter Categories" @@ -1828,15 +1997,15 @@ msgstr "Indica le categorie" #: cps/templates/book_table.html:68 msgid "Enter Series" -msgstr "Indica le serie" +msgstr "Inserisci le serie" #: cps/templates/book_table.html:69 msgid "Series Index" -msgstr "Indice delle serie" +msgstr "Numero serie" #: cps/templates/book_table.html:70 msgid "Enter Languages" -msgstr "Indica le lingue" +msgstr "Inserisci le lingue" #: cps/templates/book_table.html:71 msgid "Publishing Date" @@ -1844,37 +2013,45 @@ msgstr "Data di pubblicazione" #: cps/templates/book_table.html:72 msgid "Enter Publishers" -msgstr "Indica gli editori" +msgstr "Inserisci gli editori" #: cps/templates/book_table.html:73 -#, fuzzy msgid "Enter comments" -msgstr "Digita il nome di dominio" +msgstr "Inserisci un commento" #: cps/templates/book_table.html:73 msgid "Comments" -msgstr "" +msgstr "Commento" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "Archiviato" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Letto" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 msgid "Enter " -msgstr "Conferma " +msgstr "Inserisci" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Sei veramente sicuro?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "I libri con il titolo vengono uniti da:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "Nel libro con il titolo:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "Unisci" @@ -1884,7 +2061,7 @@ msgstr "Posizione del database di Calibre" #: cps/templates/config_db.html:22 msgid "Use Google Drive?" -msgstr "Utilizza Google Drive" +msgstr "Usa Google Drive" #: cps/templates/config_db.html:27 msgid "Authenticate Google Drive" @@ -1896,7 +2073,7 @@ msgstr "Cartella di Calibre in Google Drive" #: cps/templates/config_db.html:40 msgid "Metadata Watch Channel ID" -msgstr "ID canale Watch Metadata" +msgstr "ID del canale di visualizzazione dei metadati" #: cps/templates/config_db.html:43 msgid "Revoke" @@ -1904,7 +2081,7 @@ msgstr "Revoca" #: cps/templates/config_db.html:68 msgid "New db location is invalid, please enter valid path" -msgstr "La nuova posizione del DB non è valida, per favore indica un percorso corretto" +msgstr "La nuova posizione del database non è valida, inserisci un percorso valido" #: cps/templates/config_edit.html:18 msgid "Server Configuration" @@ -1916,11 +2093,11 @@ msgstr "Porta del server" #: cps/templates/config_edit.html:28 msgid "SSL certfile location (leave it empty for non-SSL Servers)" -msgstr "Percorso del file del certificato SSL (lascia vuoto per una configurazione del server senza SSL)" +msgstr "Posizione del file del certificato SSL (lascia vuoto per una configurazione del server senza SSL)" #: cps/templates/config_edit.html:35 msgid "SSL Keyfile location (leave it empty for non-SSL Servers)" -msgstr "Percorso del file della chiave SSL (lascia vuoto per una configurazione del server senza SSL)" +msgstr "Posizione del file della chiave SSL (lascia vuoto per una configurazione del server senza SSL)" #: cps/templates/config_edit.html:43 msgid "Update Channel" @@ -1936,23 +2113,23 @@ msgstr "Nightly" #: cps/templates/config_edit.html:50 msgid "Trusted Hosts (Comma Separated)" -msgstr "" +msgstr "Host attendibili (separati da virgole)" #: cps/templates/config_edit.html:61 msgid "Logfile Configuration" -msgstr "Configurazione del Logfile" +msgstr "Configurazione del file di log" #: cps/templates/config_edit.html:77 msgid "Location and name of logfile (calibre-web.log for no entry)" -msgstr "Percorso e nome del Logfile (senza indicazioni sarà calibre-web.log)" +msgstr "Posizione e nome del file di log (se non specificato sarà calibre-web.log)" #: cps/templates/config_edit.html:82 msgid "Enable Access Log" -msgstr "Abilita l'Access Log" +msgstr "Abilita il log degli accessi" #: cps/templates/config_edit.html:85 msgid "Location and name of access logfile (access.log for no entry)" -msgstr "Percorso e nome del Logfile di accesso (senza indicazioni sarà access.log)" +msgstr "Posizione e nome del file di log degli accessi (se non specificato sarà access.log)" #: cps/templates/config_edit.html:96 msgid "Feature Configuration" @@ -1966,6 +2143,10 @@ msgstr "Converti caratteri non inglesi del titolo e dell'autore durante il salva msgid "Enable Uploads" msgstr "Abilita il caricamento" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(per favore assicurati che gli utenti abbiano anche i permessi per caricare i file)" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "Formati di file autorizzati ad essere caricati" @@ -1979,20 +2160,20 @@ msgid "Enable Public Registration" msgstr "Abilita la registrazione pubblica" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" -msgstr "Utilizza l'e-mail quale nome di utente" +msgid "Use Email as Username" +msgstr "Usa l'e-mail come nome utente" #: cps/templates/config_edit.html:132 msgid "Enable Magic Link Remote Login" -msgstr "Attiva login remoto Magic Link" +msgstr "Abilita l'accesso remoto con Magic Link" #: cps/templates/config_edit.html:137 msgid "Enable Kobo sync" -msgstr "Abilita la sincronia per Kobo" +msgstr "Abilita la sincronizzazione Kobo" #: cps/templates/config_edit.html:142 msgid "Proxy unknown requests to Kobo Store" -msgstr "Richieste proxy sconosciute allo store di Kobo" +msgstr "Inoltra le richieste sconosciute al Kobo Store" #: cps/templates/config_edit.html:145 msgid "Server External Port (for port forwarded API calls)" @@ -2000,43 +2181,43 @@ msgstr "Porta esterna del server (per chiamate API alle porte inoltrate)" #: cps/templates/config_edit.html:153 msgid "Use Goodreads" -msgstr "Utilizza Goodreads" +msgstr "Usa Goodreads" #: cps/templates/config_edit.html:154 msgid "Create an API Key" -msgstr "Otteni una chiave API" +msgstr "Crea una chiave API" #: cps/templates/config_edit.html:158 msgid "Goodreads API Key" -msgstr "API di Goodreads" +msgstr "Chiave API di Goodreads" #: cps/templates/config_edit.html:162 msgid "Goodreads API Secret" -msgstr "Goodreads API Secret" +msgstr "API segreta di Goodreads" #: cps/templates/config_edit.html:169 msgid "Allow Reverse Proxy Authentication" -msgstr "Permetti l'autenticazione Reverse Proxy" +msgstr "Consenti autenticazione con reverse proxy" #: cps/templates/config_edit.html:180 msgid "Login type" -msgstr "Tipo di login" +msgstr "Tipo di accesso" #: cps/templates/config_edit.html:182 msgid "Use Standard Authentication" -msgstr "Utilizza l'autenticazione standard" +msgstr "Usa l'autenticazione standard" #: cps/templates/config_edit.html:184 msgid "Use LDAP Authentication" -msgstr "Utilizza l'autenticazione LDAP" +msgstr "Usa l'autenticazione LDAP" #: cps/templates/config_edit.html:187 msgid "Use OAuth" -msgstr "Utilizza OAuth" +msgstr "Usa OAuth" #: cps/templates/config_edit.html:194 msgid "LDAP Server Host Name or IP Address" -msgstr "Nome o indirizzo IP del server LDAP" +msgstr "Nome host o indirizzo IP del server LDAP" #: cps/templates/config_edit.html:198 msgid "LDAP Server Port" @@ -2046,11 +2227,6 @@ msgstr "Porta del server LDAP" msgid "LDAP Encryption" msgstr "Crittografia LDAP" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Nessuna" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2089,11 +2265,11 @@ msgstr "Semplice" #: cps/templates/config_edit.html:242 msgid "LDAP Administrator Username" -msgstr "Nome di utente dell'amministratore LDAP" +msgstr "Nome utente amministratore LDAP" #: cps/templates/config_edit.html:248 msgid "LDAP Administrator Password" -msgstr "Password dell'amministratore LDAP" +msgstr "Password amministratore LDAP" #: cps/templates/config_edit.html:253 msgid "LDAP Distinguished Name (DN)" @@ -2101,35 +2277,35 @@ msgstr "LDAP Distinguished Name (DN)" #: cps/templates/config_edit.html:257 msgid "LDAP User Object Filter" -msgstr "LDAP User Object Filter" +msgstr "Object Filter utente LDAP" #: cps/templates/config_edit.html:262 msgid "LDAP Server is OpenLDAP?" -msgstr "Il server LDAP è un server OpenLDAP." +msgstr "Il server LDAP è OpenLDAP?" #: cps/templates/config_edit.html:264 msgid "Following Settings are Needed For User Import" -msgstr "I seguenti parametri sono necessari per importare utenti" +msgstr "Le seguenti impostazioni sono necessarie per l'importazione degli utenti" #: cps/templates/config_edit.html:266 msgid "LDAP Group Object Filter" -msgstr "LDAP Group Object Filter" +msgstr "Object Filter gruppo LDAP" #: cps/templates/config_edit.html:270 msgid "LDAP Group Name" -msgstr "LDAP Group Name" +msgstr "Nome gruppo LDAP" #: cps/templates/config_edit.html:274 msgid "LDAP Group Members Field" -msgstr "LDAP Group Members Field" +msgstr "Campo membri del gruppo LDAP" #: cps/templates/config_edit.html:278 msgid "LDAP Member User Filter Detection" -msgstr "LDAP Member User Filter Detection" +msgstr "Rilevamento filtro utente membro LDAP" #: cps/templates/config_edit.html:280 msgid "Autodetect" -msgstr "Autodetect - identifica automaticamente" +msgstr "Trova automaticamente" #: cps/templates/config_edit.html:281 msgid "Custom Filter" @@ -2137,7 +2313,7 @@ msgstr "Filtro personalizzato" #: cps/templates/config_edit.html:286 msgid "LDAP Member User Filter" -msgstr "LDAP Member User Filter" +msgstr "Filtro utente membro LDAP" #: cps/templates/config_edit.html:297 #, python-format @@ -2147,16 +2323,16 @@ msgstr "Ottieni le credenziali OAuth di %(provider)s" #: cps/templates/config_edit.html:300 #, python-format msgid "%(provider)s OAuth Client Id" -msgstr "%(provider)s OAuth Client Id" +msgstr "%(provider)s ID client OAuth" #: cps/templates/config_edit.html:304 #, python-format msgid "%(provider)s OAuth Client Secret" -msgstr "%(provider)s OAuth Client Secret" +msgstr "Secret client OAuth %(provider)s" #: cps/templates/config_edit.html:320 msgid "External binaries" -msgstr "Files binari esterni" +msgstr "File binari esterni" #: cps/templates/config_edit.html:326 msgid "Path to Calibre E-Book Converter" @@ -2164,7 +2340,7 @@ msgstr "Percorso del convertitore di libri di Calibre" #: cps/templates/config_edit.html:334 msgid "Calibre E-Book Converter Settings" -msgstr "Configurazione del convertitore di libri di Calibre" +msgstr "Impostazioni del convertitore di libri di Calibre" #: cps/templates/config_edit.html:337 msgid "Path to Kepubify E-Book Converter" @@ -2176,7 +2352,7 @@ msgstr "Percorso del file binario di UnRar" #: cps/templates/config_view_edit.html:17 msgid "View Configuration" -msgstr "Configurazione aspetto biblioteca" +msgstr "Visualizza configurazione" #: cps/templates/config_view_edit.html:32 msgid "No. of Random Books to Display" @@ -2184,9 +2360,9 @@ msgstr "Numero di libri casuali da mostrare" #: cps/templates/config_view_edit.html:36 msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" -msgstr "Numero di autori da mostrare prima di nascondere (0=disabilita mascheramento)" +msgstr "Numero di autori da mostrare prima di nascondere (0=disabilita nascondere)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Tema" @@ -2196,7 +2372,7 @@ msgstr "Tema standard" #: cps/templates/config_view_edit.html:43 msgid "caliBlur! Dark Theme" -msgstr "Tema caliBlur! Dark" +msgstr "Tema caliBlur! scuro" #: cps/templates/config_view_edit.html:47 msgid "Regular Expression for Ignoring Columns" @@ -2204,7 +2380,7 @@ msgstr "Espressione regolare per ignorare le colonne" #: cps/templates/config_view_edit.html:51 msgid "Link Read/Unread Status to Calibre Column" -msgstr "Collega lo stato letto/non letto nella colonna di Calibre" +msgstr "Collega lo stato letto/da leggere nella colonna di Calibre" #: cps/templates/config_view_edit.html:60 msgid "View Restrictions based on Calibre column" @@ -2218,141 +2394,143 @@ msgstr "Espressione regolare per ordinare la visualizzazione dei titoli" msgid "Default Settings for New Users" msgstr "Impostazioni predefinite per i nuovi utenti" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Utente amministratore" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" -msgstr "Permetti il download" +msgstr "Consenti download" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" -msgstr "Permetti l'utilizzo del visualizzatore di libri" +msgstr "Consenti l'utilizzo del visualizzatore di libri" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" -msgstr "Permetti l'upload" +msgstr "Consenti caricamenti" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" -msgstr "Permetti la modifica" +msgstr "Consenti modifiche" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" -msgstr "Permetti l'eliminazione di libri" +msgstr "Consenti l'eliminazione di libri" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" -msgstr "Permetti la modifica della password" +msgstr "Consenti la modifica della password" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" -msgstr "Permetti la modifica degli scaffali pubblici" +msgstr "Consenti la modifica degli scaffali pubblici" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 msgid "Default Language" msgstr "Lingua predefinita" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 msgid "Default Visible Language of Books" msgstr "Lingua predefinita di presentazione dei libri" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Visibilità predefinita per i nuovi utenti" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" -msgstr "Mostra libri scelti aleatoriamente nella vista dettagliata" +msgstr "Mostra i libri casuali nella visualizzazione dettagliata" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" -msgstr "Aggiungi categorie permesse/negate" +msgstr "Aggiungi etichetta consentiti/negati" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" -msgstr "Aggiungi valori personali permetti/nega nelle colonne" +msgstr "Aggiungi valori di colonna personalizzati consentiti/negati" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" -msgstr "Leggi nel navigatore" +msgstr "Leggi nel browser" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" -msgstr "Ascolta nel navigatore" +msgstr "Ascolta nel browser" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "Libro %(index)s di %(range)s" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Pubblicato" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" -msgstr "Marca come non letto" +msgstr "Contrassegna come da leggere" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" -msgstr "Marca come letto" +msgstr "Contrassegna come letto" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Letto" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Ripristina dall'archivio" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Aggiungi all'archivio" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "Archiviato" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Descrizione:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Aggiungi allo scaffale" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Pubblico)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Modifica metadati" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" -msgstr "Scegli il tipo di server" +msgid "Email Account Type" +msgstr "Tipo di account e-mail" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" -msgstr "Utilizza un account e-mail standard" +msgid "Standard Email Account" +msgstr "Account e-mail standard" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "Account Gmail con verifica OAuth2" +msgid "Gmail Account" +msgstr "Account Gmail" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" -msgstr "Configura l'account Gmail quale server e-mail" +msgid "Setup Gmail Account" +msgstr "Configura l'account Gmail" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" -msgstr "Revoca l'accesso Gmail" +msgstr "Revoca l'accesso a Gmail" #: cps/templates/email_edit.html:42 msgid "STARTTLS" @@ -2371,17 +2549,17 @@ msgid "Attachment Size Limit" msgstr "Dimensione massima dell'allegato" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" -msgstr "Salva le impostazioni e invia e-mail di test" +msgid "Save and Send Test Email" +msgstr "Salva e invia e-mail di prova" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Indietro" #: cps/templates/email_edit.html:74 msgid "Allowed Domains (Whitelist)" -msgstr "Dominii autorizzati alla registrazione (Whitelist)" +msgstr "Domini consentiti (lista bianca)" #: cps/templates/email_edit.html:78 cps/templates/email_edit.html:105 msgid "Add Domain" @@ -2394,53 +2572,69 @@ msgstr "Aggiungi" #: cps/templates/email_edit.html:86 cps/templates/email_edit.html:96 msgid "Enter domainname" -msgstr "Digita il nome di dominio" +msgstr "Inserisci il nome del dominio" #: cps/templates/email_edit.html:92 msgid "Denied Domains (Blacklist)" -msgstr "Dominii bloccati per la registrazione (Blacklist)" +msgstr "Domini bloccati (lista nera)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Prossimo" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "Apri il file .kobo/Kobo eReader.conf in un editore di testi e aggiungi (o edita):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Apri il file .kobo/Kobo/Kobo eReader.conf in un editor di testo e aggiungi (o modifica):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "Token di Kobo:" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "Elenco" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "L'istanza Calibre-Web non è configurata, per favore contatta l'amministratore" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Crea un rapporto di segnalazione di problema" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Ritorna alla pagina principale" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" -msgstr "Disconnetti l'utente" +msgstr "Disconnetti utente" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "Ordina in ordine ascendente in base al numero di download" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "Ordina in ordine discendente in base al numero di download" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "Ordina gli autori in ordine alfabetico" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "Ordina gli autori in ordine alfabetico inverso" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" -msgstr "Ordina in ordine ascendente secondo l'indice della serie" +msgstr "Ordina in ordine ascendente secondo il numero della serie" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" -msgstr "Ordina in ordine discendente secondo l'indice della serie" +msgstr "Ordina in ordine discendente secondo il numero della serie" #: cps/templates/index.xml:6 msgid "Start" @@ -2472,7 +2666,7 @@ msgstr "Gli ultimi libri" #: cps/templates/index.xml:46 msgid "Random Books" -msgstr "Libri presentati aleatoriamente" +msgstr "Libri casuali" #: cps/templates/index.xml:73 msgid "Books ordered by Author" @@ -2502,7 +2696,7 @@ msgstr "Libri ordinati per valutazione" msgid "Books ordered by file formats" msgstr "Libri ordinati per formato" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Scaffali" @@ -2511,63 +2705,67 @@ msgstr "Scaffali" msgid "Books organized in shelves" msgstr "Libri organizzati in scaffali" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Home" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" -msgstr "Alterna navigazione" +msgstr "Attiva/disattiva navigazione" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Ricerca nella libreria" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Uploading..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Errore" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Caricamento riuscito, sto elaborando, per favore aspetta..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Configurazione" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Account" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" -msgstr "Logout" +msgstr "Disconnettersi" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Caricamento in corso..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Errore" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Caricamento riuscito, elaborazione in corso, attendi per favore..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Impostazioni" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Per favore non ricaricare la pagina" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Naviga" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Informazioni su" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Precedente" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Dettagli del libro" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "Griglia" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Ricordami" @@ -2576,7 +2774,7 @@ msgstr "Ricordami" msgid "Forgot Password?" msgstr "Password dimenticata?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Accedi con Magic Link" @@ -2590,7 +2788,7 @@ msgstr "Calibre-Web log: " #: cps/templates/logviewer.html:8 msgid "Stream output, can't be displayed" -msgstr "Flusso attivo, non può essere visualizzato" +msgstr "Flusso in uscita, non può essere visualizzato" #: cps/templates/logviewer.html:12 msgid "Show Access Log: " @@ -2606,7 +2804,7 @@ msgstr "Scarica il log di accesso" #: cps/templates/modal_dialogs.html:6 msgid "Select Allowed/Denied Tags" -msgstr "Seleziona le categorie consentite/negate" +msgstr "Seleziona le etchette consentite/negate" #: cps/templates/modal_dialogs.html:7 msgid "Select Allowed/Denied Custom Column Values" @@ -2622,7 +2820,7 @@ msgstr "Seleziona i valori personali consentiti/negati per le colonne dell'utent #: cps/templates/modal_dialogs.html:15 msgid "Enter Tag" -msgstr "Indica le categorie" +msgstr "Inserisci etichetta" #: cps/templates/modal_dialogs.html:24 msgid "Add View Restriction" @@ -2630,11 +2828,11 @@ msgstr "Aggiungi restrizioni di visualizzazione" #: cps/templates/modal_dialogs.html:50 msgid "This book format will be permanently erased from database" -msgstr "Questo formato di libro viene rimosso definitivamente dal database" +msgstr "Questo formato di libro verrà definitivamente cancellato dal database" #: cps/templates/modal_dialogs.html:51 msgid "This book will be permanently erased from database" -msgstr "Il libro verrà cancellato dal database di Calibre" +msgstr "Questo libro verrà definitivamente cancellato dal database" #: cps/templates/modal_dialogs.html:52 msgid "and hard disk" @@ -2672,9 +2870,9 @@ msgstr "Cartella principale" msgid "Select" msgstr "Seleziona" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 msgid "Ok" -msgstr "Ok" +msgstr "OK" #: cps/templates/osd.xml:5 msgid "Calibre-Web eBook Catalog" @@ -2684,127 +2882,139 @@ msgstr "Catalogo Calibre-Web" msgid "epub Reader" msgstr "Lettore epub" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Chiaro" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Scuro" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "Seppia" + +#: cps/templates/read.html:84 +msgid "Black" +msgstr "Nero" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Adatta il testo quando le barre laterali sono aperte." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "Dimensioni dei caratteri" + #: cps/templates/readcbr.html:7 msgid "Comic Reader" msgstr "Lettore di fumetti" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Scorciatoie della tastiera" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Pagina precedente" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Pagina successiva" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Adatta al meglio" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Adatta alla larghezza" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Adatta all'altezza" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" -msgstr "Scala alla dimensione originale" +msgstr "Adatta alla dimensione originale" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Ruota a destra" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Ruota a sinistra" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Capovolgi immagine" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Chiaro" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Scuro" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Scala" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Migliore" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Larghezza" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Altezza" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Originale" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Ruota" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Capovolgi" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Orizzontale" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Verticale" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Orientamento" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Da sinistra a destra" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Da destra a sinistra" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" -msgstr "Ripristina all'inizio" +msgstr "Ripristina in alto" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "Ricorda la posizione" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "Barra di scorrimento" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "Mostra" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "Nascondi" @@ -2812,7 +3022,7 @@ msgstr "Nascondi" msgid "DJVU Reader" msgstr "Lettore DJVU" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 msgid "PDF Reader" msgstr "Lettore PDF" @@ -2829,52 +3039,52 @@ msgid "Choose a username" msgstr "Scegli un nome utente" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Il tuo indirizzo e-mail" #: cps/templates/remote_login.html:5 msgid "Magic Link - Authorise New Device" -msgstr "Magic Link - Autorizza un nuovo apparecchio" +msgstr "Magic Link - Autorizza nuovo dispositivo" #: cps/templates/remote_login.html:7 msgid "On another device, login and visit:" -msgstr "Utilizza il tuo altro apparecchio, accedi e visita" +msgstr "Su un altro dispositivo, accedi e visita:" #: cps/templates/remote_login.html:11 msgid "Once verified, you will automatically be logged in on this device." -msgstr "Una volta completato, verrai automaticamente connesso con questo dispositivo." +msgstr "Una volta verificato, accederai automaticamente a questo dispositivo." #: cps/templates/remote_login.html:14 msgid "This verification link will expire in 10 minutes." -msgstr "Il link scadrà tra 10 minuti." +msgstr "Questo link di verifica scadrà tra 10 minuti." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "Genera miniature delle copertine delle serie" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Nessun risultato trovato" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Termine di ricerca:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Risultati per:" #: cps/templates/search_form.html:21 msgid "Published Date From" -msgstr "Data di pubblicazione da" +msgstr "Data di pubblicazione dal" #: cps/templates/search_form.html:31 msgid "Published Date To" -msgstr "Data di pubblicazione fino a" - -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "Stato di lettura" +msgstr "Data di pubblicazione fino al" #: cps/templates/search_form.html:59 msgid "Exclude Tags" -msgstr "Escludi categorie" +msgstr "Escludi etichette" #: cps/templates/search_form.html:77 msgid "Exclude Series" @@ -2912,30 +3122,26 @@ msgstr "Da:" msgid "To:" msgstr "A:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Cancella questo scaffale" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "Modifica le caratteristiche dello scaffale" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "Disponi i libri manualmente" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "Disabilita la modifica della disposizione" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "Abilita la modifica della disposizione" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Lo scaffale verrà eliminato per tutti gli utenti" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Condividi con tutti" @@ -2977,8 +3183,8 @@ msgid "System Statistics" msgstr "Statistiche del sistema" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Programma libreria" +msgid "Program" +msgstr "Programma" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -2990,7 +3196,7 @@ msgstr "Utente" #: cps/templates/tasks.html:14 msgid "Task" -msgstr "Operazione" +msgstr "Attività" #: cps/templates/tasks.html:15 msgid "Status" @@ -3004,9 +3210,17 @@ msgstr "Avanzamento" msgid "Run Time" msgstr "Tempo d'esecuzione" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Ora d'inizio" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "Azioni" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "Questa attività verrà annullata. Tutti i progressi compiuti da questa attività verranno salvati." + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "Se si tratta di un'attività pianificata, verrà eseguita nuovamente durante il prossimo orario pianificato." #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3014,11 +3228,11 @@ msgstr "Reimposta la password dell'utente" #: cps/templates/user_edit.html:43 msgid "Language of Books" -msgstr "Mostra libri in" +msgstr "Lingua dei libri" #: cps/templates/user_edit.html:54 msgid "OAuth Settings" -msgstr "Configurazione OAuth" +msgstr "Impostazioni OAuth" #: cps/templates/user_edit.html:56 msgid "Link" @@ -3030,25 +3244,29 @@ msgstr "Scollega" #: cps/templates/user_edit.html:64 msgid "Kobo Sync Token" -msgstr "Token Kobo Sync" +msgstr "Token di sincronizzazione Kobo" #: cps/templates/user_edit.html:66 msgid "Create/View" msgstr "Crea/Visualizza" -#: cps/templates/user_edit.html:85 -msgid "Add allowed/Denied Custom Column Values" -msgstr "Aggiungi valori personali permessi/negati nelle colonne" +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "Forza la sincronizzazione kobo completa" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:88 +msgid "Add allowed/Denied Custom Column Values" +msgstr "Aggiungi valori personali consentiti/negati nelle colonne" + +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "Sincronizza con Kobo unicamene i libri negli scaffali selezionati" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Elimina utente" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Genera un URL di autenticazione per Kobo" @@ -3062,19 +3280,19 @@ msgstr "Modifica utente" #: cps/templates/user_table.html:134 msgid "Enter Username" -msgstr "Digita il nome utente" +msgstr "Inserisci nome utente" #: cps/templates/user_table.html:135 -msgid "Enter E-mail Address" -msgstr "Digita l'indirizzo e-mail" +msgid "Enter Email" +msgstr "Inserisci e-mail" #: cps/templates/user_table.html:136 -msgid "Enter Kindle E-mail Address" -msgstr "Digita l'email di Kindle" +msgid "Enter eReader Email" +msgstr "Inserisci l'e-mail dell'eReader" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" -msgstr "E-mail di Kindle" +msgid "eReader Email" +msgstr "E-mail dell'eReader" #: cps/templates/user_table.html:137 msgid "Locale" @@ -3082,31 +3300,31 @@ msgstr "Locale" #: cps/templates/user_table.html:138 msgid "Visible Book Languages" -msgstr "Lingue dei libri visualizzabili" +msgstr "Lingue dei libri visibili" #: cps/templates/user_table.html:139 msgid "Edit Allowed Tags" -msgstr "Modifica le categorie permesse" +msgstr "Modifica le etichette consentite" #: cps/templates/user_table.html:139 msgid "Allowed Tags" -msgstr "Categorie permesse" +msgstr "Etichette consentite" #: cps/templates/user_table.html:140 msgid "Edit Denied Tags" -msgstr "Modifica le categorie negate" +msgstr "Modifica le etichette negate" #: cps/templates/user_table.html:140 msgid "Denied Tags" -msgstr "Categorie negate" +msgstr "Etichette negate" #: cps/templates/user_table.html:141 msgid "Edit Allowed Column Values" -msgstr "Modifica i valori delle colonne permesse" +msgstr "Modifica i valori delle colonne consentite" #: cps/templates/user_table.html:141 msgid "Allowed Column Values" -msgstr "Valori delle colonne permesse" +msgstr "Valori delle colonne consentite" #: cps/templates/user_table.html:142 msgid "Edit Denied Column Values" @@ -3114,11 +3332,11 @@ msgstr "Modifica i valori delle colonne negate" #: cps/templates/user_table.html:142 msgid "Denied Column Values" -msgstr "Valori negati per le colonne" +msgstr "Valori delle colonne negate" #: cps/templates/user_table.html:144 msgid "Change Password" -msgstr "Modifica la password" +msgstr "Cambia la password" #: cps/templates/user_table.html:147 msgid "View" @@ -3133,10 +3351,6 @@ msgid "Sync selected Shelves with Kobo" msgstr "Sincronizza con Kobo gli scaffali selezionati" #: cps/templates/user_table.html:156 -msgid "Show read/unread selection" -msgstr "Mostra l'opzione per la selezione dello stato letto/non letto" - -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Mostra l'opzione per presentare libri aleatoriamente" +msgid "Show Read/Unread Section" +msgstr "Mostra la sezione letto/da leggere" diff --git a/cps/translations/ja/LC_MESSAGES/messages.mo b/cps/translations/ja/LC_MESSAGES/messages.mo index 35e759cf8..404adb209 100644 Binary files a/cps/translations/ja/LC_MESSAGES/messages.mo and b/cps/translations/ja/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/ja/LC_MESSAGES/messages.po b/cps/translations/ja/LC_MESSAGES/messages.po index ca0705889..3b9fc22b6 100644 --- a/cps/translations/ja/LC_MESSAGES/messages.po +++ b/cps/translations/ja/LC_MESSAGES/messages.po @@ -7,584 +7,638 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2018-02-07 02:20-0500\n" -"Last-Translator: white \n" +"Last-Translator: subdiox \n" "Language: ja\n" "Language-Team: ja \n" -"Plural-Forms: nplurals=1; plural=0\n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "インストールされていません" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "統計" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" -msgstr "サーバを再起動しました。ページを再読み込みしてください" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." +msgstr "サーバーを再起動しました。ページを再読み込みしてください" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" -msgstr "サーバをシャットダウンしています。ページを閉じてください" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." +msgstr "サーバーをシャットダウンしています。ページを閉じてください" -#: cps/admin.py:154 -msgid "Reconnect successful" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" -msgstr "" +msgstr "不明なコマンド" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "本の %(eReadermail)s への送信がキューに追加されました" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "不明" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "管理者ページ" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "基本設定" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "UI設定" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" -msgstr "" +msgstr "ユーザーを編集" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" -msgstr "" +msgstr "全て" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" -msgstr "" +msgstr "ユーザーが見つかりません" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" -msgstr "" +msgstr "{}人のユーザーが削除されました" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" -msgstr "" +msgstr "全て表示" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" -msgstr "" +msgstr "不正なリクエスト" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" -msgstr "" +msgstr "ゲストユーザーの名前は変更できません" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" -msgstr "" +msgstr "ゲストユーザーはこのロールを持つことができません" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" -msgstr "" +msgstr "管理者ユーザーが残っておらず、管理者ロールを削除できません" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" -msgstr "" +msgstr "値はtrueかfalseのどちらかでなければなりません" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" -msgstr "" +msgstr "無効なロール" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" -msgstr "" +msgstr "ゲストユーザーはこの画面を表示できません" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" -msgstr "" +msgstr "無効な表示" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" -msgstr "" +msgstr "ゲストユーザーの言語設定は自動的に決定されるため、固定することはできません" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" -msgstr "" +msgstr "有効な言語設定がありません" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" -msgstr "" +msgstr "有効な本の言語がありません" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" -msgstr "" +msgstr "パラメータが見つかりません" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" -msgstr "" +msgstr "無効な読み取り列" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" -msgstr "" +msgstr "無効な制限列" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" -msgstr "Calibre-Web の設定を更新しました" +msgstr "Calibre-Webの設定を更新しました" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" -msgstr "" +msgstr "Koboのトークンを削除してもよろしいですか?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" -msgstr "" +msgstr "このドメインを削除してもよろしいですか?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" -msgstr "" +msgstr "このユーザーを削除してもよろしいですか?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" -msgstr "" +msgstr "この本棚を削除してもよろしいですか?" -#: cps/admin.py:580 +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" -msgstr "" +msgstr "選択したユーザーの言語設定を変更してもよろしいですか?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" -msgstr "" +msgstr "選択したユーザーが表示できる本の言語を変更してもよろしいですか?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" -msgstr "" +msgstr "選択したユーザーの選択したロールを変更してもよろしいですか?" -#: cps/admin.py:586 +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" -msgstr "" +msgstr "選択したユーザーの選択した制限を変更してもよろしいですか?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" -msgstr "" +msgstr "選択したユーザーの選択した表示制限を変更してもよろしいですか?" -#: cps/admin.py:590 +#: cps/admin.py:622 msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" -msgstr "" +msgstr "選択したユーザーの本棚同期の動作を変更してもよろしいですか?" -#: cps/admin.py:592 +#: cps/admin.py:624 msgid "Are you sure you want to change Calibre library location?" -msgstr "" +msgstr "Calibreライブラリのパスを変更してもよろしいですか?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "Calibre-Webは新しい表紙を検索してそのサムネイルを更新しますが、これにはしばらく時間がかかるかもしれません" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Calibre-Webの同期DBを削除して強制的にKoboリーダーと同期してもよろしいですか?" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" -msgstr "" +msgstr "拒否" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" -msgstr "" +msgstr "許可" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{}件の同期項目を削除しました" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "タグが見つかりません" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "無効なアクションです" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" -msgstr "" +msgstr "client_secrets.jsonがWebアプリケーション用に設定されていません" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" -msgstr "" +msgstr "ログファイルの場所が無効です。正しいパスを入力してください" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" -msgstr "" +msgstr "アクセスログファイルの場所が無効です。正しいパスを入力してください" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" -msgstr "" +msgstr "LDAPのプロバイダ、ポート番号、DN、ユーザーIDを入力してください" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" -msgstr "" +msgstr "LDAPのサービスアカウント名とパスワードを入力してください" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" -msgstr "" +msgstr "LDAPのサービスアカウント名を入力してください" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" -msgstr "" +msgstr "LDAPのグループフィルタには \"%s\" というフォーマットのIDが一つ必要です" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" -msgstr "" - -#: cps/admin.py:1116 -#, python-format -msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" -msgstr "" - -#: cps/admin.py:1118 -msgid "LDAP User Object Filter Has Unmatched Parenthesis" -msgstr "" - -#: cps/admin.py:1125 -#, python-format -msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" -msgstr "" - -#: cps/admin.py:1127 -msgid "LDAP Member User Filter Has Unmatched Parenthesis" -msgstr "" - -#: cps/admin.py:1134 -msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "" +msgstr "LDAPのグループフィルタ内の括弧が一致しません" #: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "メールサーバの設定を更新しました" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "機能設定" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "全ての項目を入力してください" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "このメールは有効なドメインからのものではありません" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "新規ユーザ追加" - -#: cps/admin.py:1363 #, python-format -msgid "User '%(user)s' created" -msgstr "ユーザ '%(user)s' を作成しました" +msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" +msgstr "LDAPのユーザーフィルタには \"%s\" というフォーマットのIDが一つ必要です" -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "このメールアドレスかニックネームで登録されたアカウントが見つかりました" +#: cps/admin.py:1207 +msgid "LDAP User Object Filter Has Unmatched Parenthesis" +msgstr "LDAPのユーザーフィルタ内の括弧が一致しません" -#: cps/admin.py:1389 +#: cps/admin.py:1214 #, python-format -msgid "User '%(nick)s' deleted" -msgstr "ユーザ '%(nick)s' を削除しました" +msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" +msgstr "LDAPのメンバーフィルタには \"%s\" というフォーマットのIDが一つ必要です" -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" +#: cps/admin.py:1216 +msgid "LDAP Member User Filter Has Unmatched Parenthesis" +msgstr "LDAPのメンバーフィルタ内の括弧が一致しません" + +#: cps/admin.py:1223 +msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" +msgstr "LDAPのCA証明書、証明書、キーの場所が無効です。正しいパスを入力してください" + +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "新規ユーザーを追加" + +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" +msgstr "メールサーバー設定を編集" + +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "" - -#: cps/admin.py:1467 cps/admin.py:1590 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 #, python-format -msgid "Edit User %(nick)s" -msgstr "%(nick)s を編集" +msgid "Oops! Database Error: %(error)s." +msgstr "DBエラー: %(error)s" -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "ユーザ '%(nick)s' を更新しました" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "不明なエラーが発生しました。あとで再試行してください。" - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" -msgstr "SMTP設定を変更" - -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "" - -#: cps/admin.py:1554 +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" -msgstr "" +msgstr "%(email)s へのテストメール送信がキューに追加されました。結果を見るにはタスクを確認してください" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" -msgstr "テストメールを %(res)s に送信中にエラーが発生しました" +msgstr "%(res)s へのテストメール送信中にエラーが発生しました" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." -msgstr "" +msgstr "初めにメールアドレスを設定してください" -#: cps/admin.py:1561 -msgid "E-mail server settings updated" -msgstr "メールサーバの設定を更新しました" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" +msgstr "メールサーバーの設定を更新しました" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "スケジュールタスク設定を編集" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "指定したタスクの開始時刻が無効です" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "指定したタスクの期間が無効です" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "スケジュールタスクの設定を更新しました" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "不明なエラーが発生しました。あとで再試行してください。" + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "設定DBが書き込みできません" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" -msgstr "%(user)s 用のパスワードをリセット" +msgid "Edit User %(nick)s" +msgstr "ユーザー %(nick)s を編集" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" +msgstr "ユーザー %(user)s のパスワードをリセット" + +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "初めにSMTPメールの設定をしてください" -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" -msgstr "" +msgstr "ログファイルビューア" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "更新データを要求中" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "更新データをダウンロード中" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "更新データを展開中" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "ファイルを置換中" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" -msgstr "データベースの接続を切断完了" +msgstr "DB接続を切断" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" -msgstr "サーバ停止中" +msgstr "サーバー停止中" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" -msgstr "アップデート完了、OKを押してページをリロードしてください" +msgstr "アップデート完了、OKを押してページを再読み込みしてください" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "アップデート失敗:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTPエラー" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "接続エラー" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" -msgstr "接続を確立中にタイムアウトしました" +msgstr "接続確立中にタイムアウトしました" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "エラー発生" -#: cps/admin.py:1696 +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" -msgstr "" +msgstr "更新データを一時フォルダに保存できませんでした" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" -msgstr "" +msgstr "更新中にファイルを置換できませんでした" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" -msgstr "" +msgstr "少なくとも1人のLDAPユーザーの抽出に失敗しました" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" -msgstr "" +msgstr "少なくとも1人のLDAPユーザーの作成に失敗しました" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" -msgstr "" +msgstr "エラー: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" -msgstr "" +msgstr "エラー: LDAPサーバーのレスポンスでユーザーが返されません" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" -msgstr "" +msgstr "DB内にLDAPユーザーが1人も見つかりません" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" +msgstr "{}人のユーザーをインポートしました" + +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "DBの場所が無効です。正しいパスを入力してください" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "DBへの書き込みができません" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "キーファイルの場所が無効です。正しいパスを入力してください" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "証明書ファイルの場所が無効です。正しいパスを入力してください" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "DB設定を更新しました" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "DB設定" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "全ての項目を入力してください" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "このメールは有効なドメインからのものではありません" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "新規ユーザー追加" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "ユーザー '%(user)s' を作成しました" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "このメールアドレスかニックネームで登録されたアカウントがすでに存在します。" + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "ユーザー '%(nick)s' を削除しました" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "ゲストユーザーは削除できません" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "管理者ユーザーが残っておらず、ユーザーを削除できません" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" msgstr "" -#: cps/converter.py:30 -msgid "not configured" -msgstr "" +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "ユーザー '%(nick)s' を更新しました" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "インストールされていません" #: cps/converter.py:32 msgid "Execution permissions missing" -msgstr "" +msgstr "実行権限がありません" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" -msgstr "" +msgid "Custom Column No.%(column)d does not exist in calibre database" +msgstr "カスタムカラムの%(column)d列目がcalibreのDBに存在しません" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "なし" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" +msgstr "選択した本は利用できません。ファイルが存在しないか、アクセスできません" -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" -msgstr "" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "ユーザーは表紙をアップロードする権限がありません" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "メタデータを編集" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s は有効な言語ではありません" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "ファイル拡張子 '%(ext)s' をこのサーバにアップロードすることは許可されていません" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "アップロードするファイルには拡張子が必要です" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "%(path)s の作成に失敗しました (Permission denied)。" - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "%(file)s を保存できません。" - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "ファイル形式 %(ext)s が %(book)s に追加されました" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" -msgstr "" +msgstr "IDは大文字小文字を区別しません。元のIDを上書きします" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "メタデータを更新しました" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "本の編集でエラーが発生しました。詳細はログファイルを確認してください" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "本編集中のエラー: {}" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "" - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" -msgstr "" +msgstr "ファイル %(file)s をアップロードしました" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "変換元の形式または変換後の形式が指定されていません" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "本の %(book_format)s への変換がキューに追加されました" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "この本の変換中にエラーが発生しました: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "アップロードした本はすでにライブラリに存在します。新しくアップロードする前に変更を加えてください: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "'%(langname)s' は有効な言語ではありません" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "ファイル拡張子 '%(ext)s' をこのサーバーにアップロードすることは許可されていません" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "アップロードするファイルには拡張子が必要です" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "ファイル %(filename)s は一時フォルダに保存できませんでした" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "表紙ファイル %(file)s の移動に失敗しました: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "本の形式を削除しました" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "本を削除しました" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "本を削除する権限がありません" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "メタデータを編集" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s は有効な数字ではありません。スキップします" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "新たなファイル形式をアップロードする権限がありません" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "%(path)s の作成に失敗しました (Permission denied)。" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "ファイル %(file)s を保存できません。" + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "ファイル形式 %(ext)s が %(book)s に追加されました" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" -msgstr "Googleドライブの設定が完了していません。Googleドライブを無効化してから再度有効にしてみてください" +msgstr "Googleドライブの設定が完了していません。Googleドライブを無効にしてから再度有効にしてみてください" #: cps/gdrive.py:95 msgid "Callback domain is not verified, please follow steps to verify domain in google developer console" @@ -595,756 +649,871 @@ msgstr "コールバックドメインが認証されていません。Google De msgid "%(format)s format not found for book id: %(book)d" msgstr "ID: %(book)d の本に %(format)s フォーマットはありません" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "Googleドライブ: %(fn)s に %(format)s はありません" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s がありません: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" -msgstr "Kindleに送信" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +msgid "Send to eReader" +msgstr "E-Readerに送信" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "このメールはCalibre-Web経由で送信されました。" -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Calibre-Web テストメール" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "テストメール" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Calibre-Webを始める" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" -msgstr "ユーザ: %(name)s 用の登録メール" - -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" -msgstr "%(orig)s を %(format)s に変換してからKindleに送信" - -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" -msgstr "Kindleに %(format)s を送信" - -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:137 #, fuzzy, python-format -msgid "%(book)s send to Kindle" -msgstr "Kindleに送信" +msgid "Registration Email for user: %(name)s" +msgstr "ユーザー: %(name)s 用の登録メール" -#: cps/helper.py:224 +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "%(orig)s を %(format)s に変換してからE-Readerに送信" + +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" +msgstr "E-Readerに %(format)s を送信" + +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" +msgstr "%(book)s をE-Readerに送信" + +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "要求されたファイルを読み込めませんでした。権限設定が正しいか確認してください。" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "読み込みステータスを設定できません: {}" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" -msgstr "" +msgstr "%(id)s の本フォルダの削除に失敗しました。そこにはサブフォルダがあります: %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" -msgstr "" +msgstr "本 %(id)s の削除に失敗しました: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" -msgstr "" +msgstr "本 %(id)s はDBのみから削除されます。DB内の本のパスが有効ではありません: %(path)s" -#: cps/helper.py:388 +#: cps/helper.py:450 #, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "エラー: %(error)s により、タイトルを %(src)s から %(dest)s に変更できませんでした。" +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "エラー: %(error)s により、著者名を %(src)s から %(dest)s に変更できませんでした" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "エラー: %(error)s により、ファイルパスを %(src)s から %(dest)s に変更できませんでした。" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "ファイル %(file)s はGoogleドライブ上にありません" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "エラー: %(error)s により、タイトルを %(src)s から %(dest)s に変更できませんでした" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "ファイル名の変更でエラーが発生しました: {}" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "本のパス %(path)s はGoogleドライブ上にありません" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "このメールアドレスで登録されたアカウントがあります" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" -msgstr "" +msgstr "このユーザー名はすでに使われています" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" -msgstr "" +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" +msgstr "メールアドレスの形式が無効" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "表紙のアップロードに必要なPythonモジュール 'advocate' がインストールされていません" + +#: cps/helper.py:825 msgid "Error Downloading Cover" -msgstr "" +msgstr "表紙のダウンロードに失敗しました" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" -msgstr "" +msgstr "表紙形式エラー" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "表紙アップロードのためにlocalhostやローカルネットワークにアクセスすることは許可されていません" + +#: cps/helper.py:841 msgid "Failed to create path for cover" -msgstr "" +msgstr "表紙ファイルの作成に失敗しました" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" -msgstr "" +msgstr "表紙ファイルが有効な画像ファイルでないか、または保存できませんでした" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" -msgstr "" +msgstr "表紙ファイルは jpg/jpeg/png/webp/bmp のみ対応しています" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "表紙ファイルの内容が無効です" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" -msgstr "" +msgstr "表紙ファイルは jpg/jpeg のみ対応しています" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" +msgstr "Unrarのバイナリファイルが見つかりません" + +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" +msgstr "Unrarの実行中にエラーが発生しました" + +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "見つける" + +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" msgstr "" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" -msgstr "" +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "localhost以外からCalibre-Webにアクセスし、有効なKobo端末用APIエンドポイントを取得してください" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "待機中" - -#: cps/helper.py:764 -msgid "Failed" -msgstr "失敗" - -#: cps/helper.py:766 -msgid "Started" -msgstr "開始" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "終了" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "不明" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" -msgstr "" - -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" -msgstr "" +msgstr "Kobo設定" #: cps/oauth_bb.py:77 #, python-format msgid "Register with %(provider)s" -msgstr "" +msgstr "%(provider)s で登録" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "%(nickname)s としてログイン中" #: cps/oauth_bb.py:148 #, python-format msgid "Link to %(oauth)s Succeeded" -msgstr "" +msgstr "%(oauth)s との連携に成功しました" #: cps/oauth_bb.py:155 msgid "Login failed, No User Linked With OAuth Account" -msgstr "" +msgstr "ログイン失敗、OAuthアカウントと連携しているユーザーが存在しません" #: cps/oauth_bb.py:197 #, python-format msgid "Unlink to %(oauth)s Succeeded" -msgstr "" +msgstr "%(oauth)s との連携解除に成功しました" #: cps/oauth_bb.py:202 #, python-format msgid "Unlink to %(oauth)s Failed" -msgstr "" +msgstr "%(oauth)s との連携解除に失敗しました" #: cps/oauth_bb.py:205 #, python-format msgid "Not Linked to %(oauth)s" -msgstr "" +msgstr "%(oauth)s と連携していません" #: cps/oauth_bb.py:261 msgid "Failed to log in with GitHub." -msgstr "" +msgstr "GitHubアカウントでのログインに失敗しました。" #: cps/oauth_bb.py:267 msgid "Failed to fetch user info from GitHub." -msgstr "" +msgstr "GitHubからのユーザー情報取得に失敗しました。" #: cps/oauth_bb.py:279 msgid "Failed to log in with Google." -msgstr "" +msgstr "Googleアカウントでのログインに失敗しました。" #: cps/oauth_bb.py:285 msgid "Failed to fetch user info from Google." -msgstr "" +msgstr "Googleからのユーザー情報取得に失敗しました。" #: cps/oauth_bb.py:332 msgid "GitHub Oauth error, please retry later." -msgstr "" +msgstr "GitHub OAuth エラー、再度お試しください。" #: cps/oauth_bb.py:335 msgid "GitHub Oauth error: {}" -msgstr "" +msgstr "GitHub OAuth エラー: {}" #: cps/oauth_bb.py:356 msgid "Google Oauth error, please retry later." -msgstr "" +msgstr "Google OAuth エラー、再度お試しください。" #: cps/oauth_bb.py:359 msgid "Google Oauth error: {}" -msgstr "" +msgstr "Google OAuth エラー: {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" -msgstr "" +msgstr "星{}" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "ログイン" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "トークンが見つかりません" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "トークンが無効です" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "成功です!端末に戻ってください" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" -msgstr "" +msgstr "本" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "最近追加された本を表示" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "人気の本" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" -msgstr "" +msgstr "人気の本を表示" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" -msgstr "" +msgstr "ダウンロードされた本" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" -msgstr "" +msgstr "ダウンロードされた本を表示" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" -msgstr "" +msgstr "高評価の本" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" -msgstr "" +msgstr "高評価の本を表示" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" -msgstr "読んだ本" +msgstr "既読の本" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "既読の本と未読の本を表示" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "未読の本" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" -msgstr "" +msgstr "未読の本を表示" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "見つける" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" -msgstr "ランダムで本を表示" +msgstr "ランダムに本を表示" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "カテゴリ" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "カテゴリ選択を表示" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "シリーズ" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "シリーズ選択を表示" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "著者" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "著者選択を表示" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "出版社" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "出版社選択を表示" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "言語" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "言語選択を表示" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" -msgstr "" +msgstr "評価" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" -msgstr "" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "評価選択を表示" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" -msgstr "" +msgstr "ファイル形式" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" -msgstr "" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" +msgstr "ファイル形式選択を表示" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" -msgstr "" +msgstr "アーカイブされた本" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" -msgstr "" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "アーカイブされた本を表示" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" -msgstr "" +msgstr "本の一覧" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" -msgstr "" +msgstr "本の一覧を表示" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "指定された本棚は無効です" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "申し訳ありませんが、あなたは %(shelfname)s に本を追加することが許可されていません" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "この本は %(shelfname)s にすでに追加されています" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "本を %(sname)s に追加しました" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "%(name)s に本を追加することが許可されていません" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "これらの本は %(name)s にすでに追加されています" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "本が %(sname)s に追加されました" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "%(sname)s に本を追加できません" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "本が %(sname)s から削除されました" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "申し訳ありませんが、%(sname)s から本を削除することが許可されていません" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "本棚を作成する" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "申し訳ありませんが、%(sname)s から本を削除することが許可されていません" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "本棚を編集する" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "%(title)s を作成しました" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "%(title)s を変更しました" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "エラーが発生しました" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "'%(name)s' 内の本の順番を変更する" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "本棚: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "本棚を開けません。この本棚は存在しないかアクセスできません" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "アップデート情報を読み込み中に予期しないデータが見つかりました" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "アップデートはありません。すでに最新バージョンがインストールされています" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "アップデートが利用可能です。下のボタンをクリックして最新バージョンにアップデートしてください。" - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "アップデート情報を取得できません" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "" - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "アップデートが利用可能です。下のボタンをクリックしてバージョン: %(version)s にアップデートしてください。" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "リリース情報がありません" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "本を見つける (ランダムで表示)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "出版社: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "シリーズ: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "カテゴリ: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "言語: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "詳細検索" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "検索" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "タスク" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "これ以降に出版 " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "これ以前に出版 " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "評価 <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "評価 >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" -msgstr "" +msgstr "既読/未読状況 = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" -msgstr "" +msgstr "カスタムカラムの検索でエラーが発生しました。Calibre-Webを再起動してください" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "本の %(kindlemail)s への送信がキューに追加されました" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "詳細検索" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "指定された本棚は無効です" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "申し訳ありませんが、あなたはこの本棚に本を追加することが許可されていません" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "この本は %(shelfname)s にすでに追加されています" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "本を %(sname)s に追加しました" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "あなたはこの本棚に本を追加することが許可されていません" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "これらの本は %(name)s にすでに追加されています" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "本が %(sname)s に追加されました" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "%(sname)s に本を追加できません" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "本が %(sname)s から削除されました" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "申し訳ありませんが、あなたはこの本棚から本を削除することが許可されていません" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "本棚を作成する" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "申し訳ありませんが、あなたはこの本棚を編集することが許可されていません" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "本棚を編集する" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "本棚の削除中にエラーが発生しました" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "本棚を削除しました" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "'%(name)s' 内の本の順番を変更する" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "申し訳ありませんが、あなたはみんなの本棚を作成することが許可されていません" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "%(title)s を作成しました" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "%(title)s を変更しました" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "エラーが発生しました" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "'%(title)s' という名前のみんなの本棚はすでに存在します。" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "'%(title)s' という名前の本棚はすでに存在します。" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "本棚: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "本棚を開けません。この本棚は存在しないかアクセスできません" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "タスク" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "待機中" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "失敗" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "開始" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "終了" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "終了" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "キャンセル" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "不明" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "アップデート情報の読み込み中に予期しないデータが見つかりました" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "アップデートはありません。すでに最新バージョンがインストールされています" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "アップデートが利用可能です。下のボタンをクリックして最新バージョンにアップデートしてください。" + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "アップデート情報を取得できません" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "下のボタンをクリックして最新の安定バージョンにアップデートしてください。" + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "アップデートが利用可能です。下のボタンをクリックしてバージョン: %(version)s にアップデートしてください。" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "リリース情報がありません" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "本を見つける (ランダムに表示)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "人気の本 (最もダウンロードされた本)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "%(user)s がダウンロードした本" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "著者: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "出版社: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "シリーズ: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "評価: なし" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "評価: 星%(rating)s" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "ファイル形式: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "カテゴリ: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "言語: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "ダウンロード数" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "評価一覧" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "ファイル形式一覧" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "初めにSMTPメールの設定をしてください" + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "本の %(eReadermail)s への送信がキューに追加されました" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "%(res)s を送信中にエラーが発生しました" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "初めにKindleのメールアドレスを設定してください" -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" -msgstr "" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "メールサーバーが設定されていません。管理者に連絡してください" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "登録" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "このメールアドレスは登録が許可されていません" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "確認メールがこのメールアドレスに送信されました。" -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" -msgstr "" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" +msgstr "LDAP認証を有効化できません" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" -msgstr "" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" +msgstr "代わりに '%(nickname)s' としてログインします。LDAPサーバーにアクセスできないか、ユーザーが存在しません" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" -msgstr "" +msgid "Oops! Login Failed: %(message)s" +msgstr "ログインできません: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" -msgstr "ユーザ名またはパスワードが違います" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." +msgstr "ユーザー名またはパスワードが違います" -#: cps/web.py:1555 -msgid "New Password was send to your email address" -msgstr "" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." +msgstr "新しいパスワードがあなたのメールアドレスに送信されました" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" -msgstr "" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" +msgstr "パスワードをリセットするには、有効なユーザー名を入力してください" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)s のプロフィール" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "プロフィールを更新しました" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "このメールアドレスで登録されたアカウントがすでに存在します" + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" -msgstr "" +msgstr "OAuth情報を含んだ有効なgmail.jsonファイルが見つかりません" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s をE-Readerに送信" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" -msgstr "" +msgstr "Calibre ebook-convert %(tool)s が見つかりません" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" -msgstr "" +msgstr "%(format)s 形式は存在しません" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" -msgstr "" +msgstr "Ebook converter が不明なエラーで失敗しました" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" -msgstr "" +msgstr "Kepubify-converter が失敗しました: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" -msgstr "" +msgstr "変換されたファイルが見つからないか、またはフォルダー %(folder)s 内に複数存在します" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Ebook-converter が失敗しました: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" -msgstr "" +msgstr "Calibre が失敗しました: %(error)s" + +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "変換" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "Calibre DBと再接続中" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "メール" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "メタデータを編集" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "表紙サムネイルを%(count)s個生成しました" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "表紙サムネイル" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "シリーズのサムネイルを{0}個生成しました" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "表紙サムネイルのキャッシュを消去中" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "アップロード" #: cps/templates/admin.html:9 msgid "Users" -msgstr "" +msgstr "ユーザー" #: cps/templates/admin.html:13 cps/templates/login.html:9 #: cps/templates/login.html:10 cps/templates/register.html:9 #: cps/templates/user_edit.html:10 cps/templates/user_table.html:134 msgid "Username" -msgstr "ユーザ名" +msgstr "ユーザー名" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" -msgstr "" +msgid "Email" +msgstr "メールアドレス" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" -msgstr "" +msgid "Send to eReader Email" +msgstr "E-Readerメールアドレス" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "管理者" @@ -1354,214 +1523,231 @@ msgstr "管理者" msgid "Password" msgstr "パスワード" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "アップロード" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "ダウンロード" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" -msgstr "" +msgstr "閲覧" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "編集" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "削除" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" -msgstr "" +msgstr "みんなの本棚" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" -msgstr "" +msgstr "LDAPユーザーをインポート" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" -msgstr "" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" +msgstr "メールサーバー設定" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" -msgstr "" +msgstr "SMTPホスト名" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" -msgstr "" +msgstr "SMTPポート番号" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "暗号化" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" -msgstr "" +msgstr "SMTPログイン" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" -msgstr "" +msgid "From Email" +msgstr "Fromメールアドレス" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" -msgstr "" +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" +msgstr "メールサービス" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" -msgstr "" +msgstr "OAuth2経由のGmail" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "設定" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" -msgstr "" +msgstr "Calibre DBのディレクトリ" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "ログレベル" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "ポート番号" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" -msgstr "" +msgstr "外部ポート" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" -msgstr "" +msgstr "1ページに表示する冊数" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" -msgstr "" +msgstr "アップロード" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" -msgstr "" +msgstr "匿名での閲覧" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" -msgstr "" +msgstr "誰でも登録可能" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" -msgstr "" +msgstr "マジックリンクによるリモートログイン" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" -msgstr "" +msgstr "リバースプロキシによるログイン" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" -msgstr "" +msgstr "リバースプロキシのヘッダー名" -#: cps/templates/admin.html:153 -#, fuzzy +#: cps/templates/admin.html:159 msgid "Edit Calibre Database Configuration" -msgstr "Calibre-Web の設定を更新しました" - -#: cps/templates/admin.html:154 -msgid "Edit Basic Configuration" -msgstr "" - -#: cps/templates/admin.html:155 -msgid "Edit UI Configuration" -msgstr "" +msgstr "Calibre DBの設定を編集" #: cps/templates/admin.html:160 +msgid "Edit Basic Configuration" +msgstr "基本設定を編集" + +#: cps/templates/admin.html:161 +msgid "Edit UI Configuration" +msgstr "UI設定を編集" + +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "スケジュールタスク" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "タスクを開始する時間" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "最大タスク継続時間" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "本の表紙サムネイルを生成" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "シリーズの表紙サムネイルを生成" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "Calibreライブラリに再接続" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "表紙サムネイルのキャッシュを更新" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "管理" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" -msgstr "" +msgstr "デバッグパッケージをダウンロード" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" -msgstr "" +msgstr "ログを表示" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" -msgstr "" +msgstr "再起動" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" -msgstr "" +msgstr "シャットダウン" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "アップデート" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "バージョン情報" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "バージョン" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "詳細" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "現在のバージョン" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" -msgstr "" - -#: cps/templates/admin.html:192 -msgid "Perform Update" -msgstr "更新を実行" - -#: cps/templates/admin.html:205 -msgid "Are you sure you want to restart?" -msgstr "" - -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 -msgid "OK" -msgstr "" - -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 -#: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 -#: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 -msgid "Cancel" -msgstr "" - -#: cps/templates/admin.html:223 -msgid "Are you sure you want to shutdown?" -msgstr "" +msgstr "アップデートを確認" #: cps/templates/admin.html:235 +msgid "Perform Update" +msgstr "アップデートを実行" + +#: cps/templates/admin.html:248 +msgid "Are you sure you want to restart?" +msgstr "再起動してもよろしいですか?" + +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 +msgid "OK" +msgstr "OK" + +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 +#: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 +#: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 +msgid "Cancel" +msgstr "キャンセル" + +#: cps/templates/admin.html:266 +msgid "Are you sure you want to shutdown?" +msgstr "シャットダウンしてもよろしいですか?" + +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" -msgstr "" +msgstr "アップデート中です。このページをリロードしないでください" #: cps/templates/author.html:15 msgid "via" @@ -1571,206 +1757,205 @@ msgstr "経由" msgid "In Library" msgstr "ライブラリ内" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" -msgstr "" +msgstr "追加日が新しい順にソート" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" -msgstr "" +msgstr "追加日が古い順にソート" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" -msgstr "" +msgstr "五十音順にソート" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" -msgstr "" +msgstr "逆五十音順にソート" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" -msgstr "" +msgstr "発売日が新しい順にソート" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" -msgstr "" +msgstr "発売日が古い順にソート" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "減らす" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" -msgstr "" +msgstr "同じ著者が書いた本: " -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "本を削除" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "削除する形式:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "変換する形式:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "変換元:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" -msgstr "選択肢を選ぶ" +msgstr "選択肢から選ぶ" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "変換先:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "本を変換" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "本のタイトル" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "著者" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "詳細" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" -msgstr "" +msgstr "識別子" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" -msgstr "" +msgstr "識別子タイプ" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" -msgstr "" +msgstr "識別子の値" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" -msgstr "" +msgstr "削除" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" -msgstr "" +msgstr "識別子を追加" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "タグ" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" -msgstr "" +msgstr "巻数" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "評価" #: cps/templates/book_edit.html:104 msgid "Fetch Cover from URL (JPEG - Image will be downloaded and stored in database)" -msgstr "" +msgstr "表紙をURLから取得 (JPEG画像がダウンロードされDBに保存されます)" #: cps/templates/book_edit.html:108 msgid "Upload Cover from Local Disk" -msgstr "" +msgstr "表紙をアップロード" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" -msgstr "" +msgstr "発売日" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "出版社" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "言語" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" -msgstr "はい" +msgstr "既読" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" -msgstr "いいえ" +msgstr "未読" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" -msgstr "" +msgstr "アップロード形式" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" -msgstr "" +msgstr "保存後に本を表示" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" -msgstr "" +msgstr "メタデータを取得" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" -msgstr "" +msgstr "保存" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "キーワード" -#: cps/templates/book_edit.html:237 -#, fuzzy +#: cps/templates/book_edit.html:234 msgid "Search keyword" -msgstr "キーワードを検索" +msgstr "キーワード検索" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "カバー画像をクリックしてメタデータをフォームに読み込んでください" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "読み込み中..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "閉じる" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "ソース" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "検索エラー" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "検索結果が見つかりません。別のキーワードで検索してみてください。" @@ -1778,31 +1963,31 @@ msgstr "検索結果が見つかりません。別のキーワードで検索し #: cps/templates/user_table.html:14 cps/templates/user_table.html:77 #: cps/templates/user_table.html:100 msgid "This Field is Required" -msgstr "" +msgstr "この項目は必須です" #: cps/templates/book_table.html:37 msgid "Merge selected books" -msgstr "" +msgstr "選択した本を統合" #: cps/templates/book_table.html:38 cps/templates/user_table.html:124 msgid "Remove Selections" -msgstr "" +msgstr "選択した本を削除" #: cps/templates/book_table.html:41 msgid "Exchange author and title" -msgstr "" +msgstr "著者とタイトルを交換" #: cps/templates/book_table.html:47 msgid "Update Title Sort automatically" -msgstr "" +msgstr "タイトルのよみがなを自動で更新" #: cps/templates/book_table.html:51 msgid "Update Author Sort automatically" -msgstr "" +msgstr "著者のよみがなを自動で更新" #: cps/templates/book_table.html:63 cps/templates/book_table.html:69 msgid "Enter Title" -msgstr "" +msgstr "タイトルを入力" #: cps/templates/book_table.html:63 cps/templates/config_view_edit.html:24 #: cps/templates/shelf_edit.html:8 @@ -1811,84 +1996,91 @@ msgstr "タイトル" #: cps/templates/book_table.html:64 msgid "Enter Title Sort" -msgstr "" +msgstr "タイトルのよみがなを入力" #: cps/templates/book_table.html:64 msgid "Title Sort" -msgstr "" +msgstr "タイトルのよみがな" #: cps/templates/book_table.html:65 msgid "Enter Author Sort" -msgstr "" +msgstr "著者名のよみがなを入力" #: cps/templates/book_table.html:65 msgid "Author Sort" -msgstr "" +msgstr "著者名のよみがな" #: cps/templates/book_table.html:66 msgid "Enter Authors" -msgstr "" +msgstr "著者名を入力" #: cps/templates/book_table.html:67 msgid "Enter Categories" -msgstr "" +msgstr "カテゴリ名を入力" #: cps/templates/book_table.html:68 msgid "Enter Series" -msgstr "" +msgstr "シリーズ名を入力" #: cps/templates/book_table.html:69 msgid "Series Index" -msgstr "" +msgstr "巻数" #: cps/templates/book_table.html:70 msgid "Enter Languages" -msgstr "" +msgstr "言語を入力" #: cps/templates/book_table.html:71 msgid "Publishing Date" -msgstr "" +msgstr "発売日" #: cps/templates/book_table.html:72 msgid "Enter Publishers" -msgstr "" +msgstr "出版社を入力" #: cps/templates/book_table.html:73 -#, fuzzy msgid "Enter comments" -msgstr "ドメイン名を入力" +msgstr "コメントを入力" #: cps/templates/book_table.html:73 msgid "Comments" -msgstr "" +msgstr "コメント" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 -#, fuzzy +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "アーカイブ状況" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "既読/未読" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 msgid "Enter " -msgstr "登録" +msgstr "入力: " -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "よろしいですか?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" -msgstr "" +msgstr "このタイトルの本から" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" -msgstr "" +msgstr "このタイトルの本に統合します" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" -msgstr "" +msgstr "統合" #: cps/templates/config_db.html:12 msgid "Location of Calibre Database" -msgstr "" +msgstr "Calibre DBの場所" #: cps/templates/config_db.html:22 msgid "Use Google Drive?" @@ -1904,7 +2096,7 @@ msgstr "Googleドライブ上のCalibreフォルダ" #: cps/templates/config_db.html:40 msgid "Metadata Watch Channel ID" -msgstr "" +msgstr "メタデータ監視用チャンネルID" #: cps/templates/config_db.html:43 msgid "Revoke" @@ -1912,27 +2104,27 @@ msgstr "取り消す" #: cps/templates/config_db.html:68 msgid "New db location is invalid, please enter valid path" -msgstr "" +msgstr "入力したDBの場所が無効です。有効なパスを入力してください" #: cps/templates/config_edit.html:18 msgid "Server Configuration" -msgstr "サーバ設定" +msgstr "サーバー設定" #: cps/templates/config_edit.html:25 msgid "Server Port" -msgstr "ポート" +msgstr "ポート番号" #: cps/templates/config_edit.html:28 msgid "SSL certfile location (leave it empty for non-SSL Servers)" -msgstr "SSL証明書の場所 (非SSLサーバでは空欄にしてください)" +msgstr "SSL証明書の場所 (非SSLサーバーでは空欄にしてください)" #: cps/templates/config_edit.html:35 msgid "SSL Keyfile location (leave it empty for non-SSL Servers)" -msgstr "SSL鍵ファイルの場所 (非SSLサーバでは空欄にしてください)" +msgstr "SSL鍵ファイルの場所 (非SSLサーバーでは空欄にしてください)" #: cps/templates/config_edit.html:43 msgid "Update Channel" -msgstr "" +msgstr "アップデートチャンネル" #: cps/templates/config_edit.html:45 msgid "Stable" @@ -1944,11 +2136,11 @@ msgstr "最新" #: cps/templates/config_edit.html:50 msgid "Trusted Hosts (Comma Separated)" -msgstr "" +msgstr "信頼するホスト名 (カンマ区切り)" #: cps/templates/config_edit.html:61 msgid "Logfile Configuration" -msgstr "ログファイルの設定" +msgstr "ログファイル設定" #: cps/templates/config_edit.html:77 msgid "Location and name of logfile (calibre-web.log for no entry)" @@ -1956,11 +2148,11 @@ msgstr "ログファイル名 (空欄の場合はcalibre-web.log)" #: cps/templates/config_edit.html:82 msgid "Enable Access Log" -msgstr "" +msgstr "アクセスログを保存する" #: cps/templates/config_edit.html:85 msgid "Location and name of access logfile (access.log for no entry)" -msgstr "" +msgstr "アクセスログのファイル名 (空欄の場合はaccess.log)" #: cps/templates/config_edit.html:96 msgid "Feature Configuration" @@ -1968,51 +2160,55 @@ msgstr "機能設定" #: cps/templates/config_edit.html:104 msgid "Convert non-English characters in title and author while saving to disk" -msgstr "" +msgstr "ダウンロード時にタイトルと著者名の中にある2バイト文字を変換する" #: cps/templates/config_edit.html:108 msgid "Enable Uploads" -msgstr "" +msgstr "アップロード機能を有効にする" + +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(ユーザーにアップロード権限を与えることも忘れないでください)" #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" -msgstr "" +msgstr "アップロードを許可するファイル形式" #: cps/templates/config_edit.html:118 msgid "Enable Anonymous Browsing" -msgstr "" +msgstr "匿名での閲覧を許可" #: cps/templates/config_edit.html:122 msgid "Enable Public Registration" -msgstr "" +msgstr "誰でも登録可能にする" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" -msgstr "" +msgid "Use Email as Username" +msgstr "メールアドレスをユーザー名として使う" #: cps/templates/config_edit.html:132 msgid "Enable Magic Link Remote Login" -msgstr "" +msgstr "マジックリンクによるリモートログインを有効にする" #: cps/templates/config_edit.html:137 msgid "Enable Kobo sync" -msgstr "" +msgstr "Koboの同期を有効にする" #: cps/templates/config_edit.html:142 msgid "Proxy unknown requests to Kobo Store" -msgstr "" +msgstr "Koboストアへの不明なリクエストをプロキシ" #: cps/templates/config_edit.html:145 msgid "Server External Port (for port forwarded API calls)" -msgstr "" +msgstr "サーバーの外部ポート番号 (APIの呼び出しをポートフォワーディングするため)" #: cps/templates/config_edit.html:153 msgid "Use Goodreads" -msgstr "" +msgstr "Goodreadsを利用" #: cps/templates/config_edit.html:154 msgid "Create an API Key" -msgstr "" +msgstr "APIキーを作成" #: cps/templates/config_edit.html:158 msgid "Goodreads API Key" @@ -2024,143 +2220,138 @@ msgstr "GoodreadsのAPIシークレット" #: cps/templates/config_edit.html:169 msgid "Allow Reverse Proxy Authentication" -msgstr "" +msgstr "リバースプロキシの認証を許可" #: cps/templates/config_edit.html:180 msgid "Login type" -msgstr "" +msgstr "ログインの種類" #: cps/templates/config_edit.html:182 msgid "Use Standard Authentication" -msgstr "" +msgstr "通常の認証を利用" #: cps/templates/config_edit.html:184 msgid "Use LDAP Authentication" -msgstr "" +msgstr "LDAP認証を利用" #: cps/templates/config_edit.html:187 msgid "Use OAuth" -msgstr "" +msgstr "OAuthを利用" #: cps/templates/config_edit.html:194 msgid "LDAP Server Host Name or IP Address" -msgstr "" +msgstr "LDAPサーバーのホスト名またはIPアドレス" #: cps/templates/config_edit.html:198 msgid "LDAP Server Port" -msgstr "" +msgstr "LDAPサーバーのポート番号" #: cps/templates/config_edit.html:202 msgid "LDAP Encryption" -msgstr "" - -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "なし" +msgstr "LDAPの暗号化方式" #: cps/templates/config_edit.html:205 msgid "TLS" -msgstr "" +msgstr "TLS" #: cps/templates/config_edit.html:206 msgid "SSL" -msgstr "" +msgstr "SSL" #: cps/templates/config_edit.html:210 msgid "LDAP CACertificate Path (Only needed for Client Certificate Authentication)" -msgstr "" +msgstr "LDAPのCA証明書のパス (クライアント証明書による認証の場合のみ必要)" #: cps/templates/config_edit.html:217 msgid "LDAP Certificate Path (Only needed for Client Certificate Authentication)" -msgstr "" +msgstr "LDAP証明書のパス (クライアント証明書による認証の場合のみ必要)" #: cps/templates/config_edit.html:224 msgid "LDAP Keyfile Path (Only needed for Client Certificate Authentication)" -msgstr "" +msgstr "LDAPのキーファイルのパス (クライアント証明書による認証の場合のみ必要)" #: cps/templates/config_edit.html:233 msgid "LDAP Authentication" -msgstr "" +msgstr "LDAP認証" #: cps/templates/config_edit.html:235 msgid "Anonymous" -msgstr "" +msgstr "匿名" #: cps/templates/config_edit.html:236 msgid "Unauthenticated" -msgstr "" +msgstr "認証失敗" #: cps/templates/config_edit.html:237 msgid "Simple" -msgstr "" +msgstr "簡単" #: cps/templates/config_edit.html:242 msgid "LDAP Administrator Username" -msgstr "" +msgstr "LDAP管理者のユーザー名" #: cps/templates/config_edit.html:248 msgid "LDAP Administrator Password" -msgstr "" +msgstr "LDAP管理者のパスワード" #: cps/templates/config_edit.html:253 msgid "LDAP Distinguished Name (DN)" -msgstr "" +msgstr "LDAPの識別名 (DN)" #: cps/templates/config_edit.html:257 msgid "LDAP User Object Filter" -msgstr "" +msgstr "LDAPユーザーフィルタ" #: cps/templates/config_edit.html:262 msgid "LDAP Server is OpenLDAP?" -msgstr "" +msgstr "LDAPサーバーはOpenLDAPですか?" #: cps/templates/config_edit.html:264 msgid "Following Settings are Needed For User Import" -msgstr "" +msgstr "以下の設定はユーザーのインポートのために必要です" #: cps/templates/config_edit.html:266 msgid "LDAP Group Object Filter" -msgstr "" +msgstr "LDAPグループフィルタ" #: cps/templates/config_edit.html:270 msgid "LDAP Group Name" -msgstr "" +msgstr "LDAPグループ名" #: cps/templates/config_edit.html:274 msgid "LDAP Group Members Field" -msgstr "" +msgstr "LDAPグループメンバーフィールド" #: cps/templates/config_edit.html:278 msgid "LDAP Member User Filter Detection" -msgstr "" +msgstr "LDAPメンバーユーザーフィルタ検出" #: cps/templates/config_edit.html:280 msgid "Autodetect" -msgstr "" +msgstr "自動検出" #: cps/templates/config_edit.html:281 msgid "Custom Filter" -msgstr "" +msgstr "カスタムフィルタ" #: cps/templates/config_edit.html:286 msgid "LDAP Member User Filter" -msgstr "" +msgstr "LDAPメンバーユーザーフィルタ" #: cps/templates/config_edit.html:297 #, python-format msgid "Obtain %(provider)s OAuth Credential" -msgstr "" +msgstr "%(provider)s OAuth 認証情報を入手" #: cps/templates/config_edit.html:300 #, python-format msgid "%(provider)s OAuth Client Id" -msgstr "" +msgstr "%(provider)s OAuth クライアントID" #: cps/templates/config_edit.html:304 #, python-format msgid "%(provider)s OAuth Client Secret" -msgstr "" +msgstr "%(provider)s OAuth クライアントシークレット" #: cps/templates/config_edit.html:320 msgid "External binaries" @@ -2168,15 +2359,15 @@ msgstr "外部バイナリ" #: cps/templates/config_edit.html:326 msgid "Path to Calibre E-Book Converter" -msgstr "" +msgstr "Calibre E-Book Converterのパス" #: cps/templates/config_edit.html:334 msgid "Calibre E-Book Converter Settings" -msgstr "" +msgstr "Calibre E-Book Converterの設定" #: cps/templates/config_edit.html:337 msgid "Path to Kepubify E-Book Converter" -msgstr "" +msgstr "Kepubify E-Book Converterのパス" #: cps/templates/config_edit.html:345 msgid "Location of Unrar binary" @@ -2188,13 +2379,13 @@ msgstr "表示設定" #: cps/templates/config_view_edit.html:32 msgid "No. of Random Books to Display" -msgstr "" +msgstr "ランダムに表示する本の冊数" #: cps/templates/config_view_edit.html:36 msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" -msgstr "" +msgstr "非表示にする前に表示する著者数 (0=非表示にしない)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "テーマ" @@ -2208,160 +2399,163 @@ msgstr "caliBlur! ダークテーマ" #: cps/templates/config_view_edit.html:47 msgid "Regular Expression for Ignoring Columns" -msgstr "" +msgstr "無視するカラムの正規表現" #: cps/templates/config_view_edit.html:51 msgid "Link Read/Unread Status to Calibre Column" -msgstr "" +msgstr "既読/未読をリンクするCalibreのカラム" #: cps/templates/config_view_edit.html:60 msgid "View Restrictions based on Calibre column" -msgstr "" +msgstr "表示制限をリンクするCalibreのカラム" #: cps/templates/config_view_edit.html:69 msgid "Regular Expression for Title Sorting" -msgstr "" +msgstr "タイトルをソートするための正規表現" #: cps/templates/config_view_edit.html:80 msgid "Default Settings for New Users" -msgstr "" +msgstr "新規ユーザーのデフォルト設定" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" -msgstr "" +msgstr "管理者ユーザー" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "ダウンロードを許可" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" -msgstr "" +msgstr "本のビューアを許可" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "アップロードを許可" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "編集を許可" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" -msgstr "" +msgstr "本の削除を許可" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "パスワード変更を許可" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "みんなの本棚の編集を許可" -#: cps/templates/config_view_edit.html:119 -#, fuzzy +#: cps/templates/config_view_edit.html:123 msgid "Default Language" -msgstr "言語を除外" +msgstr "言語設定のデフォルト" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 msgid "Default Visible Language of Books" -msgstr "" +msgstr "表示する本の言語設定のデフォルト" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" -msgstr "" +msgstr "新規ユーザーのデフォルト表示設定" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" -msgstr "" +msgstr "詳細画面でランダムに本を表示" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" -msgstr "" +msgstr "許可/拒否タグを追加" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" -msgstr "" +msgstr "許可/拒否カスタムカラムを追加" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" -msgstr "" +msgstr "ブラウザで読む" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" -msgstr "" +msgstr "ブラウザで聞く" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" -msgstr "" +msgstr "%(range)s 第%(index)s巻" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" -msgstr "" +msgstr "発売日" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "未読に設定" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "既読に設定" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" -msgstr "読んだ" +msgstr "既読" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" -msgstr "" +msgstr "アーカイブから復元" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" -msgstr "" +msgstr "アーカイブに追加" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" -msgstr "" +msgstr "アーカイブ済み" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "詳細:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "本棚に追加" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" -msgstr "" +msgstr "(公開)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" -msgstr "" +msgstr "メタデータを編集" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" -msgstr "" +msgid "Email Account Type" +msgstr "サーバーの種類を選択" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" -msgstr "" +#, fuzzy +msgid "Standard Email Account" +msgstr "標準のメールアカウントを使用" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "" +#, fuzzy +msgid "Gmail Account" +msgstr "サーバーの種類を選択" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" -msgstr "" +msgstr "Gmailへのアクセスを失効" #: cps/templates/email_edit.html:42 msgid "STARTTLS" @@ -2373,24 +2567,25 @@ msgstr "SSL/TLS" #: cps/templates/email_edit.html:51 msgid "SMTP Password" -msgstr "" +msgstr "SMTPのパスワード" #: cps/templates/email_edit.html:58 msgid "Attachment Size Limit" -msgstr "" +msgstr "添付ファイルのサイズ制限" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" -msgstr "" +#, fuzzy +msgid "Save and Send Test Email" +msgstr "保存してテストメールを送信" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "戻る" #: cps/templates/email_edit.html:74 msgid "Allowed Domains (Whitelist)" -msgstr "" +msgstr "許可するドメイン名 (ホワイトリスト)" #: cps/templates/email_edit.html:78 cps/templates/email_edit.html:105 msgid "Add Domain" @@ -2407,49 +2602,65 @@ msgstr "ドメイン名を入力" #: cps/templates/email_edit.html:92 msgid "Denied Domains (Blacklist)" -msgstr "" +msgstr "拒否するドメイン名 (ブラックリスト)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "次" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr ".kobo/Kobo/Kobo eReader.confファイルをテキストエディタで開いて追加(編集)してください:" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "Koboトークン:" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "一覧" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" -msgstr "" +msgstr "Calibre-Webインスタンスが未設定です。管理者に連絡してください" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" -msgstr "" +msgstr "Issueを作成" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" -msgstr "" +msgstr "ホームに戻る" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" -msgstr "" +msgstr "ユーザーをログアウト" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "ダウンロード数が少ない順にソート" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "ダウンロード数が多い順にソート" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" -msgstr "" +msgstr "著者名を五十音順にソート" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" -msgstr "" +msgstr "著者名を逆五十音順にソート" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" -msgstr "" +msgstr "巻数が小さい順にソート" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" -msgstr "" +msgstr "巻数が大きい順にソート" #: cps/templates/index.xml:6 msgid "Start" @@ -2457,11 +2668,11 @@ msgstr "開始" #: cps/templates/index.xml:18 msgid "Alphabetical Books" -msgstr "" +msgstr "五十音順の本" #: cps/templates/index.xml:22 msgid "Books sorted alphabetically" -msgstr "" +msgstr "五十音順にソートされた本" #: cps/templates/index.xml:29 msgid "Popular publications from this catalog based on Downloads." @@ -2473,7 +2684,7 @@ msgstr "評価に基づいた、この出版社が出している有名な本" #: cps/templates/index.xml:39 msgid "Recently added Books" -msgstr "" +msgstr "最近追加された本" #: cps/templates/index.xml:43 msgid "The latest Books" @@ -2501,496 +2712,505 @@ msgstr "シリーズ順" #: cps/templates/index.xml:101 msgid "Books ordered by Languages" -msgstr "" +msgstr "言語順" #: cps/templates/index.xml:108 msgid "Books ordered by Rating" -msgstr "" +msgstr "評価順" #: cps/templates/index.xml:116 msgid "Books ordered by file formats" -msgstr "" +msgstr "ファイル形式順" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" -msgstr "" +msgstr "本棚" #: cps/templates/index.xml:123 msgid "Books organized in shelves" -msgstr "" +msgstr "本棚に整理された本" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "ホーム" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" -msgstr "" +msgstr "ナビゲーションを実行" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" -msgstr "" +msgstr "ライブラリ内を検索" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "アップロード中..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "エラー" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "アップロード完了。現在処理中ですのでお待ち下さい..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "設定" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "アカウント" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "ログアウト" -#: cps/templates/layout.html:120 -msgid "Please do not refresh the page" -msgstr "" +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "アップロード中..." -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "エラー" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "アップロード完了。現在処理中ですのでお待ち下さい..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "設定" + +#: cps/templates/layout.html:136 +msgid "Please do not refresh the page" +msgstr "ページを更新しないでください" + +#: cps/templates/layout.html:146 msgid "Browse" msgstr "閲覧" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "このサイトについて" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "前" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "本の詳細" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "表" + #: cps/templates/login.html:18 msgid "Remember Me" -msgstr "" +msgstr "アカウント情報を記憶する" #: cps/templates/login.html:23 msgid "Forgot Password?" -msgstr "" +msgstr "パスワードを忘れた場合" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" -msgstr "" +msgstr "マジックリンクでログイン" #: cps/templates/logviewer.html:6 msgid "Show Calibre-Web Log: " -msgstr "" +msgstr "Calibre-Webのログを表示: " #: cps/templates/logviewer.html:8 msgid "Calibre-Web Log: " -msgstr "" +msgstr "Calibre-Webのログ: " #: cps/templates/logviewer.html:8 msgid "Stream output, can't be displayed" -msgstr "" +msgstr "ストリームの出力を表示できません" #: cps/templates/logviewer.html:12 msgid "Show Access Log: " -msgstr "" +msgstr "アクセスログを表示: " #: cps/templates/logviewer.html:18 msgid "Download Calibre-Web Log" -msgstr "" +msgstr "Calibre-Webのログをダウンロード" #: cps/templates/logviewer.html:21 msgid "Download Access Log" -msgstr "" +msgstr "アクセスログをダウンロード" #: cps/templates/modal_dialogs.html:6 msgid "Select Allowed/Denied Tags" -msgstr "" +msgstr "許可/拒否タグを選択" #: cps/templates/modal_dialogs.html:7 msgid "Select Allowed/Denied Custom Column Values" -msgstr "" +msgstr "許可/拒否カスタムカラムを選択" #: cps/templates/modal_dialogs.html:8 msgid "Select Allowed/Denied Tags of User" -msgstr "" +msgstr "ユーザーの許可/拒否タグを選択" #: cps/templates/modal_dialogs.html:9 msgid "Select Allowed/Denied Custom Column Values of User" -msgstr "" +msgstr "ユーザーの許可/拒否カスタムカラムを選択" #: cps/templates/modal_dialogs.html:15 msgid "Enter Tag" -msgstr "" +msgstr "タグを入力" #: cps/templates/modal_dialogs.html:24 msgid "Add View Restriction" -msgstr "" +msgstr "表示制限を追加" #: cps/templates/modal_dialogs.html:50 msgid "This book format will be permanently erased from database" -msgstr "" +msgstr "このファイル形式はDBから完全に削除されます" #: cps/templates/modal_dialogs.html:51 msgid "This book will be permanently erased from database" -msgstr "" +msgstr "この本はDBと" #: cps/templates/modal_dialogs.html:52 msgid "and hard disk" -msgstr "" +msgstr "ローカルから完全に削除されます" #: cps/templates/modal_dialogs.html:56 msgid "Important Kobo Note: deleted books will remain on any paired Kobo device." -msgstr "" +msgstr "Koboに関する重要な注意: 削除された本はどの連携されたKobo端末にも残ります。" #: cps/templates/modal_dialogs.html:57 msgid "Books must first be archived and the device synced before a book can safely be deleted." -msgstr "" +msgstr "本を安全に削除するためには、初めに本をアーカイブした上で端末と同期する必要があります" #: cps/templates/modal_dialogs.html:76 msgid "Choose File Location" -msgstr "" +msgstr "ファイルの場所を選択" #: cps/templates/modal_dialogs.html:82 msgid "type" -msgstr "" +msgstr "種類" #: cps/templates/modal_dialogs.html:83 msgid "name" -msgstr "" +msgstr "名前" #: cps/templates/modal_dialogs.html:84 msgid "size" -msgstr "" +msgstr "サイズ" #: cps/templates/modal_dialogs.html:90 msgid "Parent Directory" -msgstr "" +msgstr "親ディレクトリ" #: cps/templates/modal_dialogs.html:98 msgid "Select" -msgstr "" +msgstr "選択" -#: cps/templates/modal_dialogs.html:134 -#, fuzzy +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 msgid "Ok" -msgstr "本" +msgstr "OK" #: cps/templates/osd.xml:5 msgid "Calibre-Web eBook Catalog" -msgstr "" +msgstr "Calibre-WebのeBookカタログ" #: cps/templates/read.html:6 msgid "epub Reader" -msgstr "" +msgstr "EPUBリーダー" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "ライト" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "ダーク" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "セピア" + +#: cps/templates/read.html:84 +msgid "Black" +msgstr "ブラック" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." +msgstr "サイドバーが開いているとき、テキストを再度流し込みます。" + +#: cps/templates/read.html:93 +msgid "Font Sizes" msgstr "" #: cps/templates/readcbr.html:7 msgid "Comic Reader" -msgstr "" +msgstr "コミックリーダー" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "キーボードショートカット" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "前のページ" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "次のページ" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "最適なサイズにする" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "横に合わせる" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "縦に合わせる" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "オリジナルのサイズにする" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "右に回転する" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "左に回転する" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "画像を反転する" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "ライト" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "ダーク" - -#: cps/templates/readcbr.html:122 -msgid "Scale" -msgstr "サイズ" - #: cps/templates/readcbr.html:125 +msgid "Scale" +msgstr "スケール" + +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "最適" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "横に合わせる" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "縦に合わせる" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "オリジナル" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "回転" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "反転" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "水平方向" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "垂直方向" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "読む方向" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "左から右" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "右から左" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" -msgstr "" +msgstr "一番上にリセット" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" -msgstr "" - -#: cps/templates/readcbr.html:171 -msgid "Scrollbar" -msgstr "" +msgstr "位置を維持" #: cps/templates/readcbr.html:174 -msgid "Show" -msgstr "" +msgid "Scrollbar" +msgstr "スクロールバー" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:177 +msgid "Show" +msgstr "表示" + +#: cps/templates/readcbr.html:178 msgid "Hide" -msgstr "" +msgstr "非表示" #: cps/templates/readdjvu.html:5 msgid "DJVU Reader" -msgstr "" +msgstr "DJVUリーダー" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 msgid "PDF Reader" -msgstr "" +msgstr "PDFリーダー" #: cps/templates/readtxt.html:6 -#, fuzzy msgid "txt Reader" -msgstr "テキストリーダ" +msgstr "テキストリーダー" #: cps/templates/register.html:4 msgid "Register New Account" -msgstr "" +msgstr "新規アカウントを登録" #: cps/templates/register.html:10 msgid "Choose a username" -msgstr "ユーザ名を入力してください" +msgstr "ユーザー名を入力してください" #: cps/templates/register.html:15 -msgid "Your email address" -msgstr "あなたのメールアドレス" +msgid "Your Email" +msgstr "メールアドレス" #: cps/templates/remote_login.html:5 msgid "Magic Link - Authorise New Device" -msgstr "" +msgstr "マジックリンク - 新規端末を認証する" #: cps/templates/remote_login.html:7 msgid "On another device, login and visit:" -msgstr "" +msgstr "他の端末でログインしてアクセスしてください:" #: cps/templates/remote_login.html:11 msgid "Once verified, you will automatically be logged in on this device." -msgstr "" +msgstr "一度承認されると、自動的にこの端末でログインされます。" #: cps/templates/remote_login.html:14 msgid "This verification link will expire in 10 minutes." -msgstr "" +msgstr "この確認リンクの有効期限は10分です。" -#: cps/templates/search.html:5 -msgid "No Results Found" -msgstr "" +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "シリーズの表紙サムネイルを生成" #: cps/templates/search.html:6 -msgid "Search Term:" -msgstr "" +msgid "No Results Found" +msgstr "結果が見つかりません" -#: cps/templates/search.html:8 +#: cps/templates/search.html:7 +msgid "Search Term:" +msgstr "検索する単語:" + +#: cps/templates/search.html:9 msgid "Results for:" msgstr "結果:" #: cps/templates/search_form.html:21 msgid "Published Date From" -msgstr "" +msgstr "発売日(〜から)" #: cps/templates/search_form.html:31 msgid "Published Date To" -msgstr "" - -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" +msgstr "発売日(〜まで)" #: cps/templates/search_form.html:59 msgid "Exclude Tags" -msgstr "タグを除外" +msgstr "除外するタグ" #: cps/templates/search_form.html:77 msgid "Exclude Series" -msgstr "シリーズを除外" +msgstr "除外するシリーズ" #: cps/templates/search_form.html:95 -#, fuzzy msgid "Exclude Shelves" -msgstr "シリーズを除外" +msgstr "除外する本棚" #: cps/templates/search_form.html:115 msgid "Exclude Languages" -msgstr "言語を除外" +msgstr "除外する言語" #: cps/templates/search_form.html:126 msgid "Extensions" -msgstr "" +msgstr "拡張子" #: cps/templates/search_form.html:134 msgid "Exclude Extensions" -msgstr "" +msgstr "除外する拡張子" #: cps/templates/search_form.html:144 msgid "Rating Above" -msgstr "" +msgstr "評価(〜以上)" #: cps/templates/search_form.html:148 msgid "Rating Below" -msgstr "" +msgstr "評価(〜以下)" #: cps/templates/search_form.html:180 msgid "From:" -msgstr "" +msgstr "〜から:" #: cps/templates/search_form.html:190 msgid "To:" -msgstr "" +msgstr "〜まで:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "この本棚を削除" -#: cps/templates/shelf.html:12 -msgid "Edit Shelf Properties" -msgstr "" - #: cps/templates/shelf.html:14 +msgid "Edit Shelf Properties" +msgstr "本棚のプロパティを編集" + +#: cps/templates/shelf.html:17 msgid "Arrange books manually" -msgstr "" +msgstr "手動で本を並び替える" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" -msgstr "" +msgstr "並び順の変更を無効にする" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" -msgstr "" - -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "" +msgstr "並び順の変更を有効にする" #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" -msgstr "" +msgstr "みんなと共有" #: cps/templates/shelf_edit.html:21 msgid "Sync this shelf with Kobo device" -msgstr "" +msgstr "この本棚をKobo端末と同期" #: cps/templates/shelf_order.html:5 msgid "Drag to Rearrange Order" -msgstr "" +msgstr "ドラッグして並び順を変更" #: cps/templates/shelf_order.html:33 msgid "Hidden Book" -msgstr "" +msgstr "非表示の本" #: cps/templates/stats.html:7 msgid "Library Statistics" -msgstr "" +msgstr "ライブラリの統計" #: cps/templates/stats.html:12 msgid "Books in this Library" -msgstr "このライブラリ内の本" +msgstr "このライブラリ内の本の冊数" #: cps/templates/stats.html:16 msgid "Authors in this Library" -msgstr "このライブラリ内の著者" +msgstr "このライブラリ内の著者数" #: cps/templates/stats.html:20 msgid "Categories in this Library" -msgstr "このライブラリ内のカテゴリ" +msgstr "このライブラリ内のカテゴリ数" #: cps/templates/stats.html:24 msgid "Series in this Library" -msgstr "このライブラリ内のシリーズ" +msgstr "このライブラリ内のシリーズ数" #: cps/templates/stats.html:29 msgid "System Statistics" -msgstr "" +msgstr "システムの統計" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "" +msgid "Program" +msgstr "プログラム" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -2998,7 +3218,7 @@ msgstr "インストールされたバージョン" #: cps/templates/tasks.html:12 msgid "User" -msgstr "ユーザ" +msgstr "ユーザー" #: cps/templates/tasks.html:14 msgid "Task" @@ -3014,149 +3234,153 @@ msgstr "進捗" #: cps/templates/tasks.html:17 msgid "Run Time" -msgstr "" +msgstr "稼働時間" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "アクション" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "このタスクはキャンセルされます。このタスクによる進捗はすべて保存されます。" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "これがスケジュールタスクの場合、次のスケジュールの時刻にはもう一度実行されます。" #: cps/templates/user_edit.html:20 msgid "Reset user Password" -msgstr "ユーザパスワードをリセット" +msgstr "パスワードをリセット" #: cps/templates/user_edit.html:43 msgid "Language of Books" -msgstr "" +msgstr "本の言語" #: cps/templates/user_edit.html:54 msgid "OAuth Settings" -msgstr "" +msgstr "OAuth設定" #: cps/templates/user_edit.html:56 msgid "Link" -msgstr "" +msgstr "リンク" #: cps/templates/user_edit.html:58 msgid "Unlink" -msgstr "" +msgstr "リンク解除" #: cps/templates/user_edit.html:64 msgid "Kobo Sync Token" -msgstr "" +msgstr "Kobo同期トークン" #: cps/templates/user_edit.html:66 msgid "Create/View" -msgstr "" +msgstr "作成/表示" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "強制的にKoboと完全同期" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" -msgstr "" +msgstr "許可/拒否カスタムカラムを追加" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" -msgstr "" +msgstr "選択した本棚内の本のみKoboと同期" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" -msgstr "" +msgstr "ユーザーを削除" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" -msgstr "" +msgstr "Koboの認証URLを生成" #: cps/templates/user_table.html:80 cps/templates/user_table.html:103 msgid "Select..." -msgstr "" +msgstr "選択..." #: cps/templates/user_table.html:131 msgid "Edit User" -msgstr "" +msgstr "ユーザーを編集" #: cps/templates/user_table.html:134 -#, fuzzy msgid "Enter Username" -msgstr "ユーザ名を入力してください" +msgstr "ユーザー名を入力してください" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "あなたのメールアドレス" - -#: cps/templates/user_table.html:136 -#, fuzzy -msgid "Enter Kindle E-mail Address" -msgstr "あなたのメールアドレス" - -#: cps/templates/user_table.html:136 -#, fuzzy -msgid "Kindle E-mail" +msgid "Enter Email" msgstr "テストメール" -#: cps/templates/user_table.html:137 +#: cps/templates/user_table.html:136 #, fuzzy +msgid "Enter eReader Email" +msgstr "E-Readerメールアドレス" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "eReader Email" +msgstr "E-Readerメール" + +#: cps/templates/user_table.html:137 msgid "Locale" -msgstr "サイズ" +msgstr "地域" #: cps/templates/user_table.html:138 msgid "Visible Book Languages" -msgstr "" +msgstr "表示する本の言語" #: cps/templates/user_table.html:139 msgid "Edit Allowed Tags" -msgstr "" +msgstr "許可タグを編集" #: cps/templates/user_table.html:139 msgid "Allowed Tags" -msgstr "" +msgstr "許可タグ" #: cps/templates/user_table.html:140 msgid "Edit Denied Tags" -msgstr "" +msgstr "拒否タグを編集" #: cps/templates/user_table.html:140 msgid "Denied Tags" -msgstr "" +msgstr "拒否タグ" #: cps/templates/user_table.html:141 msgid "Edit Allowed Column Values" -msgstr "" +msgstr "許可カスタムカラムを編集" #: cps/templates/user_table.html:141 msgid "Allowed Column Values" -msgstr "" +msgstr "許可カスタムカラム" #: cps/templates/user_table.html:142 msgid "Edit Denied Column Values" -msgstr "" +msgstr "拒否カスタムカラムを編集" #: cps/templates/user_table.html:142 msgid "Denied Column Values" -msgstr "" +msgstr "拒否カスタムカラム" #: cps/templates/user_table.html:144 -#, fuzzy msgid "Change Password" -msgstr "パスワード変更を許可" +msgstr "パスワード変更" #: cps/templates/user_table.html:147 msgid "View" -msgstr "" +msgstr "閲覧" #: cps/templates/user_table.html:150 -#, fuzzy msgid "Edit Public Shelves" -msgstr "本棚を編集する" +msgstr "みんなの本棚を編集" #: cps/templates/user_table.html:152 msgid "Sync selected Shelves with Kobo" -msgstr "" +msgstr "選択した本棚をKoboと同期" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" -msgstr "シリーズ選択を表示" - -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "ランダムで本を表示" +msgid "Show Read/Unread Section" +msgstr "既読/未読の選択を表示" diff --git a/cps/translations/km/LC_MESSAGES/messages.mo b/cps/translations/km/LC_MESSAGES/messages.mo index 91e2659d3..7e7db8a99 100644 Binary files a/cps/translations/km/LC_MESSAGES/messages.mo and b/cps/translations/km/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/km/LC_MESSAGES/messages.po b/cps/translations/km/LC_MESSAGES/messages.po index 1a1cc0941..c65f54e97 100644 --- a/cps/translations/km/LC_MESSAGES/messages.po +++ b/cps/translations/km/LC_MESSAGES/messages.po @@ -8,585 +8,642 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2018-08-27 17:06+0700\n" "Last-Translator: \n" "Language: km_KH\n" "Language-Team: \n" -"Plural-Forms: nplurals=1; plural=0\n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "មិនបានតម្លើង" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "ស្ថិតិ" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "ម៉ាស៊ីន server បានដំណើរការម្តងទៀត សូមបើកទំព័រជាថ្មី" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "កំពុងបិទម៉ាស៊ីន server សូមបិទផ្ទាំងនេះ" -#: cps/admin.py:154 -msgid "Reconnect successful" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "សៀវភៅបានចូលជួរសម្រាប់ផ្ញើទៅ %(eReadermail)s ដោយជោគជ័យ" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "មិនដឹង" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "ទំព័ររដ្ឋបាល" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "ការកំណត់សាមញ្ញ" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "ការកំណត់ផ្ទាំងប្រើប្រាស់" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" msgstr "អ្នកប្រើប្រាស់រដ្ឋបាល" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "បង្ហាញទាំងអស់" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "តើអ្នកពិតជាចង់លុបធ្នើនេះមែនទេ?" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "តើអ្នកពិតជាចង់លុបធ្នើនេះមែនទេ?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "តើអ្នកពិតជាចង់លុបធ្នើនេះមែនទេ?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "តើអ្នកពិតជាចង់លុបធ្នើនេះមែនទេ?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "តើអ្នកពិតជាចង់លុបធ្នើនេះមែនទេ?" -#: cps/admin.py:741 -msgid "Tag not found" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "ទំនាក់ទំនងទៅមូលដ្ឋានទិន្នន័យត្រូវបានផ្តាច់" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "ការកំណត់មុខងារ" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "សូមបំពេញចន្លោះទាំងអស់!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "បន្ថែមអ្នកប្រើប្រាស់ថ្មី" - -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "បានបង្កើតអ្នកប្រើប្រាស់ ‘%(user)s’" - -#: cps/admin.py:1369 -msgid "Found an existing account for this e-mail address or name." -msgstr "" - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "អ្នកប្រើប្រាស់ ‘%(nick)s’ ត្រូវបានលុប" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "កែប្រែអ្នកប្រើប្រាស់ %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "អ្នកប្រើប្រាស់ ‘%(nick)s’ ត្រូវបានកែប្រែ" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "" - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "ប្តូរការកំណត់ SMTP" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "" + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "" -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "" + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "កែប្រែអ្នកប្រើប្រាស់ %(nick)s" + +#: cps/admin.py:1423 +#, python-format +msgid "Success! Password for user %(user)s reset" msgstr "" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "សូមកំណត់អ៊ីមែល SMTP ជាមុនសិន" -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "កំពុងស្នើសុំឯកសារបច្ចុប្បន្នភាព" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "កំពុងទាញយកឯកសារបច្ចុប្បន្នភាព" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "កំពុងពន្លាឯកសារបច្ចុប្បន្នភាព" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "ទំនាក់ទំនងទៅមូលដ្ឋានទិន្នន័យត្រូវបានផ្តាច់" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "ការធ្វើបច្ចុប្បន្នភាពបានបញ្ចប់ សូមចុច okay រួចបើកទំព័រជាថ្មី" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "" -#: cps/admin.py:1696 +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" msgstr "" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" msgstr "" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "" -#: cps/converter.py:30 -msgid "not configured" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" msgstr "" +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "ទំនាក់ទំនងទៅមូលដ្ឋានទិន្នន័យត្រូវបានផ្តាច់" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "ការកំណត់មុខងារ" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "សូមបំពេញចន្លោះទាំងអស់!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "បន្ថែមអ្នកប្រើប្រាស់ថ្មី" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "បានបង្កើតអ្នកប្រើប្រាស់ ‘%(user)s’" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "" + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "អ្នកប្រើប្រាស់ ‘%(nick)s’ ត្រូវបានលុប" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "អ្នកប្រើប្រាស់ ‘%(nick)s’ ត្រូវបានកែប្រែ" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "មិនបានតម្លើង" + #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "គ្មាន" + +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" -msgstr "" - -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "កែប្រែទិន្នន័យមេតា" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "ឯកសារប្រភេទ '%(ext)s' មិនត្រូវបានអនុញ្ញាតឲអាប់ឡូដទៅម៉ាស៊ីន server នេះទេ" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "ឯកសារដែលត្រូវអាប់ឡូដត្រូវមានកន្ទុយឯកសារ" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "មិនអាចបង្កើតទីតាំង %(path)s (ពុំមានសិទ្ធិ)។" - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "មិនអាចរក្សាទុកឯកសារ %(file)s ។" - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "ឯកសារទម្រង់ %(ext)s ត្រូវបានបន្ថែមទៅ %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "មានបញ្ហាពេលកែប្រែសៀវភៅ សូមពិនិត្យមើល logfile សម្រាប់ព័ត៌មានបន្ថែម" - -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " +#: cps/editbooks.py:234 +msgid "Error editing book: {}" msgstr "" -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "" + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "ឯកសារប្រភេទ '%(ext)s' មិនត្រូវបានអនុញ្ញាតឲអាប់ឡូដទៅម៉ាស៊ីន server នេះទេ" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "ឯកសារដែលត្រូវអាប់ឡូដត្រូវមានកន្ទុយឯកសារ" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "កែប្រែទិន្នន័យមេតា" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "មិនអាចបង្កើតទីតាំង %(path)s (ពុំមានសិទ្ធិ)។" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "មិនអាចរក្សាទុកឯកសារ %(file)s ។" + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "ឯកសារទម្រង់ %(ext)s ត្រូវបានបន្ថែមទៅ %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "" @@ -600,165 +657,175 @@ msgstr "Callback domain មិនទាន់បានផ្ទៀងផ្ទ msgid "%(format)s format not found for book id: %(book)d" msgstr "" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "ផ្ញើទៅ Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +msgid "This Email has been sent via Calibre-Web." msgstr "" -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +msgid "Calibre-Web Test Email" msgstr "" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +msgid "Test Email" msgstr "" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "" -#: cps/helper.py:135 +#: cps/helper.py:137 #, python-format -msgid "Registration e-mail for user: %(name)s" +msgid "Registration Email for user: %(name)s" msgstr "" -#: cps/helper.py:146 cps/helper.py:152 +#: cps/helper.py:148 cps/helper.py:154 #, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" -msgstr "" - -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "Send %(format)s to eReader" msgstr "ផ្ញើទៅ Kindle" -#: cps/helper.py:224 +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" +msgstr "ផ្ញើទៅ Kindle" + +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "ឯកសារដែលបានស្នើសុំមិនអាចបើកបានទេ។ អាចនឹងខុសសិទ្ធិប្រើប្រាស់ទេដឹង?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "ប្តូរចំណងជើងពី “%(src)s” ទៅជា “%(dest)s” បរាជ័យដោយបញ្ហា: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "ឯកសារ %(file)s រកមិនឃើញក្នុង Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "ប្តូរចំណងជើងពី “%(src)s” ទៅជា “%(dest)s” បរាជ័យដោយបញ្ហា: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "ទីតាំងសៀវភៅ %(path)s រកមិនឃើញក្នុង Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -msgid "Found an existing account for this e-mail address" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +msgid "Error executing UnRar" msgstr "" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "កំពុងរង់ចាំ" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "ស្រាវជ្រាវ" -#: cps/helper.py:764 -msgid "Failed" -msgstr "បានបរាជ័យ" - -#: cps/helper.py:766 -msgid "Started" -msgstr "បានចាប់ផ្តើម" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "បានបញ្ចប់" - -#: cps/helper.py:770 -msgid "Unknown Status" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" msgstr "" -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "" @@ -767,9 +834,9 @@ msgstr "" msgid "Register with %(provider)s" msgstr "" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "ឥឡូវអ្នកបានចូលដោយមានឈ្មោះថា៖ ‘%(nickname)s’" #: cps/oauth_bb.py:148 @@ -828,507 +895,610 @@ msgstr "" msgid "Google Oauth error: {}" msgstr "" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "ចូលប្រើប្រាស់" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "រកមិនឃើញវត្ថុតាង" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "វត្ថុតាងហួសពេលកំណត់" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "ជោគជ័យ! សូមវិលមកឧបករណ៍អ្នកវិញ" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "បង្ហាញសៀវភៅមកថ្មី" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "សៀវភៅដែលមានប្រជាប្រិយភាព" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "បង្ហាញសៀវភៅដែលមានប្រជាប្រិយភាព" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "សៀវភៅដែលមានការវាយតម្លៃល្អជាងគេ" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "បង្ហាញសៀវភៅដែលមានការវាយតម្លៃល្អជាងគេ" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "សៀវភៅដែលបានអានរួច" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "បង្ហាញអានរួច និងមិនទាន់អាន" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "សៀវភៅដែលមិនទាន់បានអាន" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "ស្រាវជ្រាវ" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "បង្ហាញសៀវភៅចៃដន្យ" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "ប្រភេទនានា" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "បង្ហាញជម្រើសប្រភេទ" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "ស៊េរី" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "បង្ហាញជម្រើសស៊េរី" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "អ្នកនិពន្ធ" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "បង្ហាញជម្រើសអ្នកនិពន្ធ" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" -msgstr "" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" +msgstr "បង្ហាញជម្រើសស៊េរី" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "ភាសានានា" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "បង្ហាញផ្នែកភាសា" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" -msgstr "" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "បង្ហាញជម្រើសស៊េរី" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" -msgstr "" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" +msgstr "បង្ហាញជម្រើសស៊េរី" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" -msgstr "" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "បង្ហាញសៀវភៅមកថ្មី" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "សូមអភ័យទោស អ្នកមិនមានសិទ្ធិដកសៀវភៅចេញពីធ្នើនេះទេ៖ %(sname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "សៀវភៅត្រូវបានបន្ថែមទៅធ្នើ៖ %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "សៀវភៅត្រូវបានដកចេញពីធ្នើ៖ %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "សូមអភ័យទោស អ្នកមិនមានសិទ្ធិដកសៀវភៅចេញពីធ្នើនេះទេ៖ %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "បង្កើតធ្នើ" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "សូមអភ័យទោស អ្នកមិនមានសិទ្ធិដកសៀវភៅចេញពីធ្នើនេះទេ៖ %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "កែប្រែធ្នើ" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "ធ្នើឈ្មោះ %(title)s ត្រូវបានបង្កើត" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "ធ្នើឈ្មោះ %(title)s ត្រូវបានប្តូរ" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "មានបញ្ហា" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "ប្តូរលំដាប់ធ្នើ៖ ‘%(name)s’" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "ធ្នើ៖ ‘%(name)s’" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "មានបញ្ហាពេលបើកធ្នើ។ ពុំមានធ្នើ ឬមិនអាចបើកបាន" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "" - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "" - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "ស្រាវជ្រាវ (សៀវភៅចៃដន្យ)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "សៀវភៅដែលត្រូវបានទាញយកច្រើនជាងគេ" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "ស៊េរី៖ %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "ប្រភេទ៖ %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "ភាសា៖ %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "ស្វែងរកកម្រិតខ្ពស់" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "ស្វែងរក" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "ឯកសារ DLS" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "កិច្ចការនានា" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "បានបោះពុម្ភក្រោយ " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "បានបោះពុម្ភមុន " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "ការវាយតម្លៃ <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "ការវាយតម្លៃ >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "សៀវភៅបានចូលជួរសម្រាប់ផ្ញើទៅ %(kindlemail)s ដោយជោគជ័យ" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "ស្វែងរកកម្រិតខ្ពស់" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "សូមអភ័យទោស អ្នកមិនមានសិទ្ធិដកសៀវភៅចេញពីធ្នើនេះទេ៖ %(sname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "សៀវភៅត្រូវបានបន្ថែមទៅធ្នើ៖ %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "សៀវភៅត្រូវបានដកចេញពីធ្នើ៖ %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "បង្កើតធ្នើ" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "សូមអភ័យទោស អ្នកមិនមានសិទ្ធិដកសៀវភៅចេញពីធ្នើនេះទេ៖ %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "កែប្រែធ្នើ" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "ប្តូរលំដាប់ធ្នើ៖ ‘%(name)s’" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "ធ្នើឈ្មោះ %(title)s ត្រូវបានបង្កើត" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "ធ្នើឈ្មោះ %(title)s ត្រូវបានប្តូរ" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "មានបញ្ហា" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "ធ្នើ៖ ‘%(name)s’" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "មានបញ្ហាពេលបើកធ្នើ។ ពុំមានធ្នើ ឬមិនអាចបើកបាន" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "កិច្ចការនានា" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "កំពុងរង់ចាំ" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "បានបរាជ័យ" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "បានចាប់ផ្តើម" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "បានបញ្ចប់" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "" + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "" + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "ស្រាវជ្រាវ (សៀវភៅចៃដន្យ)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "សៀវភៅដែលត្រូវបានទាញយកច្រើនជាងគេ" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "ស៊េរី៖ %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "ប្រភេទ៖ %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "ភាសា៖ %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "ឯកសារ DLS" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "សូមកំណត់អ៊ីមែល SMTP ជាមុនសិន" + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "សៀវភៅបានចូលជួរសម្រាប់ផ្ញើទៅ %(eReadermail)s ដោយជោគជ័យ" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "មានបញ្ហានៅពេលផ្ញើសៀវភៅនេះ៖ %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "" -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "ចុះឈ្មោះ" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "" -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "ខុសឈ្មោះអ្នកប្រើប្រាស់ ឬលេខសម្ងាត់" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "ព័ត៌មានសង្ខេបរបស់ %(name)s" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "ព័ត៌មានសង្ខេបបានកែប្រែ" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "" + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "ផ្ញើទៅ Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Ebook-converter បានបរាជ័យ៖ %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "កែប្រែទិន្នន័យមេតា" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "អាប់ឡូដ" + #: cps/templates/admin.html:9 msgid "Users" msgstr "បញ្ជីអ្នកប្រើប្រាស់" @@ -1341,14 +1511,15 @@ msgstr "ឈ្មោះហៅក្រៅ" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "ឧបករណ៍ Kindle" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "រដ្ឋបាល" @@ -1358,212 +1529,229 @@ msgstr "រដ្ឋបាល" msgid "Password" msgstr "លេខសម្ងាត់" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "អាប់ឡូដ" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "ទាញយក" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "កែប្រែ" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "លុប" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "ឈ្មោះម៉ាស៊ីន SMTP" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "លេខ port SMTP" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "SSL" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "អ្នកចូលប្រើ SMTP" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "ពីអ៊ីមែល" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "ការកំណត់" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "ទីតាំង database Calibre" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "លេខ port" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "ចំនួនសៀវភៅក្នុងមួយទំព័រ" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "កំពុងអាប់ឡូដ" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "ការចុះឈ្មាះសាធារណៈ" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "ការចូលប្រើប្រាស់ពីចម្ងាយ" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "ទីតាំង database Calibre" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "កិច្ចការរដ្ឋបាល" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "ភ្ជាប់ទៅ database Calibre ម្តងទៀត" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "" -#: cps/templates/admin.html:172 -msgid "Update" +#: cps/templates/admin.html:216 +msgid "Version Information" msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "រកមើលបច្ចុប្បន្នភាព" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "ធ្វើបច្ចុប្បន្នភាព" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "បាទ/ចាស" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "កំពុងធ្វើបច្ចុប្បន្នភាព សូមកុំបើកទំព័រជាថ្មី" @@ -1575,119 +1763,118 @@ msgstr "តាមរយៈ" msgid "In Library" msgstr "នៅក្នុងបណ្ណាល័យ" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "បន្ថែមទៀតដោយ" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "លុបសៀវភៅ" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "លុបឯកសារទម្រង់៖" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "ចំណងជើងសៀវភៅ" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "អ្នកនិពន្ធ" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "ពិពណ៌នា" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Tag" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "លេខសម្គាល់ស៊េរី" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "ការវាយតម្លៃ" @@ -1699,82 +1886,83 @@ msgstr "URL របស់ក្របមុខ (ឯកសារ JPG ក្រប msgid "Upload Cover from Local Disk" msgstr "" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "ថ្ងៃបោះពុម្ភ" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "អ្នកបោះពុម្ភ" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "ភាសា" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "បាទ/ចាស" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "ទេ" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "ទម្រង់អាប់ឡូដ" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "មើលសៀវភៅក្រោយពីកែប្រែ" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "មើលទិន្នន័យមេតា" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "ពាក្យគន្លឹះ" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr "ស្វែងរកពាក្យគន្លឹះ" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "ចុចលើគម្របដើម្បីបញ្ចូលទិន្នន័យមេតាទៅក្នុង form" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "កំពុងដំណើរការ..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "បិទ" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "ប្រភព" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "ការស្វែងរកមានកំហុស!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "" @@ -1865,27 +2053,36 @@ msgstr "" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "ចុះឈ្មោះ" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "" @@ -1977,6 +2174,10 @@ msgstr "" msgid "Enable Uploads" msgstr "" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "" @@ -1990,7 +2191,7 @@ msgid "Enable Public Registration" msgstr "អនុញ្ញាតការចុះឈ្មោះសាធារណៈ" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "" #: cps/templates/config_edit.html:132 @@ -2057,11 +2258,6 @@ msgstr "" msgid "LDAP Encryption" msgstr "" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "គ្មាន" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "" @@ -2197,7 +2393,7 @@ msgstr "ចំនួនសៀវភៅចៃដន្យដើម្បីបង msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "ការតុបតែង" @@ -2229,138 +2425,140 @@ msgstr "Regular expression ដើម្បីរៀបចំណងជើងត msgid "Default Settings for New Users" msgstr "ការកំណត់មកស្រាប់សម្រាប់អ្នកប្រើប្រាស់ថ្មី" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "អ្នកប្រើប្រាស់រដ្ឋបាល" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "អនុញ្ញាតឲទាញយក" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "អនុញ្ញាតឲអាប់ឡូត" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "អនុញ្ញាតឲកែប្រែ" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "អនុញ្ញាតឲលុបសៀវភៅ" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "អនុញ្ញាតឲប្តូរលេខសម្ងាត់" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "អនុញ្ញាតឲកែប្រែធ្នើសាធារណៈ" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "លើកលែងភាសា" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "បង្ហាញសៀវភៅដែលមានភាសា" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "ភាពមើលឃើញដែលមកស្រាប់សម្រាប់អ្នកប្រើប្រាស់ថ្មី" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "បង្ហាញសៀវភៅចៃដន្យក្នុងការបង្ហាញជាពិស្តារ" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "អានក្នុងកម្មវិធី browser" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "អាន" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "ពិពណ៌នា" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "បន្ថែមទៅធ្នើ" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "កែប្រែទិន្នន័យមេតា" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" +msgid "Gmail Account" msgstr "" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 @@ -2384,10 +2582,11 @@ msgid "Attachment Size Limit" msgstr "" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "រក្សាទុកការកំណត់រួចផ្ញើអ៊ីមែលសាកល្បង" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "មកក្រោយ" @@ -2413,45 +2612,61 @@ msgstr "" msgid "Denied Domains (Blacklist)" msgstr "" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "បន្ទាប់" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" msgstr "" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "" @@ -2515,7 +2730,7 @@ msgstr "" msgid "Books ordered by file formats" msgstr "" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "" @@ -2524,63 +2739,67 @@ msgstr "" msgid "Books organized in shelves" msgstr "" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "បិទ/បើកការរុករក" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "កំពុងអាប់ឡូត..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "" - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "ការកំណត់" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "ចេញពីការប្រើប្រាស់" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "កំពុងអាប់ឡូត..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "" + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "ការកំណត់" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "រុករក" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "អំពី" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "មុន" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "ព័ត៌មានលម្អិតរបស់សៀវភៅ" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "ចងចាំខ្ញុំ" @@ -2589,7 +2808,7 @@ msgstr "ចងចាំខ្ញុំ" msgid "Forgot Password?" msgstr "" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "ចូលប្រើប្រាស់ដោយ magic link" @@ -2685,7 +2904,7 @@ msgstr "" msgid "Select" msgstr "" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "សៀវភៅ" @@ -2698,127 +2917,140 @@ msgstr "" msgid "epub Reader" msgstr "" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "មកក្រោយ" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "សេរេអត្ថបទនៅពេលបើកផ្ទាំងចំហៀង។" +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 msgid "Comic Reader" msgstr "" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "" @@ -2826,7 +3058,7 @@ msgstr "" msgid "DJVU Reader" msgstr "" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 msgid "PDF Reader" msgstr "" @@ -2844,7 +3076,7 @@ msgid "Choose a username" msgstr "ជ្រើសរើសឈ្មោះអ្នកប្រើប្រាស់" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "អាសយដ្ឋានអ៊ីមែលរបស់អ្នក" #: cps/templates/remote_login.html:5 @@ -2863,15 +3095,19 @@ msgstr "ក្រោយពីនេះ អ្នកនឹងត្រូវប msgid "This verification link will expire in 10 minutes." msgstr "" -#: cps/templates/search.html:5 -msgid "No Results Found" +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" msgstr "" #: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "" + +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "លទ្ធផលសម្រាប់៖" @@ -2883,10 +3119,6 @@ msgstr "ថ្ងៃបោះពុម្ភចាប់ពី" msgid "Published Date To" msgstr "ថ្ងៃបោះពុម្ភរហូតដល់" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "លើកលែង tag" @@ -2928,30 +3160,26 @@ msgstr "" msgid "To:" msgstr "" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "លុបធ្នើនេះ" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "ធ្នើនេះនឹងបាត់បង់ជាអចិន្ត្រៃយ៍សម្រាប់គ្រប់គ្នា!" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "តើធ្នើនេះគួរជាសាធារណៈទេ?" @@ -2993,8 +3221,8 @@ msgid "System Statistics" msgstr "" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Library របស់កម្មវិធី" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3020,9 +3248,17 @@ msgstr "ដំណើរការ" msgid "Run Time" msgstr "រយៈពេលដែលបានចាប់ផ្តើម" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "ពេលចាប់ផ្តើម" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3052,19 +3288,23 @@ msgstr "" msgid "Create/View" msgstr "" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "លុបអ្នកប្រើប្រាស់នេះ" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "" @@ -3084,17 +3324,18 @@ msgstr "ជ្រើសរើសឈ្មោះអ្នកប្រើប្រ #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "អាសយដ្ឋានអ៊ីមែលរបស់អ្នក" - -#: cps/templates/user_table.html:136 -#, fuzzy -msgid "Enter Kindle E-mail Address" +msgid "Enter Email" msgstr "ឧបករណ៍ Kindle" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" -msgstr "" +#, fuzzy +msgid "Enter eReader Email" +msgstr "ឧបករណ៍ Kindle" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "eReader Email" +msgstr "ឧបករណ៍ Kindle" #: cps/templates/user_table.html:137 msgid "Locale" @@ -3156,10 +3397,6 @@ msgstr "" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "បង្ហាញជម្រើសស៊េរី" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "បង្ហាញសៀវភៅចៃដន្យ" - diff --git a/cps/translations/ko/LC_MESSAGES/messages.mo b/cps/translations/ko/LC_MESSAGES/messages.mo new file mode 100644 index 000000000..a29c34d3a Binary files /dev/null and b/cps/translations/ko/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/ko/LC_MESSAGES/messages.po b/cps/translations/ko/LC_MESSAGES/messages.po new file mode 100644 index 000000000..b6fa2e16f --- /dev/null +++ b/cps/translations/ko/LC_MESSAGES/messages.po @@ -0,0 +1,3391 @@ +# Korean translation for Calibre-web +# Copyright (C) 2022 EPUBGUIDE.NET +# This file is distributed under the same license as the Calibre-web project +# First korean translation by 내맘대로의 EPUBGUIDE.NET +msgid "" +msgstr "" +"Project-Id-Version: Calibre-web\n" +"Report-Msgid-Bugs-To: https://github.com/janeczku/calibre-web\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" +"PO-Revision-Date: 2022-01-10 11:30+0900\n" +"Last-Translator: 내맘대로의 EPUBGUIDE.NET \n" +"Language: ko\n" +"Language-Team: 내맘대로의 epubguide.net \n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.10.3\n" + +#: cps/about.py:84 +msgid "Statistics" +msgstr "통계" + +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." +msgstr "서버 다시 시작으로 새로고침 필요" + +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." +msgstr "서버를 종료하는 중, 창을 닫아야 함" + +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" + +#: cps/admin.py:156 +msgid "Unknown command" +msgstr "알 수 없는 명령" + +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "성공적으로 %(eReadermail)s에 보내기 예약이 되었습니다" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 +msgid "Unknown" +msgstr "알 수 없음" + +#: cps/admin.py:225 +msgid "Admin page" +msgstr "관리자 페이지" + +#: cps/admin.py:245 +msgid "Basic Configuration" +msgstr "기본 설정" + +#: cps/admin.py:283 +msgid "UI Configuration" +msgstr "UI 설정" + +#: cps/admin.py:317 cps/templates/admin.html:51 +msgid "Edit Users" +msgstr "사용자 관리" + +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 +msgid "All" +msgstr "모두" + +#: cps/admin.py:388 cps/admin.py:1392 +msgid "User not found" +msgstr "사용자를 찾을 수 없음" + +#: cps/admin.py:402 +msgid "{} users deleted successfully" +msgstr "{} 사용자를 성공적으로 삭제함" + +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 +#: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 +msgid "Show All" +msgstr "모두 보기" + +#: cps/admin.py:446 cps/admin.py:452 +msgid "Malformed request" +msgstr "잘못된 요청" + +#: cps/admin.py:464 cps/admin.py:1993 +msgid "Guest Name can't be changed" +msgstr "Guest 이름은 수정할 수 없음" + +#: cps/admin.py:476 +msgid "Guest can't have this role" +msgstr "Guest는 이 권한을 사용할 수 없음" + +#: cps/admin.py:488 cps/admin.py:1948 +msgid "No admin user remaining, can't remove admin role" +msgstr "관리자 계정이 하나 뿐일 때는 관리자를 삭제할 수 없음" + +#: cps/admin.py:492 cps/admin.py:506 +msgid "Value has to be true or false" +msgstr "값으로 rue 또는 false만 설정 가능" + +#: cps/admin.py:494 +msgid "Invalid role" +msgstr "잘못된 권한" + +#: cps/admin.py:498 +msgid "Guest can't have this view" +msgstr "Guest는 이 view를 사용할 수 없음" + +#: cps/admin.py:508 +msgid "Invalid view" +msgstr "잘못된 view" + +#: cps/admin.py:511 +msgid "Guest's Locale is determined automatically and can't be set" +msgstr "Guest의 로케일은 자동으로 결정되며 설정할 수 없음" + +#: cps/admin.py:515 +msgid "No Valid Locale Given" +msgstr "유효한 로케일이 아님" + +#: cps/admin.py:526 +msgid "No Valid Book Language Given" +msgstr "제공된 책의 언어가 유효하지 않음" + +#: cps/admin.py:528 cps/editbooks.py:442 +msgid "Parameter not found" +msgstr "매개변수를 찾을 수 없음" + +#: cps/admin.py:565 +msgid "Invalid Read Column" +msgstr "잘못된 읽기 열" + +#: cps/admin.py:571 +msgid "Invalid Restricted Column" +msgstr "잘못된 제한된 열" + +#: cps/admin.py:591 cps/admin.py:1819 +msgid "Calibre-Web configuration updated" +msgstr "Calibre-Web 설정이 업데이트 됨" + +#: cps/admin.py:603 +msgid "Do you really want to delete the Kobo Token?" +msgstr "Kobo Token을 삭제하시겠습니까?" + +#: cps/admin.py:605 +msgid "Do you really want to delete this domain?" +msgstr "이 도메인을 삭제하시겠습니까?" + +#: cps/admin.py:607 +msgid "Do you really want to delete this user?" +msgstr "이 사용자를 삭제하시겠습니까?" + +#: cps/admin.py:609 +msgid "Are you sure you want to delete this shelf?" +msgstr "이 서재를 삭제하시겠습니까?" + +#: cps/admin.py:611 +msgid "Are you sure you want to change locales of selected user(s)?" +msgstr "선택한 사용자의 언어를 변경하시겠습니까?" + +#: cps/admin.py:613 +msgid "Are you sure you want to change visible book languages for selected user(s)?" +msgstr "선택한 사용자에 대해 표시되는 책 언어를 변경하시겠습니까?" + +#: cps/admin.py:615 +msgid "Are you sure you want to change the selected role for the selected user(s)?" +msgstr "선택한 사용자에 대해 선택한 권한을 변경하시겠습니까?" + +#: cps/admin.py:617 +msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" +msgstr "선택한 사용자에 대해 선택한 제한을 변경하시겠습니까?" + +#: cps/admin.py:619 +msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" +msgstr "선택한 사용자에 대해 선택한 가시성 제한을 변경하시겠습니까?" + +#: cps/admin.py:622 +msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" +msgstr "선택한 사용자의 실행기 동기화 동작을 변경하시겠습니까?" + +#: cps/admin.py:624 +msgid "Are you sure you want to change Calibre library location?" +msgstr "캘리버 서재의 언어를 변경하시겠습니까?" + +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "" + +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Kobo Reader와 전체 동기화를 강제 실행하기 위해 Calibre-Web의 동기화 데이터베이스를 삭제하시겠습니까?" + +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 +#: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 +#: cps/templates/user_table.html:58 +msgid "Deny" +msgstr "거부됨" + +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 +#: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 +#: cps/templates/user_table.html:61 +msgid "Allow" +msgstr "허용됨" + +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{} 동기화 항목이 삭제됨" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "태그를 찾을 수 없음" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "잘못된 액션" + +#: cps/admin.py:1104 +msgid "client_secrets.json Is Not Configured For Web Application" +msgstr "client_secrets.json이 Web 응용프로그램에 대해 설정되지 않음" + +#: cps/admin.py:1149 +msgid "Logfile Location is not Valid, Please Enter Correct Path" +msgstr "로그 파일 위치가 오류. 올바른 경로 입력 필요" + +#: cps/admin.py:1155 +msgid "Access Logfile Location is not Valid, Please Enter Correct Path" +msgstr "액세스 로그 파일 위치가 올바르지 않음. 올바른 경로 입력 필요" + +#: cps/admin.py:1185 +msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" +msgstr "LDAP 공급자, 포트, DN 및 사용자 개체 식별자를 입력" + +#: cps/admin.py:1191 +msgid "Please Enter a LDAP Service Account and Password" +msgstr "LDAP 서비스 계정 및 비밀번호를 입력하십시오" + +#: cps/admin.py:1194 +msgid "Please Enter a LDAP Service Account" +msgstr "LDAP 서비스 계정을 입력하십시오" + +#: cps/admin.py:1199 +#, python-format +msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" +msgstr "LDAP 그룹 개체 필터에는 하나의 \"%s\" 형식 식별자가 필요함" + +#: cps/admin.py:1201 +msgid "LDAP Group Object Filter Has Unmatched Parenthesis" +msgstr "LDAP 그룹 개체 필터에 일치하지 않는 괄호가 있음" + +#: cps/admin.py:1205 +#, python-format +msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" +msgstr "LDAP 사용자 개체 필터에는 하나의 \"%s\" 형식 식별자 필요" + +#: cps/admin.py:1207 +msgid "LDAP User Object Filter Has Unmatched Parenthesis" +msgstr "LDAP 사용자 개체 필터에 일치하지 않는 괄호가 있음" + +#: cps/admin.py:1214 +#, python-format +msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" +msgstr "LDAP 구성원 사용자 필터에는 하나의 \"%s\" 형식 식별자 필요" + +#: cps/admin.py:1216 +msgid "LDAP Member User Filter Has Unmatched Parenthesis" +msgstr "LDAP 구성원 사용자 필터에 일치하지 않는 괄호가 있음" + +#: cps/admin.py:1223 +msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" +msgstr "유요하지 않은 LDAP CACertificate, 인증서 또는 키 위치. 올바른 경로를 입력 필요" + +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "사용자 추가" + +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" +msgstr "이메일 서버 설정 편집" + +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" + +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "데이터베이스 오류: %(error)s." + +#: cps/admin.py:1311 +#, python-format +msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" +msgstr "%(email)s에 테스트를 위한 이메일을 보냄. 결과 확인 필요" + +#: cps/admin.py:1314 +#, python-format +msgid "There was an error sending the Test e-mail: %(res)s" +msgstr "테스트 이메일을 보내는 동안 오류가 발생했습니다: %(res)s" + +#: cps/admin.py:1316 +msgid "Please configure your e-mail address first..." +msgstr "먼저 이메일 주소를 구성하십시오..." + +#: cps/admin.py:1318 +msgid "Email Server Settings updated" +msgstr "이메일 서버 설정 업데이트됨" + +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "알 수없는 오류가 발생했습니다. 나중에 다시 시도 해주십시오." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 +#, python-format +msgid "Edit User %(nick)s" +msgstr "사용자 %(nick)s 편집" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" +msgstr "사용자 %(user)s의 비밀번호 재설정" + +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." +msgstr "먼저 SMTP 메일 설정을 구성하십시오..." + +#: cps/admin.py:1440 +msgid "Logfile viewer" +msgstr "로그 파일 뷰어" + +#: cps/admin.py:1506 +msgid "Requesting update package" +msgstr "업데이트 패키지 요청" + +#: cps/admin.py:1507 +msgid "Downloading update package" +msgstr "업데이트 패키지 다운로드" + +#: cps/admin.py:1508 +msgid "Unzipping update package" +msgstr "업데이트 패키지 압축 풀기" + +#: cps/admin.py:1509 +msgid "Replacing files" +msgstr "파일 교체" + +#: cps/admin.py:1510 +msgid "Database connections are closed" +msgstr "데이터베이스 연결이 닫힙니다" + +#: cps/admin.py:1511 +msgid "Stopping server" +msgstr "서버 중지" + +#: cps/admin.py:1512 +msgid "Update finished, please press okay and reload page" +msgstr "업데이트가 완료되었습니다. 확인을 누르고 페이지를 새로고침하세요" + +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 +msgid "Update failed:" +msgstr "업데이트 실패:" + +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 +msgid "HTTP Error" +msgstr "HTTP 오류" + +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 +msgid "Connection error" +msgstr "연결 오류" + +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 +msgid "Timeout while establishing connection" +msgstr "연결 설정 중 시간 초과" + +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 +msgid "General error" +msgstr "일반 오류" + +#: cps/admin.py:1517 +msgid "Update file could not be saved in temp dir" +msgstr "임시 디렉토리에 업데이트 파일을 저장할 수 없습니다" + +#: cps/admin.py:1518 +msgid "Files could not be replaced during update" +msgstr "업데이트하는 동안 파일을 교체할 수 없습니다" + +#: cps/admin.py:1542 +msgid "Failed to extract at least One LDAP User" +msgstr "하나 이상의 LDAP 사용자를 추출하지 못했습니다" + +#: cps/admin.py:1587 +msgid "Failed to Create at Least One LDAP User" +msgstr "하나 이상의 LDAP 사용자를 생성하지 못했습니다" + +#: cps/admin.py:1600 +#, python-format +msgid "Error: %(ldaperror)s" +msgstr "오류: %(ldaperror)s" + +#: cps/admin.py:1604 +msgid "Error: No user returned in response of LDAP server" +msgstr "오류: LDAP 서버의 응답으로 사용자가 반환되지 않았습니다" + +#: cps/admin.py:1637 +msgid "At Least One LDAP User Not Found in Database" +msgstr "데이터베이스에서 하나 이상의 LDAP 사용자를 찾을 수 없습니다" + +#: cps/admin.py:1639 +msgid "{} User Successfully Imported" +msgstr "{} 사용자 가져오기 성공" + +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "올바르지 않은 DB 위치. 올바른 경로 입력 필요" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "쓰기 권한이 없는 DB" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "올바르지 않은 키 파일 위치. 올바른 경로 입력 필요" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "올바르지 않은 인증서 파일 위치. 올바른 경로 입력 필요" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "데이터베이스 설정이 업데이트 되었습니다" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "데이터베이스 구성" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "모든 필드를 채워주십시오!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "유효한 도메인에서 온 이메일이 아니" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "새 사용자 추가" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "사용자 '%(user)s'이(가) 생성됨" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "동일한 이메일 주소 또는 이름이 이미 등록되어 있습니다." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "사용자 '%(nick)s'이(가) 삭제됨" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "게스트 사용자는 삭제할 수 없습니다" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "관리자 계정이 하나 뿐일 때는 관리자 권한을 삭제할 수 없음" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "사용자 '%(nick)s'가 업데이트 됨" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "설치되지 않음" + +#: cps/converter.py:32 +msgid "Execution permissions missing" +msgstr "실행 권한 누락" + +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, fuzzy, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" +msgstr "사용자 정의 열 번호 %(column)d이(가) calibre 데이터베이스에 없습니다" + +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "None" + +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" +msgstr "선택한 책 제목을 사용할 수 없습니다. 파일이 존재하지 않거나 액세스할 수 없습니다" + +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "" + +#: cps/editbooks.py:174 cps/editbooks.py:716 +msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" +msgstr "식별자는 대소문자를 구분하지 않으며 이전 식별자를 덮어씁니다" + +#: cps/editbooks.py:216 +msgid "Metadata successfully updated" +msgstr "메타데이터가 성공적으로 업데이트되었습니다" + +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" + +#: cps/editbooks.py:291 +#, python-format +msgid "File %(file)s uploaded" +msgstr "파일 %(file)s 업로드됨" + +#: cps/editbooks.py:318 +msgid "Source or destination format for conversion missing" +msgstr "변환을 위한 소스 또는 대상 형식이 누락되었습니다" + +#: cps/editbooks.py:326 +#, python-format +msgid "Book successfully queued for converting to %(book_format)s" +msgstr "책이 %(book_format)s(으)로 변환하기 위해 대기 중입니다" + +#: cps/editbooks.py:330 +#, python-format +msgid "There was an error converting this book: %(res)s" +msgstr "이 책을 변환하는 동안 오류가 발생했습니다: %(res)s" + +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "업로드한 책이 라이브러리에 있을 수 있음. 새로 업로드하기 전에 확인 필요: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "'%(langname)s'은(는) 유효한 언어가 아닙니다" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "파일 확장자 '%(ext)s'은(는) 이 서버에 업로드할 수 없습니다" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "업로드할 파일에는 확장자가 있어야 합니다" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "파일 %(filename)s을(를) 임시 디렉토리에 저장할 수 없습니다" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "표지 파일%(file)s를 이동하지 못했습니다.:%(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "책 형식이 성공적으로 삭제되었습니다" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "책이 성공적으로 삭제되었습니다" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "메타데이터 편집" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s은(는) 유효한 숫자가 아닙니다. 건너뜁니다" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "%(path)s 경로를 생성하지 못했습니다(권한이 없음)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "%(file)s 파일을 저장하지 못했습니다." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "파일 형식 %(ext)s이(가) %(book)s에 추가되었습니다" + +#: cps/gdrive.py:58 +msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" +msgstr "Google 드라이브 설정이 완료되지 않았습니다. Google 드라이브를 비활성화했다가 다시 활성화해 보세요" + +#: cps/gdrive.py:95 +msgid "Callback domain is not verified, please follow steps to verify domain in google developer console" +msgstr "콜백 도메인이 확인되지 않았습니다. 단계에 따라 Google 개발자 콘솔에서 도메인을 확인하세요" + +#: cps/helper.py:80 +#, python-format +msgid "%(format)s format not found for book id: %(book)d" +msgstr "책 ID에 대한 %(format)s 형식을 찾을 수 없음: %(book)d" + +#: cps/helper.py:87 cps/tasks/convert.py:75 +#, python-format +msgid "%(format)s not found on Google Drive: %(fn)s" +msgstr "%(format)s을(를) Google 드라이브에서 찾을 수 없음: %(fn)s" + +#: cps/helper.py:92 +#, python-format +msgid "%(format)s not found: %(fn)s" +msgstr "%(format)s을(를) 찾을 수 없음: %(fn)s" + +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" +msgstr "킨들로 보내기" + +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." +msgstr "이 이메일은 Calibre Web을 통해 전송되었습니다." + +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" +msgstr "Calibre-Web 테스트 이메일" + +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" +msgstr "테스트 이메일" + +#: cps/helper.py:132 +msgid "Get Started with Calibre-Web" +msgstr "Calibre-Web 시작하기" + +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" +msgstr "사용자 등록 이메일: %(name)s" + +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "%(orig)s를 %(format)s로 변환하고 킨들로 보내기" + +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" +msgstr "킨들에 %(format)s 보내기" + +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" +msgstr "%(book)s을 킨들로 보내기" + +#: cps/helper.py:230 +msgid "The requested file could not be read. Maybe wrong permissions?" +msgstr "요청한 파일을 읽을 수 없습니다. 올바른 권한인가요?" + +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 +#, python-format +msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" +msgstr "책 %(id)s에 대한 책 폴더를 삭제하지 못했습니다. 경로에 하위 폴더가 있습니다: %(path)s" + +#: cps/helper.py:374 +#, python-format +msgid "Deleting book %(id)s failed: %(message)s" +msgstr "%(id)s 도서 삭제 실패: %(message)s" + +#: cps/helper.py:385 +#, python-format +msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" +msgstr "데이터베이스에서만 책 %(id)s 을(를) 삭제 중, 데이터베이스의 책 경로가 유효하지 않음: %(path)s" + +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "제목 이름을 '%(src)s'에서 '%(dest)s'(으)로 변경하지 못했습니다. 오류: %(error)s" + +#: cps/helper.py:522 cps/helper.py:531 +#, python-format +msgid "File %(file)s not found on Google Drive" +msgstr "Google 드라이브에서 %(file)s 파일을 찾을 수 없습니다" + +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "제목 이름을 '%(src)s'에서 '%(dest)s'(으)로 변경하지 못했습니다. 오류: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 +#, python-format +msgid "Book path %(path)s not found on Google Drive" +msgstr "Google 드라이브에서 책 경로 %(path)s을(를) 찾을 수 없습니다" + +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" + +#: cps/helper.py:652 +msgid "This username is already taken" +msgstr "등록되어 있는 username입니다" + +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" +msgstr "이메일 주소 형식이 잘못되었습니다" + +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 +msgid "Error Downloading Cover" +msgstr "표지 다운로드 중 오류 발생" + +#: cps/helper.py:828 +msgid "Cover Format Error" +msgstr "표지 형식 오류" + +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 +msgid "Failed to create path for cover" +msgstr "표지 경로 생성 실패" + +#: cps/helper.py:857 +msgid "Cover-file is not a valid image file, or could not be stored" +msgstr "표지 파일이 유효한 이미지 파일이 아니거나 저장할 수 없습니다" + +#: cps/helper.py:868 +msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" +msgstr "표지는 jpg/jpeg/png/webp/bmp 파일만 지원됩니다" + +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "잘못된 표지 파일 콘텐츠" + +#: cps/helper.py:884 +msgid "Only jpg/jpeg files are supported as coverfile" +msgstr "표지 파일로 jpg/jpeg 파일만 지원됩니다" + +#: cps/helper.py:936 +msgid "Unrar binary file not found" +msgstr "Unrar 바이너리 파일을 찾을 수 없습니다" + +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" +msgstr "UnRar 실행 오류" + +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "발견" + +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" + +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "코보(kobo) 장치에 대한 유효한 api_endpoint를 얻으려면 로컬 호스트가 아닌 곳에서 calibre-web에 액세스하십시오" + +#: cps/kobo_auth.py:115 +msgid "Kobo Setup" +msgstr "Kobo 설정" + +#: cps/oauth_bb.py:77 +#, python-format +msgid "Register with %(provider)s" +msgstr "%(provider)s에 등록" + +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 +#, python-format +msgid "Success! You are now logged in as: %(nickname)s" +msgstr "다음 사용자로 로그인했습니다: '%(nickname)s'" + +#: cps/oauth_bb.py:148 +#, python-format +msgid "Link to %(oauth)s Succeeded" +msgstr "%(oauth)s에 성공적으로 연결됨" + +#: cps/oauth_bb.py:155 +msgid "Login failed, No User Linked With OAuth Account" +msgstr "로그인 실패, OAuth 계정과 연결된 사용자 없음" + +#: cps/oauth_bb.py:197 +#, python-format +msgid "Unlink to %(oauth)s Succeeded" +msgstr "%(oauth)s에 연결 해제 성공" + +#: cps/oauth_bb.py:202 +#, python-format +msgid "Unlink to %(oauth)s Failed" +msgstr "%(oauth)s에 연결 해제 실패" + +#: cps/oauth_bb.py:205 +#, python-format +msgid "Not Linked to %(oauth)s" +msgstr "%(oauth)s에 연결되지 않음" + +#: cps/oauth_bb.py:261 +msgid "Failed to log in with GitHub." +msgstr "GitHub에 로그인하지 못했습니다." + +#: cps/oauth_bb.py:267 +msgid "Failed to fetch user info from GitHub." +msgstr "GitHub에서 사용자 정보를 가져오지 못했습니다." + +#: cps/oauth_bb.py:279 +msgid "Failed to log in with Google." +msgstr "구글 로그인에 실패했습니다." + +#: cps/oauth_bb.py:285 +msgid "Failed to fetch user info from Google." +msgstr "Google에서 사용자 정보를 가져오지 못했습니다." + +#: cps/oauth_bb.py:332 +msgid "GitHub Oauth error, please retry later." +msgstr "GitHub Oauth 오류입니다. 나중에 다시 시도하세요." + +#: cps/oauth_bb.py:335 +msgid "GitHub Oauth error: {}" +msgstr "GitHub 인증 오류: {}" + +#: cps/oauth_bb.py:356 +msgid "Google Oauth error, please retry later." +msgstr "Google 인증 오류입니다. 나중에 다시 시도하세요." + +#: cps/oauth_bb.py:359 +msgid "Google Oauth error: {}" +msgstr "Google 인증 오류: {}" + +#: cps/opds.py:273 +msgid "{} Stars" +msgstr "{} Stars" + +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 +msgid "Login" +msgstr "로그인" + +#: cps/remotelogin.py:74 cps/remotelogin.py:108 +msgid "Token not found" +msgstr "토큰을 찾을 수 없습니다" + +#: cps/remotelogin.py:83 cps/remotelogin.py:116 +msgid "Token has expired" +msgstr "토큰이 만료되었습니다" + +#: cps/remotelogin.py:92 +msgid "Success! Please return to your device" +msgstr "성공! 기기로 돌아가주세요" + +#: cps/render_template.py:42 cps/web.py:410 +msgid "Books" +msgstr "책" + +#: cps/render_template.py:44 +msgid "Show recent books" +msgstr "최근 책 보기" + +#: cps/render_template.py:45 cps/templates/index.xml:25 +msgid "Hot Books" +msgstr "인기있는 책" + +#: cps/render_template.py:47 +msgid "Show Hot Books" +msgstr "주목받는 책 보기" + +#: cps/render_template.py:49 cps/render_template.py:54 +msgid "Downloaded Books" +msgstr "다운로드된 책" + +#: cps/render_template.py:51 cps/render_template.py:56 +#: cps/templates/user_table.html:167 +msgid "Show Downloaded Books" +msgstr "다운로드된 책 보기" + +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 +msgid "Top Rated Books" +msgstr "평점이 높은 책" + +#: cps/render_template.py:61 cps/templates/user_table.html:161 +msgid "Show Top Rated Books" +msgstr "평점이 높은 책 보기" + +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 +msgid "Read Books" +msgstr "읽은 책" + +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" +msgstr "읽은 책과 읽지 않은 책 보기" + +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 +msgid "Unread Books" +msgstr "읽지 않은 책" + +#: cps/render_template.py:68 +msgid "Show unread" +msgstr "읽지 않은 책 보기" + +#: cps/render_template.py:69 +msgid "Discover" +msgstr "발견" + +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 +msgid "Show Random Books" +msgstr "무작위 추천" + +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 +msgid "Categories" +msgstr "카테고리" + +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" +msgstr "카테고리별 보기" + +#: cps/render_template.py:75 cps/templates/book_edit.html:91 +#: cps/templates/book_table.html:68 cps/templates/index.xml:90 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 +msgid "Series" +msgstr "시리즈" + +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" +msgstr "시리즈별 보기" + +#: cps/render_template.py:78 cps/templates/book_table.html:66 +#: cps/templates/index.xml:69 +msgid "Authors" +msgstr "저자" + +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" +msgstr "저자별 보기" + +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 +msgid "Publishers" +msgstr "출판사" + +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" +msgstr "출판사별 보기" + +#: cps/render_template.py:85 cps/templates/book_table.html:70 +#: cps/templates/index.xml:97 cps/templates/search_form.html:107 +#: cps/web.py:1078 +msgid "Languages" +msgstr "언어" + +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" +msgstr "언어별 보기" + +#: cps/render_template.py:89 cps/templates/index.xml:104 +msgid "Ratings" +msgstr "평점" + +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "평점별 보기" + +#: cps/render_template.py:92 cps/templates/index.xml:112 +msgid "File formats" +msgstr "파일 유형" + +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" +msgstr "파일 유형별 보기" + +#: cps/render_template.py:96 cps/web.py:772 +msgid "Archived Books" +msgstr "보관된 책" + +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "보관된 책 보기" + +#: cps/render_template.py:101 cps/web.py:803 +msgid "Books List" +msgstr "책 목록" + +#: cps/render_template.py:103 cps/templates/user_table.html:168 +msgid "Show Books List" +msgstr "책 목록 보기" + +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 +msgid "Search" +msgstr "검색" + +#: cps/search.py:189 +msgid "Published after " +msgstr "Published after " + +#: cps/search.py:196 +msgid "Published before " +msgstr "Published before " + +#: cps/search.py:218 +#, python-format +msgid "Rating <= %(rating)s" +msgstr "평점 <= %(rating)s" + +#: cps/search.py:220 +#, python-format +msgid "Rating >= %(rating)s" +msgstr "평점 >= %(rating)s" + +#: cps/search.py:222 +#, python-format +msgid "Read Status = %(status)s" +msgstr "읽은 상태 = %(status)s" + +#: cps/search.py:324 +msgid "Error on search for custom columns, please restart Calibre-Web" +msgstr "사용자 정의 열을 검색하는 동안 오류가 발생했습니다. Calibre-Web을 다시 시작하십시오" + +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "상세 검색" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "잘못된 책장 지정" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "죄송합니다. 해당 책장에 책을 추가할 권한이 없습니다" + +#: cps/shelf.py:64 +#, python-format +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "책이 이미 책장에 등록됨: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "책장에 책이 등록됨: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "책장에 책을 추가할 권한이 없습니다" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "책장에 이미 책이 등록됨: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "책이 책장에 등록됨: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "책장에 책을 추가할 수 없음: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "책이 책장에서 삭제됨: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "죄송합니다. 이 서가에서 책을 삭제할 권한이 없습니다" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "책장 추가" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "죄송합니다. 이 책장을 편집할 권한이 없습니다" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "책장 편집" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "책이 성공적으로 삭제되었습니다" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "책장 순서 변경: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "죄송합니다. 이 공개 책장을 만들 권한이 없습니다" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "%(title)s 책장이 추가됨" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "%(title)s 책장이 변경됨" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "오류가 발생하였습니다" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "이름이 '%(title)s'인 공개 책장이 이미 있습니다." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "이름이 '%(title)s'인 개인 책장이 이미 있습니다." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "책장: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "책장을 여는 동안 오류가 발생했습니다. 책장이 존재하지 않거나 접근할 수 없습니다" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "작업" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "대기중" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "실패" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "시작됨" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "종료" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "알 수 없는 상태" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "업데이트 정보를 읽는 동안 예기치 않은 데이터" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "업데이트가 없습니다. 이미 최신 버전이 설치되어 있습니다" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "새로운 업데이트가 있습니다. 아래 버튼을 클릭하여 최신 버전으로 업데이트하십시오." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "업데이트 정보를 가져올 수 없습니다" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "새로운 업데이트가 있습니다. 아래 버튼을 클릭하여 최신 버전으로 업데이트하십시오." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "최신 안정 버전 %(version)s으로 업데이트하려면 아래 버튼을 클릭하세요" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "출시 정보가 없습니다" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "발견(무작위 도서)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "인기있는 책(가장 많이 다운로드됨)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "%(user)s이(가) 다운로드한 책" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "저자: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "출판사: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "시리즈: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "평가: %(rating)s 별" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "파일 유형: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "카테고리: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "언어: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "다운로드" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "평점 목록" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "파일 유형 목록" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "먼저 SMTP 메일 설정을 구성하십시오..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "성공적으로 %(eReadermail)s에 보내기 예약이 되었습니다" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "책을 보내는 중에 오류 발생: %(res)s" + +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "Kindle로 보내는 유효한 이메일 주소로 프로필을 업데이트하십시오." + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "이메일 서버가 구성되지 않았습니다. 관리자에게 문의하십시오!" + +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 +msgid "Register" +msgstr "등록" + +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." +msgstr "이메일을 등록할 수 없습니다" + +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." +msgstr "확인을 위한 이메일이 발송되었습니다." + +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" +msgstr "LDAP 인증을 활성화할 수 없습니다" + +#: cps/web.py:1303 +#, python-format +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" +msgstr "대체 로그인: '%(nickname)s', LDAP 서버에 연결할 수 없음 또는 사용자를 알 수 없음" + +#: cps/web.py:1309 +#, python-format +msgid "Oops! Login Failed: %(message)s" +msgstr "로그인 실패: %(message)s" + +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." +msgstr "잘못된 사용자명 또는 비밀번호" + +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." +msgstr "새 비밀번호가 이메일로 전송되었습니다" + +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" +msgstr "비밀번호를 재설정하려면 유효한 사용자 이름을 입력하십시오" + +#: cps/web.py:1400 cps/web.py:1449 +#, python-format +msgid "%(name)s's Profile" +msgstr "%(name)s 프로필" + +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" +msgstr "프로필이 업데이트 됨" + +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "등록되어 있는 이메일 주소입니다" + +#: cps/services/gmail.py:58 +msgid "Found no valid gmail.json file with OAuth information" +msgstr "인증 정보가 포함된 유효한 gmail.json 파일을 찾을 수 없습니다" + +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s을 킨들로 보내기" + +#: cps/tasks/convert.py:153 +#, python-format +msgid "Calibre ebook-convert %(tool)s not found" +msgstr "Calibre ebook-convert %(tool)s을(를) 찾을 수 없습니다" + +#: cps/tasks/convert.py:186 +#, python-format +msgid "%(format)s format not found on disk" +msgstr "%(format)s 형식을 찾을 수 없습니다" + +#: cps/tasks/convert.py:190 +msgid "Ebook converter failed with unknown error" +msgstr "알 수 없는 오류로 인해 전자책 변환이 실패했습니다" + +#: cps/tasks/convert.py:202 +#, python-format +msgid "Kepubify-converter failed: %(error)s" +msgstr "Kepubify 변환 실패: %(error)s" + +#: cps/tasks/convert.py:224 +#, python-format +msgid "Converted file not found or more than one file in folder %(folder)s" +msgstr "변환된 파일을 찾을 수 없거나 %(folder)s 폴더에 하나 이상의 파일이 존재합니다" + +#: cps/tasks/convert.py:247 +#, python-format +msgid "Ebook-converter failed: %(error)s" +msgstr "\"전자책 변환 실패: %(error)s" + +#: cps/tasks/convert.py:270 +#, python-format +msgid "Calibre failed with error: %(error)s" +msgstr "오류로 인한 Calibre 실패: %(error)s" + +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "메타데이터 편집" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "업로드" + +#: cps/templates/admin.html:9 +msgid "Users" +msgstr "사용자" + +#: cps/templates/admin.html:13 cps/templates/login.html:9 +#: cps/templates/login.html:10 cps/templates/register.html:9 +#: cps/templates/user_edit.html:10 cps/templates/user_table.html:134 +msgid "Username" +msgstr "사용자명" + +#: cps/templates/admin.html:14 cps/templates/register.html:14 +#: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 +msgid "Email" +msgstr "이메일 주소" + +#: cps/templates/admin.html:15 cps/templates/user_edit.html:28 +#, fuzzy +msgid "Send to eReader Email" +msgstr "킨들로 보내기 이메일 주소" + +#: cps/templates/admin.html:17 cps/templates/layout.html:92 +#: cps/templates/user_table.html:143 +msgid "Admin" +msgstr "관리자" + +#: cps/templates/admin.html:18 cps/templates/login.html:13 +#: cps/templates/login.html:14 cps/templates/user_edit.html:23 +msgid "Password" +msgstr "비밀번호" + +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 +#: cps/templates/user_table.html:146 +msgid "Download" +msgstr "다운로드" + +#: cps/templates/admin.html:23 +msgid "View Books" +msgstr "책 보기" + +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 +#: cps/templates/user_table.html:148 +msgid "Edit" +msgstr "편집" + +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 +#: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 +#: cps/templates/user_table.html:149 +msgid "Delete" +msgstr "삭제" + +#: cps/templates/admin.html:26 +msgid "Public Shelf" +msgstr "공개 책장" + +#: cps/templates/admin.html:55 +msgid "Import LDAP Users" +msgstr "LDAP 사용자 가져오기" + +#: cps/templates/admin.html:62 +msgid "Email Server Settings" +msgstr "이메일 서버 설정" + +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 +msgid "SMTP Hostname" +msgstr "SMTP Hostname" + +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 +msgid "SMTP Port" +msgstr "SMTP Port" + +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 +msgid "Encryption" +msgstr "암호화" + +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 +msgid "SMTP Login" +msgstr "SMTP Login" + +#: cps/templates/admin.html:83 cps/templates/admin.html:94 +#: cps/templates/email_edit.html:55 +msgid "From Email" +msgstr "From Email" + +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" +msgstr "EMail Service" + +#: cps/templates/admin.html:91 +msgid "Gmail via Oauth2" +msgstr "Gmail via Oauth2" + +#: cps/templates/admin.html:106 +msgid "Configuration" +msgstr "환경 설정" + +#: cps/templates/admin.html:109 +msgid "Calibre Database Directory" +msgstr "Calibre DB 폴더" + +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 +msgid "Log Level" +msgstr "Log Level" + +#: cps/templates/admin.html:117 +msgid "Port" +msgstr "Port" + +#: cps/templates/admin.html:122 +msgid "External Port" +msgstr "External Port" + +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 +msgid "Books per Page" +msgstr "페이지당 보여 줄 책 수" + +#: cps/templates/admin.html:133 +msgid "Uploads" +msgstr "업로드" + +#: cps/templates/admin.html:137 +msgid "Anonymous Browsing" +msgstr "익명 보기" + +#: cps/templates/admin.html:141 +msgid "Public Registration" +msgstr "공개 등록" + +#: cps/templates/admin.html:145 +msgid "Magic Link Remote Login" +msgstr "Magic Link Remote Login" + +#: cps/templates/admin.html:149 +msgid "Reverse Proxy Login" +msgstr "Reverse Proxy Login" + +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 +msgid "Reverse Proxy Header Name" +msgstr "Reverse Proxy Header Name" + +#: cps/templates/admin.html:159 +msgid "Edit Calibre Database Configuration" +msgstr "Calibre Database 환경 설정 편집" + +#: cps/templates/admin.html:160 +msgid "Edit Basic Configuration" +msgstr "기본 환경 설정 편집" + +#: cps/templates/admin.html:161 +msgid "Edit UI Configuration" +msgstr "UI 환경 설정 편집" + +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 +msgid "Administration" +msgstr "관리" + +#: cps/templates/admin.html:200 +msgid "Download Debug Package" +msgstr "Debug Package 다운로드" + +#: cps/templates/admin.html:201 +msgid "View Logs" +msgstr "로그 보기" + +#: cps/templates/admin.html:207 +msgid "Restart" +msgstr "재시작" + +#: cps/templates/admin.html:208 +msgid "Shutdown" +msgstr "종료" + +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" + +#: cps/templates/admin.html:220 +msgid "Version" +msgstr "버전" + +#: cps/templates/admin.html:221 +msgid "Details" +msgstr "세부 정보" + +#: cps/templates/admin.html:227 +msgid "Current Version" +msgstr "현재 버전" + +#: cps/templates/admin.html:234 +msgid "Check for Update" +msgstr "업데이트 확인" + +#: cps/templates/admin.html:235 +msgid "Perform Update" +msgstr "업데이트 실행" + +#: cps/templates/admin.html:248 +msgid "Are you sure you want to restart?" +msgstr "재시작을 하시겠습니까?" + +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 +msgid "OK" +msgstr "예" + +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 +#: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 +#: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 +msgid "Cancel" +msgstr "취소" + +#: cps/templates/admin.html:266 +msgid "Are you sure you want to shutdown?" +msgstr "종료를 하시겠습니까?" + +#: cps/templates/admin.html:278 +msgid "Updating, please do not reload this page" +msgstr "Встановлення оновлень, будь-ласка, не оновлюйте сторінку" + +#: cps/templates/author.html:15 +msgid "via" +msgstr "via" + +#: cps/templates/author.html:23 +msgid "In Library" +msgstr "In Library" + +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 +msgid "Sort according to book date, newest first" +msgstr "책 목록 정렬, 최신순" + +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 +msgid "Sort according to book date, oldest first" +msgstr "책 목록 정렬, 오래된 순" + +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 +msgid "Sort title in alphabetical order" +msgstr "가나다 순 정렬" + +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 +msgid "Sort title in reverse alphabetical order" +msgstr "가나다 역순 정렬" + +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 +msgid "Sort according to publishing date, newest first" +msgstr "발행일 순으로 정렬, 최신순" + +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 +msgid "Sort according to publishing date, oldest first" +msgstr "발행일 순으로 정렬, 오래된 순" + +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 +msgid "reduce" +msgstr "reduce" + +#: cps/templates/author.html:99 +msgid "More by" +msgstr "More by" + +#: cps/templates/book_edit.html:11 +msgid "Delete Book" +msgstr "책 삭제" + +#: cps/templates/book_edit.html:14 +msgid "Delete formats:" +msgstr "유형 삭제:" + +#: cps/templates/book_edit.html:25 +msgid "Convert book format:" +msgstr "책 유형 변경:" + +#: cps/templates/book_edit.html:30 +msgid "Convert from:" +msgstr "변경전 유형:" + +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 +msgid "select an option" +msgstr "옵션 선택" + +#: cps/templates/book_edit.html:37 +msgid "Convert to:" +msgstr "변경후 유형:" + +#: cps/templates/book_edit.html:46 +msgid "Convert book" +msgstr "책 변경" + +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 +msgid "Book Title" +msgstr "책 제목" + +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 +msgid "Author" +msgstr "저자" + +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 +msgid "Description" +msgstr "책 소개" + +#: cps/templates/book_edit.html:73 +msgid "Identifiers" +msgstr "식별자" + +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 +msgid "Identifier Type" +msgstr "식별자 유형" + +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 +msgid "Identifier Value" +msgstr "식별자 값" + +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 +#: cps/templates/user_table.html:24 +msgid "Remove" +msgstr "삭제" + +#: cps/templates/book_edit.html:83 +msgid "Add Identifier" +msgstr "식별자 추가" + +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 +msgid "Tags" +msgstr "태그" + +#: cps/templates/book_edit.html:95 +msgid "Series ID" +msgstr "시리즈 ID" + +#: cps/templates/book_edit.html:99 +msgid "Rating" +msgstr "평점" + +#: cps/templates/book_edit.html:104 +msgid "Fetch Cover from URL (JPEG - Image will be downloaded and stored in database)" +msgstr "URL로 표지 추가(JPEG - 이미지를 다운로드 하여 DB에 저장합니다)" + +#: cps/templates/book_edit.html:108 +msgid "Upload Cover from Local Disk" +msgstr "로컬 디스크에서 표지 업로드" + +#: cps/templates/book_edit.html:113 +msgid "Published Date" +msgstr "출간일" + +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 +msgid "Publisher" +msgstr "출판사" + +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 +msgid "Language" +msgstr "언어" + +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 +#: cps/templates/search_form.html:164 +msgid "Yes" +msgstr "예" + +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 +#: cps/templates/search_form.html:165 +msgid "No" +msgstr "아니오" + +#: cps/templates/book_edit.html:201 +msgid "Upload Format" +msgstr "업로드 유형" + +#: cps/templates/book_edit.html:209 +msgid "View Book on Save" +msgstr "저장 후 책 보기" + +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 +msgid "Fetch Metadata" +msgstr "메타정보 가져오기" + +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 +msgid "Save" +msgstr "저장" + +#: cps/templates/book_edit.html:233 +msgid "Keyword" +msgstr "키워드" + +#: cps/templates/book_edit.html:234 +msgid "Search keyword" +msgstr "키워드 검색" + +#: cps/templates/book_edit.html:240 +msgid "Click the cover to load metadata to the form" +msgstr "표지를 클릭하여 양식에 메타데이터 로드" + +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 +msgid "Loading..." +msgstr "불러오는 중..." + +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 +msgid "Close" +msgstr "닫기" + +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 +msgid "Source" +msgstr "출처" + +#: cps/templates/book_edit.html:287 +msgid "Search error!" +msgstr "오류 검색!" + +#: cps/templates/book_edit.html:288 +msgid "No Result(s) found! Please try another keyword." +msgstr "검색 결과가 없습니다! 다른 키워드를 시도하십시오." + +#: cps/templates/book_table.html:12 cps/templates/book_table.html:69 +#: cps/templates/user_table.html:14 cps/templates/user_table.html:77 +#: cps/templates/user_table.html:100 +msgid "This Field is Required" +msgstr "이 필드는 필수 항목입니다" + +#: cps/templates/book_table.html:37 +msgid "Merge selected books" +msgstr "선택한 책 병합" + +#: cps/templates/book_table.html:38 cps/templates/user_table.html:124 +msgid "Remove Selections" +msgstr "선택 제거" + +#: cps/templates/book_table.html:41 +msgid "Exchange author and title" +msgstr "저자 및 제목 교환" + +#: cps/templates/book_table.html:47 +msgid "Update Title Sort automatically" +msgstr "자동으로 제목 정렬 업데이트" + +#: cps/templates/book_table.html:51 +msgid "Update Author Sort automatically" +msgstr "자동으로 작성자 정렬 업데이트" + +#: cps/templates/book_table.html:63 cps/templates/book_table.html:69 +msgid "Enter Title" +msgstr "제목 입력" + +#: cps/templates/book_table.html:63 cps/templates/config_view_edit.html:24 +#: cps/templates/shelf_edit.html:8 +msgid "Title" +msgstr "제목" + +#: cps/templates/book_table.html:64 +msgid "Enter Title Sort" +msgstr "제목 정렬 입력" + +#: cps/templates/book_table.html:64 +msgid "Title Sort" +msgstr "제목 정렬" + +#: cps/templates/book_table.html:65 +msgid "Enter Author Sort" +msgstr "저자 정렬 입력" + +#: cps/templates/book_table.html:65 +msgid "Author Sort" +msgstr "저자 정렬" + +#: cps/templates/book_table.html:66 +msgid "Enter Authors" +msgstr "저자 입력" + +#: cps/templates/book_table.html:67 +msgid "Enter Categories" +msgstr "카테고리 입력" + +#: cps/templates/book_table.html:68 +msgid "Enter Series" +msgstr "시리즈 입력" + +#: cps/templates/book_table.html:69 +msgid "Series Index" +msgstr "시리즈 색인" + +#: cps/templates/book_table.html:70 +msgid "Enter Languages" +msgstr "언어 입력" + +#: cps/templates/book_table.html:71 +msgid "Publishing Date" +msgstr "출간일" + +#: cps/templates/book_table.html:72 +msgid "Enter Publishers" +msgstr "출판사 입력" + +#: cps/templates/book_table.html:73 +msgid "Enter comments" +msgstr "코멘트 입력" + +#: cps/templates/book_table.html:73 +msgid "Comments" +msgstr "코멘트" + +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "읽은 상태" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 +msgid "Enter " +msgstr "입력 " + +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 +msgid "Are you really sure?" +msgstr "정말 확신합니까?" + +#: cps/templates/book_table.html:117 +msgid "Books with Title will be merged from:" +msgstr "제목이 있는 책은 다음에서 병합됨:" + +#: cps/templates/book_table.html:121 +msgid "Into Book with Title:" +msgstr "제목이 있는 책으로:" + +#: cps/templates/book_table.html:126 +msgid "Merge" +msgstr "병합" + +#: cps/templates/config_db.html:12 +msgid "Location of Calibre Database" +msgstr "Calibre Database 위치" + +#: cps/templates/config_db.html:22 +msgid "Use Google Drive?" +msgstr "Google 드라이브를 사용하시겠습니까?" + +#: cps/templates/config_db.html:27 +msgid "Authenticate Google Drive" +msgstr "구글 드라이브 인증" + +#: cps/templates/config_db.html:32 +msgid "Google Drive Calibre folder" +msgstr "Google Drive Calibre 폴더" + +#: cps/templates/config_db.html:40 +msgid "Metadata Watch Channel ID" +msgstr "Metadata Watch Channel ID" + +#: cps/templates/config_db.html:43 +msgid "Revoke" +msgstr "취소" + +#: cps/templates/config_db.html:68 +msgid "New db location is invalid, please enter valid path" +msgstr "잘못된 새 DB 위치. 올바른 경로 입력 필요" + +#: cps/templates/config_edit.html:18 +msgid "Server Configuration" +msgstr "서버 구성" + +#: cps/templates/config_edit.html:25 +msgid "Server Port" +msgstr "Server Port" + +#: cps/templates/config_edit.html:28 +msgid "SSL certfile location (leave it empty for non-SSL Servers)" +msgstr "SSL 인증서 파일 위치(비 SSL 서버의 경우 비워 둡니다)" + +#: cps/templates/config_edit.html:35 +msgid "SSL Keyfile location (leave it empty for non-SSL Servers)" +msgstr "SSL 키 파일 위치(비 SSL 서버의 경우 비워 둡니다)" + +#: cps/templates/config_edit.html:43 +msgid "Update Channel" +msgstr "업데이트 취소" + +#: cps/templates/config_edit.html:45 +msgid "Stable" +msgstr "안정버전" + +#: cps/templates/config_edit.html:46 +msgid "Nightly" +msgstr "실험버전" + +#: cps/templates/config_edit.html:50 +msgid "Trusted Hosts (Comma Separated)" +msgstr "신뢰할 수 있는 호스트(쉼표로 구분)" + +#: cps/templates/config_edit.html:61 +msgid "Logfile Configuration" +msgstr "Logfile 설정" + +#: cps/templates/config_edit.html:77 +msgid "Location and name of logfile (calibre-web.log for no entry)" +msgstr "로그 파일의 위치 및 이름(항목이 없는 경우 calibre-web.log)" + +#: cps/templates/config_edit.html:82 +msgid "Enable Access Log" +msgstr "액세스 로그 활성화" + +#: cps/templates/config_edit.html:85 +msgid "Location and name of access logfile (access.log for no entry)" +msgstr "액세스 로그 파일의 위치 및 이름(항목이 없는 경우 access.log)" + +#: cps/templates/config_edit.html:96 +msgid "Feature Configuration" +msgstr "기능 설정" + +#: cps/templates/config_edit.html:104 +msgid "Convert non-English characters in title and author while saving to disk" +msgstr "제목과 저자가 영어가 아닌 경우 원어로 저장하기" + +#: cps/templates/config_edit.html:108 +msgid "Enable Uploads" +msgstr "업로드 활성화" + +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(사용자에게 업로드 권한도 있는지 확인하십시오)" + +#: cps/templates/config_edit.html:112 +msgid "Allowed Upload Fileformats" +msgstr "허용된 업로드 파일 형식" + +#: cps/templates/config_edit.html:118 +msgid "Enable Anonymous Browsing" +msgstr "익명 탐색 활성화" + +#: cps/templates/config_edit.html:122 +msgid "Enable Public Registration" +msgstr "공개 등록 활성화" + +#: cps/templates/config_edit.html:127 +msgid "Use Email as Username" +msgstr "이메일을 사용자 이름으로 사용" + +#: cps/templates/config_edit.html:132 +msgid "Enable Magic Link Remote Login" +msgstr "Enable Magic Link Remote Login" + +#: cps/templates/config_edit.html:137 +msgid "Enable Kobo sync" +msgstr "Kobo sync 활성화" + +#: cps/templates/config_edit.html:142 +msgid "Proxy unknown requests to Kobo Store" +msgstr "Kobo Store에 알 수 없는 요청 프록시" + +#: cps/templates/config_edit.html:145 +msgid "Server External Port (for port forwarded API calls)" +msgstr "서버 외부 포트(포트 전달 API 호출용)" + +#: cps/templates/config_edit.html:153 +msgid "Use Goodreads" +msgstr "Goodreads 사용" + +#: cps/templates/config_edit.html:154 +msgid "Create an API Key" +msgstr "API 키 생성" + +#: cps/templates/config_edit.html:158 +msgid "Goodreads API Key" +msgstr "Goodreads API Key" + +#: cps/templates/config_edit.html:162 +msgid "Goodreads API Secret" +msgstr "Goodreads API Secret" + +#: cps/templates/config_edit.html:169 +msgid "Allow Reverse Proxy Authentication" +msgstr "역방향 프록시 인증 허용" + +#: cps/templates/config_edit.html:180 +msgid "Login type" +msgstr "로그인 유형" + +#: cps/templates/config_edit.html:182 +msgid "Use Standard Authentication" +msgstr "표준 인증 사용" + +#: cps/templates/config_edit.html:184 +msgid "Use LDAP Authentication" +msgstr "LDAP 인증 사용" + +#: cps/templates/config_edit.html:187 +msgid "Use OAuth" +msgstr "OAuth 사용" + +#: cps/templates/config_edit.html:194 +msgid "LDAP Server Host Name or IP Address" +msgstr "LDAP 서버 호스트 이름 또는 IP 주소" + +#: cps/templates/config_edit.html:198 +msgid "LDAP Server Port" +msgstr "LDAP 서버 포트" + +#: cps/templates/config_edit.html:202 +msgid "LDAP Encryption" +msgstr "LDAP 암호화" + +#: cps/templates/config_edit.html:205 +msgid "TLS" +msgstr "TLS" + +#: cps/templates/config_edit.html:206 +msgid "SSL" +msgstr "SSL" + +#: cps/templates/config_edit.html:210 +msgid "LDAP CACertificate Path (Only needed for Client Certificate Authentication)" +msgstr "LDAP CACertificate 경로(클라이언트 인증서 인증에만 필요)" + +#: cps/templates/config_edit.html:217 +msgid "LDAP Certificate Path (Only needed for Client Certificate Authentication)" +msgstr "LDAP 인증서 경로(클라이언트 인증서 인증에만 필요)" + +#: cps/templates/config_edit.html:224 +msgid "LDAP Keyfile Path (Only needed for Client Certificate Authentication)" +msgstr "LDAP 키 파일 경로(클라이언트 인증서 인증에만 필요)" + +#: cps/templates/config_edit.html:233 +msgid "LDAP Authentication" +msgstr "LDAP 인증" + +#: cps/templates/config_edit.html:235 +msgid "Anonymous" +msgstr "익명" + +#: cps/templates/config_edit.html:236 +msgid "Unauthenticated" +msgstr "인증되지 않음" + +#: cps/templates/config_edit.html:237 +msgid "Simple" +msgstr "Simple" + +#: cps/templates/config_edit.html:242 +msgid "LDAP Administrator Username" +msgstr "LDAP 관리자 사용자 이름" + +#: cps/templates/config_edit.html:248 +msgid "LDAP Administrator Password" +msgstr "LDAP 관리자 비밀번호" + +#: cps/templates/config_edit.html:253 +msgid "LDAP Distinguished Name (DN)" +msgstr "LDAP 고유 이름(DN)" + +#: cps/templates/config_edit.html:257 +msgid "LDAP User Object Filter" +msgstr "LDAP 사용자 개체 필터" + +#: cps/templates/config_edit.html:262 +msgid "LDAP Server is OpenLDAP?" +msgstr "LDAP 서버는 OpenLDAP입니까?" + +#: cps/templates/config_edit.html:264 +msgid "Following Settings are Needed For User Import" +msgstr "사용자 가져오기에는 다음 설정이 필요" + +#: cps/templates/config_edit.html:266 +msgid "LDAP Group Object Filter" +msgstr "LDAP 그룹 개체 필터" + +#: cps/templates/config_edit.html:270 +msgid "LDAP Group Name" +msgstr "DAP 그룹 이름" + +#: cps/templates/config_edit.html:274 +msgid "LDAP Group Members Field" +msgstr "LDAP 그룹 구성원 필드" + +#: cps/templates/config_edit.html:278 +msgid "LDAP Member User Filter Detection" +msgstr "LDAP 구성원 사용자 필터 감지" + +#: cps/templates/config_edit.html:280 +msgid "Autodetect" +msgstr "자동 감지" + +#: cps/templates/config_edit.html:281 +msgid "Custom Filter" +msgstr "맞춤 필터" + +#: cps/templates/config_edit.html:286 +msgid "LDAP Member User Filter" +msgstr "LDAP 구성원 사용자 필터" + +#: cps/templates/config_edit.html:297 +#, python-format +msgid "Obtain %(provider)s OAuth Credential" +msgstr "%(provider)s OAuth 자격 증명 얻기" + +#: cps/templates/config_edit.html:300 +#, python-format +msgid "%(provider)s OAuth Client Id" +msgstr "%(provider)s OAuth 클라이언트 ID" + +#: cps/templates/config_edit.html:304 +#, python-format +msgid "%(provider)s OAuth Client Secret" +msgstr "%(provider)s OAuth 클라이언트 암호" + +#: cps/templates/config_edit.html:320 +msgid "External binaries" +msgstr "외부 바이너리" + +#: cps/templates/config_edit.html:326 +msgid "Path to Calibre E-Book Converter" +msgstr "Calibre E-Book 변환기 경로" + +#: cps/templates/config_edit.html:334 +msgid "Calibre E-Book Converter Settings" +msgstr "Calibre E-Book 변환기 경로 설정" + +#: cps/templates/config_edit.html:337 +msgid "Path to Kepubify E-Book Converter" +msgstr "Kepubify 전자책 변환기 경로" + +#: cps/templates/config_edit.html:345 +msgid "Location of Unrar binary" +msgstr "Unrar 바이너리의 위치" + +#: cps/templates/config_view_edit.html:17 +msgid "View Configuration" +msgstr "환경 설정 보기" + +#: cps/templates/config_view_edit.html:32 +msgid "No. of Random Books to Display" +msgstr "랜덤 보기시 표시할 책 수" + +#: cps/templates/config_view_edit.html:36 +msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" +msgstr "숨기기 전에 표시할 저자 수(0=숨기기 비활성화)" + +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 +msgid "Theme" +msgstr "테마" + +#: cps/templates/config_view_edit.html:42 +msgid "Standard Theme" +msgstr "기본 테마" + +#: cps/templates/config_view_edit.html:43 +msgid "caliBlur! Dark Theme" +msgstr "caliBlur! 다크 모드" + +#: cps/templates/config_view_edit.html:47 +msgid "Regular Expression for Ignoring Columns" +msgstr "열을 무시하는 정규식" + +#: cps/templates/config_view_edit.html:51 +msgid "Link Read/Unread Status to Calibre Column" +msgstr "읽음/읽지 않음 상태를 Calibre 열에 연결" + +#: cps/templates/config_view_edit.html:60 +msgid "View Restrictions based on Calibre column" +msgstr "Calibre 열을 기반으로 한 보기 제한" + +#: cps/templates/config_view_edit.html:69 +msgid "Regular Expression for Title Sorting" +msgstr "제목 정렬을 위한 정규식" + +#: cps/templates/config_view_edit.html:80 +msgid "Default Settings for New Users" +msgstr "새 사용자를 위한 기본 설정" + +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 +msgid "Admin User" +msgstr "관리자" + +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 +msgid "Allow Downloads" +msgstr "다운로드 허용" + +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 +msgid "Allow eBook Viewer" +msgstr "책 보기 허용" + +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 +msgid "Allow Uploads" +msgstr "업로드 허용" + +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 +msgid "Allow Edit" +msgstr "편집 허용" + +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 +msgid "Allow Delete Books" +msgstr "책 삭제 허용" + +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 +msgid "Allow Changing Password" +msgstr "비밀번호 변경 허용" + +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 +msgid "Allow Editing Public Shelves" +msgstr "공개 서재 편집 허용" + +#: cps/templates/config_view_edit.html:123 +msgid "Default Language" +msgstr "기본 언어" + +#: cps/templates/config_view_edit.html:131 +msgid "Default Visible Language of Books" +msgstr "책의 기본 표시 언어" + +#: cps/templates/config_view_edit.html:147 +msgid "Default Visibilities for New Users" +msgstr "신규 사용자를 위한 기본 기능" + +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 +#: cps/templates/user_table.html:154 +msgid "Show Random Books in Detail View" +msgstr "상세 보기에서 임의의 책 표시" + +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 +msgid "Add Allowed/Denied Tags" +msgstr "허용/거부 태그 추가" + +#: cps/templates/config_view_edit.html:167 +msgid "Add Allowed/Denied custom column values" +msgstr "허용/거부 사용자 정의 열 값 추가" + +#: cps/templates/detail.html:62 cps/templates/detail.html:71 +msgid "Read in Browser" +msgstr "부라우저에서 보기" + +#: cps/templates/detail.html:79 cps/templates/detail.html:96 +msgid "Listen in Browser" +msgstr "브라우저에서 듣기" + +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 +#, python-format +msgid "Book %(index)s of %(range)s" +msgstr "책 %(index)s의 %(range)s" + +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 +msgid "Published" +msgstr "출간일" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Unread" +msgstr "읽지 않은 상태로 표시" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Read" +msgstr "읽은 상태로 표시" + +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 +msgid "Read" +msgstr "읽기" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Restore from archive" +msgstr "아카이브에서 복원" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Add to archive" +msgstr "아카이브에 추가" + +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 +msgid "Archived" +msgstr "보관됨" + +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 +msgid "Description:" +msgstr "설명:" + +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 +msgid "Add to shelf" +msgstr "서재에 추가" + +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 +msgid "(Public)" +msgstr "(공개)" + +#: cps/templates/detail.html:300 +msgid "Edit Metadata" +msgstr "메타저오 편집" + +#: cps/templates/email_edit.html:13 +msgid "Email Account Type" +msgstr "서버 유형 선택" + +#: cps/templates/email_edit.html:15 +#, fuzzy +msgid "Standard Email Account" +msgstr "표준 이메일 계정 사용" + +#: cps/templates/email_edit.html:16 +#, fuzzy +msgid "Gmail Account" +msgstr "서버 유형 선택" + +#: cps/templates/email_edit.html:22 +msgid "Setup Gmail Account" +msgstr "" + +#: cps/templates/email_edit.html:24 +msgid "Revoke Gmail Access" +msgstr "Gmail 액세스 취소" + +#: cps/templates/email_edit.html:42 +msgid "STARTTLS" +msgstr "STARTTLS" + +#: cps/templates/email_edit.html:43 +msgid "SSL/TLS" +msgstr "SSL/TLS" + +#: cps/templates/email_edit.html:51 +msgid "SMTP Password" +msgstr "SMTP 비밀번호" + +#: cps/templates/email_edit.html:58 +msgid "Attachment Size Limit" +msgstr "첨부 파일 크기 제한" + +#: cps/templates/email_edit.html:66 +#, fuzzy +msgid "Save and Send Test Email" +msgstr "저장 후 테스트 이메일 보내기" + +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 +#: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 +msgid "Back" +msgstr "뒤로" + +#: cps/templates/email_edit.html:74 +msgid "Allowed Domains (Whitelist)" +msgstr "허용하는 도메인(화이트 리스트)" + +#: cps/templates/email_edit.html:78 cps/templates/email_edit.html:105 +msgid "Add Domain" +msgstr "도메인 추가" + +#: cps/templates/email_edit.html:81 cps/templates/email_edit.html:108 +#: cps/templates/user_table.html:27 +msgid "Add" +msgstr "추가" + +#: cps/templates/email_edit.html:86 cps/templates/email_edit.html:96 +msgid "Enter domainname" +msgstr "도메인 입력" + +#: cps/templates/email_edit.html:92 +msgid "Denied Domains (Blacklist)" +msgstr "거부 도메인(블랙리스트)" + +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 +msgid "Next" +msgstr "다음" + +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "텍스트 편집기에서 .kobo/Kobo/Kobo eReader.conf 파일을 열고 다음을 추가(또는 편집):" + +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "코보 연동 토큰" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 +msgid "Calibre-Web Instance is unconfigured, please contact your administrator" +msgstr "Calibre-Web Instance가 구성되지 않았습니다. 관리자에게 문의" + +#: cps/templates/http_error.html:44 +msgid "Create Issue" +msgstr "이슈 생성" + +#: cps/templates/http_error.html:51 +msgid "Return to Home" +msgstr "홈으로" + +#: cps/templates/http_error.html:53 +msgid "Logout User" +msgstr "로그아웃" + +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "다운로드 횟수에 따라 오름차순 정렬" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "다운로드 횟수에 따라 내림차순 정렬" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 +msgid "Sort authors in alphabetical order" +msgstr "저자를 가나다순(알파벳순)으로 정렬" + +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 +msgid "Sort authors in reverse alphabetical order" +msgstr "저자를 가나다(알파벳) 역순으로 정렬" + +#: cps/templates/index.html:83 +msgid "Sort ascending according to series index" +msgstr "시리즈 인덱스에 따라 오름차순 정렬" + +#: cps/templates/index.html:84 +msgid "Sort descending according to series index" +msgstr "시리즈 인덱스에 따라 내림차순 정렬" + +#: cps/templates/index.xml:6 +msgid "Start" +msgstr "시작" + +#: cps/templates/index.xml:18 +msgid "Alphabetical Books" +msgstr "가나다(알파벳) 순" + +#: cps/templates/index.xml:22 +msgid "Books sorted alphabetically" +msgstr "가나다(알파벳)순으로 정렬한 책" + +#: cps/templates/index.xml:29 +msgid "Popular publications from this catalog based on Downloads." +msgstr "다운로드 기준 인기 도서." + +#: cps/templates/index.xml:36 +msgid "Popular publications from this catalog based on Rating." +msgstr "별점 기준 인기 도서." + +#: cps/templates/index.xml:39 +msgid "Recently added Books" +msgstr "최근 추가된 도서" + +#: cps/templates/index.xml:43 +msgid "The latest Books" +msgstr "최신 도서" + +#: cps/templates/index.xml:46 +msgid "Random Books" +msgstr "랜덤 정렬" + +#: cps/templates/index.xml:73 +msgid "Books ordered by Author" +msgstr "저자별 정렬" + +#: cps/templates/index.xml:80 +msgid "Books ordered by publisher" +msgstr "출판사별 정렬" + +#: cps/templates/index.xml:87 +msgid "Books ordered by category" +msgstr "카테고리별 정렬" + +#: cps/templates/index.xml:94 +msgid "Books ordered by series" +msgstr "시리즈별 정렬" + +#: cps/templates/index.xml:101 +msgid "Books ordered by Languages" +msgstr "언어별 정렬" + +#: cps/templates/index.xml:108 +msgid "Books ordered by Rating" +msgstr "평점별 정렬" + +#: cps/templates/index.xml:116 +msgid "Books ordered by file formats" +msgstr "파일 종류별 정렬" + +#: cps/templates/index.xml:119 cps/templates/layout.html:153 +#: cps/templates/search_form.html:87 +msgid "Shelves" +msgstr "서재" + +#: cps/templates/index.xml:123 +msgid "Books organized in shelves" +msgstr "서재별 정렬" + +#: cps/templates/layout.html:26 cps/templates/login.html:30 +msgid "Home" +msgstr "홈" + +#: cps/templates/layout.html:32 +msgid "Toggle Navigation" +msgstr "탐색 활성화" + +#: cps/templates/layout.html:48 +msgid "Search Library" +msgstr "검색" + +#: cps/templates/layout.html:66 cps/templates/layout.html:95 +msgid "Account" +msgstr "계정" + +#: cps/templates/layout.html:72 cps/templates/layout.html:97 +msgid "Logout" +msgstr "로그아웃" + +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "업로드 중..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "오류" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "업로드 완료, 처리 중입니다. 잠시만 기다려 주십시오..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "설정" + +#: cps/templates/layout.html:136 +msgid "Please do not refresh the page" +msgstr "페이지를 새로고침 하지 마세요" + +#: cps/templates/layout.html:146 +msgid "Browse" +msgstr "탐색" + +#: cps/templates/layout.html:159 cps/templates/stats.html:3 +msgid "About" +msgstr "서재 정보" + +#: cps/templates/layout.html:173 +msgid "Previous" +msgstr "이전" + +#: cps/templates/layout.html:200 +msgid "Book Details" +msgstr "책 상세정보" + +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + +#: cps/templates/login.html:18 +msgid "Remember Me" +msgstr "로그인 유지" + +#: cps/templates/login.html:23 +msgid "Forgot Password?" +msgstr "비밀번호를 잊으셨나요?" + +#: cps/templates/login.html:34 +msgid "Log in with Magic Link" +msgstr "Magic Link로 로그인" + +#: cps/templates/logviewer.html:6 +msgid "Show Calibre-Web Log: " +msgstr "Calibre-Web 로그 표시: " + +#: cps/templates/logviewer.html:8 +msgid "Calibre-Web Log: " +msgstr "Calibre-Web 로그: " + +#: cps/templates/logviewer.html:8 +msgid "Stream output, can't be displayed" +msgstr "스트림 출력, 표시할 수 없음" + +#: cps/templates/logviewer.html:12 +msgid "Show Access Log: " +msgstr "액세스 로그 표시: " + +#: cps/templates/logviewer.html:18 +msgid "Download Calibre-Web Log" +msgstr "Calibre-Web 로그 다운로드" + +#: cps/templates/logviewer.html:21 +msgid "Download Access Log" +msgstr "Access Log 다운로드" + +#: cps/templates/modal_dialogs.html:6 +msgid "Select Allowed/Denied Tags" +msgstr "허용/거부 태그 선택" + +#: cps/templates/modal_dialogs.html:7 +msgid "Select Allowed/Denied Custom Column Values" +msgstr "허용/거부 사용자 정의 열 값 선택" + +#: cps/templates/modal_dialogs.html:8 +msgid "Select Allowed/Denied Tags of User" +msgstr "사용자의 허용/거부 태그 선택" + +#: cps/templates/modal_dialogs.html:9 +msgid "Select Allowed/Denied Custom Column Values of User" +msgstr "사용자의 사용자 정의 열 값 허용/거부 선택" + +#: cps/templates/modal_dialogs.html:15 +msgid "Enter Tag" +msgstr "태그 입력" + +#: cps/templates/modal_dialogs.html:24 +msgid "Add View Restriction" +msgstr "보기 제한 추가" + +#: cps/templates/modal_dialogs.html:50 +msgid "This book format will be permanently erased from database" +msgstr "이 책 형식은 데이터베이스에서 영구적으로 삭제됨" + +#: cps/templates/modal_dialogs.html:51 +msgid "This book will be permanently erased from database" +msgstr "이 책은 데이터베이스에서 영구적으로 삭제됨" + +#: cps/templates/modal_dialogs.html:52 +msgid "and hard disk" +msgstr "그리고 하드디스크" + +#: cps/templates/modal_dialogs.html:56 +msgid "Important Kobo Note: deleted books will remain on any paired Kobo device." +msgstr "Kobo 참고 사항: 삭제된 책은 페어링된 모든 Kobo 기기에 남아 있습니다." + +#: cps/templates/modal_dialogs.html:57 +msgid "Books must first be archived and the device synced before a book can safely be deleted." +msgstr "책을 안전하게 삭제하려면 먼저 책을 보관하고 기기를 동기화해야 합니다." + +#: cps/templates/modal_dialogs.html:76 +msgid "Choose File Location" +msgstr "파일 위치 선택" + +#: cps/templates/modal_dialogs.html:82 +msgid "type" +msgstr "유형" + +#: cps/templates/modal_dialogs.html:83 +msgid "name" +msgstr "이름" + +#: cps/templates/modal_dialogs.html:84 +msgid "size" +msgstr "크기" + +#: cps/templates/modal_dialogs.html:90 +msgid "Parent Directory" +msgstr "상위 폴더" + +#: cps/templates/modal_dialogs.html:98 +msgid "Select" +msgstr "선택" + +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 +msgid "Ok" +msgstr "Ok" + +#: cps/templates/osd.xml:5 +msgid "Calibre-Web eBook Catalog" +msgstr "Calibre-Web 책 목록" + +#: cps/templates/read.html:6 +msgid "epub Reader" +msgstr "epub 리더" + +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "밝게" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "어둡게" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "뒤로" + +#: cps/templates/read.html:88 +msgid "Reflow text when sidebars are open." +msgstr "사이드바가 열려 있을 때 텍스트 다시 배열." + +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + +#: cps/templates/readcbr.html:7 +msgid "Comic Reader" +msgstr "코믹 리더" + +#: cps/templates/readcbr.html:92 +msgid "Keyboard Shortcuts" +msgstr "키보드 단축키" + +#: cps/templates/readcbr.html:95 +msgid "Previous Page" +msgstr "이전 페이지" + +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 +msgid "Next Page" +msgstr "다음 페이지" + +#: cps/templates/readcbr.html:97 +msgid "Scale to Best" +msgstr "최적 크기" + +#: cps/templates/readcbr.html:98 +msgid "Scale to Width" +msgstr "폭 조절" + +#: cps/templates/readcbr.html:99 +msgid "Scale to Height" +msgstr "높이 조절" + +#: cps/templates/readcbr.html:100 +msgid "Scale to Native" +msgstr "기본 크기" + +#: cps/templates/readcbr.html:101 +msgid "Rotate Right" +msgstr "오른쪽으로 회전" + +#: cps/templates/readcbr.html:102 +msgid "Rotate Left" +msgstr "왼쪽으로 회전" + +#: cps/templates/readcbr.html:103 +msgid "Flip Image" +msgstr "이미지 뒤집기" + +#: cps/templates/readcbr.html:125 +msgid "Scale" +msgstr "크기" + +#: cps/templates/readcbr.html:128 +msgid "Best" +msgstr "최적" + +#: cps/templates/readcbr.html:129 +msgid "Width" +msgstr "폭" + +#: cps/templates/readcbr.html:130 +msgid "Height" +msgstr "높이" + +#: cps/templates/readcbr.html:131 +msgid "Native" +msgstr "기본" + +#: cps/templates/readcbr.html:136 +msgid "Rotate" +msgstr "회전" + +#: cps/templates/readcbr.html:147 +msgid "Flip" +msgstr "뒤집기" + +#: cps/templates/readcbr.html:150 +msgid "Horizontal" +msgstr "수평" + +#: cps/templates/readcbr.html:151 +msgid "Vertical" +msgstr "수직" + +#: cps/templates/readcbr.html:156 +msgid "Direction" +msgstr "방향" + +#: cps/templates/readcbr.html:159 +msgid "Left to Right" +msgstr "왼쪽에서 오른쪽" + +#: cps/templates/readcbr.html:160 +msgid "Right to Left" +msgstr "오른쪽에서 왼쪽" + +#: cps/templates/readcbr.html:168 +msgid "Reset to Top" +msgstr "맨 위로 재설정" + +#: cps/templates/readcbr.html:169 +msgid "Remember Position" +msgstr "위치 기억" + +#: cps/templates/readcbr.html:174 +msgid "Scrollbar" +msgstr "스크롤바" + +#: cps/templates/readcbr.html:177 +msgid "Show" +msgstr "보기" + +#: cps/templates/readcbr.html:178 +msgid "Hide" +msgstr "숨기기" + +#: cps/templates/readdjvu.html:5 +msgid "DJVU Reader" +msgstr "DJVU 리더" + +#: cps/templates/readpdf.html:32 +msgid "PDF Reader" +msgstr "PDF 리더" + +#: cps/templates/readtxt.html:6 +msgid "txt Reader" +msgstr "텍스트 리더" + +#: cps/templates/register.html:4 +msgid "Register New Account" +msgstr "새 계정 등록" + +#: cps/templates/register.html:10 +msgid "Choose a username" +msgstr "사용자 이름 선택" + +#: cps/templates/register.html:15 +msgid "Your Email" +msgstr "이메일 주소" + +#: cps/templates/remote_login.html:5 +msgid "Magic Link - Authorise New Device" +msgstr "Magic Link - 새 장치 승인" + +#: cps/templates/remote_login.html:7 +msgid "On another device, login and visit:" +msgstr "다른 기기에서는 로그인 하고 방문:" + +#: cps/templates/remote_login.html:11 +msgid "Once verified, you will automatically be logged in on this device." +msgstr "승인이 되면 이 장치에 자동으로 로그인됩니다." + +#: cps/templates/remote_login.html:14 +msgid "This verification link will expire in 10 minutes." +msgstr "이 확인 링크는 10분 후에 만료됩니다." + +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "결과 없음" + +#: cps/templates/search.html:7 +msgid "Search Term:" +msgstr "검색어:" + +#: cps/templates/search.html:9 +msgid "Results for:" +msgstr "결과:" + +#: cps/templates/search_form.html:21 +msgid "Published Date From" +msgstr "출간일(부터)" + +#: cps/templates/search_form.html:31 +msgid "Published Date To" +msgstr "출간일(까지)" + +#: cps/templates/search_form.html:59 +msgid "Exclude Tags" +msgstr "태그 제외" + +#: cps/templates/search_form.html:77 +msgid "Exclude Series" +msgstr "시리즈 제외" + +#: cps/templates/search_form.html:95 +msgid "Exclude Shelves" +msgstr "서재 제외" + +#: cps/templates/search_form.html:115 +msgid "Exclude Languages" +msgstr "언어 제외" + +#: cps/templates/search_form.html:126 +msgid "Extensions" +msgstr "확장자" + +#: cps/templates/search_form.html:134 +msgid "Exclude Extensions" +msgstr "확장자 제외" + +#: cps/templates/search_form.html:144 +msgid "Rating Above" +msgstr "평점(이상)" + +#: cps/templates/search_form.html:148 +msgid "Rating Below" +msgstr "평점(이하)" + +#: cps/templates/search_form.html:180 +msgid "From:" +msgstr "부터:" + +#: cps/templates/search_form.html:190 +msgid "To:" +msgstr "까지:" + +#: cps/templates/shelf.html:13 +msgid "Delete this Shelf" +msgstr "이 서재 삭제" + +#: cps/templates/shelf.html:14 +msgid "Edit Shelf Properties" +msgstr "서재 속성 편집" + +#: cps/templates/shelf.html:17 +msgid "Arrange books manually" +msgstr "수동으로 책 정렬" + +#: cps/templates/shelf.html:18 +msgid "Disable Change order" +msgstr "정렬 변경 비활성화" + +#: cps/templates/shelf.html:18 +msgid "Enable Change order" +msgstr "정렬 변경 활성화" + +#: cps/templates/shelf_edit.html:14 +msgid "Share with Everyone" +msgstr "모두와 공유" + +#: cps/templates/shelf_edit.html:21 +msgid "Sync this shelf with Kobo device" +msgstr "이 서재를 Kobo 기기와 동기화" + +#: cps/templates/shelf_order.html:5 +msgid "Drag to Rearrange Order" +msgstr "드래그하여 순서 변경" + +#: cps/templates/shelf_order.html:33 +msgid "Hidden Book" +msgstr "숨겨진 책" + +#: cps/templates/stats.html:7 +msgid "Library Statistics" +msgstr "Calibre 서재 통계" + +#: cps/templates/stats.html:12 +msgid "Books in this Library" +msgstr "이 서재의 책들" + +#: cps/templates/stats.html:16 +msgid "Authors in this Library" +msgstr "이 서재의 저자" + +#: cps/templates/stats.html:20 +msgid "Categories in this Library" +msgstr "이 서재의 카테고리" + +#: cps/templates/stats.html:24 +msgid "Series in this Library" +msgstr "이 서재의 시리즈" + +#: cps/templates/stats.html:29 +msgid "System Statistics" +msgstr "시스템 통계" + +#: cps/templates/stats.html:33 +msgid "Program" +msgstr "" + +#: cps/templates/stats.html:34 +msgid "Installed Version" +msgstr "설치 버전" + +#: cps/templates/tasks.html:12 +msgid "User" +msgstr "사용자" + +#: cps/templates/tasks.html:14 +msgid "Task" +msgstr "작업" + +#: cps/templates/tasks.html:15 +msgid "Status" +msgstr "상태" + +#: cps/templates/tasks.html:16 +msgid "Progress" +msgstr "Progress" + +#: cps/templates/tasks.html:17 +msgid "Run Time" +msgstr "실행 시간" + +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" + +#: cps/templates/user_edit.html:20 +msgid "Reset user Password" +msgstr "사용자 비밀번호 초기화" + +#: cps/templates/user_edit.html:43 +msgid "Language of Books" +msgstr "책 언어" + +#: cps/templates/user_edit.html:54 +msgid "OAuth Settings" +msgstr "OAuth 설정" + +#: cps/templates/user_edit.html:56 +msgid "Link" +msgstr "링크" + +#: cps/templates/user_edit.html:58 +msgid "Unlink" +msgstr "링크 해제" + +#: cps/templates/user_edit.html:64 +msgid "Kobo Sync Token" +msgstr "코보 연동 토큰" + +#: cps/templates/user_edit.html:66 +msgid "Create/View" +msgstr "생성/보기" + +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "강제로 코보 전체 동기화" + +#: cps/templates/user_edit.html:88 +msgid "Add allowed/Denied Custom Column Values" +msgstr "허용/거부 사용자 정의 열 값 추가" + +#: cps/templates/user_edit.html:137 +msgid "Sync only books in selected shelves with Kobo" +msgstr "선택한 서가에 있는 책만 Kobo와 동기화" + +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 +msgid "Delete User" +msgstr "사용자 삭제" + +#: cps/templates/user_edit.html:159 +msgid "Generate Kobo Auth URL" +msgstr "Kobo Auth URL 생성" + +#: cps/templates/user_table.html:80 cps/templates/user_table.html:103 +msgid "Select..." +msgstr "선택..." + +#: cps/templates/user_table.html:131 +msgid "Edit User" +msgstr "사용자 편집" + +#: cps/templates/user_table.html:134 +msgid "Enter Username" +msgstr "사용자 이름" + +#: cps/templates/user_table.html:135 +#, fuzzy +msgid "Enter Email" +msgstr "테스트 이메일" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "Enter eReader Email" +msgstr "킨들로 보내기 이메일 주소" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "eReader Email" +msgstr "테스트 이메일" + +#: cps/templates/user_table.html:137 +msgid "Locale" +msgstr "언어" + +#: cps/templates/user_table.html:138 +msgid "Visible Book Languages" +msgstr "표시할 책 언어" + +#: cps/templates/user_table.html:139 +msgid "Edit Allowed Tags" +msgstr "허용된 태그 편집" + +#: cps/templates/user_table.html:139 +msgid "Allowed Tags" +msgstr "허용된 태그" + +#: cps/templates/user_table.html:140 +msgid "Edit Denied Tags" +msgstr "거부된 태그 편집" + +#: cps/templates/user_table.html:140 +msgid "Denied Tags" +msgstr "거부된 태그" + +#: cps/templates/user_table.html:141 +msgid "Edit Allowed Column Values" +msgstr "허용된 열 값 편집" + +#: cps/templates/user_table.html:141 +msgid "Allowed Column Values" +msgstr "허용되는 열 값" + +#: cps/templates/user_table.html:142 +msgid "Edit Denied Column Values" +msgstr "거부된 열 값 편집" + +#: cps/templates/user_table.html:142 +msgid "Denied Column Values" +msgstr "거부된 열 값" + +#: cps/templates/user_table.html:144 +msgid "Change Password" +msgstr "비밀번호 변경" + +#: cps/templates/user_table.html:147 +msgid "View" +msgstr "보기" + +#: cps/templates/user_table.html:150 +msgid "Edit Public Shelves" +msgstr "공개 서재 편집" + +#: cps/templates/user_table.html:152 +msgid "Sync selected Shelves with Kobo" +msgstr "선택한 서재를 코보와 동기화" + +#: cps/templates/user_table.html:156 +#, fuzzy +msgid "Show Read/Unread Section" +msgstr "읽음/읽지 않음 선택 표시" + diff --git a/cps/translations/nl/LC_MESSAGES/messages.mo b/cps/translations/nl/LC_MESSAGES/messages.mo index fb07d0353..3159f77fc 100644 Binary files a/cps/translations/nl/LC_MESSAGES/messages.mo and b/cps/translations/nl/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/nl/LC_MESSAGES/messages.po b/cps/translations/nl/LC_MESSAGES/messages.po index 844839968..da3b17192 100644 --- a/cps/translations/nl/LC_MESSAGES/messages.po +++ b/cps/translations/nl/LC_MESSAGES/messages.po @@ -8,588 +8,645 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web (GPLV3)\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2020-12-12 08:20+0100\n" "Last-Translator: Marcel Maas \n" "Language: nl\n" "Language-Team: ed.driesen@telenet.be\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "niet geïnstalleerd" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "geïnstalleerd" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Statistieken" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "De server is herstart, vernieuw de pagina" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Bezig met het afsluiten van de server, sluit het venster" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Opnieuw verbinden gelukt" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Onbekende opdracht" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Het boek is in de wachtrij geplaatst om te worden verstuurd aan %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Onbekend" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Systeembeheer" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Basisconfiguratie" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Uiterlijk aanpassen" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" msgstr "Systeembeheerder" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Alles" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "Gebruiker niet gevonden" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "{} gebruikers succesvol verwijderd" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Alle talen" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "Misvormd verzoek" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "Gast naam kan niet worden veranderd" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "Gast kan deze rol niet hebben" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "Kan systeembeheerder rol niet verwijderen van de laatste systeembeheerder" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "Waarde moet Waar of Onwaar zijn" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "Ongeldige rol" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "Gast kan dit niet bekijken" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "Ongeldige waarde" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "Gasts locale is automatisch bepaald en kan niet handmatig worden ingesteld" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "Geen geldige locale is opgegeven" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "Geen geldige boek taal is opgegeven" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "Parameter is niet gevonden" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "Ongeldige gelezen kolom" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "Ongeldige beperkte kolom" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Calibre-Web-configuratie bijgewerkt" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "Wil je je Kobo Token echt verwijderen?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "Wil je dit domein echt verwijderen?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "Wil je deze gebruiker echt verwijderen?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Weet je zeker dat je deze boekenplank wilt verwijderen?" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Weet je zeker dat je de locales van de geselecteerde gebruiker(s) wil veranderen?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "Weet je zeker dat je de zichtbare talen voor de geselecteerde gebruiker(s) wil veranderen?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "Weet je zeker dat je de geselecteerde rol van de geselecteerde gebruiker(s) wil veranderen?" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Weet je zeker dat je de geselecteerde beperkingen voor de geselecteerde gebruikers(s) wil verwijderen?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "Weet je zeker dat je de geselecteerde zichtbaarheidsbeperkingen voor de geselecteerde gebruiker(s) wil veranderen?" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Weet je zeker dat je de synchronisatiegedrag van boekenplanken voor de geselecteerde gebruiker(s) wil veranderen?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "Weet je zeker dat je de locatie van de Calibre-bibliotheek wil veranderen?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "Tag niet gevonden" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "Ongeldige actie" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Weigeren" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Toestaan" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Tag niet gevonden" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Ongeldige actie" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json is niet geconfigureerd voor webapplicatie" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "De locatie van het logbestand is onjuist, voer een geldige locatie in" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "De locatie vam het toegangslog is onjuist, voer een geldige locatie in" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Voer alsjeblieft een LDAP Provider, Port, DN en User Object Identifier in" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "Voer een geldig LDAP Service Account en wachtwoord in" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "Voer een LDAP Service Account in" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "LDAP Groep Object Filter Moet Een \"%s\" Formaat Identificiatie hebben" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "LDAP Groep Object Filter heeft een niet-gebalanceerd haakje" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "LDAP Gebruiker Object Filter moet \"%s\" Formaat Identificatie hebben" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "LDAP Gebruiker Filter heeft een niet-gebalanceerd haakje" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "LDAP Lid Gebruiker Filter moet een \"%s\" Formaat Identificatie hebben" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "LDAP Lid Gebruiker Filter heeft een niet-gebalanceerd haakje" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "LDAP CACertficaat, Certificaat of Sleutel Locatie is ongeldig. Voer alsjeblieft een geldig pad in." -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "DB-instellingen niet opgeslagen" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "Database niet gevonden, voer de juiste locatie in" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "Kan niet schrijven naar database" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "SSL-sleutellocatie is niet geldig, voer een geldig pad in" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "SSL-certificaatlocatie is niet geldig, voer een geldig pad in" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "E-mailserver-instellingen bijgewerkt" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Databaseconfiguratie" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Vul alle velden in!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "Het e-mailadres bevat geen geldige domeinnaam" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "Gebruiker toevoegen" -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Gebruiker '%(user)s' aangemaakt" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Bestaand account met dit e-mailadres of deze gebruikersnaam aangetroffen." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Gebruiker '%(nick)s' verwijderd" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "Kan Gast gebruiker niet verwijderen" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Kan laatste systeembeheerder niet verwijderen" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Gebruiker '%(nick)s' bewerken" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Gebruiker '%(nick)s' bijgewerkt" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Onbekende fout opgetreden. Probeer het later nog eens." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "SMTP-instellingen bewerken" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "Gmail Account succesvol geverifieerd" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Database fout: %(error)s." + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "Test E-Mail wordt verzonden naar %(email)s, controleer de taken voor het resultaat" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Fout opgetreden bij het versturen van de test-e-mail: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Gelieve eerst je e-mail adres configureren..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "E-mailserver-instellingen bijgewerkt" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Onbekende fout opgetreden. Probeer het later nog eens." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Gebruiker '%(nick)s' bewerken" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Wachtwoord voor gebruiker %(user)s is hersteld" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Stel eerst SMTP-mail in..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Logbestand lezer" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Update opvragen" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Update downloaden" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Update uitpakken" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Update toepassen" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Databaseverbindingen zijn gesloten" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Bezig met stoppen van Calibre-Web" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Update voltooid, klik op 'Oké' en vernieuw de pagina" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Update mislukt:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTP-fout" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Verbindingsfout" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Time-out tijdens maken van verbinding" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Algemene fout" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "Geüpload bestand kon niet opgeslagen worden in de tijdelijke map" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 #, fuzzy msgid "Failed to extract at least One LDAP User" msgstr "Mislukt om minstens een LDAP gebruiker aan te maken" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "Het is niet gelukt tenminste een LDAP gebruiker aan te maken" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Fout: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Fout: No user returned in response of LDAP server" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "Minstens een LDAP Gebruiker is niet gevonden in de Database" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} Gebruiker succesvol geïmporteerd" -#: cps/converter.py:30 -msgid "not configured" -msgstr "niet geconfigureerd" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "Database niet gevonden, voer de juiste locatie in" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "Kan niet schrijven naar database" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "SSL-sleutellocatie is niet geldig, voer een geldig pad in" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "SSL-certificaatlocatie is niet geldig, voer een geldig pad in" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "E-mailserver-instellingen bijgewerkt" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Databaseconfiguratie" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Vul alle velden in!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "Het e-mailadres bevat geen geldige domeinnaam" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Gebruiker toevoegen" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Gebruiker '%(user)s' aangemaakt" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Bestaand account met dit e-mailadres of deze gebruikersnaam aangetroffen." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Gebruiker '%(nick)s' verwijderd" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Kan Gast gebruiker niet verwijderen" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Kan laatste systeembeheerder niet verwijderen" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Gebruiker '%(nick)s' bijgewerkt" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "niet geïnstalleerd" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Kan programma niet uitvoeren" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 -#, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, fuzzy, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "Aangepaste kolom Nr.%(column)d bestaat niet in de Calibre Database" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Het boekformaat is verwijderd" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Geen" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Het boek is verwijderd" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Oeps! Geselecteerd boek is niet beschikbaar. Bestand bestaat niet of is niet toegankelijk" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "metagegevens bewerken" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "" -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "%(seriesindex)s is geen geldig nummer, sla het over" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s is geen geldige taal" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "De bestandsextensie '%(ext)s' is niet toegestaan op deze server" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Het te uploaden bestand moet voorzien zijn van een extensie" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Kan de locatie '%(path)s' niet aanmaken (niet gemachtigd)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Kan %(file)s niet opslaan." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Database fout: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Bestandsformaat %(ext)s toegevoegd aan %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "Identificatoren zijn niet hoofdlettergevoelig, overschrijf huidige identificatoren" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "De metagegevens zijn bijgewerkt" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Kan het boek niet bewerken, controleer het logbestand" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Geüpload boek staat mogelijk al in de bibliotheek, controleer alvorens door te gaan: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "Bestand %(filename)s kon niet opgeslagen worden in de tijdelijke map" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Omslag %(file)s niet verplaatst: %(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Bestand %(file)s geüpload" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Bron- of doelformaat ontbreekt voor conversie" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Het boek is in de wachtrij geplaatst voor conversie naar %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Er is een fout opgetreden bij het converteren van dit boek: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Geüpload boek staat mogelijk al in de bibliotheek, controleer alvorens door te gaan: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s is geen geldige taal" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "De bestandsextensie '%(ext)s' is niet toegestaan op deze server" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Het te uploaden bestand moet voorzien zijn van een extensie" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Bestand %(filename)s kon niet opgeslagen worden in de tijdelijke map" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Omslag %(file)s niet verplaatst: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Het boekformaat is verwijderd" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Het boek is verwijderd" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "metagegevens bewerken" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s is geen geldig nummer, sla het over" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Kan de locatie '%(path)s' niet aanmaken (niet gemachtigd)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Kan %(file)s niet opslaan." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Bestandsformaat %(ext)s toegevoegd aan %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Het instellen van Google Drive is niet afgerond, heractiveer Google Drive" @@ -603,166 +660,181 @@ msgstr "Het callback-domein is niet geverifieerd. Volg de stappen in de Google-o msgid "%(format)s format not found for book id: %(book)d" msgstr "%(format)s formaat niet gevonden voor boek met id: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s niet aangetroffen op Google Drive: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s niet gevonden %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Versturen naar Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Deze e-mail is verstuurd via Calibre-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Calibre-Web - test-e-mail" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Test-e-mail" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Aan de slag met Calibre-Web" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Registratie-e-mailadres van gebruiker: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "%(orig)s converteren naar %(format)s en versturen naar Kindle" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "%(format)s versturen naar Kindle" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "%(book)s verzonden naar Kindle" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Het opgevraagde bestand kan niet worden gelezen. Ben je hiertoe gemachtigd?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "Het verwijderen van de boekenmap voor boek %(id)s is mislukt, het pad heeft submappen: %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "Verwijderen van boek %(id)s mislukt: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, fuzzy, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "Verwijder boek %(id)s alleen uit database, boek pad is ongeldig: %(path)s" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "Kan de titel '%(src)s' niet wijzigen in '%(dest)s': %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Kan het bestand in '%(src)s' niet wijzigen naar '%(dest)s': %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Bestand '%(file)s' niet aangetroffen op Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Kan de titel '%(src)s' niet wijzigen in '%(dest)s': %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Boeken locatie '%(path)s' niet aangetroffen op Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Bestaand account met dit e-mailadres aangetroffen." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Deze gebruikersnaam is al in gebruik" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" msgstr "Ongeldig E-Mail adres" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Fout bij downloaden omslag" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "Onjuist omslagformaat" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Locatie aanmaken voor omslag mislukt" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "Omslag-bestand is geen afbeelding of kon niet opgeslagen worden" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "Alleen jpg/jpeg/png/webp/bmp bestanden worden ondersteund als omslag" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Alleen jpg/jpeg bestanden zijn toegestaan als omslag" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "Unrar executable niet gevonden" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" msgstr "Fout bij het uitvoeren van Unrar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Wachten" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Willekeurige boeken" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Mislukt" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "Gestart" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Voltooid" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Onbekende status" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Je kunt Calibre-Web niet vanaf de lokale computer openen om een geldige api_endpoint te krijgen voor je kobo toestel" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Kobo Instellen" @@ -771,9 +843,9 @@ msgstr "Kobo Instellen" msgid "Register with %(provider)s" msgstr "Aanmelden bij %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "je bent ingelogd als: '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -832,507 +904,613 @@ msgstr "Google OAuth fout, probeer het later nog eens." msgid "Google Oauth error: {}" msgstr "Google OAuth foutmelding: {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "{} sterren" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Inloggen" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Toegangssleutel niet gevonden" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Toegangssleutel is verlopen" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Gelukt! Ga terug naar je apparaat" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Boeken" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Recent toegevoegde boeken tonen" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Populaire boeken" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Populaire boeken tonen" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "Gedownloade boeken" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "Gedownloade boeken tonen" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Best beoordeelde boeken" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Best beoordeelde boeken tonen" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Gelezen boeken" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Gelezen/Ongelezen boeken tonen" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Ongelezen boeken" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Ongelezen boeken tonen" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Willekeurige boeken" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Willekeurige boeken tonen" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Categorieën" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Categoriekeuze tonen" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Boekenreeksen" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Boekenreeksenkeuze tonen" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Auteurs" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Auteurkeuze tonen" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Uitgevers" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Uitgeverskeuze tonen" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Talen" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Taalkeuze tonen" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Beoordelingen" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Beoordelingen tonen" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Bestandsformaten" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Bestandsformaten tonen" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Gearchiveerde boeken" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" msgstr "Gearchiveerde boeken tonen" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "Boekenlijst" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "Boekenlijst tonen" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Ongeldige boekenplank opgegeven" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Sorry, je mag geen boeken toevoegen aan boekenplank: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Dit boek maakt al deel uit van boekenplank: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Het boek is toegevoegd aan boekenplank: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Je bent niet gemachtigd om boeken toe te voegen aan boekenplank: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Deze boeken maken al deel uit van boekenplank: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "De boeken zijn toegevoegd aan boekenplank: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Kan boeken niet toevoegen aan boekenplank: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Het boek is verwijderd van boekenplank: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Je bent niet gemachtigd om boeken te verwijderen van boekenplank: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Boekenplank maken" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Je bent niet gemachtigd deze boekenplank aan te passen" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Pas een boekenplank aan" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Boekenplank '%(title)s' aangemaakt" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Boekenplank '%(title)s' is aangepast" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Er is een fout opgetreden" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Een openbare boekenplank met de naam '%(title)s' bestaat al." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Een persoonlijke boekenplank met de naam '%(title)s' bestaat al." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Volgorde van boekenplank veranderen: '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Boekenplank: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Kan boekenplank niet openen: de boekenplank bestaat niet of is ontoegankelijk" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Onverwachte gegevens tijdens het uitlezen van de update-informatie" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Er is geen update beschikbaar." - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Er is een update beschikbaar. Klik op de knop hieronder om te updaten naar de nieuwste versie." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "De update-informatie kan niet worden opgehaald" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Klik op de onderstaande knop om de laatste stabiele versie te installeren." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Er is een update beschikbaar. Klik op de knop hieronder om te updaten naar versie: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Geen update-informatie beschikbaar" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Verkennen (willekeurige boeken)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Populaire boeken (meest gedownload)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "Gedownloade boeken door %(user)s" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Auteur: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Uitgever: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Reeks: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Beoordeling: %(rating)s sterren" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Bestandsformaat: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Categorie: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Taal: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Geavanceerd zoeken" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Zoeken" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Downloads" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Beoordelingen" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Alle bestandsformaten" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Taken" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Gepubliceerd na " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Gepubliceerd vóór " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Beoordeling <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Beoordeling >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "Lees Status = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "Fout tijdens het zoeken van aangepaste kolommen, start Calibre-Web opnieuw op" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Het boek is in de wachtrij geplaatst om te worden verstuurd aan %(kindlemail)s" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Geavanceerd zoeken" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Ongeldige boekenplank opgegeven" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Sorry, je mag geen boeken toevoegen aan boekenplank: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Dit boek maakt al deel uit van boekenplank: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Het boek is toegevoegd aan boekenplank: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Deze boeken maken al deel uit van boekenplank: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "De boeken zijn toegevoegd aan boekenplank: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Kan boeken niet toevoegen aan boekenplank: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Het boek is verwijderd van boekenplank: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Boekenplank maken" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Je bent niet gemachtigd deze boekenplank aan te passen" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Pas een boekenplank aan" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Het boek is verwijderd" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Volgorde van boekenplank veranderen: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Boekenplank '%(title)s' aangemaakt" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Boekenplank '%(title)s' is aangepast" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Er is een fout opgetreden" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Een openbare boekenplank met de naam '%(title)s' bestaat al." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Een persoonlijke boekenplank met de naam '%(title)s' bestaat al." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Boekenplank: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Kan boekenplank niet openen: de boekenplank bestaat niet of is ontoegankelijk" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Taken" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Wachten" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Mislukt" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Gestart" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Voltooid" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Onbekende status" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Onverwachte gegevens tijdens het uitlezen van de update-informatie" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Er is geen update beschikbaar." + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Er is een update beschikbaar. Klik op de knop hieronder om te updaten naar de nieuwste versie." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "De update-informatie kan niet worden opgehaald" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Klik op de onderstaande knop om de laatste stabiele versie te installeren." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Er is een update beschikbaar. Klik op de knop hieronder om te updaten naar versie: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Geen update-informatie beschikbaar" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Verkennen (willekeurige boeken)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Populaire boeken (meest gedownload)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Gedownloade boeken door %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Auteur: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Uitgever: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Reeks: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Beoordeling: %(rating)s sterren" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Bestandsformaat: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Categorie: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Taal: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Downloads" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Beoordelingen" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Alle bestandsformaten" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Stel eerst SMTP-mail in..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Het boek is in de wachtrij geplaatst om te worden verstuurd aan %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "Fout opgetreden bij het versturen van dit boek: %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "Stel je kindle-e-mailadres in..." -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "E-mailserver is niet geconfigureerd, neem contact op met de beheerder!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Registreren" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Dit e-mailadres mag niet worden gebruikt voor registratie" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Er is een bevestigings-e-mail verstuurd naar je e-mailadres." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "Kan de LDAP authenticatie niet activeren" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "Terugvallen op login: '%(nickname)s', LDAP Server is onbereikbaar, of de gebruiker is onbekend" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Inloggen mislukt: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Verkeerde gebruikersnaam of wachtwoord" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "Een nieuw wachtwoord is verzonden naar je e-mailadres" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Geef een geldige gebruikersnaam op om je wachtwoord te herstellen" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Je bent ingelogd als: '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)ss profiel" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Profiel bijgewerkt" +#: cps/web.py:1420 +#, fuzzy +msgid "Oops! An account already exists for this Email." +msgstr "Bestaand account met dit e-mailadres aangetroffen." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "Geen geldig gmail.json bestand gevonden met OAuth informatie" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s verzonden naar Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "Calibre ebook-convert %(tool)s niet gevonden" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "%(format)s formaat is niet gevonden op de schijf" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "E-Book converter mislukt met een onbekende foutmelding" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Kepubify-converteerder mislukt: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "Omgezette bestand is niet gevonden of meer dan een bestand in map %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "E-boek-conversie mislukt: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "Calibre mislukt met foutmelding: %(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "metagegevens bewerken" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Uploaden" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Gebruikers" @@ -1345,14 +1523,15 @@ msgstr "Gebruikersnaam" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "E-mailadres" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Kindle-e-mailadres" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Beheer" @@ -1362,212 +1541,230 @@ msgstr "Beheer" msgid "Password" msgstr "Wachtwoord" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Uploaden" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Downloaden" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Boeken lezen" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Bewerken" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Verwijderen" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Openbare boekenplank" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Gebruiker toevoegen" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "LDAP gebruikers importeren" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "SMTP-serverinstellingen" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "SMTP-hostnaam (gebruik mail.example.org om wachtwoordherstel uit te schakelen)" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP-poort" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "Encryptie" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "SMTP-gebruikersnaam" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Van e-mail" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" -msgstr "E-Mail Service" +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" +msgstr "EMail Service" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "Gmail via OAuth2" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Instellingen" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Calibre-database locatie" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Logniveau" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Poort" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "Externe poort" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Aantal boeken per pagina" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Uploaden toestaan" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Anoniem verkennen" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Openbare registratie" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Inloggen op afstand" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "Reverse Proxy Login" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Reverse proxy header naam" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Bewerk Calibre databaseconfiguratie" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Bewerk basisconfiguratie" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "Bewerk gebruikersinterface configuratie" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Systeembeheer" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "Download foutopsporingspakket" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Logboeken bekijken" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Opnieuw verbinden met Calibre database" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Calibre-Web herstarten" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Calibre-Web stoppen" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Bijwerken" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Versie" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Details" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Huidige versie" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Controleren op updates" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Update uitvoeren" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Weet je zeker dat je Calibre-Web wilt herstarten?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "Oké" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Annuleren" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Weet je zeker dat je Calibre-Web wilt stoppen?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Bezig met bijwerken, vernieuw de pagina niet" @@ -1579,119 +1776,118 @@ msgstr "via" msgid "In Library" msgstr "In bibliotheek" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "Sorteren op datum, nieuwste boeken eerst" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "Sorteren op datum, oudste boeken eerst" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "Sorteren op alfabetische volgorde" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "Sorteren op omgekeerde alfabetische volgorde" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "Sorteren op publicatiedatum, nieuwste boeken eerst" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "Sorteren op publicatiedatum, oudste boeken eerst" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "beperken" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Meer van" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Boek verwijderen" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Formaten verwijderen:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Boekformaat converteren:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Converteren van:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "kies een optie" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Converteren naar:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Boek converteren" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Boektitel" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Auteur" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Omschrijving" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "Identificatoren" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "Identificatie type" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "Identificatie waarde" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Verwijderen" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "Identificator toevoegen" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Labels" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "Boekenreeks volgnummer" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Beoordeling" @@ -1703,82 +1899,83 @@ msgstr "Omslag-url (jpg) (de omslag wordt gedownload en opgeslagen in de databas msgid "Upload Cover from Local Disk" msgstr "Omslag uploaden vanaf de harde schijf" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Publicatiedatum" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Uitgever" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Taal" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Ja" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Nee" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Uploadformaat" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Boek inkijken na bewerking" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Metagegevens ophalen" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Opslaan" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Trefwoord" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " Trefwoord zoeken " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Klik op de omslag om de metagegevens in het formulier te laden" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Bezig met laden..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Sluiten" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Bron" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Zoekfout!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Geen resultaten gevonden! Gebruik een ander trefwoord." @@ -1870,27 +2067,36 @@ msgstr "Voer domeinnaam in" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Lees Status" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Identificatoren" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Weet je het zeker?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "Boeken met de titel zullen worden samengevoegd van:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "In boek met titel:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "Samenvoegen" @@ -1983,6 +2189,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Uploaden inschakelen" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "Toegelaten upload bestandsformaten" @@ -1996,7 +2206,7 @@ msgid "Enable Public Registration" msgstr "Openbare registratie inschakelen" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "Gebruik e-mail als inlognaam" #: cps/templates/config_edit.html:132 @@ -2063,11 +2273,6 @@ msgstr "LDAP Server Poort" msgid "LDAP Encryption" msgstr "LDAP encryptie" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Geen" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2203,7 +2408,7 @@ msgstr "Aantal te tonen willekeurige boeken" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Aantal te tonen auteurs alvorens te verbergen (0=nooit verbergen)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Thema" @@ -2235,139 +2440,143 @@ msgstr "Reguliere expressie voor het sorteren op titel" msgid "Default Settings for New Users" msgstr "Standaardinstellingen voor nieuwe gebruikers" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Systeembeheerder" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Downloads toestaan" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Boeken lezen toestaan" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Uploads toestaan" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Bewerken toestaan" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "Verwijderen van boeken toestaan" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Wachtwoord wijzigen toestaan" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Bewerken van openbare boekenplanken toestaan" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Talen uitsluiten" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Taal van boeken" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Standaard zichtbaar voor nieuwe gebruikers" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Willekeurige boeken tonen in gedetailleerde weergave" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "Voeg toegestane/geweigerde tags toe" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "Voeg toegestane/geweigerde aangepaste kolomwaarden toe" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Lezen in webbrowser" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Luisteren in webbrowser" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, fuzzy, python-format msgid "Book %(index)s of %(range)s" msgstr "Boek %(index)s van %(range)s" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Gepubliceerd" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Markeren als ongelezen" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Markeren als gelezen" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Gelezen" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Terughalen uit archief" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Toevoegen aan archief" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "Gearchiveerd" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Beschrijving:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Toevoegen aan boekenplank" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Openbaar)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Metagegevens bewerken" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "Kies Server Type" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +#, fuzzy +msgid "Standard Email Account" msgstr "Gebruik Standaard E-Mail Account" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "Gmail Account met OAuth2 Verificatie" +#, fuzzy +msgid "Gmail Account" +msgstr "Kies Server Type" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" -msgstr "Gmail Account opzetten als E-Mail Server" +msgid "Setup Gmail Account" +msgstr "" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" @@ -2390,10 +2599,11 @@ msgid "Attachment Size Limit" msgstr "Bijlage bestandsgrootte limiet" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Opslaan en test-e-mail versturen" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Annuleren" @@ -2419,46 +2629,63 @@ msgstr "Voer domeinnaam in" msgid "Denied Domains (Blacklist)" msgstr "Geweigerde domeinen voor registratie" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Volgende" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "Open het .kobo/Kobo eReader.conf bestand in een teksteditor en voeg toe (of bewerk):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Open het .kobo/Kobo/Kobo eReader.conf bestand in een teksteditor en voeg toe (of bewerk):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Kobo Sync Token" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 #, fuzzy msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "E-mailserver is niet geconfigureerd, neem contact op met de beheerder!" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Probleem melden" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Terug naar startpagina" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "Gebruiker uitloggen" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "Auteurs sorteren op alfabetische volgorde" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "Auteurs sorteren op omgekeerde alfabetische volgorde" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "Sorteer oplopend volgens de serie index" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "Sorteer aflopend volgens de serie index" @@ -2522,7 +2749,7 @@ msgstr "Boeken gesorteerd op beoordeling" msgid "Books ordered by file formats" msgstr "Boeken gesorteerd op bestandsformaat" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Boekenplanken" @@ -2531,63 +2758,67 @@ msgstr "Boekenplanken" msgid "Books organized in shelves" msgstr "Boeken georganiseerd op boekenplanken" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Startpagina" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Navigatie aanpassen" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Zoek in bibliotheek" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Bezig met uploaden..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Fout" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Uploaden voltooid, bezig met verwerken..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Instellingen" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Account" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Afmelden" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Bezig met uploaden..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Fout" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Uploaden voltooid, bezig met verwerken..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Instellingen" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Deze pagina niet vernieuwen" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Verkennen" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Informatie" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Vorige" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Boekgegevens" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Gegevens opslaan" @@ -2596,7 +2827,7 @@ msgstr "Gegevens opslaan" msgid "Forgot Password?" msgstr "Wachtwoord Vergeten?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Inloggen met magische koppeling" @@ -2692,7 +2923,7 @@ msgstr "Bovenliggende map" msgid "Select" msgstr "Selecteer" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "Oké" @@ -2706,128 +2937,141 @@ msgstr "Calibre-Web - e-boekcatalogus" msgid "epub Reader" msgstr "PDF lezer" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Licht" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Donker" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Annuleren" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Tekstindeling automatisch aanpassen als het zijpaneel geopend is." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "Comic Reader" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Sneltoetsen" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Vorige pagina" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Volgende pagina" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Optimaal inpassen" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Aanpassen aan breedte" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Aanpassen aan hoogte" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Ware grootte" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Rechtsom draaien" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Linksom draaien" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Afbeelding omdraaien" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Licht" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Donker" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Schaal" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Beste" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Breedte" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Hoogte" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Ware grootte" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Draaien" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Omdraaien" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Horizontaal" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Verticaal" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Richting" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Links-naar-rechts" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Rechts-naar-links" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "Terugzetten naar bovenkant" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "Positie onthouden" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "Schuifbalk" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "Toon" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "Verberg" @@ -2836,7 +3080,7 @@ msgstr "Verberg" msgid "DJVU Reader" msgstr "PDF lezer" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "PDF lezer" @@ -2855,7 +3099,7 @@ msgid "Choose a username" msgstr "Kies een gebruikersnaam" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Je e-mailadres" #: cps/templates/remote_login.html:5 @@ -2874,15 +3118,19 @@ msgstr "Na controle wordt je automatisch op dit apparaat ingelogd." msgid "This verification link will expire in 10 minutes." msgstr "De link vervalt na 10 minuten." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Geen resultaten gevonden" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Zoekterm:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Resultaten voor:" @@ -2894,10 +3142,6 @@ msgstr "Publicatiedatum van" msgid "Published Date To" msgstr "Publicatiedatum tot" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "Lees Status" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Labels uitsluiten" @@ -2939,30 +3183,26 @@ msgstr "Van:" msgid "To:" msgstr "Tot:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Deze boekenplank verwijderen" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "Bewerk boekenplank eigenschappen" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "Boeken handmatig rangschikken" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "Schakel verandering van de volgorde uit" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "Schakel verandering van de volgorde in" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Boekenplank wordt permanent verwijderd voor iedereen" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Delen met iedereen" @@ -3004,8 +3244,8 @@ msgid "System Statistics" msgstr "Systeeminformatie" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Programmabibliotheek" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3031,9 +3271,17 @@ msgstr "Voortgang" msgid "Run Time" msgstr "Looptijd" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Begintijd" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3063,19 +3311,23 @@ msgstr "Kobo Sync Token" msgid "Create/View" msgstr "Aanmaken/Bekijken" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "Voeg toegestane/geweigerde aangepaste kolomwaarden toe" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "Synchroniseer alleen boeken op geselecteerde boekenplanken met Kobo" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Gebruiker verwijderen" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Genereer Kobo Auth URL" @@ -3092,16 +3344,19 @@ msgid "Enter Username" msgstr "Voer gebruikersnaam in" #: cps/templates/user_table.html:135 -msgid "Enter E-mail Address" -msgstr "Voer e-mailadres in" +#, fuzzy +msgid "Enter Email" +msgstr "Test-e-mail" #: cps/templates/user_table.html:136 -msgid "Enter Kindle E-mail Address" -msgstr "Voer Kindle-e-mailadres in" +#, fuzzy +msgid "Enter eReader Email" +msgstr "Kindle-e-mailadres" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" -msgstr "Kindle-e-mail" +#, fuzzy +msgid "eReader Email" +msgstr "Test-e-mail" #: cps/templates/user_table.html:137 msgid "Locale" @@ -3163,10 +3418,7 @@ msgid "Sync selected Shelves with Kobo" msgstr "Synchroniseer geselecteerde boekenplanken met Kobo" #: cps/templates/user_table.html:156 -msgid "Show read/unread selection" +#, fuzzy +msgid "Show Read/Unread Section" msgstr "Toon gelezen/niet gelezen selectie" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Willekeurige boeken tonen" - diff --git a/cps/translations/no/LC_MESSAGES/messages.mo b/cps/translations/no/LC_MESSAGES/messages.mo new file mode 100644 index 000000000..673826804 Binary files /dev/null and b/cps/translations/no/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/no/LC_MESSAGES/messages.po b/cps/translations/no/LC_MESSAGES/messages.po new file mode 100644 index 000000000..837647915 --- /dev/null +++ b/cps/translations/no/LC_MESSAGES/messages.po @@ -0,0 +1,3463 @@ +# Norwegian translations for Calibre-Web. +# Copyright (C) 2022 Vegard Fladby +# This file is distributed under the same license as the Calibre-Web +# project. +# FIRST AUTHOR Vegard Fladby, 2022. +msgid "" +msgstr "" +"Project-Id-Version: Calibre-Web\n" +"Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" +"PO-Revision-Date: 2023-01-06 11:00+0000\n" +"Last-Translator: Vegard Fladby \n" +"Language: no\n" +"Language-Team: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.10.3\n" + +#: cps/about.py:84 +msgid "Statistics" +msgstr "Statistikk" + +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." +msgstr "Server startet på nytt. Last inn siden på nytt" + +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." +msgstr "Utfører avslutning av server, vennligst lukk vinduet" + +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" + +#: cps/admin.py:156 +msgid "Unknown command" +msgstr "Ukjent kommando" + +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Bøker ble satt i kø for sikkerhetskopiering av metadata" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 +msgid "Unknown" +msgstr "Ukjent" + +#: cps/admin.py:225 +msgid "Admin page" +msgstr "Admin side" + +#: cps/admin.py:245 +msgid "Basic Configuration" +msgstr "Grunnleggende konfigurasjon" + +#: cps/admin.py:283 +msgid "UI Configuration" +msgstr "UI-konfigurasjon" + +#: cps/admin.py:317 cps/templates/admin.html:51 +msgid "Edit Users" +msgstr "Rediger brukere" + +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 +msgid "All" +msgstr "Alle" + +#: cps/admin.py:388 cps/admin.py:1392 +msgid "User not found" +msgstr "Bruker ikke funnet" + +#: cps/admin.py:402 +msgid "{} users deleted successfully" +msgstr "{} brukere ble slettet" + +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 +#: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 +msgid "Show All" +msgstr "Vis alt" + +#: cps/admin.py:446 cps/admin.py:452 +msgid "Malformed request" +msgstr "Feil utformet forespørsel" + +#: cps/admin.py:464 cps/admin.py:1993 +msgid "Guest Name can't be changed" +msgstr "Gjestenavn kan ikke endres" + +#: cps/admin.py:476 +msgid "Guest can't have this role" +msgstr "Gjesten kan ikke ha denne rollen" + +#: cps/admin.py:488 cps/admin.py:1948 +msgid "No admin user remaining, can't remove admin role" +msgstr "Ingen administratorbruker igjen, kan ikke fjerne administratorrollen" + +#: cps/admin.py:492 cps/admin.py:506 +msgid "Value has to be true or false" +msgstr "Verdien må være sann eller usann" + +#: cps/admin.py:494 +msgid "Invalid role" +msgstr "Ugyldig rolle" + +#: cps/admin.py:498 +msgid "Guest can't have this view" +msgstr "Gjestene kan ikke ha denne utsikten" + +#: cps/admin.py:508 +msgid "Invalid view" +msgstr "Ugyldig visning" + +#: cps/admin.py:511 +msgid "Guest's Locale is determined automatically and can't be set" +msgstr "Gjestenes lokalitet bestemmes automatisk og kan ikke angis" + +#: cps/admin.py:515 +msgid "No Valid Locale Given" +msgstr "Ingen gyldig lokalitet gitt" + +#: cps/admin.py:526 +msgid "No Valid Book Language Given" +msgstr "Ikke oppgitt gyldig bokspråk" + +#: cps/admin.py:528 cps/editbooks.py:442 +msgid "Parameter not found" +msgstr "Parameter ikke funnet" + +#: cps/admin.py:565 +msgid "Invalid Read Column" +msgstr "Ugyldig lesekolonne" + +#: cps/admin.py:571 +msgid "Invalid Restricted Column" +msgstr "Ugyldig begrenset kolonne" + +#: cps/admin.py:591 cps/admin.py:1819 +msgid "Calibre-Web configuration updated" +msgstr "Calibre-Web-konfigurasjonen er oppdatert" + +#: cps/admin.py:603 +msgid "Do you really want to delete the Kobo Token?" +msgstr "Vil du virkelig slette Kobo-tokenet?" + +#: cps/admin.py:605 +msgid "Do you really want to delete this domain?" +msgstr "Vil du virkelig slette dette domenet?" + +#: cps/admin.py:607 +msgid "Do you really want to delete this user?" +msgstr "Vil du virkelig slette denne brukeren?" + +#: cps/admin.py:609 +msgid "Are you sure you want to delete this shelf?" +msgstr "Er du sikker på at du vil slette denne hyllen?" + +#: cps/admin.py:611 +msgid "Are you sure you want to change locales of selected user(s)?" +msgstr "Er du sikker på at du vil endre lokaliteter for valgte bruker(e)?" + +#: cps/admin.py:613 +msgid "Are you sure you want to change visible book languages for selected user(s)?" +msgstr "Er du sikker på at du vil endre synlige bokspråk for valgte bruker(e)?" + +#: cps/admin.py:615 +msgid "Are you sure you want to change the selected role for the selected user(s)?" +msgstr "Er du sikker på at du vil endre den valgte rollen for den(e) valgte brukeren?" + +#: cps/admin.py:617 +msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" +msgstr "Er du sikker på at du vil endre de valgte begrensningene for den(e) valgte brukeren?" + +#: cps/admin.py:619 +msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" +msgstr "Er du sikker på at du vil endre de valgte synlighetsbegrensningene for valgte bruker(e)?" + +#: cps/admin.py:622 +msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" +msgstr "Er du sikker på at du vil endre atferden for hyllesynkronisering for de(n) valgte brukeren(e)?" + +#: cps/admin.py:624 +msgid "Are you sure you want to change Calibre library location?" +msgstr "Er du sikker på at du vil endre plassering av Caliber-biblioteket?" + +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "Calibre-Web vil søke etter oppdaterte omslag og oppdatere omslagsminiatyrbilder, kan dette ta litt tid?" + +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Er du sikker på at du vil slette Calibre-Webs synkroniseringsdatabase for å tvinge frem en full synkronisering med Kobo Reader?" + +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 +#: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 +#: cps/templates/user_table.html:58 +msgid "Deny" +msgstr "Benekte" + +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 +#: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 +#: cps/templates/user_table.html:61 +msgid "Allow" +msgstr "Tillate" + +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{} synkroniseringsoppføringer slettet" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Merket ble ikke funnet" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Ugyldig handling" + +#: cps/admin.py:1104 +msgid "client_secrets.json Is Not Configured For Web Application" +msgstr "client_secrets.json er ikke konfigurert for webapplikasjon" + +#: cps/admin.py:1149 +msgid "Logfile Location is not Valid, Please Enter Correct Path" +msgstr "Loggfilplasseringen er ikke gyldig, skriv inn riktig bane" + +#: cps/admin.py:1155 +msgid "Access Logfile Location is not Valid, Please Enter Correct Path" +msgstr "Plasseringen av tilgangsloggfilen er ikke gyldig, skriv inn riktig bane" + +#: cps/admin.py:1185 +msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" +msgstr "Angi en LDAP-leverandør, port, DN og brukerobjektidentifikator" + +#: cps/admin.py:1191 +msgid "Please Enter a LDAP Service Account and Password" +msgstr "Vennligst skriv inn en LDAP-tjenestekonto og passord" + +#: cps/admin.py:1194 +msgid "Please Enter a LDAP Service Account" +msgstr "Angi en LDAP-tjenestekonto" + +#: cps/admin.py:1199 +#, python-format +msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" +msgstr "LDAP-gruppeobjektfilter må ha én \"%s\"-formatidentifikator" + +#: cps/admin.py:1201 +msgid "LDAP Group Object Filter Has Unmatched Parenthesis" +msgstr "LDAP-gruppeobjektfilter har uovertruffen parentes" + +#: cps/admin.py:1205 +#, python-format +msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" +msgstr "LDAP-brukerobjektfilter må ha én \"%s\"-formatidentifikator" + +#: cps/admin.py:1207 +msgid "LDAP User Object Filter Has Unmatched Parenthesis" +msgstr "LDAP-brukerobjektfilter har uovertruffen parentes" + +#: cps/admin.py:1214 +#, python-format +msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" +msgstr "LDAP-medlemsbrukerfilter må ha én \"%s\"-formatidentifikator" + +#: cps/admin.py:1216 +msgid "LDAP Member User Filter Has Unmatched Parenthesis" +msgstr "LDAP-medlemsbrukerfilter har uovertruffen parentes" + +#: cps/admin.py:1223 +msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" +msgstr "LDAP CA-sertifikat, sertifikat eller nøkkelplassering er ikke gyldig. Angi riktig bane" + +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "Legg til ny bruker" + +#: cps/admin.py:1263 cps/templates/admin.html:100 +#, fuzzy +msgid "Edit Email Server Settings" +msgstr "Rediger e-postserverinnstillinger" + +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" + +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, fuzzy, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Databasefeil: %(error)s." + +#: cps/admin.py:1311 +#, python-format +msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" +msgstr "Test e-post i kø for sending til %(email)s, sjekk Oppgaver for resultat" + +#: cps/admin.py:1314 +#, python-format +msgid "There was an error sending the Test e-mail: %(res)s" +msgstr "Det oppsto en feil ved sending av test-e-posten: %(res)s" + +#: cps/admin.py:1316 +msgid "Please configure your e-mail address first..." +msgstr "Vennligst konfigurer e-postadressen din først..." + +#: cps/admin.py:1318 +#, fuzzy +msgid "Email Server Settings updated" +msgstr "E-postserverinnstillinger oppdatert" + +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "Rediger innstillinger for planlagte oppgaver" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "Ugyldig starttidspunkt for spesifisert oppgave" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "Ugyldig varighet for spesifisert oppgave" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "Innstillinger for planlagte oppgaver er oppdatert" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +#, fuzzy +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "En ukjent feil oppstod. Prøv igjen senere." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "Innstillinger DB er ikke skrivbar" + +#: cps/admin.py:1411 cps/admin.py:2009 +#, python-format +msgid "Edit User %(nick)s" +msgstr "Rediger bruker %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" +msgstr "Passord for bruker %(user)s tilbakestilling" + +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." +msgstr "Vennligst konfigurer SMTP-postinnstillingene først..." + +#: cps/admin.py:1440 +msgid "Logfile viewer" +msgstr "Loggfilviser" + +#: cps/admin.py:1506 +msgid "Requesting update package" +msgstr "Ber om oppdateringspakke" + +#: cps/admin.py:1507 +msgid "Downloading update package" +msgstr "Laster ned oppdateringspakken" + +#: cps/admin.py:1508 +msgid "Unzipping update package" +msgstr "Pakker ut oppdateringspakken" + +#: cps/admin.py:1509 +msgid "Replacing files" +msgstr "Erstatter filer" + +#: cps/admin.py:1510 +msgid "Database connections are closed" +msgstr "Databaseforbindelser er stengt" + +#: cps/admin.py:1511 +msgid "Stopping server" +msgstr "Stopper server" + +#: cps/admin.py:1512 +msgid "Update finished, please press okay and reload page" +msgstr "Oppdatering fullført, vennligst trykk OK og last inn siden på nytt" + +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 +msgid "Update failed:" +msgstr "Oppdatering mislyktes:" + +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 +msgid "HTTP Error" +msgstr "HTTP-feil" + +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 +msgid "Connection error" +msgstr "Tilkoblingsfeil" + +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 +msgid "Timeout while establishing connection" +msgstr "Tidsavbrudd under etablering av tilkobling" + +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 +msgid "General error" +msgstr "Generell feil" + +#: cps/admin.py:1517 +msgid "Update file could not be saved in temp dir" +msgstr "Oppdateringsfilen kunne ikke lagres i temp dir" + +#: cps/admin.py:1518 +msgid "Files could not be replaced during update" +msgstr "Filer kunne ikke erstattes under oppdatering" + +#: cps/admin.py:1542 +msgid "Failed to extract at least One LDAP User" +msgstr "Kunne ikke pakke ut minst én LDAP-bruker" + +#: cps/admin.py:1587 +msgid "Failed to Create at Least One LDAP User" +msgstr "Kunne ikke opprette minst én LDAP-bruker" + +#: cps/admin.py:1600 +#, python-format +msgid "Error: %(ldaperror)s" +msgstr "Feil: %(ldaperror)s" + +#: cps/admin.py:1604 +msgid "Error: No user returned in response of LDAP server" +msgstr "Feil: Ingen bruker ble returnert som svar fra LDAP-serveren" + +#: cps/admin.py:1637 +msgid "At Least One LDAP User Not Found in Database" +msgstr "Minst én LDAP-bruker ikke funnet i databasen" + +#: cps/admin.py:1639 +msgid "{} User Successfully Imported" +msgstr "{} Bruker ble importert" + +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "DB-plassering er ikke gyldig, skriv inn riktig bane" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "DB er ikke skrivbar" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "Nøkkelfilplasseringen er ikke gyldig. Angi riktig bane" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "Sertifikatfilplasseringen er ikke gyldig, vennligst skriv inn riktig bane" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "Databaseinnstillinger oppdatert" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "Databasekonfigurasjon" + +#: cps/admin.py:1866 cps/web.py:1237 +#, fuzzy +msgid "Oops! Please complete all fields." +msgstr "Vennligst fyll ut alle feltene!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "E-post er ikke fra gyldig domene" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Legg til ny bruker" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Bruker '%(user)s' opprettet" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Fant en eksisterende konto for denne e-postadressen eller navnet." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Brukeren '%(nick)s' slettet" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Kan ikke slette gjestebruker" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Ingen administratorbruker igjen, kan ikke slette bruker" + +#: cps/admin.py:1987 cps/web.py:1375 +#, fuzzy +msgid "Email can't be empty and has to be a valid Email" +msgstr "E-postadresse kan ikke være tom og må være en gyldig e-post" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Bruker '%(nick)s' oppdatert" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "ikke installert" + +#: cps/converter.py:32 +msgid "Execution permissions missing" +msgstr "Utførelsestillatelser mangler" + +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" +msgstr "Egendefinert kolonnenr.%(column)d finnes ikke i caliber-databasen" + +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Ingen" + +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +#, fuzzy +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" +msgstr "Oops! Den valgte boktittelen er utilgjengelig. Filen eksisterer ikke eller er ikke tilgjengelig" + +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "Brukeren har ingen rettigheter til å laste opp cover" + +#: cps/editbooks.py:174 cps/editbooks.py:716 +msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" +msgstr "Identifikatorer skiller ikke mellom store og små bokstaver, overskriver gammel identifikator" + +#: cps/editbooks.py:216 +msgid "Metadata successfully updated" +msgstr "Metadata ble oppdatert" + +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "Feil ved redigering av bok: {}" + +#: cps/editbooks.py:291 +#, python-format +msgid "File %(file)s uploaded" +msgstr "Fil %(file)s lastet opp" + +#: cps/editbooks.py:318 +msgid "Source or destination format for conversion missing" +msgstr "Kilde- eller målformat for konvertering mangler" + +#: cps/editbooks.py:326 +#, python-format +msgid "Book successfully queued for converting to %(book_format)s" +msgstr "Boken ble satt i kø for konvertering til %(book_format)s" + +#: cps/editbooks.py:330 +#, python-format +msgid "There was an error converting this book: %(res)s" +msgstr "Det oppsto en feil ved konvertering av denne boken: %(res)s" + +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Opplastet bok finnes sannsynligvis i biblioteket, vurder å endre før du laster opp ny: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "'%(langname)s' er ikke et gyldig språk" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Filtypen «%(ext)s» er ikke tillatt å lastes opp til denne serveren" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Filen som skal lastes opp må ha en utvidelse" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Filen %(filename)s kunne ikke lagres i midlertidig dir" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Kunne ikke flytte omslagsfil %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Bokformatet er slettet" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Boken ble slettet" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "Du mangler tillatelser til å slette bøker" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "redigere metadata" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s er ikke et gyldig tall, hopper over" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "Brukeren har ingen rettigheter til å laste opp flere filformater" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Kunne ikke opprette banen %(path)s (Tillatelse nektet)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Kunne ikke lagre filen %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Filformat %(ext)s lagt til %(book)s" + +#: cps/gdrive.py:58 +msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" +msgstr "Google Disk-konfigurasjonen er ikke fullført. Prøv å deaktivere og aktivere Google Disk på nytt" + +#: cps/gdrive.py:95 +msgid "Callback domain is not verified, please follow steps to verify domain in google developer console" +msgstr "Tilbakeringingsdomene er ikke bekreftet. Følg fremgangsmåten for å bekrefte domenet i Googles utviklerkonsoll" + +#: cps/helper.py:80 +#, python-format +msgid "%(format)s format not found for book id: %(book)d" +msgstr "%(format)s format ikke funnet for bok-ID: %(book)d" + +#: cps/helper.py:87 cps/tasks/convert.py:75 +#, python-format +msgid "%(format)s not found on Google Drive: %(fn)s" +msgstr "%(format)s ikke funnet på Google Disk: %(fn)s" + +#: cps/helper.py:92 +#, python-format +msgid "%(format)s not found: %(fn)s" +msgstr "%(format)s ikke funnet: %(fn)s" + +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" +msgstr "Send til E-Reader" + +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." +msgstr "Denne e-posten er sendt via Calibre-Web." + +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" +msgstr "Calibre-Web test e-post" + +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" +msgstr "Test e-post" + +#: cps/helper.py:132 +msgid "Get Started with Calibre-Web" +msgstr "Kom i gang med Calibre-Web" + +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" +msgstr "Registrerings-e-post for bruker: %(name)s" + +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "Konverter %(orig)s til %(format)s og send til E-Reader" + +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" +msgstr "Send %(format)s til E-Reader" + +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" +msgstr "%(book)s sendes til E-Reader" + +#: cps/helper.py:230 +msgid "The requested file could not be read. Maybe wrong permissions?" +msgstr "Den forespurte filen kunne ikke leses. Kanskje feil tillatelser?" + +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "Lesestatus kunne ikke angis: {}" + +#: cps/helper.py:368 +#, python-format +msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" +msgstr "Sletting av bokmappe for bok %(id)s mislyktes, banen har undermapper: %(path)s" + +#: cps/helper.py:374 +#, python-format +msgid "Deleting book %(id)s failed: %(message)s" +msgstr "Sletting av bok %(id)s mislyktes: %(message)s" + +#: cps/helper.py:385 +#, python-format +msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" +msgstr "Sletter bok %(id)s kun fra databasen, bokbanen i databasen er ikke gyldig: %(path)s" + +#: cps/helper.py:450 +#, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Endre navn på forfatter fra: '%(src)s' til '%(dest)s' mislyktes med feil: %(error)s" + +#: cps/helper.py:522 cps/helper.py:531 +#, python-format +msgid "File %(file)s not found on Google Drive" +msgstr "Fil %(file)s ikke funnet på Google Disk" + +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Endre navn på tittel fra: '%(src)s' til '%(dest)s' mislyktes med feil: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "Feil i endre navn på fil i banen: {}" + +#: cps/helper.py:603 +#, python-format +msgid "Book path %(path)s not found on Google Drive" +msgstr "Finner ikke bokbane %(path)s på Google Disk" + +#: cps/helper.py:644 +#, fuzzy +msgid "Found an existing account for this Email address" +msgstr "Fant en eksisterende konto for denne e-postadressen" + +#: cps/helper.py:652 +msgid "This username is already taken" +msgstr "Dette brukernavnet er allerede tatt" + +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" +msgstr "Ugyldig format for e-postadresse" + +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "Python-modulen 'advocate' er ikke installert, men er nødvendig for omslagsopplastinger" + +#: cps/helper.py:825 +msgid "Error Downloading Cover" +msgstr "Feil ved nedlasting av cover" + +#: cps/helper.py:828 +msgid "Cover Format Error" +msgstr "Omslagsformatfeil" + +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "Du har ikke tilgang til localhost eller det lokale nettverket for coveropplastinger" + +#: cps/helper.py:841 +msgid "Failed to create path for cover" +msgstr "Kunne ikke opprette bane for dekning" + +#: cps/helper.py:857 +msgid "Cover-file is not a valid image file, or could not be stored" +msgstr "Cover-filen er ikke en gyldig bildefil, eller kunne ikke lagres" + +#: cps/helper.py:868 +msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" +msgstr "Bare jpg/jpeg/png/webp/bmp-filer støttes som coverfile" + +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "Ugyldig omslagsfilinnhold" + +#: cps/helper.py:884 +msgid "Only jpg/jpeg files are supported as coverfile" +msgstr "Bare jpg/jpeg-filer støttes som coverfile" + +#: cps/helper.py:936 +msgid "Unrar binary file not found" +msgstr "Unrar binær fil ikke funnet" + +#: cps/helper.py:947 +msgid "Error executing UnRar" +msgstr "Feil ved kjøring av UnRar" + +#: cps/helper.py:1040 +msgid "Cover" +msgstr "Dekke" + +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "Sett alle bøker i kø for sikkerhetskopiering av metadata" + +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "Gå til Calibre-Web fra ikke-lokale vert for å få gyldig api_endpoint for kobo-enhet" + +#: cps/kobo_auth.py:115 +msgid "Kobo Setup" +msgstr "Kobo oppsett" + +#: cps/oauth_bb.py:77 +#, python-format +msgid "Register with %(provider)s" +msgstr "Registrer deg hos %(provider)s" + +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 +#, fuzzy, python-format +msgid "Success! You are now logged in as: %(nickname)s" +msgstr "du er nå logget på som: '%(nickname)s'" + +#: cps/oauth_bb.py:148 +#, python-format +msgid "Link to %(oauth)s Succeeded" +msgstr "Link til %(oauth)s lyktes" + +#: cps/oauth_bb.py:155 +msgid "Login failed, No User Linked With OAuth Account" +msgstr "Pålogging mislyktes, ingen bruker koblet til OAuth-konto" + +#: cps/oauth_bb.py:197 +#, python-format +msgid "Unlink to %(oauth)s Succeeded" +msgstr "Fjern koblingen til %(oauth)s" + +#: cps/oauth_bb.py:202 +#, python-format +msgid "Unlink to %(oauth)s Failed" +msgstr "Fjern koblingen til %(oauth)s mislyktes" + +#: cps/oauth_bb.py:205 +#, python-format +msgid "Not Linked to %(oauth)s" +msgstr "Ikke koblet til %(oauth)s" + +#: cps/oauth_bb.py:261 +msgid "Failed to log in with GitHub." +msgstr "Kunne ikke logge på med GitHub." + +#: cps/oauth_bb.py:267 +msgid "Failed to fetch user info from GitHub." +msgstr "Kunne ikke hente brukerinformasjon fra GitHub." + +#: cps/oauth_bb.py:279 +msgid "Failed to log in with Google." +msgstr "Kunne ikke logge på med Google." + +#: cps/oauth_bb.py:285 +msgid "Failed to fetch user info from Google." +msgstr "Kunne ikke hente brukerinformasjon fra Google." + +#: cps/oauth_bb.py:332 +msgid "GitHub Oauth error, please retry later." +msgstr "GitHub Oauth-feil, prøv igjen senere." + +#: cps/oauth_bb.py:335 +msgid "GitHub Oauth error: {}" +msgstr "GitHub Oauth-feil: {}" + +#: cps/oauth_bb.py:356 +msgid "Google Oauth error, please retry later." +msgstr "Google Oauth-feil, prøv igjen senere." + +#: cps/oauth_bb.py:359 +msgid "Google Oauth error: {}" +msgstr "Google Oauth-feil: {}" + +#: cps/opds.py:273 +msgid "{} Stars" +msgstr "{} Stjerner" + +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 +msgid "Login" +msgstr "Logg Inn" + +#: cps/remotelogin.py:74 cps/remotelogin.py:108 +msgid "Token not found" +msgstr "Token ikke funnet" + +#: cps/remotelogin.py:83 cps/remotelogin.py:116 +msgid "Token has expired" +msgstr "Token har utløpt" + +#: cps/remotelogin.py:92 +msgid "Success! Please return to your device" +msgstr "Suksess! Gå tilbake til enheten din" + +#: cps/render_template.py:42 cps/web.py:410 +msgid "Books" +msgstr "Bøker" + +#: cps/render_template.py:44 +msgid "Show recent books" +msgstr "Vis nyere bøker" + +#: cps/render_template.py:45 cps/templates/index.xml:25 +msgid "Hot Books" +msgstr "Hot bøker" + +#: cps/render_template.py:47 +msgid "Show Hot Books" +msgstr "Vis populære bøker" + +#: cps/render_template.py:49 cps/render_template.py:54 +msgid "Downloaded Books" +msgstr "Nedlastede bøker" + +#: cps/render_template.py:51 cps/render_template.py:56 +#: cps/templates/user_table.html:167 +msgid "Show Downloaded Books" +msgstr "Vis nedlastede bøker" + +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 +msgid "Top Rated Books" +msgstr "Topprangerte bøker" + +#: cps/render_template.py:61 cps/templates/user_table.html:161 +msgid "Show Top Rated Books" +msgstr "Vis best rangerte bøker" + +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 +msgid "Read Books" +msgstr "Lese bøker" + +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" +msgstr "Vis lest og ulest" + +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 +msgid "Unread Books" +msgstr "Uleste bøker" + +#: cps/render_template.py:68 +msgid "Show unread" +msgstr "Vis ulest" + +#: cps/render_template.py:69 +msgid "Discover" +msgstr "Oppdage" + +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 +msgid "Show Random Books" +msgstr "Vis tilfeldige bøker" + +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 +msgid "Categories" +msgstr "Kategorier" + +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" +msgstr "Vis kategorivalg" + +#: cps/render_template.py:75 cps/templates/book_edit.html:91 +#: cps/templates/book_table.html:68 cps/templates/index.xml:90 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 +msgid "Series" +msgstr "Serie" + +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" +msgstr "Vis serieutvalg" + +#: cps/render_template.py:78 cps/templates/book_table.html:66 +#: cps/templates/index.xml:69 +msgid "Authors" +msgstr "Forfattere" + +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" +msgstr "Vis forfattervalg" + +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 +msgid "Publishers" +msgstr "Forlag" + +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" +msgstr "Vis utgivervalg" + +#: cps/render_template.py:85 cps/templates/book_table.html:70 +#: cps/templates/index.xml:97 cps/templates/search_form.html:107 +#: cps/web.py:1078 +msgid "Languages" +msgstr "Språk" + +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" +msgstr "Vis språkvalg" + +#: cps/render_template.py:89 cps/templates/index.xml:104 +msgid "Ratings" +msgstr "Vurderinger" + +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "Vis vurderingsvalg" + +#: cps/render_template.py:92 cps/templates/index.xml:112 +msgid "File formats" +msgstr "Filformater" + +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" +msgstr "Vis valg av filformater" + +#: cps/render_template.py:96 cps/web.py:772 +msgid "Archived Books" +msgstr "Arkiverte bøker" + +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "Vis arkiverte bøker" + +#: cps/render_template.py:101 cps/web.py:803 +msgid "Books List" +msgstr "Bøker Liste" + +#: cps/render_template.py:103 cps/templates/user_table.html:168 +msgid "Show Books List" +msgstr "Vis bokliste" + +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 +msgid "Search" +msgstr "Søk" + +#: cps/search.py:189 +msgid "Published after " +msgstr "Publisert etter " + +#: cps/search.py:196 +msgid "Published before " +msgstr "Publisert før " + +#: cps/search.py:218 +#, python-format +msgid "Rating <= %(rating)s" +msgstr "Vurdering <= %(rating)s" + +#: cps/search.py:220 +#, python-format +msgid "Rating >= %(rating)s" +msgstr "Vurdering >= %(rating)s" + +#: cps/search.py:222 +#, python-format +msgid "Read Status = %(status)s" +msgstr "Lesestatus = %(status)s" + +#: cps/search.py:324 +msgid "Error on search for custom columns, please restart Calibre-Web" +msgstr "Feil ved søk etter egendefinerte kolonner. Start Calibre-Web på nytt" + +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Avansert søk" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Ugyldig hylle er angitt" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Beklager at du ikke har lov til å legge til en bok i den hyllen" + +#: cps/shelf.py:64 +#, python-format +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Boken er allerede en del av hyllen: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Boken er lagt til i hyllen: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "Du har ikke lov til å legge en bok i hyllen" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Bøker er allerede en del av hyllen: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Bøker er lagt til i hyllen: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Kunne ikke legge til bøker i hyllen: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Boken er fjernet fra hyllen: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "Beklager at du ikke har lov til å fjerne en bok fra denne hyllen" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Lag en hylle" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Beklager at du ikke har lov til å redigere denne hyllen" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Rediger en hylle" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "Feil ved sletting av hylle" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "Hylle slettet" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Endre rekkefølgen på hylle: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "Beklager at du ikke har lov til å opprette en offentlig hylle" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Hylle %(title)s opprettet" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Hylle %(title)s endret" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "det var en feil" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "En offentlig hylle med navnet '%(title)s' eksisterer allerede." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "En privat hylle med navnet '%(title)s' eksisterer allerede." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Hylle: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Feil ved åpning av hylle. Hylle finnes ikke eller er ikke tilgjengelig" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Oppgaver" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Venter" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Mislyktes" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Startet" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Ferdig" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "Endte" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "avbrutt" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Ukjent status" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Uventede data under lesing av oppdateringsinformasjon" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Ingen oppdatering tilgjengelig. Du har allerede den nyeste versjonen installert" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "En ny oppdatering er tilgjengelig. Klikk på knappen nedenfor for å oppdatere til siste versjon." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Kunne ikke hente oppdateringsinformasjon" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Klikk på knappen nedenfor for å oppdatere til siste stabile versjon." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "En ny oppdatering er tilgjengelig. Klikk på knappen nedenfor for å oppdatere til versjon: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Ingen utgivelsesinformasjon tilgjengelig" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Discover (tilfeldige bøker)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Hot Books (mest nedlastede)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Lastet ned bøker av %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Forfatter: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Utgiver: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Serie: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "Vurdering: Ingen" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Rangering: %(rating)s stjerner" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Filformat: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Kategori: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Språk: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Nedlastinger" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Rangeringsliste" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Liste over filformater" + +#: cps/web.py:1202 +#, fuzzy +msgid "Please configure the SMTP mail settings first." +msgstr "Vennligst konfigurer SMTP-postinnstillingene først..." + +#: cps/web.py:1207 +#, fuzzy, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Boken ble satt i kø for sending til %(eReadermail)s" + +#: cps/web.py:1211 +#, fuzzy, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "Oops! Det oppsto en feil ved sending av denne boken: %(res)s" + +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "Vennligst oppdater profilen din med en gyldig Send til Kindle-e-postadresse." + +#: cps/web.py:1230 +#, fuzzy +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "E-postserveren er ikke konfigurert, kontakt administratoren din!" + +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 +msgid "Register" +msgstr "Registrere" + +#: cps/web.py:1266 +#, fuzzy +msgid "Oops! Your Email is not allowed." +msgstr "Din e-post kan ikke registreres" + +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." +msgstr "" + +#: cps/web.py:1284 +#, fuzzy +msgid "Oops! Cannot activate LDAP authentication" +msgstr "Kan ikke aktivere LDAP-autentisering" + +#: cps/web.py:1303 +#, fuzzy, python-format +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" +msgstr "Reservepålogging som: '%(nickname)s', LDAP-serveren er ikke tilgjengelig, eller brukeren er ukjent" + +#: cps/web.py:1309 +#, fuzzy, python-format +msgid "Oops! Login Failed: %(message)s" +msgstr "Kunne ikke logge på: %(message)s" + +#: cps/web.py:1313 cps/web.py:1338 +#, fuzzy +msgid "Oops! Invalid Username or Password." +msgstr "Vennligst skriv inn gyldig brukernavn for å tilbakestille passordet" + +#: cps/web.py:1320 +#, fuzzy +msgid "Success! New Password was sent to your Email." +msgstr "Nytt passord ble sendt til e-postadressen din" + +#: cps/web.py:1326 +#, fuzzy +msgid "Oops! Please enter a valid username to reset password" +msgstr "Vennligst skriv inn gyldig brukernavn for å tilbakestille passordet" + +#: cps/web.py:1400 cps/web.py:1449 +#, fuzzy, python-format +msgid "%(name)s's Profile" +msgstr "%(name)s sin profil" + +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" +msgstr "Profil oppdatert" + +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "" + +#: cps/services/gmail.py:58 +msgid "Found no valid gmail.json file with OAuth information" +msgstr "Fant ingen gyldig gmail.json-fil med OAuth-informasjon" + +#: cps/tasks/convert.py:92 +#, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s sendes til E-Reader" + +#: cps/tasks/convert.py:153 +#, python-format +msgid "Calibre ebook-convert %(tool)s not found" +msgstr "Caliber ebook-convert %(tool)s ble ikke funnet" + +#: cps/tasks/convert.py:186 +#, python-format +msgid "%(format)s format not found on disk" +msgstr "%(format)s format ikke funnet på disken" + +#: cps/tasks/convert.py:190 +msgid "Ebook converter failed with unknown error" +msgstr "Ebook-konvertering mislyktes med ukjent feil" + +#: cps/tasks/convert.py:202 +#, python-format +msgid "Kepubify-converter failed: %(error)s" +msgstr "Kepubify-konvertering mislyktes: %(error)s" + +#: cps/tasks/convert.py:224 +#, python-format +msgid "Converted file not found or more than one file in folder %(folder)s" +msgstr "Konvertert fil ikke funnet eller mer enn én fil i mappen %(folder)s" + +#: cps/tasks/convert.py:247 +#, python-format +msgid "Ebook-converter failed: %(error)s" +msgstr "Ebook-konvertering mislyktes: %(error)s" + +#: cps/tasks/convert.py:270 +#, python-format +msgid "Calibre failed with error: %(error)s" +msgstr "Caliber mislyktes med feil: %(error)s" + +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "Konvertere" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "Kobler til Caliber-databasen på nytt" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "E-post" + +#: cps/tasks/metadata_backup.py:47 +msgid "Backing up Metadata" +msgstr "Sikkerhetskopierer metadata" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "Genererte %(count)s forsideminiatyrbilder" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "Forsideminiatyrbilder" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "Genererte {0} serieminiatyrbilder" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "Tømmer cache for miniatyrbilde for omslag" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Laste opp" + +#: cps/templates/admin.html:9 +msgid "Users" +msgstr "Brukere" + +#: cps/templates/admin.html:13 cps/templates/login.html:9 +#: cps/templates/login.html:10 cps/templates/register.html:9 +#: cps/templates/user_edit.html:10 cps/templates/user_table.html:134 +msgid "Username" +msgstr "Brukernavn" + +#: cps/templates/admin.html:14 cps/templates/register.html:14 +#: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 +#, fuzzy +msgid "Email" +msgstr "E-post" + +#: cps/templates/admin.html:15 cps/templates/user_edit.html:28 +#, fuzzy +msgid "Send to eReader Email" +msgstr "Send til E-Reader E-postadresse" + +#: cps/templates/admin.html:17 cps/templates/layout.html:92 +#: cps/templates/user_table.html:143 +msgid "Admin" +msgstr "Admin" + +#: cps/templates/admin.html:18 cps/templates/login.html:13 +#: cps/templates/login.html:14 cps/templates/user_edit.html:23 +msgid "Password" +msgstr "Passord" + +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 +#: cps/templates/user_table.html:146 +msgid "Download" +msgstr "nedlasting" + +#: cps/templates/admin.html:23 +msgid "View Books" +msgstr "Se bøker" + +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 +#: cps/templates/user_table.html:148 +msgid "Edit" +msgstr "Redigere" + +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 +#: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 +#: cps/templates/user_table.html:149 +msgid "Delete" +msgstr "Slett" + +#: cps/templates/admin.html:26 +msgid "Public Shelf" +msgstr "Offentlig hylle" + +#: cps/templates/admin.html:55 +msgid "Import LDAP Users" +msgstr "Importer LDAP-brukere" + +#: cps/templates/admin.html:62 +#, fuzzy +msgid "Email Server Settings" +msgstr "Innstillinger for e-postserver" + +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 +msgid "SMTP Hostname" +msgstr "SMTP vertsnavn" + +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 +msgid "SMTP Port" +msgstr "SMTP-port" + +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 +msgid "Encryption" +msgstr "Kryptering" + +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 +msgid "SMTP Login" +msgstr "SMTP-pålogging" + +#: cps/templates/admin.html:83 cps/templates/admin.html:94 +#: cps/templates/email_edit.html:55 +#, fuzzy +msgid "From Email" +msgstr "Fra e-post" + +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" +msgstr "E-posttjeneste" + +#: cps/templates/admin.html:91 +msgid "Gmail via Oauth2" +msgstr "Gmail via Oauth2" + +#: cps/templates/admin.html:106 +msgid "Configuration" +msgstr "Konfigurasjon" + +#: cps/templates/admin.html:109 +msgid "Calibre Database Directory" +msgstr "Caliber Database Directory" + +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 +msgid "Log Level" +msgstr "Loggnivå" + +#: cps/templates/admin.html:117 +msgid "Port" +msgstr "Havn" + +#: cps/templates/admin.html:122 +msgid "External Port" +msgstr "Ekstern port" + +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 +msgid "Books per Page" +msgstr "Bøker per side" + +#: cps/templates/admin.html:133 +msgid "Uploads" +msgstr "Opplastinger" + +#: cps/templates/admin.html:137 +msgid "Anonymous Browsing" +msgstr "Anonym surfing" + +#: cps/templates/admin.html:141 +msgid "Public Registration" +msgstr "Offentlig registrering" + +#: cps/templates/admin.html:145 +msgid "Magic Link Remote Login" +msgstr "Magic Link ekstern pålogging" + +#: cps/templates/admin.html:149 +msgid "Reverse Proxy Login" +msgstr "Omvendt proxy-pålogging" + +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 +msgid "Reverse Proxy Header Name" +msgstr "Omvendt proxy-overskriftsnavn" + +#: cps/templates/admin.html:159 +msgid "Edit Calibre Database Configuration" +msgstr "Rediger Caliber-databasekonfigurasjon" + +#: cps/templates/admin.html:160 +msgid "Edit Basic Configuration" +msgstr "Rediger grunnleggende konfigurasjon" + +#: cps/templates/admin.html:161 +msgid "Edit UI Configuration" +msgstr "Rediger UI-konfigurasjon" + +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "Planlagte oppgaver" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +#, fuzzy +msgid "Maximum Duration" +msgstr "Maksimal oppgavevarighet" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +#, fuzzy +msgid "Generate Thumbnails" +msgstr "Generer miniatyrbilder av bokomslag" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "Generer serieomslagsminiatyrbilder" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "Koble til Caliber-databasen på nytt" + +#: cps/templates/admin.html:193 +#, fuzzy +msgid "Refresh Thumbnail Cache" +msgstr "Oppdater thumbnail cover Cache" + +#: cps/templates/admin.html:199 +msgid "Administration" +msgstr "Administrasjon" + +#: cps/templates/admin.html:200 +msgid "Download Debug Package" +msgstr "Last ned feilsøkingspakken" + +#: cps/templates/admin.html:201 +msgid "View Logs" +msgstr "Vis logger" + +#: cps/templates/admin.html:207 +msgid "Restart" +msgstr "Omstart" + +#: cps/templates/admin.html:208 +msgid "Shutdown" +msgstr "Skru av" + +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "Versjonsinformasjon" + +#: cps/templates/admin.html:220 +msgid "Version" +msgstr "Versjon" + +#: cps/templates/admin.html:221 +msgid "Details" +msgstr "Detaljer" + +#: cps/templates/admin.html:227 +#, fuzzy +msgid "Current Version" +msgstr "Gjeldende versjon" + +#: cps/templates/admin.html:234 +msgid "Check for Update" +msgstr "Se etter oppdatering" + +#: cps/templates/admin.html:235 +msgid "Perform Update" +msgstr "Utfør oppdatering" + +#: cps/templates/admin.html:248 +msgid "Are you sure you want to restart?" +msgstr "Er du sikker på at du vil starte på nytt?" + +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 +msgid "OK" +msgstr "OK" + +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 +#: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 +#: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 +msgid "Cancel" +msgstr "Avbryt" + +#: cps/templates/admin.html:266 +msgid "Are you sure you want to shutdown?" +msgstr "Er du sikker på at du vil slå av?" + +#: cps/templates/admin.html:278 +msgid "Updating, please do not reload this page" +msgstr "Oppdaterer, vennligst ikke last inn denne siden på nytt" + +#: cps/templates/author.html:15 +msgid "via" +msgstr "via" + +#: cps/templates/author.html:23 +msgid "In Library" +msgstr "I biblioteket" + +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 +msgid "Sort according to book date, newest first" +msgstr "Sorter etter bokdato, nyeste først" + +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 +msgid "Sort according to book date, oldest first" +msgstr "Sorter etter bokdato, eldste først" + +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 +msgid "Sort title in alphabetical order" +msgstr "Sorter tittelen i alfabetisk rekkefølge" + +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 +msgid "Sort title in reverse alphabetical order" +msgstr "Sorter tittelen i omvendt alfabetisk rekkefølge" + +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 +msgid "Sort according to publishing date, newest first" +msgstr "Sorter etter publiseringsdato, nyeste først" + +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 +msgid "Sort according to publishing date, oldest first" +msgstr "Sorter etter publiseringsdato, eldste først" + +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 +msgid "reduce" +msgstr "redusere" + +#: cps/templates/author.html:99 +msgid "More by" +msgstr "Mer av" + +#: cps/templates/book_edit.html:11 +msgid "Delete Book" +msgstr "Slett bok" + +#: cps/templates/book_edit.html:14 +msgid "Delete formats:" +msgstr "Slett formater:" + +#: cps/templates/book_edit.html:25 +msgid "Convert book format:" +msgstr "Konverter bokformat:" + +#: cps/templates/book_edit.html:30 +msgid "Convert from:" +msgstr "Konverter fra:" + +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 +msgid "select an option" +msgstr "Velg et alternativ" + +#: cps/templates/book_edit.html:37 +msgid "Convert to:" +msgstr "Konvertere til:" + +#: cps/templates/book_edit.html:46 +msgid "Convert book" +msgstr "Konverter bok" + +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 +msgid "Book Title" +msgstr "Boktittel" + +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 +msgid "Author" +msgstr "Forfatter" + +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 +msgid "Description" +msgstr "Beskrivelse" + +#: cps/templates/book_edit.html:73 +msgid "Identifiers" +msgstr "Identifikatorer" + +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 +msgid "Identifier Type" +msgstr "Identifikatortype" + +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 +msgid "Identifier Value" +msgstr "Identifikatorverdi" + +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 +#: cps/templates/user_table.html:24 +msgid "Remove" +msgstr "Ta bort" + +#: cps/templates/book_edit.html:83 +msgid "Add Identifier" +msgstr "Legg til identifikator" + +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 +msgid "Tags" +msgstr "Tagger" + +#: cps/templates/book_edit.html:95 +msgid "Series ID" +msgstr "Serie-ID" + +#: cps/templates/book_edit.html:99 +msgid "Rating" +msgstr "Vurdering" + +#: cps/templates/book_edit.html:104 +msgid "Fetch Cover from URL (JPEG - Image will be downloaded and stored in database)" +msgstr "Hent omslag fra URL (JPEG - Bilde vil bli lastet ned og lagret i databasen)" + +#: cps/templates/book_edit.html:108 +msgid "Upload Cover from Local Disk" +msgstr "Last opp cover fra lokal disk" + +#: cps/templates/book_edit.html:113 +msgid "Published Date" +msgstr "Publiseringsdato" + +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 +msgid "Publisher" +msgstr "Forlegger" + +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 +msgid "Language" +msgstr "Språk" + +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 +#: cps/templates/search_form.html:164 +msgid "Yes" +msgstr "Ja" + +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 +#: cps/templates/search_form.html:165 +msgid "No" +msgstr "Nei" + +#: cps/templates/book_edit.html:201 +msgid "Upload Format" +msgstr "Last opp format" + +#: cps/templates/book_edit.html:209 +msgid "View Book on Save" +msgstr "Se bok på Lagre" + +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 +msgid "Fetch Metadata" +msgstr "Hent metadata" + +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 +msgid "Save" +msgstr "Lagre" + +#: cps/templates/book_edit.html:233 +msgid "Keyword" +msgstr "Nøkkelord" + +#: cps/templates/book_edit.html:234 +msgid "Search keyword" +msgstr "Søk nøkkelord" + +#: cps/templates/book_edit.html:240 +msgid "Click the cover to load metadata to the form" +msgstr "Klikk på omslaget for å laste metadata til skjemaet" + +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 +msgid "Loading..." +msgstr "Laster inn..." + +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 +msgid "Close" +msgstr "Lukk" + +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 +msgid "Source" +msgstr "Kilde" + +#: cps/templates/book_edit.html:287 +msgid "Search error!" +msgstr "Søkefeil!" + +#: cps/templates/book_edit.html:288 +msgid "No Result(s) found! Please try another keyword." +msgstr "Ingen resultater! Prøv et annet søkeord." + +#: cps/templates/book_table.html:12 cps/templates/book_table.html:69 +#: cps/templates/user_table.html:14 cps/templates/user_table.html:77 +#: cps/templates/user_table.html:100 +msgid "This Field is Required" +msgstr "Dette feltet er obligatorisk" + +#: cps/templates/book_table.html:37 +msgid "Merge selected books" +msgstr "Slå sammen valgte bøker" + +#: cps/templates/book_table.html:38 cps/templates/user_table.html:124 +msgid "Remove Selections" +msgstr "Fjern valg" + +#: cps/templates/book_table.html:41 +msgid "Exchange author and title" +msgstr "Bytt forfatter og tittel" + +#: cps/templates/book_table.html:47 +msgid "Update Title Sort automatically" +msgstr "Oppdater tittelsortering automatisk" + +#: cps/templates/book_table.html:51 +msgid "Update Author Sort automatically" +msgstr "Oppdater forfattersortering automatisk" + +#: cps/templates/book_table.html:63 cps/templates/book_table.html:69 +msgid "Enter Title" +msgstr "Skriv inn tittel" + +#: cps/templates/book_table.html:63 cps/templates/config_view_edit.html:24 +#: cps/templates/shelf_edit.html:8 +msgid "Title" +msgstr "Tittel" + +#: cps/templates/book_table.html:64 +msgid "Enter Title Sort" +msgstr "Skriv inn tittelsortering" + +#: cps/templates/book_table.html:64 +msgid "Title Sort" +msgstr "Tittelsortering" + +#: cps/templates/book_table.html:65 +msgid "Enter Author Sort" +msgstr "Skriv inn forfattersortering" + +#: cps/templates/book_table.html:65 +msgid "Author Sort" +msgstr "Forfatter Sort" + +#: cps/templates/book_table.html:66 +msgid "Enter Authors" +msgstr "Skriv inn forfattere" + +#: cps/templates/book_table.html:67 +msgid "Enter Categories" +msgstr "Skriv inn kategorier" + +#: cps/templates/book_table.html:68 +msgid "Enter Series" +msgstr "Gå inn i serien" + +#: cps/templates/book_table.html:69 +msgid "Series Index" +msgstr "Serieindeks" + +#: cps/templates/book_table.html:70 +msgid "Enter Languages" +msgstr "Skriv inn Språk" + +#: cps/templates/book_table.html:71 +msgid "Publishing Date" +msgstr "Publiseringsdato" + +#: cps/templates/book_table.html:72 +msgid "Enter Publishers" +msgstr "Skriv inn Publishers" + +#: cps/templates/book_table.html:73 +msgid "Enter comments" +msgstr "Skriv inn kommentarer" + +#: cps/templates/book_table.html:73 +msgid "Comments" +msgstr "Kommentarer" + +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "Arkivstatus" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Les status" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 +msgid "Enter " +msgstr "Tast inn " + +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 +msgid "Are you really sure?" +msgstr "Er du virkelig sikker?" + +#: cps/templates/book_table.html:117 +msgid "Books with Title will be merged from:" +msgstr "Bøker med tittel vil bli slått sammen fra:" + +#: cps/templates/book_table.html:121 +msgid "Into Book with Title:" +msgstr "Til bok med tittel:" + +#: cps/templates/book_table.html:126 +msgid "Merge" +msgstr "Slå sammen" + +#: cps/templates/config_db.html:12 +msgid "Location of Calibre Database" +msgstr "Plassering av Caliber-databasen" + +#: cps/templates/config_db.html:22 +msgid "Use Google Drive?" +msgstr "Bruker du Google Disk?" + +#: cps/templates/config_db.html:27 +msgid "Authenticate Google Drive" +msgstr "Autentiser Google Disk" + +#: cps/templates/config_db.html:32 +msgid "Google Drive Calibre folder" +msgstr "Google Drive Caliber-mappe" + +#: cps/templates/config_db.html:40 +msgid "Metadata Watch Channel ID" +msgstr "Metadata Se kanal-ID" + +#: cps/templates/config_db.html:43 +msgid "Revoke" +msgstr "Oppheve" + +#: cps/templates/config_db.html:68 +msgid "New db location is invalid, please enter valid path" +msgstr "Ny db-plassering er ugyldig, vennligst skriv inn gyldig bane" + +#: cps/templates/config_edit.html:18 +msgid "Server Configuration" +msgstr "Serverkonfigurasjon" + +#: cps/templates/config_edit.html:25 +msgid "Server Port" +msgstr "Serverport" + +#: cps/templates/config_edit.html:28 +msgid "SSL certfile location (leave it empty for non-SSL Servers)" +msgstr "SSL-sertfilplassering (la den stå tom for ikke-SSL-servere)" + +#: cps/templates/config_edit.html:35 +msgid "SSL Keyfile location (leave it empty for non-SSL Servers)" +msgstr "SSL-nøkkelfilplassering (la den stå tom for ikke-SSL-servere)" + +#: cps/templates/config_edit.html:43 +msgid "Update Channel" +msgstr "Oppdater kanalen" + +#: cps/templates/config_edit.html:45 +msgid "Stable" +msgstr "Stabil" + +#: cps/templates/config_edit.html:46 +msgid "Nightly" +msgstr "Nattlig" + +#: cps/templates/config_edit.html:50 +msgid "Trusted Hosts (Comma Separated)" +msgstr "Klarerte verter (kommaseparert)" + +#: cps/templates/config_edit.html:61 +msgid "Logfile Configuration" +msgstr "Loggfilkonfigurasjon" + +#: cps/templates/config_edit.html:77 +msgid "Location and name of logfile (calibre-web.log for no entry)" +msgstr "Plassering og navn på loggfil (calibre-web.log for ingen oppføring)" + +#: cps/templates/config_edit.html:82 +msgid "Enable Access Log" +msgstr "Aktiver tilgangslogg" + +#: cps/templates/config_edit.html:85 +msgid "Location and name of access logfile (access.log for no entry)" +msgstr "Plassering og navn på tilgangsloggfil (access.log for ingen oppføring)" + +#: cps/templates/config_edit.html:96 +msgid "Feature Configuration" +msgstr "Funksjonskonfigurasjon" + +#: cps/templates/config_edit.html:104 +msgid "Convert non-English characters in title and author while saving to disk" +msgstr "Konverter ikke-engelske tegn i tittel og forfatter mens du lagrer på disk" + +#: cps/templates/config_edit.html:108 +msgid "Enable Uploads" +msgstr "Aktiver opplastinger" + +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(Vennligst sørg for at brukerne også har opplastingsrettigheter)" + +#: cps/templates/config_edit.html:112 +msgid "Allowed Upload Fileformats" +msgstr "Tillatte opplastingsfilformater" + +#: cps/templates/config_edit.html:118 +msgid "Enable Anonymous Browsing" +msgstr "Aktiver anonym surfing" + +#: cps/templates/config_edit.html:122 +msgid "Enable Public Registration" +msgstr "Aktiver offentlig registrering" + +#: cps/templates/config_edit.html:127 +#, fuzzy +msgid "Use Email as Username" +msgstr "Bruk e-post som brukernavn" + +#: cps/templates/config_edit.html:132 +msgid "Enable Magic Link Remote Login" +msgstr "Aktiver Magic Link Remote Login" + +#: cps/templates/config_edit.html:137 +msgid "Enable Kobo sync" +msgstr "Aktiver Kobo-synkronisering" + +#: cps/templates/config_edit.html:142 +msgid "Proxy unknown requests to Kobo Store" +msgstr "Ukjente proxy-forespørsler til Kobo Store" + +#: cps/templates/config_edit.html:145 +msgid "Server External Port (for port forwarded API calls)" +msgstr "Server ekstern port (for portviderekoblede API-anrop)" + +#: cps/templates/config_edit.html:153 +msgid "Use Goodreads" +msgstr "Bruk Goodreads" + +#: cps/templates/config_edit.html:154 +msgid "Create an API Key" +msgstr "Opprett en API-nøkkel" + +#: cps/templates/config_edit.html:158 +msgid "Goodreads API Key" +msgstr "Goodreads API-nøkkel" + +#: cps/templates/config_edit.html:162 +msgid "Goodreads API Secret" +msgstr "Goodreads API Secret" + +#: cps/templates/config_edit.html:169 +msgid "Allow Reverse Proxy Authentication" +msgstr "Tillat omvendt proxy-autentisering" + +#: cps/templates/config_edit.html:180 +msgid "Login type" +msgstr "Påloggingstype" + +#: cps/templates/config_edit.html:182 +msgid "Use Standard Authentication" +msgstr "Bruk standardautentisering" + +#: cps/templates/config_edit.html:184 +msgid "Use LDAP Authentication" +msgstr "Bruk LDAP-autentisering" + +#: cps/templates/config_edit.html:187 +msgid "Use OAuth" +msgstr "Bruk OAuth" + +#: cps/templates/config_edit.html:194 +msgid "LDAP Server Host Name or IP Address" +msgstr "LDAP-serverens vertsnavn eller IP-adresse" + +#: cps/templates/config_edit.html:198 +msgid "LDAP Server Port" +msgstr "LDAP-serverport" + +#: cps/templates/config_edit.html:202 +msgid "LDAP Encryption" +msgstr "LDAP-kryptering" + +#: cps/templates/config_edit.html:205 +msgid "TLS" +msgstr "TLS" + +#: cps/templates/config_edit.html:206 +msgid "SSL" +msgstr "SSL" + +#: cps/templates/config_edit.html:210 +msgid "LDAP CACertificate Path (Only needed for Client Certificate Authentication)" +msgstr "LDAP CACertificate Path (Kun nødvendig for klientsertifikatautentisering)" + +#: cps/templates/config_edit.html:217 +msgid "LDAP Certificate Path (Only needed for Client Certificate Authentication)" +msgstr "LDAP-sertifikatbane (kun nødvendig for klientsertifikatautentisering)" + +#: cps/templates/config_edit.html:224 +msgid "LDAP Keyfile Path (Only needed for Client Certificate Authentication)" +msgstr "LDAP-nøkkelfilbane (kun nødvendig for klientsertifikatautentisering)" + +#: cps/templates/config_edit.html:233 +msgid "LDAP Authentication" +msgstr "LDAP-autentisering" + +#: cps/templates/config_edit.html:235 +msgid "Anonymous" +msgstr "Anonym" + +#: cps/templates/config_edit.html:236 +msgid "Unauthenticated" +msgstr "Uautentisert" + +#: cps/templates/config_edit.html:237 +msgid "Simple" +msgstr "Enkel" + +#: cps/templates/config_edit.html:242 +msgid "LDAP Administrator Username" +msgstr "LDAP-administratorbrukernavn" + +#: cps/templates/config_edit.html:248 +msgid "LDAP Administrator Password" +msgstr "LDAP-administratorpassord" + +#: cps/templates/config_edit.html:253 +msgid "LDAP Distinguished Name (DN)" +msgstr "LDAP Distinguished Name (DN)" + +#: cps/templates/config_edit.html:257 +msgid "LDAP User Object Filter" +msgstr "LDAP-brukerobjektfilter" + +#: cps/templates/config_edit.html:262 +msgid "LDAP Server is OpenLDAP?" +msgstr "LDAP Server er OpenLDAP?" + +#: cps/templates/config_edit.html:264 +msgid "Following Settings are Needed For User Import" +msgstr "Følgende innstillinger er nødvendig for brukerimport" + +#: cps/templates/config_edit.html:266 +msgid "LDAP Group Object Filter" +msgstr "LDAP gruppeobjektfilter" + +#: cps/templates/config_edit.html:270 +msgid "LDAP Group Name" +msgstr "LDAP-gruppenavn" + +#: cps/templates/config_edit.html:274 +msgid "LDAP Group Members Field" +msgstr "Felt for LDAP-gruppemedlemmer" + +#: cps/templates/config_edit.html:278 +msgid "LDAP Member User Filter Detection" +msgstr "LDAP-medlemsbrukerfilterdeteksjon" + +#: cps/templates/config_edit.html:280 +msgid "Autodetect" +msgstr "" + +#: cps/templates/config_edit.html:281 +msgid "Custom Filter" +msgstr "" + +#: cps/templates/config_edit.html:286 +msgid "LDAP Member User Filter" +msgstr "" + +#: cps/templates/config_edit.html:297 +#, python-format +msgid "Obtain %(provider)s OAuth Credential" +msgstr "" + +#: cps/templates/config_edit.html:300 +#, python-format +msgid "%(provider)s OAuth Client Id" +msgstr "" + +#: cps/templates/config_edit.html:304 +#, python-format +msgid "%(provider)s OAuth Client Secret" +msgstr "" + +#: cps/templates/config_edit.html:320 +#, fuzzy +msgid "External binaries" +msgstr "Ekstern port" + +#: cps/templates/config_edit.html:326 +msgid "Path to Calibre E-Book Converter" +msgstr "" + +#: cps/templates/config_edit.html:334 +#, fuzzy +msgid "Calibre E-Book Converter Settings" +msgstr "Caliber ebook-convert %(tool)s ble ikke funnet" + +#: cps/templates/config_edit.html:337 +msgid "Path to Kepubify E-Book Converter" +msgstr "" + +#: cps/templates/config_edit.html:345 +msgid "Location of Unrar binary" +msgstr "" + +#: cps/templates/config_view_edit.html:17 +#, fuzzy +msgid "View Configuration" +msgstr "Konfigurasjon" + +#: cps/templates/config_view_edit.html:32 +msgid "No. of Random Books to Display" +msgstr "" + +#: cps/templates/config_view_edit.html:36 +msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" +msgstr "" + +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 +msgid "Theme" +msgstr "" + +#: cps/templates/config_view_edit.html:42 +msgid "Standard Theme" +msgstr "" + +#: cps/templates/config_view_edit.html:43 +msgid "caliBlur! Dark Theme" +msgstr "" + +#: cps/templates/config_view_edit.html:47 +msgid "Regular Expression for Ignoring Columns" +msgstr "" + +#: cps/templates/config_view_edit.html:51 +msgid "Link Read/Unread Status to Calibre Column" +msgstr "" + +#: cps/templates/config_view_edit.html:60 +msgid "View Restrictions based on Calibre column" +msgstr "" + +#: cps/templates/config_view_edit.html:69 +msgid "Regular Expression for Title Sorting" +msgstr "" + +#: cps/templates/config_view_edit.html:80 +msgid "Default Settings for New Users" +msgstr "" + +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 +#, fuzzy +msgid "Admin User" +msgstr "Legg til ny bruker" + +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 +#, fuzzy +msgid "Allow Downloads" +msgstr "Nedlastinger" + +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 +msgid "Allow eBook Viewer" +msgstr "" + +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 +#, fuzzy +msgid "Allow Uploads" +msgstr "Aktiver opplastinger" + +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 +msgid "Allow Edit" +msgstr "" + +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 +#, fuzzy +msgid "Allow Delete Books" +msgstr "Vis nyere bøker" + +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 +msgid "Allow Changing Password" +msgstr "" + +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 +msgid "Allow Editing Public Shelves" +msgstr "" + +#: cps/templates/config_view_edit.html:123 +msgid "Default Language" +msgstr "" + +#: cps/templates/config_view_edit.html:131 +msgid "Default Visible Language of Books" +msgstr "" + +#: cps/templates/config_view_edit.html:147 +msgid "Default Visibilities for New Users" +msgstr "" + +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 +#: cps/templates/user_table.html:154 +msgid "Show Random Books in Detail View" +msgstr "" + +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 +msgid "Add Allowed/Denied Tags" +msgstr "" + +#: cps/templates/config_view_edit.html:167 +msgid "Add Allowed/Denied custom column values" +msgstr "" + +#: cps/templates/detail.html:62 cps/templates/detail.html:71 +msgid "Read in Browser" +msgstr "" + +#: cps/templates/detail.html:79 cps/templates/detail.html:96 +msgid "Listen in Browser" +msgstr "" + +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 +#, fuzzy, python-format +msgid "Book %(index)s of %(range)s" +msgstr "Sletting av bok %(index)s mislyktes: %(range)s" + +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 +#, fuzzy +msgid "Published" +msgstr "Forlegger" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Unread" +msgstr "" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Read" +msgstr "" + +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 +#, fuzzy +msgid "Read" +msgstr "redusere" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Restore from archive" +msgstr "" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Add to archive" +msgstr "" + +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 +#, fuzzy +msgid "Archived" +msgstr "Arkiverte bøker" + +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 +#, fuzzy +msgid "Description:" +msgstr "Beskrivelse" + +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 +#, fuzzy +msgid "Add to shelf" +msgstr "Rediger en hylle" + +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 +msgid "(Public)" +msgstr "" + +#: cps/templates/detail.html:300 +#, fuzzy +msgid "Edit Metadata" +msgstr "redigere metadata" + +#: cps/templates/email_edit.html:13 +msgid "Email Account Type" +msgstr "" + +#: cps/templates/email_edit.html:15 +msgid "Standard Email Account" +msgstr "" + +#: cps/templates/email_edit.html:16 +msgid "Gmail Account" +msgstr "" + +#: cps/templates/email_edit.html:22 +msgid "Setup Gmail Account" +msgstr "" + +#: cps/templates/email_edit.html:24 +msgid "Revoke Gmail Access" +msgstr "" + +#: cps/templates/email_edit.html:42 +#, fuzzy +msgid "STARTTLS" +msgstr "Omstart" + +#: cps/templates/email_edit.html:43 +msgid "SSL/TLS" +msgstr "" + +#: cps/templates/email_edit.html:51 +#, fuzzy +msgid "SMTP Password" +msgstr "Passord" + +#: cps/templates/email_edit.html:58 +msgid "Attachment Size Limit" +msgstr "" + +#: cps/templates/email_edit.html:66 +msgid "Save and Send Test Email" +msgstr "" + +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 +#: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 +msgid "Back" +msgstr "" + +#: cps/templates/email_edit.html:74 +msgid "Allowed Domains (Whitelist)" +msgstr "" + +#: cps/templates/email_edit.html:78 cps/templates/email_edit.html:105 +msgid "Add Domain" +msgstr "" + +#: cps/templates/email_edit.html:81 cps/templates/email_edit.html:108 +#: cps/templates/user_table.html:27 +msgid "Add" +msgstr "" + +#: cps/templates/email_edit.html:86 cps/templates/email_edit.html:96 +#, fuzzy +msgid "Enter domainname" +msgstr "Skriv inn kommentarer" + +#: cps/templates/email_edit.html:92 +msgid "Denied Domains (Blacklist)" +msgstr "" + +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 +msgid "Next" +msgstr "" + +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "" + +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 +#, fuzzy +msgid "Calibre-Web Instance is unconfigured, please contact your administrator" +msgstr "E-postserveren er ikke konfigurert, kontakt administratoren din!" + +#: cps/templates/http_error.html:44 +msgid "Create Issue" +msgstr "" + +#: cps/templates/http_error.html:51 +msgid "Return to Home" +msgstr "" + +#: cps/templates/http_error.html:53 +msgid "Logout User" +msgstr "" + +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 +#, fuzzy +msgid "Sort authors in alphabetical order" +msgstr "Sorter tittelen i alfabetisk rekkefølge" + +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 +#, fuzzy +msgid "Sort authors in reverse alphabetical order" +msgstr "Sorter tittelen i omvendt alfabetisk rekkefølge" + +#: cps/templates/index.html:83 +msgid "Sort ascending according to series index" +msgstr "" + +#: cps/templates/index.html:84 +msgid "Sort descending according to series index" +msgstr "" + +#: cps/templates/index.xml:6 +#, fuzzy +msgid "Start" +msgstr "Omstart" + +#: cps/templates/index.xml:18 +msgid "Alphabetical Books" +msgstr "" + +#: cps/templates/index.xml:22 +msgid "Books sorted alphabetically" +msgstr "" + +#: cps/templates/index.xml:29 +msgid "Popular publications from this catalog based on Downloads." +msgstr "" + +#: cps/templates/index.xml:36 +msgid "Popular publications from this catalog based on Rating." +msgstr "" + +#: cps/templates/index.xml:39 +#, fuzzy +msgid "Recently added Books" +msgstr "Vis nyere bøker" + +#: cps/templates/index.xml:43 +#, fuzzy +msgid "The latest Books" +msgstr "Slå sammen valgte bøker" + +#: cps/templates/index.xml:46 +#, fuzzy +msgid "Random Books" +msgstr "Vis tilfeldige bøker" + +#: cps/templates/index.xml:73 +msgid "Books ordered by Author" +msgstr "" + +#: cps/templates/index.xml:80 +msgid "Books ordered by publisher" +msgstr "" + +#: cps/templates/index.xml:87 +msgid "Books ordered by category" +msgstr "" + +#: cps/templates/index.xml:94 +msgid "Books ordered by series" +msgstr "" + +#: cps/templates/index.xml:101 +msgid "Books ordered by Languages" +msgstr "" + +#: cps/templates/index.xml:108 +msgid "Books ordered by Rating" +msgstr "" + +#: cps/templates/index.xml:116 +msgid "Books ordered by file formats" +msgstr "" + +#: cps/templates/index.xml:119 cps/templates/layout.html:153 +#: cps/templates/search_form.html:87 +msgid "Shelves" +msgstr "" + +#: cps/templates/index.xml:123 +msgid "Books organized in shelves" +msgstr "" + +#: cps/templates/layout.html:26 cps/templates/login.html:30 +msgid "Home" +msgstr "" + +#: cps/templates/layout.html:32 +#, fuzzy +msgid "Toggle Navigation" +msgstr "Loggfilkonfigurasjon" + +#: cps/templates/layout.html:48 +msgid "Search Library" +msgstr "" + +#: cps/templates/layout.html:66 cps/templates/layout.html:95 +msgid "Account" +msgstr "" + +#: cps/templates/layout.html:72 cps/templates/layout.html:97 +msgid "Logout" +msgstr "" + +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +#, fuzzy +msgid "Uploading..." +msgstr "Laster inn..." + +#: cps/templates/layout.html:79 +#, fuzzy +msgid "Error" +msgstr "Serverport" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "" + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +#, fuzzy +msgid "Settings" +msgstr "Vurderinger" + +#: cps/templates/layout.html:136 +#, fuzzy +msgid "Please do not refresh the page" +msgstr "Oppdaterer, vennligst ikke last inn denne siden på nytt" + +#: cps/templates/layout.html:146 +msgid "Browse" +msgstr "" + +#: cps/templates/layout.html:159 cps/templates/stats.html:3 +msgid "About" +msgstr "" + +#: cps/templates/layout.html:173 +msgid "Previous" +msgstr "" + +#: cps/templates/layout.html:200 +#, fuzzy +msgid "Book Details" +msgstr "Detaljer" + +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + +#: cps/templates/login.html:18 +msgid "Remember Me" +msgstr "" + +#: cps/templates/login.html:23 +msgid "Forgot Password?" +msgstr "" + +#: cps/templates/login.html:34 +msgid "Log in with Magic Link" +msgstr "" + +#: cps/templates/logviewer.html:6 +msgid "Show Calibre-Web Log: " +msgstr "" + +#: cps/templates/logviewer.html:8 +msgid "Calibre-Web Log: " +msgstr "" + +#: cps/templates/logviewer.html:8 +msgid "Stream output, can't be displayed" +msgstr "" + +#: cps/templates/logviewer.html:12 +msgid "Show Access Log: " +msgstr "" + +#: cps/templates/logviewer.html:18 +msgid "Download Calibre-Web Log" +msgstr "" + +#: cps/templates/logviewer.html:21 +#, fuzzy +msgid "Download Access Log" +msgstr "Aktiver tilgangslogg" + +#: cps/templates/modal_dialogs.html:6 +msgid "Select Allowed/Denied Tags" +msgstr "" + +#: cps/templates/modal_dialogs.html:7 +msgid "Select Allowed/Denied Custom Column Values" +msgstr "" + +#: cps/templates/modal_dialogs.html:8 +msgid "Select Allowed/Denied Tags of User" +msgstr "" + +#: cps/templates/modal_dialogs.html:9 +msgid "Select Allowed/Denied Custom Column Values of User" +msgstr "" + +#: cps/templates/modal_dialogs.html:15 +#, fuzzy +msgid "Enter Tag" +msgstr "Tast inn " + +#: cps/templates/modal_dialogs.html:24 +msgid "Add View Restriction" +msgstr "" + +#: cps/templates/modal_dialogs.html:50 +msgid "This book format will be permanently erased from database" +msgstr "" + +#: cps/templates/modal_dialogs.html:51 +msgid "This book will be permanently erased from database" +msgstr "" + +#: cps/templates/modal_dialogs.html:52 +msgid "and hard disk" +msgstr "" + +#: cps/templates/modal_dialogs.html:56 +msgid "Important Kobo Note: deleted books will remain on any paired Kobo device." +msgstr "" + +#: cps/templates/modal_dialogs.html:57 +msgid "Books must first be archived and the device synced before a book can safely be deleted." +msgstr "" + +#: cps/templates/modal_dialogs.html:76 +msgid "Choose File Location" +msgstr "" + +#: cps/templates/modal_dialogs.html:82 +msgid "type" +msgstr "" + +#: cps/templates/modal_dialogs.html:83 +#, fuzzy +msgid "name" +msgstr "Brukernavn" + +#: cps/templates/modal_dialogs.html:84 +msgid "size" +msgstr "" + +#: cps/templates/modal_dialogs.html:90 +msgid "Parent Directory" +msgstr "" + +#: cps/templates/modal_dialogs.html:98 +#, fuzzy +msgid "Select" +msgstr "Slett" + +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 +msgid "Ok" +msgstr "" + +#: cps/templates/osd.xml:5 +msgid "Calibre-Web eBook Catalog" +msgstr "" + +#: cps/templates/read.html:6 +msgid "epub Reader" +msgstr "" + +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +#, fuzzy +msgid "Light" +msgstr "Nattlig" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +msgid "Black" +msgstr "" + +#: cps/templates/read.html:88 +msgid "Reflow text when sidebars are open." +msgstr "" + +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + +#: cps/templates/readcbr.html:7 +msgid "Comic Reader" +msgstr "" + +#: cps/templates/readcbr.html:92 +msgid "Keyboard Shortcuts" +msgstr "" + +#: cps/templates/readcbr.html:95 +msgid "Previous Page" +msgstr "" + +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 +#, fuzzy +msgid "Next Page" +msgstr "Admin side" + +#: cps/templates/readcbr.html:97 +msgid "Scale to Best" +msgstr "" + +#: cps/templates/readcbr.html:98 +msgid "Scale to Width" +msgstr "" + +#: cps/templates/readcbr.html:99 +msgid "Scale to Height" +msgstr "" + +#: cps/templates/readcbr.html:100 +msgid "Scale to Native" +msgstr "" + +#: cps/templates/readcbr.html:101 +msgid "Rotate Right" +msgstr "" + +#: cps/templates/readcbr.html:102 +msgid "Rotate Left" +msgstr "" + +#: cps/templates/readcbr.html:103 +msgid "Flip Image" +msgstr "" + +#: cps/templates/readcbr.html:125 +msgid "Scale" +msgstr "" + +#: cps/templates/readcbr.html:128 +msgid "Best" +msgstr "" + +#: cps/templates/readcbr.html:129 +msgid "Width" +msgstr "" + +#: cps/templates/readcbr.html:130 +#, fuzzy +msgid "Height" +msgstr "Nattlig" + +#: cps/templates/readcbr.html:131 +#, fuzzy +msgid "Native" +msgstr "Lagre" + +#: cps/templates/readcbr.html:136 +#, fuzzy +msgid "Rotate" +msgstr "Startet" + +#: cps/templates/readcbr.html:147 +msgid "Flip" +msgstr "" + +#: cps/templates/readcbr.html:150 +msgid "Horizontal" +msgstr "" + +#: cps/templates/readcbr.html:151 +msgid "Vertical" +msgstr "" + +#: cps/templates/readcbr.html:156 +#, fuzzy +msgid "Direction" +msgstr "Administrasjon" + +#: cps/templates/readcbr.html:159 +msgid "Left to Right" +msgstr "" + +#: cps/templates/readcbr.html:160 +msgid "Right to Left" +msgstr "" + +#: cps/templates/readcbr.html:168 +msgid "Reset to Top" +msgstr "" + +#: cps/templates/readcbr.html:169 +msgid "Remember Position" +msgstr "" + +#: cps/templates/readcbr.html:174 +msgid "Scrollbar" +msgstr "" + +#: cps/templates/readcbr.html:177 +msgid "Show" +msgstr "" + +#: cps/templates/readcbr.html:178 +msgid "Hide" +msgstr "" + +#: cps/templates/readdjvu.html:5 +msgid "DJVU Reader" +msgstr "" + +#: cps/templates/readpdf.html:32 +msgid "PDF Reader" +msgstr "" + +#: cps/templates/readtxt.html:6 +msgid "txt Reader" +msgstr "" + +#: cps/templates/register.html:4 +msgid "Register New Account" +msgstr "" + +#: cps/templates/register.html:10 +#, fuzzy +msgid "Choose a username" +msgstr "Bruk e-post som brukernavn" + +#: cps/templates/register.html:15 +msgid "Your Email" +msgstr "" + +#: cps/templates/remote_login.html:5 +msgid "Magic Link - Authorise New Device" +msgstr "" + +#: cps/templates/remote_login.html:7 +msgid "On another device, login and visit:" +msgstr "" + +#: cps/templates/remote_login.html:11 +msgid "Once verified, you will automatically be logged in on this device." +msgstr "" + +#: cps/templates/remote_login.html:14 +msgid "This verification link will expire in 10 minutes." +msgstr "" + +#: cps/templates/schedule_edit.html:33 +#, fuzzy +msgid "Generate Series Cover Thumbnails" +msgstr "Generer serieomslagsminiatyrbilder" + +#: cps/templates/search.html:6 +#, fuzzy +msgid "No Results Found" +msgstr "Merket ble ikke funnet" + +#: cps/templates/search.html:7 +#, fuzzy +msgid "Search Term:" +msgstr "Søkefeil!" + +#: cps/templates/search.html:9 +msgid "Results for:" +msgstr "" + +#: cps/templates/search_form.html:21 +#, fuzzy +msgid "Published Date From" +msgstr "Publisert etter " + +#: cps/templates/search_form.html:31 +#, fuzzy +msgid "Published Date To" +msgstr "Publisert etter " + +#: cps/templates/search_form.html:59 +msgid "Exclude Tags" +msgstr "" + +#: cps/templates/search_form.html:77 +msgid "Exclude Series" +msgstr "" + +#: cps/templates/search_form.html:95 +msgid "Exclude Shelves" +msgstr "" + +#: cps/templates/search_form.html:115 +#, fuzzy +msgid "Exclude Languages" +msgstr "Skriv inn Språk" + +#: cps/templates/search_form.html:126 +msgid "Extensions" +msgstr "" + +#: cps/templates/search_form.html:134 +msgid "Exclude Extensions" +msgstr "" + +#: cps/templates/search_form.html:144 +#, fuzzy +msgid "Rating Above" +msgstr "Vurdering: Ingen" + +#: cps/templates/search_form.html:148 +msgid "Rating Below" +msgstr "" + +#: cps/templates/search_form.html:180 +msgid "From:" +msgstr "" + +#: cps/templates/search_form.html:190 +msgid "To:" +msgstr "" + +#: cps/templates/shelf.html:13 +msgid "Delete this Shelf" +msgstr "" + +#: cps/templates/shelf.html:14 +msgid "Edit Shelf Properties" +msgstr "" + +#: cps/templates/shelf.html:17 +msgid "Arrange books manually" +msgstr "" + +#: cps/templates/shelf.html:18 +msgid "Disable Change order" +msgstr "" + +#: cps/templates/shelf.html:18 +msgid "Enable Change order" +msgstr "" + +#: cps/templates/shelf_edit.html:14 +msgid "Share with Everyone" +msgstr "" + +#: cps/templates/shelf_edit.html:21 +msgid "Sync this shelf with Kobo device" +msgstr "" + +#: cps/templates/shelf_order.html:5 +msgid "Drag to Rearrange Order" +msgstr "" + +#: cps/templates/shelf_order.html:33 +msgid "Hidden Book" +msgstr "" + +#: cps/templates/stats.html:7 +#, fuzzy +msgid "Library Statistics" +msgstr "Statistikk" + +#: cps/templates/stats.html:12 +msgid "Books in this Library" +msgstr "" + +#: cps/templates/stats.html:16 +msgid "Authors in this Library" +msgstr "" + +#: cps/templates/stats.html:20 +msgid "Categories in this Library" +msgstr "" + +#: cps/templates/stats.html:24 +msgid "Series in this Library" +msgstr "" + +#: cps/templates/stats.html:29 +#, fuzzy +msgid "System Statistics" +msgstr "Statistikk" + +#: cps/templates/stats.html:33 +msgid "Program" +msgstr "" + +#: cps/templates/stats.html:34 +#, fuzzy +msgid "Installed Version" +msgstr "ikke installert" + +#: cps/templates/tasks.html:12 +#, fuzzy +msgid "User" +msgstr "Brukere" + +#: cps/templates/tasks.html:14 +#, fuzzy +msgid "Task" +msgstr "Oppgaver" + +#: cps/templates/tasks.html:15 +#, fuzzy +msgid "Status" +msgstr "Omstart" + +#: cps/templates/tasks.html:16 +msgid "Progress" +msgstr "" + +#: cps/templates/tasks.html:17 +msgid "Run Time" +msgstr "" + +#: cps/templates/tasks.html:20 +#, fuzzy +msgid "Actions" +msgstr "Vurderinger" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" + +#: cps/templates/user_edit.html:20 +msgid "Reset user Password" +msgstr "" + +#: cps/templates/user_edit.html:43 +#, fuzzy +msgid "Language of Books" +msgstr "Språk" + +#: cps/templates/user_edit.html:54 +#, fuzzy +msgid "OAuth Settings" +msgstr "Vis forfattervalg" + +#: cps/templates/user_edit.html:56 +msgid "Link" +msgstr "" + +#: cps/templates/user_edit.html:58 +msgid "Unlink" +msgstr "" + +#: cps/templates/user_edit.html:64 +msgid "Kobo Sync Token" +msgstr "" + +#: cps/templates/user_edit.html:66 +msgid "Create/View" +msgstr "" + +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 +msgid "Add allowed/Denied Custom Column Values" +msgstr "" + +#: cps/templates/user_edit.html:137 +msgid "Sync only books in selected shelves with Kobo" +msgstr "" + +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 +#, fuzzy +msgid "Delete User" +msgstr "Kan ikke slette gjestebruker" + +#: cps/templates/user_edit.html:159 +msgid "Generate Kobo Auth URL" +msgstr "" + +#: cps/templates/user_table.html:80 cps/templates/user_table.html:103 +msgid "Select..." +msgstr "" + +#: cps/templates/user_table.html:131 +#, fuzzy +msgid "Edit User" +msgstr "Rediger brukere" + +#: cps/templates/user_table.html:134 +#, fuzzy +msgid "Enter Username" +msgstr "Brukernavn" + +#: cps/templates/user_table.html:135 +#, fuzzy +msgid "Enter Email" +msgstr "Test e-post" + +#: cps/templates/user_table.html:136 +msgid "Enter eReader Email" +msgstr "" + +#: cps/templates/user_table.html:136 +msgid "eReader Email" +msgstr "" + +#: cps/templates/user_table.html:137 +msgid "Locale" +msgstr "" + +#: cps/templates/user_table.html:138 +msgid "Visible Book Languages" +msgstr "" + +#: cps/templates/user_table.html:139 +msgid "Edit Allowed Tags" +msgstr "" + +#: cps/templates/user_table.html:139 +msgid "Allowed Tags" +msgstr "" + +#: cps/templates/user_table.html:140 +msgid "Edit Denied Tags" +msgstr "" + +#: cps/templates/user_table.html:140 +msgid "Denied Tags" +msgstr "" + +#: cps/templates/user_table.html:141 +msgid "Edit Allowed Column Values" +msgstr "" + +#: cps/templates/user_table.html:141 +msgid "Allowed Column Values" +msgstr "" + +#: cps/templates/user_table.html:142 +msgid "Edit Denied Column Values" +msgstr "" + +#: cps/templates/user_table.html:142 +msgid "Denied Column Values" +msgstr "" + +#: cps/templates/user_table.html:144 +#, fuzzy +msgid "Change Password" +msgstr "Passord" + +#: cps/templates/user_table.html:147 +msgid "View" +msgstr "" + +#: cps/templates/user_table.html:150 +msgid "Edit Public Shelves" +msgstr "" + +#: cps/templates/user_table.html:152 +msgid "Sync selected Shelves with Kobo" +msgstr "" + +#: cps/templates/user_table.html:156 +#, fuzzy +msgid "Show Read/Unread Section" +msgstr "Vis serieutvalg" + diff --git a/cps/translations/pl/LC_MESSAGES/messages.mo b/cps/translations/pl/LC_MESSAGES/messages.mo index d9f9d7a3c..2aadf9245 100644 Binary files a/cps/translations/pl/LC_MESSAGES/messages.mo and b/cps/translations/pl/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/pl/LC_MESSAGES/messages.po b/cps/translations/pl/LC_MESSAGES/messages.po index e50d7f9b5..47927e255 100644 --- a/cps/translations/pl/LC_MESSAGES/messages.po +++ b/cps/translations/pl/LC_MESSAGES/messages.po @@ -8,589 +8,646 @@ msgid "" msgstr "" "Project-Id-Version: Calibre Web - polski (POT: 2021-06-12 08:52)\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2021-06-12 15:35+0200\n" "Last-Translator: Radosław Kierznowski \n" "Language: pl\n" "Language-Team: \n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "nie zainstalowane" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "zainstalowane" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Statystyki" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Serwer uruchomiony ponownie, proszę odświeżyć stronę" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Wykonano wyłączenie serwera, proszę zamknąć okno" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Ponowne połączenie zakończono sukcesem" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Nieznane polecenie" +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Książka została umieszczona w kolejce do wysłania do %(eReadermail)s" + # ??? -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Nieznany" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Panel administratora" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Konfiguracja podstawowa" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Konfiguracja Interfejsu" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" msgstr "Edytuj użytkowników" # ??? -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Wszystko" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "Nie znaleziono użytkownika" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "{} użytkowników usuniętych pomyślnie" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Pokaż wszystkie" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "Nieprawidłowo sformułowane żądanie" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "Nazwa gościa nie może być zmieniona" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "Gość nie może pełnić tej roli" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "Nie można odebrać praw administratora. Brak na serwerze innego konta z prawami administratora" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "Wartość musi być prawdziwa lub fałszywa" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "Nieprawidłowa rola" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "Gość nie może tego zobaczyć" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "Nieprawidłowy widok" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "Lokalizacja gościa jest określana automatycznie i nie można jej ustawić" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "Nie podano prawidłowej lokalizacji" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "Nie podano obowiązującego języka książki" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "Nie znaleziono parametru" -#: cps/admin.py:533 +#: cps/admin.py:565 #, fuzzy msgid "Invalid Read Column" msgstr "Nieprawidłowa kolumna odczytu" -#: cps/admin.py:539 +#: cps/admin.py:571 #, fuzzy msgid "Invalid Restricted Column" msgstr "Nieprawidłowa kolumna z ograniczeniami" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Konfiguracja Calibre-Web została zaktualizowana" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "Czy na pewno chcesz usunąć Token Kobo?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "Czy naprawdę chcesz usunąć tę domenę?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "Czy naprawdę chcesz usunąć tego użytkownika?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Czy na pewno chcesz usunąć półkę?" -#: cps/admin.py:580 +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Czy na pewno chcesz zmienić ustawienia lokalne wybranego użytkownika(ów)?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "Czy na pewno chcesz zmienić widoczne języki książek dla wybranego użytkownika (użytkowników)?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "Czy na pewno chcesz zmienić wybraną rolę dla wybranego użytkownika (użytkowników)?" -#: cps/admin.py:586 +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Czy na pewno chcesz zmienić wybrane ograniczenia dla wybranego użytkownika(ów)?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "Czy na pewno chcesz zmienić wybrane ograniczenia widoczności dla wybranego użytkownika(ów)?" -#: cps/admin.py:590 +#: cps/admin.py:622 msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Czy na pewno chcesz zmienić zachowanie synchronizacji półek dla wybranego użytkownika(ów)?" -#: cps/admin.py:592 +#: cps/admin.py:624 msgid "Are you sure you want to change Calibre library location?" msgstr "Czy na pewno chcesz zmienić lokalizację biblioteki Calibre?" -#: cps/admin.py:741 -#, fuzzy -msgid "Tag not found" -msgstr "Nie znaleziono znacznika" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "Nieprawidłowe działanie" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Zabroń" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Zezwalaj" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +#, fuzzy +msgid "Tag not found" +msgstr "Nie znaleziono znacznika" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Nieprawidłowe działanie" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json nie został skonfigurowany dla aplikacji webowej" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "Lokalizacja pliku dziennika jest nieprawidłowa, wprowadź poprawną ścieżkę" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "Lokalizacja pliku dziennika dostępu jest nieprawidłowa, wprowadź poprawną ścieżkę" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Wprowadź dostawcę LDAP, port, nazwę wyróżniającą i identyfikator obiektu użytkownika" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "Proszę wprowadzić konto i hasło usługi LDAP" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "Proszę wprowadzić konto usługi LDAP" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "Filtr obiektów grupy LDAP musi mieć jeden identyfikator formatu \"% s\"" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "Filtr obiektów grupy LDAP ma niedopasowany nawias" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "Filtr obiektów użytkownika LDAP musi mieć jeden identyfikator formatu \"% s\"" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "Filtr obiektów użytkownika LDAP ma niedopasowany nawias" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "Filtr użytkownika członka LDAP musi mieć jedno \"%s\" identyfikator formatu" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "Filtr użytkownika członka LDAP ma niedopasowane nawiasy" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "Główny urząd certyfikatu LDAP, Certyfikat lub Lokalizacja Klucza nie jest prawidłowa, Proszę wprowadzić poprawną ścieżkę" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "Ustawienia Bazy Danych nie są zapisywalne" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "Lokalizacja bazy danych jest nieprawidłowa, wprowadź poprawną ścieżkę" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "Baza danych nie jest zapisywalna" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "Lokalizacja pliku klucza jest nieprawidłowa, wprowadź poprawną ścieżkę" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "Lokalizacja pliku certyfikatu jest nieprawidłowa, wprowadź poprawną ścieżkę" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Zaktualizowano ustawienia serwera poczty e-mail" - -#: cps/admin.py:1324 -msgid "Database Configuration" -msgstr "Konfiguracja bazy danych" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Proszę wypełnić wszystkie pola!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "E-mail nie pochodzi z prawidłowej domeny" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "Dodaj nowego użytkownika" -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Użytkownik '%(user)s' został utworzony" - -#: cps/admin.py:1369 -msgid "Found an existing account for this e-mail address or name." -msgstr "Znaleziono istniejące konto dla tego adresu e-mail lub nazwy." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Użytkownik '%(nick)s' został usunięty" - -#: cps/admin.py:1391 cps/admin.py:1392 -#, fuzzy -msgid "Can't delete Guest User" -msgstr "Nie można usunąć użytkownika gościa" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Nie można usunąć użytkownika. Brak na serwerze innego konta z prawami administratora" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Edytuj użytkownika %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Użytkownik '%(nick)s' został zaktualizowany" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Wystąpił nieznany błąd. Spróbuj ponownie później." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Zmień ustawienia SMTP" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "Weryfikacja konta Gmail przebiegła pomyślnie" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Błąd bazy danych: %(error)s." + +#: cps/admin.py:1311 #, fuzzy, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "Testowy e-mail czeka w kolejce do wysłania do %(email)s, sprawdź zadania, aby uzyskać wynik" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Wystąpił błąd podczas wysyłania e-maila testowego: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Najpierw skonfiguruj swój adres e-mail..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Zaktualizowano ustawienia serwera poczty e-mail" -# ??? -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Wystąpił nieznany błąd. Spróbuj ponownie później." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Edytuj użytkownika %(nick)s" + +# ??? +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Zrestartowano hasło użytkownika %(user)s" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Proszę najpierw skonfigurować ustawienia SMTP poczty e-mail..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Przeglądanie dziennika" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Żądanie o pakiet aktualizacji" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Pobieranie pakietu aktualizacji" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Rozpakowywanie pakietu aktualizacji" # ??? -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Zastępowanie plików" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Połączenia z bazą danych zostały zakończone" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Zatrzymywanie serwera" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Aktualizacja zakończona, proszę nacisnąć OK i odświeżyć stronę" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Aktualizacja nieudana:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "Błąd HTTP" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Błąd połączenia" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Przekroczono limit czasu podczas nawiązywania połączenia" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Błąd ogólny" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "Plik aktualizacji nie mógł zostać zapisany w katalogu tymczasowym" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 #, fuzzy msgid "Failed to extract at least One LDAP User" msgstr "Błąd przy tworzeniu przynajmniej jednego użytkownika LDAP" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "Błąd przy tworzeniu przynajmniej jednego użytkownika LDAP" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Błąd: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Błąd. LDAP nie zwrócił żadnego użytkownika" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "Przynajmniej jeden użytkownik LDAP nie został znaleziony w bazie danych" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} Użytkownik pomyślnie zaimportowany" -#: cps/converter.py:30 -msgid "not configured" -msgstr "nie skonfigurowane" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "Lokalizacja bazy danych jest nieprawidłowa, wprowadź poprawną ścieżkę" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "Baza danych nie jest zapisywalna" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "Lokalizacja pliku klucza jest nieprawidłowa, wprowadź poprawną ścieżkę" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "Lokalizacja pliku certyfikatu jest nieprawidłowa, wprowadź poprawną ścieżkę" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "Zaktualizowano ustawienia serwera poczty e-mail" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "Konfiguracja bazy danych" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Proszę wypełnić wszystkie pola!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "E-mail nie pochodzi z prawidłowej domeny" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Dodaj nowego użytkownika" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Użytkownik '%(user)s' został utworzony" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "Znaleziono istniejące konto dla tego adresu e-mail lub nazwy." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Użytkownik '%(nick)s' został usunięty" + +#: cps/admin.py:1929 cps/admin.py:1930 +#, fuzzy +msgid "Can't delete Guest User" +msgstr "Nie można usunąć użytkownika gościa" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Nie można usunąć użytkownika. Brak na serwerze innego konta z prawami administratora" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Użytkownik '%(nick)s' został zaktualizowany" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "nie zainstalowane" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Brak uprawnienia do wykonywania pliku" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 -#, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, fuzzy, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "Niestandardowa kolumna No.%(column)d nie istnieje w bazie calibre" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Plik książki w wybranym formacie został usunięty" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Brak" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Książka została usunięta" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Błąd otwierania e-booka. Plik nie istnieje lub jest niedostępny" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "edytuj metadane" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "" -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "%(seriesindex)s nie jest poprawną liczbą, pomijanie" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s nie jest prawidłowym językiem" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "Rozszerzenie pliku '%(ext)s' nie jest dozwolone do wysłania na ten serwer" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Plik do wysłania musi mieć rozszerzenie" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Nie udało się utworzyć łącza %(path)s (Odmowa dostępu)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Nie można zapisać pliku %(file)s." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Błąd bazy danych: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Format pliku %(ext)s dodany do %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "W identyfikatorach nie jest rozróżniana wielkość liter, nadpisywanie starego identyfikatora" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Metadane zostały pomyślnie zaktualizowane" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Błąd podczas edycji książki, sprawdź plik dziennika, aby uzyskać szczegółowe informacje" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Wysłana książka prawdopodobnie istnieje w bibliotece, rozważ zmianę przed przesłaniem nowej: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "Nie można zapisać pliku %(filename)s w katalogu tymczasowym" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Nie udało się przenieść pliku okładki %(file)s:%(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Wysłano plik %(file)s" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Brak formatu źródłowego lub docelowego do konwersji" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Książka została pomyślnie umieszczona w zadaniach do konwersji %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Podczas konwersji książki wystąpił błąd: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Wysłana książka prawdopodobnie istnieje w bibliotece, rozważ zmianę przed przesłaniem nowej: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s nie jest prawidłowym językiem" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Rozszerzenie pliku '%(ext)s' nie jest dozwolone do wysłania na ten serwer" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Plik do wysłania musi mieć rozszerzenie" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Nie można zapisać pliku %(filename)s w katalogu tymczasowym" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Nie udało się przenieść pliku okładki %(file)s:%(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Plik książki w wybranym formacie został usunięty" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Książka została usunięta" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "edytuj metadane" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s nie jest poprawną liczbą, pomijanie" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Nie udało się utworzyć łącza %(path)s (Odmowa dostępu)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Nie można zapisać pliku %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Format pliku %(ext)s dodany do %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Konfiguracja Google Drive nie została zakończona, spróbuj dezaktywować i ponownie aktywować Google Drive" @@ -604,167 +661,183 @@ msgstr "Zwrotna domena nie jest zweryfikowana, proszę zweryfikowania domenę w msgid "%(format)s format not found for book id: %(book)d" msgstr "Nie znaleziono formatu %(format)s dla id książki: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "Nie znaleziono %(format)s na Google Drive: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s nie znaleziono: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Wyślij do Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Ten e-mail został wysłany za pośrednictwem Calibre-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Testowy e-mail Calibre-Web" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Testowy e-mail" # ??? -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Zacznij korzystać z Calibre-Web" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Rejestracja e-mail dla użytkownika: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "Konwertuj %(orig)s do %(format)s i wyślij do Kindle" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "Wyślij %(format)s do Kindle" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Wyślij do Kindle" # ??? -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Żądany plik nie mógł zostać odczytany. Może brakuje uprawnień?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "Usuwanie folderu książki dla książki %(id)s nie powiodło się, ścieżka ma podfoldery: %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "Usuwanie książki %(id)s zakończyło się błędem: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, fuzzy, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "Usuwanie książki %(id)s, ścieżka książki jest niepoprawna: %(path)s" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "Zmiana nazwy tytułu z: „%(src)s” na „%(dest)s” zakończyła się błędem: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Zmiana nazwy pliku w ścieżce '%(src)s' na '%(dest)s' zakończyło się błędem: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Nie znaleziono pliku %(file)s na Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Zmiana nazwy tytułu z: „%(src)s” na „%(dest)s” zakończyła się błędem: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Nie znaleziono ścieżki do książki %(path)s na Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -msgid "Found an existing account for this e-mail address" -msgstr "Znaleziono istniejące konto dla tego adresu e-mail" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Nazwa użytkownika jest już zajęta" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" msgstr "Nieprawidłowy format adresu e-mail" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Błąd przy pobieraniu okładki" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "Błędny format okładki" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Nie udało się utworzyć ścieżki dla okładki" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "Plik okładki nie jest poprawnym plikiem obrazu lub nie mógł zostać zapisany" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "Jako plik okładki obsługiwane są tylko pliki jpg/jpeg/png/webp/bmp" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Jako plik okładki dopuszczalne są jedynie pliki jpg/jpeg" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "Plik wykonywalny programu unrar nie znaleziony" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" msgstr "Błąd przy wykonywaniu unrar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Oczekiwanie" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Odkrywaj" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Nieudane" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "Rozpoczynanie" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Zakończone" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Ststus nieznany" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Aby uzyskać prawidłowy api_endpoint dla urządzenia Kobo, należy skorzystać z dostępu do calibre-web spoza localhost" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Konfiguracja Kobo" @@ -774,9 +847,9 @@ msgstr "Konfiguracja Kobo" msgid "Register with %(provider)s" msgstr "Zarejestruj się %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "zalogowałeś się jako: '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -835,508 +908,613 @@ msgstr "Błąd Google Oauth, proszę spróbować później." msgid "Google Oauth error: {}" msgstr "Błąd Google Oauth: {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "{} Gwiazdek" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Zaloguj się" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Nie znaleziono tokenu" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Token wygasł" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Powodzenie! Wróć do swojego urządzenia" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Książki" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Pokaż menu ostatnio dodanych książek" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Najpopularniejsze" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Pokaż menu najpopularniejszych książek" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "Pobrane książki" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "Pokaż pobrane książki" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Najwyżej ocenione" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Pokaż menu najwyżej ocenionych książek" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Przeczytane" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Pokaż menu przeczytane i nieprzeczytane" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Nieprzeczytane" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Pokaż nieprzeczytane" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Odkrywaj" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Pokazuj losowe książki" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Kategorie" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Pokaż menu wyboru kategorii" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Cykle" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Pokaż menu wyboru cyklu" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Autorzy" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Pokaż menu wyboru autora" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Wydawcy" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Pokaż menu wyboru wydawcy" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Języki" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Pokaż menu wyboru języka" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Oceny" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Pokaż menu listy ocen" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Formaty plików" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Pokaż menu formatu plików" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Zarchiwizowane książki" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" msgstr "Pokaż zarchiwizowane książki" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "Lista książek" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "Pokaż listę książek" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Podano niewłaściwą półkę" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Niestety, nie posiadasz uprawnień do dodania książki do półki: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Książka jest już dodana do półki: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Książka została dodana do półki: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Nie masz uprawnień do dodania ksiażki do półki: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Książki są już dodane do półki: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Książki zostały dodane do półki %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Nie można dodać książek do półki: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Książka została usunięta z półki: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Niestety nie możesz usunąć książki z tej półki %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Utwórz półkę" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Niestety nie możesz usunąć książki z tej półki %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Edytuj półkę" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Półka %(title)s została utworzona" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Półka %(title)s została zmieniona" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Wystąpił błąd" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Publiczna półka o nazwie '%(title)s' już istnieje." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Prywatna półka o nazwie '%(title)s' już istnieje." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Zmieniono kolejność półki: '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Półka: „%(name)s”" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Błąd otwierania półki. Półka nie istnieje lub jest niedostępna" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Nieoczekiwane dane podczas odczytywania informacji o aktualizacji" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Brak dostępnej aktualizacji. Masz już zainstalowaną najnowszą wersję" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Dostępna jest nowa aktualizacja. Kliknij przycisk poniżej, aby zaktualizować do najnowszej wersji." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Nie można pobrać informacji o aktualizacji" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Kliknij przycisk poniżej, aby zaktualizować do najnowszej stabilnej wersji." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Dostępna jest nowa aktualizacja. Kliknij przycisk poniżej, aby zaktualizować do wersji: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Brak dostępnych informacji o wersji" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Odkrywaj (losowe książki)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Najpopularniejsze książki (najczęściej pobierane)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "Książki pobrane przez %(user)s" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Autor: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Wydawca: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Cykl: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Ocena: %(rating)s gwiazdek" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Format pliku: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Kategoria: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Język: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Wyszukiwanie" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Szukaj" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "DLS" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Lista z ocenami" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Lista formatów" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Zadania" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Opublikowane po " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Opublikowane przed " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Ocena <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Ocena >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "Status przeczytania = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 #, fuzzy msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "Błąd podczas wyszukiwania kolumn niestandardowych, proszę zrestartować Calibre-Web" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Książka została umieszczona w kolejce do wysłania do %(kindlemail)s" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Wyszukiwanie" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Podano niewłaściwą półkę" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Niestety, nie posiadasz uprawnień do dodania książki do półki: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Książka jest już dodana do półki: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Książka została dodana do półki: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Książki są już dodane do półki: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Książki zostały dodane do półki %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Nie można dodać książek do półki: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Książka została usunięta z półki: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Utwórz półkę" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Niestety nie możesz usunąć książki z tej półki %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Edytuj półkę" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Książka została usunięta" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Zmieniono kolejność półki: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Półka %(title)s została utworzona" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Półka %(title)s została zmieniona" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Wystąpił błąd" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Publiczna półka o nazwie '%(title)s' już istnieje." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Prywatna półka o nazwie '%(title)s' już istnieje." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Półka: „%(name)s”" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Błąd otwierania półki. Półka nie istnieje lub jest niedostępna" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Zadania" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Oczekiwanie" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Nieudane" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Rozpoczynanie" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Zakończone" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Ststus nieznany" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Nieoczekiwane dane podczas odczytywania informacji o aktualizacji" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Brak dostępnej aktualizacji. Masz już zainstalowaną najnowszą wersję" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Dostępna jest nowa aktualizacja. Kliknij przycisk poniżej, aby zaktualizować do najnowszej wersji." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Nie można pobrać informacji o aktualizacji" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Kliknij przycisk poniżej, aby zaktualizować do najnowszej stabilnej wersji." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Dostępna jest nowa aktualizacja. Kliknij przycisk poniżej, aby zaktualizować do wersji: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Brak dostępnych informacji o wersji" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Odkrywaj (losowe książki)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Najpopularniejsze książki (najczęściej pobierane)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Książki pobrane przez %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Autor: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Wydawca: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Cykl: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Ocena: %(rating)s gwiazdek" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Format pliku: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Kategoria: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Język: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "DLS" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Lista z ocenami" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Lista formatów" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Proszę najpierw skonfigurować ustawienia SMTP poczty e-mail..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Książka została umieszczona w kolejce do wysłania do %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "Wystąpił błąd podczas wysyłania tej książki: %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "Najpierw skonfiguruj adres e-mail Kindle..." -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "Serwer e-mail nie jest skonfigurowany, skontaktuj się z administratorem!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Zarejestruj się" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Twój e-mail nie może się zarejestrować" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Wiadomość e-mail z potwierdzeniem została wysłana na Twoje konto e-mail." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "Nie można aktywować uwierzytelniania LDAP" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" -msgstr "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" +msgstr "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Nie można zalogować: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Błędna nazwa użytkownika lub hasło" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "Nowe hasło zostało wysłane na Twój adres e-mail" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Wprowadź prawidłową nazwę użytkownika, aby zresetować hasło" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Jesteś teraz zalogowany jako: '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "Profil użytkownika %(name)s" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Zaktualizowano profil" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "Znaleziono istniejące konto dla tego adresu e-mail" + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "Nie znaleziono poprawnego pliku gmail.json z informacjami OAuth" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Wyślij do Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "Nie znaleziono narzędzia calibre %(tool)s do konwertowania" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "Nie znaleziono na dysku formatu %(format)s" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "Konwertowanie ebooka zakończyło się niepowodzeniem z nieznanego powodu" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Kepubify-converter spowodowało błąd: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "Konwertowany plik nie został znaleziony, lub więcej niż jeden plik w folderze %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Konwertowanie nie powiodło się: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, fuzzy, python-format msgid "Calibre failed with error: %(error)s" msgstr "Calibre nie powiodło się z błędem: %(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "edytuj metadane" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Wysyłanie" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Lista użytkowników" @@ -1349,15 +1527,16 @@ msgstr "Nazwa użytkownika" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "E-mail" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Adres e-mail dla wysyłania do Kindle" # ??? -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Panel administratora" @@ -1367,213 +1546,231 @@ msgstr "Panel administratora" msgid "Password" msgstr "Hasło" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Wysyłanie" - # ??? -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Pobieranie" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Przeglądanie" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Edycja" # ??? -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Usuń" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Półka publiczna" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Dodaj nowego użytkownika" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "Importuj użytkowników LDAP" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "Ustawienia serwera e-mail SMTP" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "Adres serwera SMTP" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "Port serwera SMTP" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "SSL" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "Nazwa użytkownika SMTP" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Wyślij z adresu e-mail" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" msgstr "Usługa e-mail" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "Gmail przez Oauth2" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Konfiguracja" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Folder bazy danych Calibre" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Poziom dziennika" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Port" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "Port zewnętrzny" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Liczba książek na stronie" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Wysyłanie" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Anonimowe przeglądanie" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Publiczna rejestracja" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Zdalne logowanie (Magic Link)" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "Logowanie reverse proxy" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Nazwa nagłowka reverse proxy" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 msgid "Edit Calibre Database Configuration" msgstr "Edytuj konfigurację bazy danych Calibre" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Edytuj podstawową konfigurację" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "Edytuj konfigurację interfejsu" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Zarządzanie" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "Pobierz pakiet Debug" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Podgląd dziennika" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Połącz ponownie z bazą danych Calibre" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Uruchom ponownie Calibre Web" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Zatrzymaj Calibre Web" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Update (aktualizacja)" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Wersja" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Szczegóły" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Bieżąca wersja" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Sprawdź aktualizacje" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Wykonaj aktualizację" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Na pewno chcesz uruchomić ponownie Calibre Web?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "OK" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Anuluj" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Na pewno chcesz zatrzymać Calibre Web?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Aktualizowanie, proszę nie odświeżać strony" @@ -1585,120 +1782,119 @@ msgstr "przez" msgid "In Library" msgstr "W Bibliotece" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "Sortuj książki według daty, najnowsze jako pierwsze" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "Sortuj książki według daty, najstarsze jako pierwsze" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "Sortuj tytuły w porządku alfabetycznym" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "Sortuj tytuły w odwrotnym porządku alfabetycznym" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "Sortuj według daty publikacji, najnowsze jako pierwsze" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "Sortuj według daty publikacji, najstarsze jako pierwsze" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "zwiń" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Więcej według" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Usuń książkę" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Usuń formaty:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Konwertuj format książki:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Konwertuj z:" # ??? -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "wybierz opcję" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Konwertuj na:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Konwertuj książkę" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Tytuł książki" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Autor" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Opis" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "Identyfikatory" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "Rodzaj identyfikatora" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "Wartość identyfikatora" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Usuń" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "Dodaj identyfikator" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Etykiety" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "ID cyklu" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Ocena" @@ -1710,82 +1906,83 @@ msgstr "Pobierz okładkę z linku (JPEG - obraz zostanie pobrany i zapisany w ba msgid "Upload Cover from Local Disk" msgstr "Wyślij okładkę z dysku lokalnego" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Data publikacji" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Wydawca" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Język" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Tak" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Nie" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Wyślij format" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Po zapisaniu wyświetl szczegóły książki" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Uzyskaj metadane" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Zapisz" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Słowo kluczowe" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " Szukaj słowa kluczowego " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Kliknij okładkę, aby załadować metadane do formularza" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Ładowanie..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Zamknij" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Źródło" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Błąd wyszukiwania!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Nie znaleziono! Spróbuj użyć innego słowa kluczowego." @@ -1879,29 +2076,38 @@ msgstr "Podaj nazwę domeny" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Status odczytu" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Identyfikatory" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Czy jesteś pewny?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 #, fuzzy msgid "Books with Title will be merged from:" msgstr "Książki z tytułem będą łączone z:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 #, fuzzy msgid "Into Book with Title:" msgstr "Into Book with Title:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "Połącz" @@ -1995,6 +2201,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Włącz wysyłanie" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "Dozwolone formaty przesyłania" @@ -2008,7 +2218,7 @@ msgid "Enable Public Registration" msgstr "Włącz publiczną rejestrację" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "Użyj e-maila jako nazwy użytkownika" #: cps/templates/config_edit.html:132 @@ -2075,11 +2285,6 @@ msgstr "Port serwera LDAP" msgid "LDAP Encryption" msgstr "Szyfrowanie LDAP" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Brak" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2215,7 +2420,7 @@ msgstr "Liczba losowych książek do pokazania" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Liczba autorów do pokazania przed ukryciem (0=wyłącza ukrywanie)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Motyw" @@ -2247,139 +2452,143 @@ msgstr "Wyrażenie regularne dla tytułu sortującego" msgid "Default Settings for New Users" msgstr "Domyślne ustawienia dla nowych użytkowników" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Użytkownik z uprawnieniami administratora" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Zezwalaj na pobieranie" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Zezwalaj na przeglądanie e-booków" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Zezwalaj na wysyłanie" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Zezwalaj na edycję" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "Zezwalaj na usuwanie książek" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Zezwalaj na zmianę hasła" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Zezwalaj na edycję półek publicznych" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Wyklucz języki" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Pokaż książki w języku" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Domyślne ustawienia widoku dla nowych użytkowników" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Pokaz losowe książki w widoku szczegółowym" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "Dodaj dozwolone/zabronione etykiety" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "Dodaj dozwolone/zabronione wartości własnych kolumn" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Czytaj w przeglądarce" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Słuchaj w przeglądarce" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, fuzzy, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Data publikacji" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Oznacz jako nieprzeczytane" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Oznacz jako przeczytane" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Przeczytana" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Przywróć z archiwum" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Dodaj do archiwum" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "Zarchiwizowane" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Opis:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Dodaj do półki" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(publiczna)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Edytuj metadane" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "Wybierz typ serwera" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +#, fuzzy +msgid "Standard Email Account" msgstr "Użyj standardowego konta e-mail" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "Konto Gmail z weryfikacją OAuth2" +#, fuzzy +msgid "Gmail Account" +msgstr "Wybierz typ serwera" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" -msgstr "Skonfiguruj konto Gmail jako serwer poczty e-mail" +msgid "Setup Gmail Account" +msgstr "" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" @@ -2402,10 +2611,11 @@ msgid "Attachment Size Limit" msgstr "Limit rozmiaru załącznika" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Zapisz ustawienia i wyślij testową wiadomość e-mail" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Wróć" @@ -2431,48 +2641,65 @@ msgstr "Podaj nazwę domeny" msgid "Denied Domains (Blacklist)" msgstr "Domeny zabronione (czarna lista)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Następne" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "Otwórz plik .kobo/Kobo eReader.conf w edytorze tekstu i dodaj (lub edytuj):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Otwórz plik .kobo/Kobo/Kobo eReader.conf w edytorze tekstu i dodaj (lub edytuj):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Token Kobo Sync" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "Instancja Calibre-Web jest nieskonfigurowana, proszę skontaktować się z administratorem" # | msgid "Create a Shelf" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Zgłoś błąd" # ??? -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Powrót do głównego menu" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 #, fuzzy msgid "Logout User" msgstr "Wyloguj użytkownika" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "Sortuj autorów w porządku alfabetycznym" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "Posortuj autorów w odwrotnym porządku alfabetycznym" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "Sortuj rosnąco według indeksu serii" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "Sortuj malejąco według indeksu serii" @@ -2536,7 +2763,7 @@ msgstr "Książki sortowane według oceny" msgid "Books ordered by file formats" msgstr "Ksiązki sortowane według formatu" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Półki" @@ -2545,65 +2772,69 @@ msgstr "Półki" msgid "Books organized in shelves" msgstr "Książki ułożone na półkach" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Główne menu" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Przełącz nawigację" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Przeszukaj bibliotekę" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 +msgid "Account" +msgstr "Konto" + +#: cps/templates/layout.html:72 cps/templates/layout.html:97 +msgid "Logout" +msgstr "Wyloguj się" + +#: cps/templates/layout.html:79 cps/templates/layout.html:135 msgid "Uploading..." msgstr "Wysyłanie…" # ??? -#: cps/templates/layout.html:64 +#: cps/templates/layout.html:79 msgid "Error" msgstr "Błąd" -#: cps/templates/layout.html:64 +#: cps/templates/layout.html:79 msgid "Upload done, processing, please wait..." msgstr "Wysyłanie zakończone, przetwarzanie, proszę czekać…" -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 msgid "Settings" msgstr "Ustawienia" -#: cps/templates/layout.html:80 -msgid "Account" -msgstr "Konto" - -#: cps/templates/layout.html:82 -msgid "Logout" -msgstr "Wyloguj się" - -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Proszę nie odświeżać strony" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Przeglądaj" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Informacje" # ??? -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Poprzedni" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Szczegóły książki" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Zapamiętaj mnie" @@ -2612,7 +2843,7 @@ msgstr "Zapamiętaj mnie" msgid "Forgot Password?" msgstr "Zapomniałeś hasło?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Zaloguj się za pomocą „magic link”" @@ -2709,7 +2940,7 @@ msgstr "Główny katalog" msgid "Select" msgstr "Wybierz" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 msgid "Ok" msgstr "OK" @@ -2722,128 +2953,141 @@ msgstr "Katalog e-booków Calibre-Web" msgid "epub Reader" msgstr "Czytnik PDF" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Jasny" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Ciemny" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Wróć" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Przepływ tekstu, gdy paski boczne są otwarte." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "Czytnik PDF" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Skróty klawiaturowe" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Poprzednia strona" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Następna strona" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Skaluj do najlepszego" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Skaluj do szerokości" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Skaluj do wysokości" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Skaluj do wielkości oryginalnej" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Obróć w prawo" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Obróć w lewo" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Odwórć obraz" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Jasny" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Ciemny" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Skaluj" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Najlepszy" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Szerokość" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Wysokość" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Natywnie" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Obrót" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Odwróć" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Poziomo" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Pionowo" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Kierunek" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Od lewej do prawej" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Od prawej do lewej" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "Resetuj do góry" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "Zapamiętaj pozycję" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "Pasek przewijania" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "Pokaż" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "Ukryj" @@ -2852,7 +3096,7 @@ msgstr "Ukryj" msgid "DJVU Reader" msgstr "Czytnik PDF" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "Czytnik PDF" @@ -2871,7 +3115,7 @@ msgid "Choose a username" msgstr "Wybierz nazwę użytkownika" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Twój adres e-mail" #: cps/templates/remote_login.html:5 @@ -2890,15 +3134,19 @@ msgstr "Gdy to zrobisz, automatycznie zalogujesz się na tym urządzeniu." msgid "This verification link will expire in 10 minutes." msgstr "Link wygaśnie po 10 minutach." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Brak wyników" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Wyszukiwano:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Wyniki dla:" @@ -2910,10 +3158,6 @@ msgstr "Data publikacji od" msgid "Published Date To" msgstr "Data publikacji do" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "Status odczytu" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Wyklucz etykiety" @@ -2954,30 +3198,26 @@ msgstr "Od:" msgid "To:" msgstr "Do:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Usuń tą półkę" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "Edytuj właściwości półki" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "Ręczne porządkowanie książek" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "Wyłączenie Zlecenie zmiany" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "Włącz polecenie zmiany" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Półka zostanie usunięta dla wszystkich użytkowników" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Współdziel z wszystkimi" @@ -3019,8 +3259,8 @@ msgid "System Statistics" msgstr "Statystyki systemu" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Biblioteka programu" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3047,9 +3287,17 @@ msgstr "Postęp" msgid "Run Time" msgstr "Czas wykonania" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Start" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3079,19 +3327,23 @@ msgstr "Token Kobo Sync" msgid "Create/View" msgstr "Utwórz/Przeglądaj" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "Dodaj dozwolone/zabronione wartości własnych kolumn" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "Synchronizuj z Kobo tylko książki z wybranych półek" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Usuń tego użytkownika" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Generuj Kobo Auth URL" @@ -3108,16 +3360,19 @@ msgid "Enter Username" msgstr "Wprowadź nazwę użytkownika" #: cps/templates/user_table.html:135 -msgid "Enter E-mail Address" -msgstr "Wpisz adres e-mail" +#, fuzzy +msgid "Enter Email" +msgstr "Testowy e-mail" #: cps/templates/user_table.html:136 -msgid "Enter Kindle E-mail Address" -msgstr "Wprowadź adres e-mail Kindle" +#, fuzzy +msgid "Enter eReader Email" +msgstr "Adres e-mail dla wysyłania do Kindle" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" -msgstr "E-mail Kindle" +#, fuzzy +msgid "eReader Email" +msgstr "Testowy e-mail" #: cps/templates/user_table.html:137 #, fuzzy @@ -3179,10 +3434,7 @@ msgid "Sync selected Shelves with Kobo" msgstr "Zsynchronizuj wybrane półki z Kobo" #: cps/templates/user_table.html:156 -msgid "Show read/unread selection" +#, fuzzy +msgid "Show Read/Unread Section" msgstr "Pokaż wybór przeczytane/nieprzeczytane" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Pokaż menu losowych książek" - diff --git a/cps/translations/pt_BR/LC_MESSAGES/messages.mo b/cps/translations/pt_BR/LC_MESSAGES/messages.mo index 47fddac27..28b7fdd87 100644 Binary files a/cps/translations/pt_BR/LC_MESSAGES/messages.mo and b/cps/translations/pt_BR/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/pt_BR/LC_MESSAGES/messages.po b/cps/translations/pt_BR/LC_MESSAGES/messages.po index 6a9a773bc..0c6f38844 100644 --- a/cps/translations/pt_BR/LC_MESSAGES/messages.po +++ b/cps/translations/pt_BR/LC_MESSAGES/messages.po @@ -4,763 +4,821 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: br\n" "Language-Team: br \n" -"Plural-Forms: nplurals=6; plural=(n==1 ? 0 : n%10==1 && n%100!=11 && n%100!=71 && n%100!=91 ? 1 : n%10==2 && n%100!=12 && n%100!=72 && n%100!=92 ? 2 : (n%10==3 || n%10==4 || n%10==9) && n%100!=13 && n%100!=14 && n%100!=19 && n%100!=73 && n%100!=74 && n%100!=79 && n%100!=93 && n%100!=94 && n%100!=99 ? 3 : n%1000000==0 ? 4 : 5)\n" +"Plural-Forms: nplurals=6; plural=(n==1 ? 0 : n%10==1 && n%100!=11 && n%100!=71 && n%100!=91 ? 1 : n%10==2 && n%100!=12 && n%100!=72 && n%100!=92 ? 2 : (n%10==3 || n%10==4 || n%10==9) && n%100!=13 && n%100!=14 && n%100!=19 && n%100!=73 && n%100!=74 && n%100!=79 && n%100!=93 && n%100!=94 && n%100!=99 ? 3 : n%1000000==0 ? 4 : 5);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "não instalado" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "instalado" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" -msgstr "Estatística" +msgstr "Estatísticas" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Servidor reiniciado, por favor recarregue a página" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" -msgstr "Executando o desligamento do servidor, por favor, feche a janela" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." +msgstr "Executando o desligamento do servidor, por favor feche a janela" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Reconexão bem-sucedida" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Comando desconhecido" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Livro enfileirado com sucesso para envio para %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Desconhecido" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" -msgstr "Página de administração" +msgstr "Página de Administração" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Configuração Básica" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Configuração de UI" -#: cps/admin.py:277 cps/templates/admin.html:46 -#, fuzzy +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" -msgstr "Usuário Admin" +msgstr "Editar Usuários" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Todos" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "Usuário não encontrado" -#: cps/admin.py:357 -#, fuzzy +#: cps/admin.py:402 msgid "{} users deleted successfully" -msgstr "{} Usuário Importado com Sucesso" +msgstr "{} usuário(s) deletedos com sucesso" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" -msgstr "Mostrar tudo" +msgstr "Mostrar Tudo" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" -msgstr "" +msgstr "Requisição Malformada" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" -msgstr "" +msgstr "Nome do Convidado não pode ser alterado" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" -msgstr "" +msgstr "Convidado não pode ter esta função" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" -msgstr "Nenhum usuário administrador restante, não pode remover a função de administrador" +msgstr "Nenhum usuário administrador restante, impossível remover a função de administrador" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" -msgstr "" +msgstr "Valor não pode ser Verdadeiro ou Falso" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" -msgstr "" +msgstr "Função Inválida" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" -msgstr "" +msgstr "Convidado não pode ter esta visão" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" -msgstr "" +msgstr "Visão Inválida" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" -msgstr "" +msgstr "O idioma do Convidado é detectado automaticamente e não pode ser alterado" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" -msgstr "" +msgstr "Nenhum Idioma Válido Fornecido" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" -msgstr "" +msgstr "Nenhum Idioma do Livro Válido Fornecido" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" -msgstr "" +msgstr "Parametro não encontrado" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" -msgstr "" +msgstr "Coluna Lido Inválida" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" -msgstr "" +msgstr "Coluna Restrito Inválida" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Configuração do Calibre-Web atualizada" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" -msgstr "Você realmente quer excluir o Kobo Token?" +msgstr "Você realmente quer apagar a Kobo Token?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" -msgstr "Você realmente quer excluir este domínio?" +msgstr "Você realmente quer apagar este domínio?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" -msgstr "Você realmente quer excluir este usuário?" +msgstr "Você realmente quer apagar este usuário?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Tem certeza que quer apagar essa estante?" -#: cps/admin.py:580 -#, fuzzy +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" -msgstr "Tem certeza que quer apagar essa estante?" +msgstr "Tem certeza que quer alterar o idioma do(s) usuário(s) selecionados?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" -msgstr "" +msgstr "Tem certeza que quer alterar os idiomas de livros visíveis par o usuário(s) selecionado(s)?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" -msgstr "" +msgstr "Tem certeza que quer alterar a função selecionada para o(s) usuário(s) selecionado(s)?" -#: cps/admin.py:586 -#, fuzzy +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" -msgstr "Tem certeza que quer apagar essa estante?" +msgstr "Tem certeza que quer alterar as restriçõeo selecionada para o(s) usuário(s) selecionado(s)?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" -msgstr "" +msgstr "Tem certeza de que quer alterar as restrições de visibilidade selecionadas para os usuários selecionados?" -#: cps/admin.py:590 -#, fuzzy +#: cps/admin.py:622 msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" -msgstr "Tem certeza que quer apagar essa estante?" +msgstr "Tem certeza de que quer alterar o comportamento de sincronização da estante para o usuário selecionado?" -#: cps/admin.py:592 -#, fuzzy +#: cps/admin.py:624 msgid "Are you sure you want to change Calibre library location?" -msgstr "Tens a certeza que queres fechar?" +msgstr "Tem certeza que queres alterar a localização da biblioteca Calibre?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "O Calibre-Web buscará por Capas atualizadas e atualizará as Miniaturas de Capas, isso pode demorar um pouco" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Tem certeza de que deseja apagar o banco de dados de sincronização do Calibre-Web para forçar uma sincronização completa com seu Kobo Reader?" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Negar" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" -msgstr "Permita" +msgstr "Permitir" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{} entradas de sincronização deletadas" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Tag não encontrada" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Ação Inválida" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" -msgstr "client_secrets.json não está configurado para aplicativo da web" +msgstr "client_secrets.json Não Está Configurado para Aplicação Web" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "A localização do arquivo de log não é válida, digite o caminho correto" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "A localização do arquivo de log de acesso não é válida, digite o caminho correto" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Digite um provedor LDAP, porta, DN e identificador de objeto do usuário" -#: cps/admin.py:1102 -#, fuzzy +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" -msgstr "Por favor, digite um nome de usuário válido para redefinir a senha" +msgstr "Por favor, digite uma Conta de Serviço LDAP e Senha" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" -msgstr "" +msgstr "Por favor, digite uma Conta de Serviço LDAP" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "O filtro de objeto de grupo LDAP precisa ter um identificador de formato \"%s\"" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "Filtro de objeto de grupo LDAP tem parênteses incomparáveis" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "O filtro de objeto de usuário LDAP precisa ter um identificador de formato \"%s\"" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "Filtro de objeto de usuário LDAP tem parênteses incomparáveis" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "O filtro de usuário membro do LDAP precisa ter um identificador de formato \"%s\"" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "Filtro de usuário de membro LDAP tem parênteses incomparáveis" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" -msgstr "LDAP CACertificate, Certificados ou chave de localização não é válida, Insira o caminho correto" +msgstr "Localização de LDAP CACertificate, Certificados ou Key Inválida, Insira o Caminho Correto" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "O banco de dados de configurações não é gravável" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "Adicionar Novo Usuário" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "A localização do banco de dados não é válida, digite o caminho correto" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "DB não é gravável" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "A localização do arquivo-chave não é válida, por favor insira o caminho correto" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "A localização do arquivo de certificação não é válida, digite o caminho correto" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Atualização das configurações do servidor de e-mail" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Configuração das Características" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Por favor, preencha todos os campos!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "O e-mail não é de um domínio válido" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "Adicionar novo usuário" - -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Usuário '%(user)s' criado" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Encontrei uma conta existente para este endereço de e-mail ou apelido." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Usuário '%(nick)s' excluído" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Nenhum usuário administrador restante, não é possível excluir o usuário" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Editar usuário %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Usuário '%(nick)s' atualizado" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Ocorreu um erro desconhecido. Por favor, tente novamente mais tarde." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Editar configurações do servidor de e-mail" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Erro de banco de dados: %(error)s." + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" -msgstr "" +msgstr "E-mail de teste enfileirado para envio para %(email)s, verifique o resultado em Tarefas" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Ocorreu um erro ao enviar o e-mail de teste: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Por favor, configure seu endereço de e-mail primeiro..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Atualização das configurações do servidor de e-mail" -#: cps/admin.py:1602 -#, python-format -msgid "Password for user %(user)s reset" -msgstr "Senha para redefinição do usuário %(user)s" +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "Editar configurações de tarefas agendadas" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "Hora de início inválida para a tarefa especificada" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "Duração inválida para a tarefa especificada" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "Configurações de tarefas agendadas atualizadas" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Ocorreu um erro desconhecido. Por favor, tente novamente mais tarde." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "Settings DB não é gravável" + +#: cps/admin.py:1411 cps/admin.py:2009 +#, python-format +msgid "Edit User %(nick)s" +msgstr "Editar Usuário %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" +msgstr "Senha do usuário %(user)s redefinida" + +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Por favor, configure primeiro as configurações de correio SMTP..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" -msgstr "visualizador de arquivo de registro" +msgstr "Visualizador do Log" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Solicitação de pacote de atualização" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" -msgstr "Download do pacote de atualização" +msgstr "Baixando pacote de atualização" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" -msgstr "Descompactação de pacote de atualização" +msgstr "Descompactando pacote de atualização" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" -msgstr "Substituição de arquivos" +msgstr "Substituindo arquivos" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" -msgstr "As ligações à base de dados estão fechadas" +msgstr "As conexões à base de dados estão fechadas" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" -msgstr "Parar servidor" +msgstr "Parando servidor" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Atualização concluída, pressione okay e recarregue a página" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Atualização falhou:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "Erro HTTP" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Erro de conexão" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Tempo limite durante o estabelecimento da conexão" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Erro geral" -#: cps/admin.py:1696 -#, fuzzy +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" msgstr "Arquivo de atualização não pôde ser salvo no diretório temporário" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" -msgstr "" +msgstr "Arquivos não puderam ser substituídos durante a atualização" -#: cps/admin.py:1721 -#, fuzzy +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" -msgstr "Falha na criação no mínimo de um usuário LDAP" +msgstr "Falha ao extrair pelo menos um usuário LDAP" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" -msgstr "Falha na criação no mínimo de um usuário LDAP" +msgstr "Falha ao criar pelo menos um usuário LDAP" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Erro: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" -msgstr "Erro: Nenhum usuário retornado em resposta do servidor LDAP" +msgstr "Erro: Nenhum usuário retornado na resposta do servidor LDAP" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "No mínimo um usuário LDAP não encontrado no banco de dados" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} Usuário Importado com Sucesso" -#: cps/converter.py:30 -msgid "not configured" -msgstr "não configurado" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "A localização do banco de dados não é válida, digite o caminho correto" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "DB não é gravável" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "Localização do Keyfile Inválida, Insira o Caminho Correto" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "Localização do Certfile Inválida, Insira o Caminho Correto" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "Configurações do Banco de Dados Atualizada" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "Configuração do Banco de Dados" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Por favor, preencha todos os campos!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "O e-mail não é de um domínio válido" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Adicionar novo usuário" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Usuário '%(user)s' criado" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "Encontrada uma conta existente para este endereço de e-mail ou apelido." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Usuário '%(nick)s' excluído" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Impossível excluir Convidado" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Nenhum usuário administrador restante, não é possível apagar o usuário" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Usuário '%(nick)s' atualizado" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "não instalado" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Faltam as permissões de execução" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" -msgstr "A coluna personalizada No.%(column)d não existe no banco de dados do calibre" +msgid "Custom Column No.%(column)d does not exist in calibre database" +msgstr "A Coluna Personalizada No.%(column)d não existe no banco de dados do calibre" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Formato do Livro Eliminado com Sucesso" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Nenhum" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Livro Eliminado com Sucesso" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" +msgstr "Oops! O Livro selecionado não está disponível. O arquivo não existe ou não é acessível" -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" -msgstr "Oops! O título do livro seleccionado não está disponível. O arquivo não existe ou não é acessível" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "Usuário não tem permissão para fazer upload da capa" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "editar metadados" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s não é um idioma válido" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "A extensão de arquivo '%(ext)s' não pode ser enviada para este servidor" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "O arquivo a ser carregado deve ter uma extensão" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Falha ao criar o caminho %(path)s (Permission denied)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Falha ao armazenar o arquivo %(file)s." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Erro de banco de dados: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Formato de arquivo %(ext)s adicionado a %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" -msgstr "Os identificadores não são sensíveis a maiúsculas ou minúsculas, mas sim a maiúsculas e minúsculas" +msgstr "Os identificadores não diferenciam maiúsculas de minúsculas, substituindo o identificador antigo" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Metadados atualizados com sucesso" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Livro de edição de erros, por favor verifique o ficheiro de registo para mais detalhes" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "Erro ao editar o livro: {}" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "O livro carregado provavelmente existe na biblioteca, considere mudar antes de carregar novo: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "O arquivo %(filename)s não pôde ser salvo no diretório temporário" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Falha ao mover arquivo de capa %(file)s: %(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Arquivo %(file)s enviado" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" -msgstr "Falta o formato de origem ou destino para a conversão" +msgstr "Formato de origem ou destino para conversão ausente" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Livro enfileirado com sucesso para conversão em %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Ocorreu um erro ao converter este livro: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "O livro carregado provavelmente existe na biblioteca, considere alterar antes de carregar novo: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s não é um idioma válido" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "A extensão de arquivo '%(ext)s' não pode ser enviada para este servidor" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "O arquivo a ser carregado deve ter uma extensão" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "O arquivo %(filename)s não pôde ser salvo no diretório temporário" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Falha ao mover arquivo de capa %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Formato do Livro Apagado com Sucesso" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Livro Apagado com Sucesso" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "Você não tem permissão para apagar livros" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "editar metadados" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s não é um número válido, ignorando" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "Usuário não tem direitos para fazer upload de formatos de arquivo adicionais" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Falha ao criar o caminho %(path)s (Permission denied)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Falha ao armazenar o arquivo %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Formato de arquivo %(ext)s adicionado a %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Configuração do Google Drive não concluída, tente desativar e ativar o Google Drive novamente" #: cps/gdrive.py:95 msgid "Callback domain is not verified, please follow steps to verify domain in google developer console" -msgstr "O domínio Callback não é verificado, por favor siga os passos para verificar o domínio no console do desenvolvedor do google" +msgstr "O domínio Callback não foi verificado, por favor siga os passos para verificar o domínio no console do desenvolvedor do google" #: cps/helper.py:80 #, python-format msgid "%(format)s format not found for book id: %(book)d" msgstr "Formato %(format)s não encontrado para o id do livro: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" -msgstr "%(format)s não encontrado no Google Drive: %(fn)s" +msgstr "%(format)s não encontrado no Google Drive: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s não encontrado: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" -msgstr "Enviar para Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +msgid "Send to eReader" +msgstr "Enviar para E-Reader" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Este e-mail foi enviado via Calibre-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "E-mail de teste do Calibre-Web" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "E-mail de teste" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Comece a usar o calibre-web" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "E-mail de registro do usuário: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" -msgstr "Converta %(orig)s em %(format)s e envie para o Kindle" - -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" -msgstr "Envie %(format)s para o Kindle" - -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:148 cps/helper.py:154 #, fuzzy, python-format -msgid "%(book)s send to Kindle" -msgstr "Enviar para Kindle" +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "Converter %(orig)s em %(format)s e enviar para E-Reader" -#: cps/helper.py:224 +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" +msgstr "Enviar %(format)s para o E-Reader" + +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" +msgstr "%(book)s enviado para E-Reader" + +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "O arquivo solicitado não pôde ser lido. Talvez permissões erradas?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "Status Lido não pode ser alterado: {}" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "A exclusão da pasta de livros do livro %(id)s falhou, o caminho tem subpastas: %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "Falha ao excluir livro %(id)s: %(message)s" -#: cps/helper.py:333 -#, fuzzy, python-format +#: cps/helper.py:385 +#, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" -msgstr "Excluindo livro %(id)s, caminho do livro inválido: %(path)s" +msgstr "Excluindo livro %(id)s somente do banco de dados, caminho do livro inválido: %(path)s" -#: cps/helper.py:388 +#: cps/helper.py:450 #, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Renomear título de: '%(src)s' para '%(dest)s' falhou com o erro: %(error)s" +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Renomear autor de: '%(src)s' para '%(dest)s' falhou com o erro: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Renomear arquivo no caminho '%(src)s' para '%(dest)s' falhou com o erro: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Arquivo %(file)s não encontrado no Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Renomear título de: '%(src)s' para '%(dest)s' falhou com o erro: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "Erro ao renomear arquivo no caminho: {}" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Caminho do livro %(path)s não encontrado no Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Encontrado uma conta existente para este endereço de e-mail." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Este nome de usuário já está registrado" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" msgstr "Formato de endereço de e-mail inválido" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "O módulo Python 'advocate' não está instalado, mas é necessário para uploads de capa" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Erro ao Baixar a capa" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "Erro de Formato da Capa" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "Você não tem permissão para acessar localhost ou a rede local para uploads de capa" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Falha em criar caminho para a capa" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "O arquivo de capa não é um arquivo de imagem válido, ou não pôde ser armazenado" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" -msgstr "Apenas ficheiros jpg/jpeg/png/webp/bmp são suportados como arquivos de capa" +msgstr "Apenas arquivos jpg/jpeg/png/webp/bmp são suportados como arquivos de capa" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "Conteúdo do arquivo de capa inválido" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Apenas arquivos jpg/jpeg são suportados como arquivos de capa" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" -msgstr "Unrar arquivo binário não encontrado" +msgstr "Binário Unrar não encontrado" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" msgstr "Erro excecutando UnRar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Aguardando" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Descubra" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Falha" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "Iniciado em" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Concluído" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Status Desconhecido" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Por favor, acesse o calibre-web de um host não local para obter um api_endpoint válido para o dispositivo kobo" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Configuração Kobo" @@ -769,9 +827,9 @@ msgstr "Configuração Kobo" msgid "Register with %(provider)s" msgstr "Registre-se com %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "agora você está logado como: '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -781,7 +839,7 @@ msgstr "Link para %(oauth)s bem-sucedido" #: cps/oauth_bb.py:155 msgid "Login failed, No User Linked With OAuth Account" -msgstr "Login falhou, nenhum utilizador ligado a uma conta OAuth" +msgstr "Login falhou, nenhum usuário ligado a uma conta OAuth" #: cps/oauth_bb.py:197 #, python-format @@ -812,525 +870,627 @@ msgstr "Falha no login com o Google." #: cps/oauth_bb.py:285 msgid "Failed to fetch user info from Google." -msgstr "Falha em ir buscar informações de usuário ao Google." +msgstr "Falha na busca de informações de usuário no Google." #: cps/oauth_bb.py:332 msgid "GitHub Oauth error, please retry later." -msgstr "Erro de GitHub Oauth, por favor tente novamente mais tarde." +msgstr "Erro no Oauth do GitHub, tente novamente mais tarde." #: cps/oauth_bb.py:335 msgid "GitHub Oauth error: {}" -msgstr "" +msgstr "Erro no Oauth do GitHub: {}" #: cps/oauth_bb.py:356 msgid "Google Oauth error, please retry later." -msgstr "Erro no Google Oauth, por favor tente novamente mais tarde." +msgstr "Erro no Google Oauth, tente novamente mais tarde." #: cps/oauth_bb.py:359 msgid "Google Oauth error: {}" -msgstr "" +msgstr "Erro no Oauth do Google: {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" -msgstr "" +msgstr "{} Estrelas" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Login" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Token não encontrado" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "O Token expirou" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Sucesso! Por favor, volte ao seu aparelho" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Livros" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Mostrar livros recentes" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Livros Quentes" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Mostrar Livros Quentes" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" -msgstr "Livros descarregados" +msgstr "Livros Baixados" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" -msgstr "Mostrar Livros Descarregados" +msgstr "Mostrar Livros Baixados" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Livros Mais Bem Avaliados" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" -msgstr "Mostrar os melhores livros avaliados" +msgstr "Mostrar Livros Mais Bem Avaliados" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Livros Lidos" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Mostrar lido e não lido" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Livros Não Lidos" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" -msgstr "Mostrar não lido" +msgstr "Mostrar Não Lidos" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Descubra" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Mostrar Livros Aleatórios" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Categorias" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Mostrar seleção de categoria" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Série" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" -msgstr "Mostrar selecção de séries" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" +msgstr "Mostrar seleção de séries" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Autores" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" -msgstr "Mostrar selecção de autor" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" +msgstr "Mostrar seleção de autor" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" -msgstr "Editores" +msgstr "Editoras" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" -msgstr "Mostrar selecção de editores" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" +msgstr "Mostrar seleção de editoras" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Idiomas" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Mostrar seleção de idioma" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" -msgstr "Classificações" +msgstr "Avaliações" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" -msgstr "Mostrar selecção de classificações" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "Mostrar seleção de avaliações" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Formatos de arquivo" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Mostrar seleção de formatos de arquivo" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Livros Arquivados" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" msgstr "Mostrar livros arquivados" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "Lista de Livros" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "Mostrar Lista de Livros" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Estante inválida especificada" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Desculpe, você não tem permissão para adicionar um livro à estante: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "O livro já faz parte da estante: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "O livro foi adicionado à estante: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Você não tem permissão para adicionar um livro à estante: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Os livros já fazem parte da estante: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Livros foram adicionados à estante: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Não foi possível adicionar livros à estante: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "O livro foi removido da estante: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Desculpe, você não tem permissão para remover um livro desta estante: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Crie uma estante" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Desculpe, você não tem permissão para remover um livro desta estante: %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Editar uma estante" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Estante %(title)s criada" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Estante %(title)s alterada" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Houve um erro" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Já existe uma estante pública com o nome '%(title)s' ." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Já existe uma estante privada com o nome'%(title)s' ." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Alterar ordem da Estante: '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Estante: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Erro ao abrir estante. A estante não existe ou não está acessível" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Dados inesperados ao ler informações de atualização" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Não há atualização disponível. Você já tem a última versão instalada" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Uma nova atualização está disponível. Clique no botão abaixo para atualizar para a versão mais recente." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Não consegui obter informações actualizadas" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Clique no botão abaixo para atualizar para a última versão estável." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Uma nova atualização está disponível. Clique no botão abaixo para atualizar para a versão: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Não há informações de lançamento disponíveis" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Descobrir (Livros Aleatórios)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Hot Books (Os Mais Descarregados)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "Livros baixados por %(user)s" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Autor: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Editor: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Série: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Avaliação: %(rating)s estrelas" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Formato do arquivo: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Categoria: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Idioma: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Pesquisa Avançada" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" -msgstr "Pesquisa" +msgstr "Pesquisar" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Downloads" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Lista de classificações" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Lista de formatos de arquivo" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Tarefas" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Publicado depois de " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Publicado antes de " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Avaliação <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Avaliação >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" -msgstr "Status de leitura = %(status)s" +msgstr "Status de leitura = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" -msgstr "" +msgstr "Erro na pesquisa de colunas personalizadas, reinicie o Calibre-Web" -#: cps/web.py:1441 +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Pesquisa Avançada" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Estante inválida especificada" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Desculpe, você não tem permissão para adicionar um livro a esta estante" + +#: cps/shelf.py:64 #, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Livro enfileirado com sucesso para envio para %(kindlemail)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "O livro já faz parte da estante: %(shelfname)s" -#: cps/web.py:1445 +#: cps/shelf.py:89 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" -msgstr "Ups! Ocorreu um erro ao enviar este livro: %(res)s" +msgid "Book has been added to shelf: %(sname)s" +msgstr "O livro foi adicionado à estante: %(sname)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." -msgstr "Por favor, atualize seu perfil com um endereço de e-mail válido para Kindle." +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "Você não tem permissão para adicionar um livro à estante" -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Os livros já fazem parte da estante: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Livros foram adicionados à estante: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Não foi possível adicionar livros à estante: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "O livro foi removido da estante: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "Desculpe, você não tem permissão para remover um livro desta estante" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Crie uma Estante" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Desculpe, você não tem permissão para editar esta estante" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Editar uma estante" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "Erro apagando Estante" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "Estante Apagada com Sucesso" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Alterar ordem da Estante: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "Desculpe, você não tem permissão para criar uma estante pública" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Estante %(title)s criada" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Estante %(title)s alterada" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Houve um erro" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Já existe uma estante pública com o nome '%(title)s' ." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Já existe uma estante privada com o nome'%(title)s' ." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Estante: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Erro ao abrir estante. A estante não existe ou não está acessível" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Tarefas" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Aguardando" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Falha" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Iniciado" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Concluído" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "Terminado" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "Cancelado" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Status Desconhecido" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Dados inesperados ao ler informações de atualização" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Não há atualização disponível. Você já tem a última versão instalada" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Uma nova atualização está disponível. Clique no botão abaixo para atualizar para a versão mais recente." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Não foi possível buscar as informações de atualização" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Clique no botão abaixo para atualizar para a última versão estável." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Uma nova atualização está disponível. Clique no botão abaixo para atualizar para a versão: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Não há informações de lançamento disponíveis" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Descobrir (Livros Aleatórios)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Livros Quentess (Mais Baixados)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Livros baixados por %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Autor: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Editora: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Série: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "Avaliação: Nenhuma" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Avaliação: %(rating)s estrelas" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Formato do arquivo: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Categoria: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Idioma: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Downloads" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Lista de Avaliações" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Lista de formatos de arquivo" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Por favor, configure primeiro as configurações de correio SMTP..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Livro enfileirado com sucesso para envio para %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "Ops! Ocorreu um erro ao enviar este livro: %(res)s" + +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "Por favor, atualize seu perfil com um endereço de e-mail Envie Para o Kindle válido." + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "O servidor de E-Mail não está configurado, por favor contacte o seu administrador!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Registe-se" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Seu e-mail não tem permissão para registrar" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "O e-mail de confirmação foi enviado para a sua conta de e-mail." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "Não é possível ativar a autenticação LDAP" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "Login de reserva como:'%(nickname)s', servidor LDAP não acessível ou usuário desconhecido" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Não foi possível fazer o login: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" -msgstr "Nome de usuário ou senha incorretos" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." +msgstr "Nome de Usuário ou Senha incorretos" -#: cps/web.py:1555 -msgid "New Password was send to your email address" -msgstr "Nova senha foi enviada para seu endereço de e-mail" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." +msgstr "Nova Senha foi enviada para seu endereço de e-mail" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Por favor, digite um nome de usuário válido para redefinir a senha" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Você agora está logado como: '%(nickname)s'" +msgid "%(name)s's Profile" +msgstr "Perfil de %(name)s" -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" -msgstr "Perfil de %(name)s's" - -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Perfil atualizado" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "Encontrada uma conta existente para este endereço de e-mail." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" -msgstr "" +msgstr "Não foi encontrado nenhum arquivo gmail.json válido com informações do OAuth" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s enviado para E-Reader" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "Calibre ebook-convert %(tool)s não encontrado" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "Formato %(format)s não encontrado no disco" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "O conversor de Ebook falhou com erro desconhecido" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" -msgstr "O conversor de Kepubify falhou: %(error)s" +msgstr "Kepubify-converter falhou: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "Arquivo convertido não encontrado ou mais de um arquivo na pasta %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" -msgstr "Conversor de ebook falhou: %(error)s" +msgstr "Ebook-converter falhou: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "Calibre falhou com erro: %(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "Converter" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "Reconectando banco de dados Calibre" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "E-mail" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "editar metadados" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "Gerado %(count)s miniaturas de capa" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "Miniatura da Capa" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "Gerado {0} miniaturas de série" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "Limpando o cache de miniaturas da capa" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Upload" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Usuários" @@ -1343,14 +1503,14 @@ msgstr "Nome de usuário" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "Endereço de e-mail" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" -msgstr "Enviar para o endereço de e-mail do Kindle" +msgid "Send to eReader Email" +msgstr "Enviar para o endereço de e-mail do E-Reader" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Admin" @@ -1360,214 +1520,231 @@ msgstr "Admin" msgid "Password" msgstr "Senha" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Upload" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Baixar" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Ver Livros" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Editar" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" -msgstr "Eliminar" +msgstr "Apagar" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Estante Pública" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Adicionar Novo Usuário" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "Importar usuários LDAP" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "Configurações do servidor de e-mail" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" -msgstr "SMTP Nome do anfitrião" +msgstr "SMTP Hostname" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" -msgstr "Porto SMTP" +msgstr "Porta SMTP" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "Criptografia" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "Login SMTP" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Do E-mail" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" -msgstr "" +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" +msgstr "Serviço de E-Mail" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" -msgstr "" +msgstr "Gmail via Oauth2" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Configuração" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" -msgstr "Diretório do Banco de Dados de Calibres" +msgstr "Diretório do Banco de Dados Calibre" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" -msgstr "Nível de registo" +msgstr "Nível de Log" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" -msgstr "Porto" +msgstr "Porta" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" -msgstr "Porto externo" +msgstr "Porta externa" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Livros por página" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Uploads" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Navegação Anónima" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Inscrição Pública" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Login remoto Magic Link" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" -msgstr "Login de Proxy Reversa" +msgstr "Login de Proxy Reverso" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Nome do cabeçalho do Proxy Reverso" -#: cps/templates/admin.html:153 -#, fuzzy +#: cps/templates/admin.html:159 msgid "Edit Calibre Database Configuration" -msgstr "Editar Configuração Básica" - -#: cps/templates/admin.html:154 -msgid "Edit Basic Configuration" -msgstr "Editar Configuração Básica" - -#: cps/templates/admin.html:155 -msgid "Edit UI Configuration" -msgstr "Editar configuração da IU" +msgstr "Editar Configuração do Banco de Dados do Calibre" #: cps/templates/admin.html:160 +msgid "Edit Basic Configuration" +msgstr "Editar Configurações Básicas" + +#: cps/templates/admin.html:161 +msgid "Edit UI Configuration" +msgstr "Editar Configuração de UI" + +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "Tarefas Agendadas" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "Hora em que as tarefas começam a ser executadas" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "Duração máxima das tarefas" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "Gerar miniaturas de capa de livro" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "Gerar miniaturas de capa de séries" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "Reconectar à Biblioteca do Calibre" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "Atualizar Cache de Capas de Miniaturas" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Administração" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" -msgstr "Download do Pacote de Depuração" +msgstr "Baixar Pacote de Depuração" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Ver Logs" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Reconectar base de dados de calibração" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" -msgstr "Reinicie" +msgstr "Reiniciar" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" -msgstr "Encerramento" +msgstr "Desligar" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Atualização" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "Informação da Versão" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Versão" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Detalhes" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Versão atual" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Verificar Atualizações" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Realizar Atualizações" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" -msgstr "Tem a certeza que quer recomeçar?" +msgstr "Tem a certeza que quer reiniciar?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "Ok" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Cancelar" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" -msgstr "Tens a certeza que queres fechar?" +msgstr "Tem certeza que quer encerrar?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" -msgstr "Atualizando, por favor, não recarregue esta página" +msgstr "Atualizando, por favor não recarregue esta página" #: cps/templates/author.html:15 msgid "via" @@ -1577,121 +1754,120 @@ msgstr "via" msgid "In Library" msgstr "Na Biblioteca" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "Classificar de acordo com a data do livro, o mais recente primeiro" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "Classificar de acordo com a data do livro, o mais antigo primeiro" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "Classificar título em ordem alfabética" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "Classificar título em ordem alfabética inversa" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "Classificar de acordo com a data de publicação, o mais novo primeiro" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "Classificar de acordo com a data de publicação, primeiro mais antigo" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "reduzir" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Mais por" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" -msgstr "Eliminar Livro" +msgstr "Apagar Livro" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" -msgstr "Eliminar formatos:" +msgstr "Apagar formatos:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" -msgstr "Converta o formato do livro:" +msgstr "Converter formato do livro:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" -msgstr "Converte de:" +msgstr "Converter de:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "selecione uma opção" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" -msgstr "Converte para:" +msgstr "Converter para:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Converter livro" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Título do Livro" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Autor" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Descrição" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "Identificadores" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "Tipo de identificador" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "Valor do Identificador" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Remover" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "Adicionar Identificador" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" -msgstr "Etiquetas" +msgstr "Tags" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "Identificação da série" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" -msgstr "Classificação" +msgstr "Avaliação" #: cps/templates/book_edit.html:104 msgid "Fetch Cover from URL (JPEG - Image will be downloaded and stored in database)" @@ -1699,84 +1875,84 @@ msgstr "Buscar capa na URL (JPEG - Imagem será baixada e armazenada na base de #: cps/templates/book_edit.html:108 msgid "Upload Cover from Local Disk" -msgstr "Upload de capa do disco local" +msgstr "Upload de Capa do Disco Local" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Data de Publicação" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Editora" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Idioma" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Sim" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Não" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Formato de upload" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" -msgstr "Ver Livro ao salvar" +msgstr "Ver Livro ao Salvar" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Buscar Metadados" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Salvar" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Palavra-chave" -#: cps/templates/book_edit.html:237 -#, fuzzy +#: cps/templates/book_edit.html:234 msgid "Search keyword" -msgstr " Pesquisar palavra-chave " +msgstr "Pesquisar palavra-chave" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Clique na capa para carregar os metadados para o formulário" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." -msgstr "A carregar..." +msgstr "Carregando..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Fechar" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Fonte" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Erro de busca!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Nenhum resultado(s) encontrado(s)! Por favor, tente outra palavra-chave." @@ -1788,7 +1964,7 @@ msgstr "Este campo é obrigatório" #: cps/templates/book_table.html:37 msgid "Merge selected books" -msgstr "Fundir livros selecionados" +msgstr "Mesclar livros selecionados" #: cps/templates/book_table.html:38 cps/templates/user_table.html:124 msgid "Remove Selections" @@ -1796,19 +1972,19 @@ msgstr "Remover Seleções" #: cps/templates/book_table.html:41 msgid "Exchange author and title" -msgstr "" +msgstr "Trocar autor e título" #: cps/templates/book_table.html:47 msgid "Update Title Sort automatically" -msgstr "Atualizar a Classificação de Título automaticamente" +msgstr "Atualizar Ordenação de Título automaticamente" #: cps/templates/book_table.html:51 msgid "Update Author Sort automatically" -msgstr "Atualizar a Classificação do Autor automaticamente" +msgstr "Atualizar Ordenação de Autor automaticamente" #: cps/templates/book_table.html:63 cps/templates/book_table.html:69 msgid "Enter Title" -msgstr "Digite o título" +msgstr "Digite o Título" #: cps/templates/book_table.html:63 cps/templates/config_view_edit.html:24 #: cps/templates/shelf_edit.html:8 @@ -1817,19 +1993,19 @@ msgstr "Título" #: cps/templates/book_table.html:64 msgid "Enter Title Sort" -msgstr "Digite o título Sort" +msgstr "Digite a ordenação do título" #: cps/templates/book_table.html:64 msgid "Title Sort" -msgstr "Título Ordenar" +msgstr "Ordenação de Título" #: cps/templates/book_table.html:65 msgid "Enter Author Sort" -msgstr "Digite Author Sort" +msgstr "Digite a Ordenação de Author" #: cps/templates/book_table.html:65 msgid "Author Sort" -msgstr "Ordenar Autor" +msgstr "Ordenação de Autor" #: cps/templates/book_table.html:66 msgid "Enter Authors" @@ -1837,60 +2013,67 @@ msgstr "Entrar Autores" #: cps/templates/book_table.html:67 msgid "Enter Categories" -msgstr "Entrar nas categorias" +msgstr "Entrar Categorias" #: cps/templates/book_table.html:68 msgid "Enter Series" -msgstr "Entrar na série" +msgstr "Entrar Série" #: cps/templates/book_table.html:69 msgid "Series Index" -msgstr "Índice da série" +msgstr "Índice da Série" #: cps/templates/book_table.html:70 msgid "Enter Languages" -msgstr "Entrar idiomas" +msgstr "Entrar Idiomas" #: cps/templates/book_table.html:71 msgid "Publishing Date" -msgstr "Data de publicação" +msgstr "Data de Publicação" #: cps/templates/book_table.html:72 msgid "Enter Publishers" -msgstr "Entrar Editores" +msgstr "Entrar Editoras" #: cps/templates/book_table.html:73 -#, fuzzy msgid "Enter comments" -msgstr "Digite o nome do domínio" +msgstr "Entrar Comentários" #: cps/templates/book_table.html:73 msgid "Comments" -msgstr "" +msgstr "Comentários" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 -#, fuzzy +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "Status Arquivado" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Status Lido" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 msgid "Enter " -msgstr "Identificadores" +msgstr "Entrar " -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" -msgstr "Tens mesmo a certeza?" +msgstr "Você realmente tem certeza?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" -msgstr "Os livros com título serão fundidos a partir de:" +msgstr "Livros com Título serão mesclados de:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" -msgstr "Into Book with Title:" +msgstr "Em livro com título:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" -msgstr "Fundir" +msgstr "Mesclar" #: cps/templates/config_db.html:12 msgid "Location of Calibre Database" @@ -1898,7 +2081,7 @@ msgstr "Localização da Base de Dados Calibre" #: cps/templates/config_db.html:22 msgid "Use Google Drive?" -msgstr "Use o Google Drive?" +msgstr "User Google Drive?" #: cps/templates/config_db.html:27 msgid "Authenticate Google Drive" @@ -1906,7 +2089,7 @@ msgstr "Autenticar o Google Drive" #: cps/templates/config_db.html:32 msgid "Google Drive Calibre folder" -msgstr "Pasta Google Drive Calibre" +msgstr "Pasta Calibre no Google Drive" #: cps/templates/config_db.html:40 msgid "Metadata Watch Channel ID" @@ -1917,9 +2100,8 @@ msgid "Revoke" msgstr "Revogar" #: cps/templates/config_db.html:68 -#, fuzzy msgid "New db location is invalid, please enter valid path" -msgstr "A localização do banco de dados não é válida, digite o caminho correto" +msgstr "Novo local do banco de dados inválido, insira um caminho válido" #: cps/templates/config_edit.html:18 msgid "Server Configuration" @@ -1927,19 +2109,19 @@ msgstr "Configuração do Servidor" #: cps/templates/config_edit.html:25 msgid "Server Port" -msgstr "Porta do servidor" +msgstr "Porta do Servidor" #: cps/templates/config_edit.html:28 msgid "SSL certfile location (leave it empty for non-SSL Servers)" -msgstr "SSL certfile location (deixe-o vazio para Servidores não-SSL)" +msgstr "Localização do certfile SSL (deixe vazio para Servidores não-SSL)" #: cps/templates/config_edit.html:35 msgid "SSL Keyfile location (leave it empty for non-SSL Servers)" -msgstr "SSL Keyfile location (deixe-o vazio para servidores não-SSL)" +msgstr "Localização do Keyfile SSL (deixe vazio para Servidores não-SSL)" #: cps/templates/config_edit.html:43 msgid "Update Channel" -msgstr "Canal de atualização" +msgstr "Canal de Atualização" #: cps/templates/config_edit.html:45 msgid "Stable" @@ -1947,15 +2129,15 @@ msgstr "Estável" #: cps/templates/config_edit.html:46 msgid "Nightly" -msgstr "Nocturno" +msgstr "Nightly" #: cps/templates/config_edit.html:50 msgid "Trusted Hosts (Comma Separated)" -msgstr "" +msgstr "Hosts confiáveis (Separado por vírgula)" #: cps/templates/config_edit.html:61 msgid "Logfile Configuration" -msgstr "Configuração do ficheiro de registo" +msgstr "Configuração do Arquivo de Log" #: cps/templates/config_edit.html:77 msgid "Location and name of logfile (calibre-web.log for no entry)" @@ -1971,19 +2153,23 @@ msgstr "Localização e nome do arquivo de log de acesso (access.log para nenhum #: cps/templates/config_edit.html:96 msgid "Feature Configuration" -msgstr "Configuração das Características" +msgstr "Configuração do Recursos" #: cps/templates/config_edit.html:104 msgid "Convert non-English characters in title and author while saving to disk" -msgstr "" +msgstr "Converta caracteres não ingleses em título e autor enquanto salva em disco" #: cps/templates/config_edit.html:108 msgid "Enable Uploads" msgstr "Habilitar Uploads" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(Por favor, certifique-se de que os usuários também tenham direitos de upload)" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" -msgstr "Upload de formatos de arquivo permitidos" +msgstr "Formatos de arquivo de upload permitidos" #: cps/templates/config_edit.html:118 msgid "Enable Anonymous Browsing" @@ -1994,28 +2180,28 @@ msgid "Enable Public Registration" msgstr "Habilitar Registro Público" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "Use e-mail como nome de usuário" #: cps/templates/config_edit.html:132 msgid "Enable Magic Link Remote Login" -msgstr "Habilitar login remoto do Magic Link" +msgstr "Habilitar Login Remoto do Magic Link" #: cps/templates/config_edit.html:137 msgid "Enable Kobo sync" -msgstr "Activar a sincronização de Kobo" +msgstr "Ativar Kobo sync" #: cps/templates/config_edit.html:142 msgid "Proxy unknown requests to Kobo Store" -msgstr "Proxy de pedidos desconhecidos para a loja Kobo" +msgstr "Solicitações desconhecidas de proxy para a Kobo Store" #: cps/templates/config_edit.html:145 msgid "Server External Port (for port forwarded API calls)" -msgstr "Porta externa do servidor (para chamadas API de porta encaminhadas)" +msgstr "Porta externa do servidor (para chamadas API encaminhadas)" #: cps/templates/config_edit.html:153 msgid "Use Goodreads" -msgstr "Use Goodreads" +msgstr "Usar Goodreads" #: cps/templates/config_edit.html:154 msgid "Create an API Key" @@ -2023,15 +2209,15 @@ msgstr "Criar uma chave API" #: cps/templates/config_edit.html:158 msgid "Goodreads API Key" -msgstr "Goodreads Chave API" +msgstr "Chave API Goodreads" #: cps/templates/config_edit.html:162 msgid "Goodreads API Secret" -msgstr "Goodreads API Secreto" +msgstr "Senha API Goodreads" #: cps/templates/config_edit.html:169 msgid "Allow Reverse Proxy Authentication" -msgstr "Permitir a Autenticação por Proxy Reversa" +msgstr "Permitir a Autenticação por Proxy Reverso" #: cps/templates/config_edit.html:180 msgid "Login type" @@ -2039,15 +2225,15 @@ msgstr "Tipo de Login" #: cps/templates/config_edit.html:182 msgid "Use Standard Authentication" -msgstr "Usar autenticação padrão" +msgstr "Usar Autenticação padrão" #: cps/templates/config_edit.html:184 msgid "Use LDAP Authentication" -msgstr "Usar autenticação LDAP" +msgstr "Usar Autenticação LDAP" #: cps/templates/config_edit.html:187 msgid "Use OAuth" -msgstr "Use OAuth" +msgstr "Usar OAuth" #: cps/templates/config_edit.html:194 msgid "LDAP Server Host Name or IP Address" @@ -2061,11 +2247,6 @@ msgstr "Porta do servidor LDAP" msgid "LDAP Encryption" msgstr "Criptografia LDAP" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Nenhum" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2076,15 +2257,15 @@ msgstr "SSL" #: cps/templates/config_edit.html:210 msgid "LDAP CACertificate Path (Only needed for Client Certificate Authentication)" -msgstr "LDAP CACertificate Path (Somente necessário para Autenticação de Certificado de Cliente)" +msgstr "Caminho do CACertificate LDAP (Necessário apenas para autenticação de certificado de cliente)" #: cps/templates/config_edit.html:217 msgid "LDAP Certificate Path (Only needed for Client Certificate Authentication)" -msgstr "LDAP Certificate Path (Somente necessário para Autenticação de Certificado de Cliente)" +msgstr "Caminho do Certificado LDAP (Necessário apenas para autenticação de certificado de cliente)" #: cps/templates/config_edit.html:224 msgid "LDAP Keyfile Path (Only needed for Client Certificate Authentication)" -msgstr "LDAP Keyfile Path (Somente necessário para Autenticação de Certificado de Cliente)" +msgstr "Caminho do Keyfile LDAP (Necessário apenas para autenticação de certificado de cliente)" #: cps/templates/config_edit.html:233 msgid "LDAP Authentication" @@ -2112,19 +2293,19 @@ msgstr "Senha de Administrador LDAP" #: cps/templates/config_edit.html:253 msgid "LDAP Distinguished Name (DN)" -msgstr "Nome distinto LDAP (DN)" +msgstr "Nome Distinto LDAP (DN)" #: cps/templates/config_edit.html:257 msgid "LDAP User Object Filter" -msgstr "Filtro de objeto do usuário LDAP" +msgstr "Filtro de Objeto do Usuário LDAP" #: cps/templates/config_edit.html:262 msgid "LDAP Server is OpenLDAP?" -msgstr "O LDAP Server é OpenLDAP?" +msgstr "O Servidor LDAP é OpenLDAP?" #: cps/templates/config_edit.html:264 msgid "Following Settings are Needed For User Import" -msgstr "As seguintes configurações são necessárias para a importação do usuário" +msgstr "As seguintes configurações são necessárias para a mportação de Usuários" #: cps/templates/config_edit.html:266 msgid "LDAP Group Object Filter" @@ -2157,7 +2338,7 @@ msgstr "Filtro de Utilizador Membro LDAP" #: cps/templates/config_edit.html:297 #, python-format msgid "Obtain %(provider)s OAuth Credential" -msgstr "Obtenha a credencial OAuth de %(provider)s" +msgstr "Obter credenciais OAuth de %(provider)s" #: cps/templates/config_edit.html:300 #, python-format @@ -2167,7 +2348,7 @@ msgstr "ID do cliente OAuth de %(provider)s" #: cps/templates/config_edit.html:304 #, python-format msgid "%(provider)s OAuth Client Secret" -msgstr "%(provider)s Cliente segredo do OAuth" +msgstr "Senha do cliente Oauth de %(provider)s" #: cps/templates/config_edit.html:320 msgid "External binaries" @@ -2179,7 +2360,7 @@ msgstr "Caminho para o Calibre E-Book Converter" #: cps/templates/config_edit.html:334 msgid "Calibre E-Book Converter Settings" -msgstr "Configurações do conversor de E-Book Calibre" +msgstr "Configurações do Calibre E-Book Converter" #: cps/templates/config_edit.html:337 msgid "Path to Kepubify E-Book Converter" @@ -2187,11 +2368,11 @@ msgstr "Caminho para Kepubify E-Book Converter" #: cps/templates/config_edit.html:345 msgid "Location of Unrar binary" -msgstr "Localização do binário Unrar" +msgstr "Caminho para o binário Unrar" #: cps/templates/config_view_edit.html:17 msgid "View Configuration" -msgstr "Ver configuração" +msgstr "Configuração de Visualização" #: cps/templates/config_view_edit.html:32 msgid "No. of Random Books to Display" @@ -2199,9 +2380,9 @@ msgstr "Nº de Livros Aleatórios a Exibir" #: cps/templates/config_view_edit.html:36 msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" -msgstr "Nº de Autores a Exibir Antes de Esconder (0=Esconder Desativado)" +msgstr "Nº de Autores a Exibir Antes de Esconder (0=Desativar Esconder)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Tema" @@ -2211,7 +2392,7 @@ msgstr "Tema Padrão" #: cps/templates/config_view_edit.html:43 msgid "caliBlur! Dark Theme" -msgstr "caliBlur! Tema Negro" +msgstr "Tema caliBlur! Dark" #: cps/templates/config_view_edit.html:47 msgid "Regular Expression for Ignoring Columns" @@ -2219,7 +2400,7 @@ msgstr "Expressão Regular para Ignorar Colunas" #: cps/templates/config_view_edit.html:51 msgid "Link Read/Unread Status to Calibre Column" -msgstr "Ligar o estado de leitura/análise à coluna Calibre" +msgstr "Ligar Lido/Não Lido à coluna Calibre" #: cps/templates/config_view_edit.html:60 msgid "View Restrictions based on Calibre column" @@ -2227,149 +2408,151 @@ msgstr "Exibir restrições com base na coluna Calibre" #: cps/templates/config_view_edit.html:69 msgid "Regular Expression for Title Sorting" -msgstr "Expressão regular para classificação de títulos" +msgstr "Expressão regular para ordenação de Títulos" #: cps/templates/config_view_edit.html:80 msgid "Default Settings for New Users" -msgstr "Configurações padrão para novos usuários" +msgstr "Configuração padrão para novos usuários" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Usuário Admin" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Permitir Downloads" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" -msgstr "Permitir que o eBook Viewer" +msgstr "Permitir Visualizador de eBook" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Permitir Uploads" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Permitir Editar" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" -msgstr "Permitir Livros Excluídos" +msgstr "Permitir Apagar Livros" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" -msgstr "Permitir mudança de senha" +msgstr "Permitir Alterar Senha" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" -msgstr "Permitir a Edição de Prateleiras Públicas" +msgstr "Permitir a Edição de Estantes Públicas" -#: cps/templates/config_view_edit.html:119 -#, fuzzy +#: cps/templates/config_view_edit.html:123 msgid "Default Language" -msgstr "Excluir idiomas" +msgstr "Idioma Padrão" -#: cps/templates/config_view_edit.html:127 -#, fuzzy +#: cps/templates/config_view_edit.html:131 msgid "Default Visible Language of Books" -msgstr "Língua dos Livros" +msgstr "Idioma Padrão dos Livros Visíveis" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" -msgstr "Visibilidades por defeito para novos utilizadores" +msgstr "Visibilidade Padrão para Novos Usuários" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" -msgstr "Mostrar Livros Aleatórios em Vista de Detalhe" +msgstr "Mostrar Livros Aleatórios em Visualização de Detalhes" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" -msgstr "Adicionar Etiquetas permitidas/negadas" +msgstr "Adicionar Tags Permitidas/Negadas" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" -msgstr "Adicionar valores permitidos/negados da coluna personalizada" +msgstr "Adicionar Valores Permitidos/Negados de Coluna Personalizada" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Ler no Browser" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Ouvir no Browser" -#: cps/templates/detail.html:124 -#, fuzzy, python-format +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 +#, python-format msgid "Book %(index)s of %(range)s" -msgstr "" +msgstr "Livro %(index)s de %(range)s" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Publicado em" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" -msgstr "Marcar como não lido" +msgstr "Marcar como Não Lido" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" -msgstr "Marcar como lido" +msgstr "Marcar como Lido" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Lido" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Restaurar do arquivo" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Adicionar ao arquivo" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" -msgstr "Arquivado em" +msgstr "Arquivado" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Descrição:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Adicionar à estante" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Público)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Editar Metadados" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" -msgstr "" +msgid "Email Account Type" +msgstr "Escolha o Tipo do Servidor" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" -msgstr "" +#, fuzzy +msgid "Standard Email Account" +msgstr "Use Conta de E-Mail Padrão" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "" +#, fuzzy +msgid "Gmail Account" +msgstr "Escolha o Tipo do Servidor" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" -msgstr "" +msgstr "Revogar Acesso ao GMail" #: cps/templates/email_edit.html:42 msgid "STARTTLS" @@ -2385,20 +2568,21 @@ msgstr "Senha SMTP" #: cps/templates/email_edit.html:58 msgid "Attachment Size Limit" -msgstr "Limite do tamanho do anexo" +msgstr "Limite do Tamanho do Anexo" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Salvar e enviar e-mail de teste" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Voltar" #: cps/templates/email_edit.html:74 msgid "Allowed Domains (Whitelist)" -msgstr "Domínios Permitidos (Whitelist)" +msgstr "Domínios Permitidos (Lista Branca)" #: cps/templates/email_edit.html:78 cps/templates/email_edit.html:105 msgid "Add Domain" @@ -2407,7 +2591,7 @@ msgstr "Adicionar Domínio" #: cps/templates/email_edit.html:81 cps/templates/email_edit.html:108 #: cps/templates/user_table.html:27 msgid "Add" -msgstr "Adicione" +msgstr "Adicionar" #: cps/templates/email_edit.html:86 cps/templates/email_edit.html:96 msgid "Enter domainname" @@ -2415,50 +2599,65 @@ msgstr "Digite o nome do domínio" #: cps/templates/email_edit.html:92 msgid "Denied Domains (Blacklist)" -msgstr "Domínios negados (Blacklist)" +msgstr "Domínios Negados (Lista Negra)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Próximo" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "Abra o arquivo .kobo/Kobo eReader.conf em um editor de texto e adicione (ou edite):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Abra o arquivo .kobo/Kobo/Kobo eReader.conf em um editor de texto e adicione (ou edite):" -#: cps/templates/http_error.html:31 -#, fuzzy +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "Token Kobo:" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "Lista" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" -msgstr "O servidor de E-Mail não está configurado, por favor contacte o seu administrador!" +msgstr "Instancia do Calibre-Web não configurado, por favor contacte o seu administrador" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" -msgstr "Criar Edição" +msgstr "Criar Issue" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" -msgstr "Voltar para casa" +msgstr "Voltar para Início" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" -msgstr "" +msgstr "Deslogar" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "Ordenar em ordem crescente de acordo com a contagem de downloads" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "Ordenar em ordem decrescente de acordo com a contagem de downloads" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" -msgstr "Ordenar os autores em ordem alfabética" +msgstr "Ordenar Autores em ordem alfabética" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" -msgstr "Ordenar os autores em ordem alfabética inversa" +msgstr "Ordenar Autores em ordem alfabética inversa" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" -msgstr "Ordenar ascendente de acordo com o índice de série" +msgstr "Ordenar em ordem crescente de acordo com o índice de série" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" -msgstr "Ordenação decrescente de acordo com o índice de série" +msgstr "Ordenação em ordem decrescente de acordo com o índice de série" #: cps/templates/index.xml:6 msgid "Start" @@ -2466,11 +2665,11 @@ msgstr "Início" #: cps/templates/index.xml:18 msgid "Alphabetical Books" -msgstr "" +msgstr "Livros Alfabéticos" #: cps/templates/index.xml:22 msgid "Books sorted alphabetically" -msgstr "" +msgstr "Livros ordenados alfabeticamente" #: cps/templates/index.xml:29 msgid "Popular publications from this catalog based on Downloads." @@ -2478,7 +2677,7 @@ msgstr "Publicações populares deste catálogo baseadas em Downloads." #: cps/templates/index.xml:36 msgid "Popular publications from this catalog based on Rating." -msgstr "Publicações populares deste catálogo baseadas em Rating." +msgstr "Publicações populares deste catálogo baseadas em Avaliação." #: cps/templates/index.xml:39 msgid "Recently added Books" @@ -2494,11 +2693,11 @@ msgstr "Livros Aleatórios" #: cps/templates/index.xml:73 msgid "Books ordered by Author" -msgstr "Livros encomendados pelo Autor" +msgstr "Livros ordenados por Autor" #: cps/templates/index.xml:80 msgid "Books ordered by publisher" -msgstr "Livros encomendados pela editora" +msgstr "Livros ordenados por editora" #: cps/templates/index.xml:87 msgid "Books ordered by category" @@ -2506,105 +2705,109 @@ msgstr "Livros ordenados por categoria" #: cps/templates/index.xml:94 msgid "Books ordered by series" -msgstr "Livros encomendados por série" +msgstr "Livros ordenados por série" #: cps/templates/index.xml:101 msgid "Books ordered by Languages" -msgstr "Livros encomendados por Idiomas" +msgstr "Livros ordenados por Idiomas" #: cps/templates/index.xml:108 msgid "Books ordered by Rating" -msgstr "Livros encomendados por Rating" +msgstr "Livros ordenados por Avaliação" #: cps/templates/index.xml:116 msgid "Books ordered by file formats" msgstr "Livros ordenados por formatos de arquivo" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" -msgstr "Prateleiras" +msgstr "Estantes" #: cps/templates/index.xml:123 msgid "Books organized in shelves" -msgstr "Livros organizados em prateleiras" +msgstr "Livros organizados em Estantes" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Início" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" -msgstr "Alternar a navegação" +msgstr "Alternar Navegação" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" -msgstr "Biblioteca de Pesquisa" +msgstr "Pesquisar na Biblioteca" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Enviando..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Erro" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Upload feito, processando, por favor aguarde ..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Configurações" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Conta" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Sair" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Enviando..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Erro" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Upload concluído, processando, por favor aguarde ..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Configurações" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Por favor, não atualize a página" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Navegue em" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Sobre" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Anterior" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Detalhes do Livro" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "Grade" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Lembre-se de mim" #: cps/templates/login.html:23 msgid "Forgot Password?" -msgstr "Esqueceu-se da senha?" +msgstr "Esqueceu a senha?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Entre com o Magic Link" #: cps/templates/logviewer.html:6 msgid "Show Calibre-Web Log: " -msgstr "Mostrar Calibre-Web Log: " +msgstr "Mostrar Log Calibre-Web: " #: cps/templates/logviewer.html:8 msgid "Calibre-Web Log: " -msgstr "Calibre-Web Log: " +msgstr "Log Calibre-Web: " #: cps/templates/logviewer.html:8 msgid "Stream output, can't be displayed" @@ -2612,31 +2815,31 @@ msgstr "Saída do fluxo, não pode ser exibida" #: cps/templates/logviewer.html:12 msgid "Show Access Log: " -msgstr "Mostrar registo de acesso: " +msgstr "Mostrar Log de Acesso: " #: cps/templates/logviewer.html:18 msgid "Download Calibre-Web Log" -msgstr "Baixar Calibre-Web Log" +msgstr "Baixar Log Calibre-Web" #: cps/templates/logviewer.html:21 msgid "Download Access Log" -msgstr "Download do Log de Acesso" +msgstr "Baixar Log de Acesso" #: cps/templates/modal_dialogs.html:6 msgid "Select Allowed/Denied Tags" -msgstr "Selecione Etiquetas permitidas/negadas" +msgstr "Selecione Tags Permitidas/Negadas" #: cps/templates/modal_dialogs.html:7 msgid "Select Allowed/Denied Custom Column Values" -msgstr "Selecione Valores Permitidos/Não Permitidos da Coluna Personalizada" +msgstr "Selecione Valores Permitidos/Negadaos da Coluna Personalizada" #: cps/templates/modal_dialogs.html:8 msgid "Select Allowed/Denied Tags of User" -msgstr "Selecione Etiquetas de usuário permitidas/negadas" +msgstr "Selecione Tags de usuário Permitidas/Negadas" #: cps/templates/modal_dialogs.html:9 msgid "Select Allowed/Denied Custom Column Values of User" -msgstr "Selecione Valores de Coluna Personalizada Permitidos/Denegados do Usuário" +msgstr "Selecione Valores de Coluna Personalizada Permitidos/Negados do Usuário" #: cps/templates/modal_dialogs.html:15 msgid "Enter Tag" @@ -2644,15 +2847,15 @@ msgstr "Digite a tag" #: cps/templates/modal_dialogs.html:24 msgid "Add View Restriction" -msgstr "Adicionar restrição de visualização" +msgstr "Adicionar Restrição de Visualização" #: cps/templates/modal_dialogs.html:50 msgid "This book format will be permanently erased from database" -msgstr "Este formato de livro será permanentemente apagado da base de dados" +msgstr "Este formato de livro será apagado permanentemente do banco de dados" #: cps/templates/modal_dialogs.html:51 msgid "This book will be permanently erased from database" -msgstr "Este livro será apagado permanentemente da base de dados" +msgstr "Este livro será apagado permanentemente do banco de dados" #: cps/templates/modal_dialogs.html:52 msgid "and hard disk" @@ -2660,7 +2863,7 @@ msgstr "e disco rígido" #: cps/templates/modal_dialogs.html:56 msgid "Important Kobo Note: deleted books will remain on any paired Kobo device." -msgstr "Nota importante Kobo Nota: os livros apagados permanecerão em qualquer dispositivo Kobo emparelhado." +msgstr "Nota importante Kobo: os livros apagados permanecerão em qualquer dispositivo Kobo emparelhado." #: cps/templates/modal_dialogs.html:57 msgid "Books must first be archived and the device synced before a book can safely be deleted." @@ -2668,7 +2871,7 @@ msgstr "Os livros devem primeiro ser arquivados e o dispositivo deve ser sincron #: cps/templates/modal_dialogs.html:76 msgid "Choose File Location" -msgstr "Escolha a localização do arquivo" +msgstr "Escolha a Localização do Arquivo" #: cps/templates/modal_dialogs.html:82 msgid "type" @@ -2684,165 +2887,171 @@ msgstr "tamanho" #: cps/templates/modal_dialogs.html:90 msgid "Parent Directory" -msgstr "Diretório dos Pais" +msgstr "Diretório Acima" #: cps/templates/modal_dialogs.html:98 msgid "Select" msgstr "Selecione" -#: cps/templates/modal_dialogs.html:134 -#, fuzzy +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 msgid "Ok" -msgstr "Livro" +msgstr "Ok" #: cps/templates/osd.xml:5 msgid "Calibre-Web eBook Catalog" msgstr "Catálogo de e-books Calibre-Web" #: cps/templates/read.html:6 -#, fuzzy msgid "epub Reader" -msgstr "leitor de PDF" +msgstr "leitor de epub" -#: cps/templates/read.html:74 -msgid "Reflow text when sidebars are open." -msgstr "Refluxo de texto quando as barras laterais estão abertas." - -#: cps/templates/readcbr.html:7 -#, fuzzy -msgid "Comic Reader" -msgstr "leitor de PDF" - -#: cps/templates/readcbr.html:89 -msgid "Keyboard Shortcuts" -msgstr "Atalhos de Teclado" - -#: cps/templates/readcbr.html:92 -msgid "Previous Page" -msgstr "Página Anterior" - -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 -msgid "Next Page" -msgstr "Página seguinte" - -#: cps/templates/readcbr.html:94 -msgid "Scale to Best" -msgstr "Escala ao Melhor" - -#: cps/templates/readcbr.html:95 -msgid "Scale to Width" -msgstr "Escala à Largura" - -#: cps/templates/readcbr.html:96 -msgid "Scale to Height" -msgstr "Escala à Altura" - -#: cps/templates/readcbr.html:97 -msgid "Scale to Native" -msgstr "Escala para Nativo" - -#: cps/templates/readcbr.html:98 -msgid "Rotate Right" -msgstr "Rodar para a direita" - -#: cps/templates/readcbr.html:99 -msgid "Rotate Left" -msgstr "Rodar para a esquerda" - -#: cps/templates/readcbr.html:100 -msgid "Flip Image" -msgstr "Flip Image" - -#: cps/templates/readcbr.html:116 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 msgid "Light" -msgstr "Luz" +msgstr "Claro" -#: cps/templates/readcbr.html:117 +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 msgid "Dark" msgstr "Escuro" -#: cps/templates/readcbr.html:122 -msgid "Scale" -msgstr "Balança" +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "Sépia" + +#: cps/templates/read.html:84 +msgid "Black" +msgstr "Preto" + +#: cps/templates/read.html:88 +msgid "Reflow text when sidebars are open." +msgstr "Refluir o texto quando as barras laterais estiverem abertas." + +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + +#: cps/templates/readcbr.html:7 +msgid "Comic Reader" +msgstr "Leitor de Quadrinhos" + +#: cps/templates/readcbr.html:92 +msgid "Keyboard Shortcuts" +msgstr "Atalhos de Teclado" + +#: cps/templates/readcbr.html:95 +msgid "Previous Page" +msgstr "Página Anterior" + +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 +msgid "Next Page" +msgstr "Página seguinte" + +#: cps/templates/readcbr.html:97 +msgid "Scale to Best" +msgstr "Dimensionar para Melhor" + +#: cps/templates/readcbr.html:98 +msgid "Scale to Width" +msgstr "Dimensionar para Largura" + +#: cps/templates/readcbr.html:99 +msgid "Scale to Height" +msgstr "Dimensionar para Altura" + +#: cps/templates/readcbr.html:100 +msgid "Scale to Native" +msgstr "Dimensionar para a Nativo" + +#: cps/templates/readcbr.html:101 +msgid "Rotate Right" +msgstr "Girar para direita" + +#: cps/templates/readcbr.html:102 +msgid "Rotate Left" +msgstr "Girar para esqueda" + +#: cps/templates/readcbr.html:103 +msgid "Flip Image" +msgstr "Inverter Imagem" #: cps/templates/readcbr.html:125 +msgid "Scale" +msgstr "Dimensionar" + +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Melhor" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Largura" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Altura" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Nativo" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Rodar" -#: cps/templates/readcbr.html:144 -msgid "Flip" -msgstr "Flip" - #: cps/templates/readcbr.html:147 +msgid "Flip" +msgstr "Inverter" + +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Horizontal" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Vertical" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Direção" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Esquerda para a direita" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" -msgstr "Da direita para a esquerda" +msgstr "Direita para a esquerda" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" -msgstr "" +msgstr "Redefinir para o topo" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" -msgstr "" - -#: cps/templates/readcbr.html:171 -msgid "Scrollbar" -msgstr "" +msgstr "Lembrar Posição" #: cps/templates/readcbr.html:174 -msgid "Show" -msgstr "" +msgid "Scrollbar" +msgstr "Barra de Rolagem" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:177 +msgid "Show" +msgstr "Mostrar" + +#: cps/templates/readcbr.html:178 msgid "Hide" -msgstr "" +msgstr "Esconder" #: cps/templates/readdjvu.html:5 -#, fuzzy msgid "DJVU Reader" -msgstr "leitor de PDF" +msgstr "leitor de DJVU" -#: cps/templates/readpdf.html:29 -#, fuzzy +#: cps/templates/readpdf.html:32 msgid "PDF Reader" -msgstr "leitor de PDF" +msgstr "Leitor de PDF" #: cps/templates/readtxt.html:6 -#, fuzzy msgid "txt Reader" -msgstr "leitor de PDF" +msgstr "Leitor de TXT" #: cps/templates/register.html:4 msgid "Register New Account" @@ -2853,12 +3062,12 @@ msgid "Choose a username" msgstr "Escolha um nome de usuário" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Seu endereço de e-mail" #: cps/templates/remote_login.html:5 msgid "Magic Link - Authorise New Device" -msgstr "Magic Link - Autorizar novo dispositivo" +msgstr "Magic Link - Autorizar Novo Dispositivo" #: cps/templates/remote_login.html:7 msgid "On another device, login and visit:" @@ -2870,17 +3079,21 @@ msgstr "Uma vez verificado, você será automaticamente conectado a este disposi #: cps/templates/remote_login.html:14 msgid "This verification link will expire in 10 minutes." -msgstr "Este link de verificação expirará dentro de 10 minutos." +msgstr "Este link de verificação irá expirar em 10 minutos." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "Gerar miniaturas de capa de Série" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Nenhum resultado encontrado" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Termo de busca:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Resultados para:" @@ -2892,22 +3105,17 @@ msgstr "Data de Publicação de" msgid "Published Date To" msgstr "Data de Publicação Até" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "Ler Estado" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" -msgstr "Excluir Etiquetas" +msgstr "Excluir Tags" #: cps/templates/search_form.html:77 msgid "Exclude Series" msgstr "Excluir Série" #: cps/templates/search_form.html:95 -#, fuzzy msgid "Exclude Shelves" -msgstr "Excluir Série" +msgstr "Excluir Estante" #: cps/templates/search_form.html:115 msgid "Exclude Languages" @@ -2923,51 +3131,47 @@ msgstr "Excluir extensões" #: cps/templates/search_form.html:144 msgid "Rating Above" -msgstr "Classificação Acima" +msgstr "Avaliação Acima" #: cps/templates/search_form.html:148 msgid "Rating Below" -msgstr "Classificação Abaixo" +msgstr "Avaliação Abaixo" #: cps/templates/search_form.html:180 msgid "From:" -msgstr "" +msgstr "De:" #: cps/templates/search_form.html:190 msgid "To:" -msgstr "" +msgstr "Para:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" -msgstr "Excluir esta estante" - -#: cps/templates/shelf.html:12 -msgid "Edit Shelf Properties" -msgstr "Editar as propriedades da estante" +msgstr "Apagar esta estante" #: cps/templates/shelf.html:14 +msgid "Edit Shelf Properties" +msgstr "Editar Propriedades da Estante" + +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "Organizar os livros manualmente" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" -msgstr "Desativar ordem de modificação" +msgstr "Desabilitar Alterar Ordem" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" -msgstr "Habilitar ordem de modificação" - -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "A estante será excluída para todos os usuários" +msgstr "Habilitar Alterar Ordem" #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" -msgstr "Partilhar com Todos" +msgstr "Compartilhar com Todos" #: cps/templates/shelf_edit.html:21 msgid "Sync this shelf with Kobo device" -msgstr "" +msgstr "sincronizar esta Estante com o Dispositivo Kobo" #: cps/templates/shelf_order.html:5 msgid "Drag to Rearrange Order" @@ -3002,8 +3206,8 @@ msgid "System Statistics" msgstr "Estatísticas do Sistema" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Biblioteca de programas" +msgid "Program" +msgstr "Programa" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3029,9 +3233,17 @@ msgstr "Progresso" msgid "Run Time" msgstr "Tempo de execução" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Hora de início" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "Ações" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "Esta tarefa será cancelada. Qualquer progresso feito por esta tarefa será salvo." + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "Se esta for uma tarefa agendada, ela será executada novamente durante o próximo horário agendado." #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3039,7 +3251,7 @@ msgstr "Redefinir senha do usuário" #: cps/templates/user_edit.html:43 msgid "Language of Books" -msgstr "Língua dos Livros" +msgstr "Idioma dos Livros" #: cps/templates/user_edit.html:54 msgid "OAuth Settings" @@ -3051,133 +3263,121 @@ msgstr "Link" #: cps/templates/user_edit.html:58 msgid "Unlink" -msgstr "Desbloqueio" +msgstr "Desvincular" #: cps/templates/user_edit.html:64 msgid "Kobo Sync Token" -msgstr "Kobo Sync Token" +msgstr "Token de Sincronização Kobo" #: cps/templates/user_edit.html:66 msgid "Create/View" msgstr "Criar/Ver" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "Forçar sincronização completa Kobo" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" -msgstr "Adicionar valores permitidos/definidos da coluna personalizada" +msgstr "Adicionar valores Permitidos/Negados da coluna personalizada" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" -msgstr "" +msgstr "Sincronizar apenas livros em estantes selecionadas com Kobo" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" -msgstr "Eliminar Utilizador" +msgstr "Apagar Usuário" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" -msgstr "Gerar o Kobo Auth URL" +msgstr "Gerar URL de Autenticação Kobo" #: cps/templates/user_table.html:80 cps/templates/user_table.html:103 -#, fuzzy msgid "Select..." -msgstr "Selecione" +msgstr "Selecione..." #: cps/templates/user_table.html:131 -#, fuzzy msgid "Edit User" -msgstr "Usuário Admin" +msgstr "Editar Usuário" #: cps/templates/user_table.html:134 -#, fuzzy msgid "Enter Username" msgstr "Escolha um nome de usuário" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "Seu endereço de e-mail" - -#: cps/templates/user_table.html:136 -#, fuzzy -msgid "Enter Kindle E-mail Address" -msgstr "Enviar para o endereço de e-mail do Kindle" - -#: cps/templates/user_table.html:136 -#, fuzzy -msgid "Kindle E-mail" +msgid "Enter Email" msgstr "E-mail de teste" -#: cps/templates/user_table.html:137 +#: cps/templates/user_table.html:136 #, fuzzy +msgid "Enter eReader Email" +msgstr "Enviar para o endereço de e-mail do E-Reader" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "eReader Email" +msgstr "E-mail do E-Reader" + +#: cps/templates/user_table.html:137 msgid "Locale" -msgstr "Balança" +msgstr "Idioma" #: cps/templates/user_table.html:138 msgid "Visible Book Languages" -msgstr "" +msgstr "Idiomas dos Livros Visíveis" #: cps/templates/user_table.html:139 -#, fuzzy msgid "Edit Allowed Tags" -msgstr "Selecione Etiquetas permitidas/negadas" +msgstr "Editar Tags Permitidas" #: cps/templates/user_table.html:139 msgid "Allowed Tags" -msgstr "" +msgstr "Tags Permitidas" #: cps/templates/user_table.html:140 -#, fuzzy msgid "Edit Denied Tags" -msgstr "Selecione Etiquetas permitidas/negadas" +msgstr "Editar Tags Não Permitidas" #: cps/templates/user_table.html:140 msgid "Denied Tags" -msgstr "" +msgstr "Tags Não Permitidas" #: cps/templates/user_table.html:141 -#, fuzzy msgid "Edit Allowed Column Values" -msgstr "Adicionar valores permitidos/negados da coluna personalizada" +msgstr "Editar Valores de Coluna Permitidos" #: cps/templates/user_table.html:141 -#, fuzzy msgid "Allowed Column Values" -msgstr "Adicionar valores permitidos/negados da coluna personalizada" +msgstr "Valores de Coluna Permitidos" #: cps/templates/user_table.html:142 -#, fuzzy msgid "Edit Denied Column Values" -msgstr "Adicionar valores permitidos/negados da coluna personalizada" +msgstr "Editar Valores de Coluna Não Permitidos" #: cps/templates/user_table.html:142 -#, fuzzy msgid "Denied Column Values" -msgstr "Adicionar valores permitidos/negados da coluna personalizada" +msgstr "Valores de Coluna Não Permitidos" #: cps/templates/user_table.html:144 -#, fuzzy msgid "Change Password" -msgstr "Permitir mudança de senha" +msgstr "Alterar senha" #: cps/templates/user_table.html:147 msgid "View" -msgstr "" +msgstr "Ver" #: cps/templates/user_table.html:150 -#, fuzzy msgid "Edit Public Shelves" -msgstr "Estante Pública" +msgstr "Editar Estantes Públicas" #: cps/templates/user_table.html:152 msgid "Sync selected Shelves with Kobo" -msgstr "" +msgstr "Sincronizar Estantes Selecionadas com Kobo" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" -msgstr "Mostrar selecção de séries" - -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Mostrar livros aleatórios" +msgid "Show Read/Unread Section" +msgstr "Mostrar seleção de lidos/não lidos" diff --git a/cps/translations/ru/LC_MESSAGES/messages.mo b/cps/translations/ru/LC_MESSAGES/messages.mo index f712f2a54..4b7e74d47 100644 Binary files a/cps/translations/ru/LC_MESSAGES/messages.mo and b/cps/translations/ru/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/ru/LC_MESSAGES/messages.po b/cps/translations/ru/LC_MESSAGES/messages.po index 705c61ff6..a9847a367 100644 --- a/cps/translations/ru/LC_MESSAGES/messages.po +++ b/cps/translations/ru/LC_MESSAGES/messages.po @@ -8,589 +8,646 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2020-04-29 01:20+0400\n" "Last-Translator: ZIZA\n" "Language: ru\n" "Language-Team: \n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "не установлено" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "установлено" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Статистика" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Сервер перезагружен, пожалуйста, обновите страницу" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Производится остановка сервера, пожалуйста, закройте окно" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Успешно переподключено" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Неизвестная команда" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Книга успешно поставлена в очередь для отправки на %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Неизвестно" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Администрирование" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Настройки сервера" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Настройка интерфейса" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" msgstr "Управление сервером" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Все" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Показать все" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Конфигурация Calibre-Web обновлена" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "Вы действительно хотите удалить Kobo Token ?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Вы действительно хотите удалить эту книжную полку?" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Вы действительно хотите удалить эту книжную полку?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Вы действительно хотите удалить эту книжную полку?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Вы действительно хотите удалить эту книжную полку?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "Вы действительно хотите остановить Calibre-Web?" -#: cps/admin.py:741 -msgid "Tag not found" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Запретить" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Разрешить" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json не настроен для веб-приложения" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "Неправильное расположение файла журнала, пожалуйста, введите правильный путь." -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "Недопустимое расположение файла журнала доступа, пожалуйста, введите правильный путь" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Пожалуйста, введите провайдера LDAP, порт, DN и идентификатор объекта пользователя" -#: cps/admin.py:1102 +#: cps/admin.py:1191 #, fuzzy msgid "Please Enter a LDAP Service Account and Password" msgstr "Пожалуйста, введите действительное имя пользователя для сброса пароля" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "Фильтр объектов группы LDAP должен иметь один идентификатор формата \"%s\"" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "Фильтр объектов группы LDAP имеет незавершённые круглые скобки" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "Фильтр объектов пользователя LDAP должен иметь один идентификатор формата \"%s\"" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "Фильтр объектов пользователя LDAP имеет незавершенную круглую скобку" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "Добавить нового пользователя" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "Расположение Базы Данных неверно, пожалуйста, введите правильный путь." - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "Расположение ключевого файла неверно, пожалуйста, введите правильный путь" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "Расположение Certfile не является действительным, пожалуйста, введите правильный путь" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "Настройки E-mail сервера обновлены" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Дополнительный Настройки" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Пожалуйста, заполните все поля!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "E-mail не из существующей доменной зоны" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "Добавить пользователя" - -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Пользователь '%(user)s' добавлен" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Для этого адреса электронной почты или логина уже есть учётная запись." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Пользователь '%(nick)s' удалён" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Это последний администратор, невозможно удалить пользователя" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Изменить пользователя %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Пользователь '%(nick)s' обновлён" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Неизвестная ошибка. Попробуйте позже." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Изменить настройки SMTP" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "" + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Произошла ошибка при отправке тестового письма на: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Пожалуйста, сначала настройте свой адрес электронной почты ..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "Настройки E-mail сервера обновлены" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Неизвестная ошибка. Попробуйте позже." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Изменить пользователя %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Пароль для пользователя %(user)s сброшен" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Пожалуйста, сперва настройте параметры SMTP....." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Просмотр лога" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Проверка обновлений" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Загрузка обновлений" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Распаковка обновлений" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Замена файлов" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Соединения с базой данных закрыты" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Остановка сервера" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Обновления установлены, нажмите ок и перезагрузите страницу" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Ошибка обновления:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "Ошибка HTTP" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Ошибка соединения" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Тайм-аут при установлении соединения" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Общая ошибка" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "Не удалось сохранить файл обновления во временной папке." -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 #, fuzzy msgid "Failed to extract at least One LDAP User" msgstr "Не удалось создать хотя бы одного пользователя LDAP" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "Не удалось создать хотя бы одного пользователя LDAP" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Ошибка: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Ошибка: ни одного пользователя не найдено в ответ на запрос сервер LDAP" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "По крайней мере, один пользователь LDAP не найден в базе данных" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "" -#: cps/converter.py:30 -msgid "not configured" -msgstr "не настроено" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "Расположение Базы Данных неверно, пожалуйста, введите правильный путь." + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "Расположение ключевого файла неверно, пожалуйста, введите правильный путь" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "Расположение Certfile не является действительным, пожалуйста, введите правильный путь" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "Настройки E-mail сервера обновлены" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Дополнительный Настройки" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Пожалуйста, заполните все поля!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "E-mail не из существующей доменной зоны" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Добавить пользователя" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Пользователь '%(user)s' добавлен" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Для этого адреса электронной почты или логина уже есть учётная запись." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Пользователь '%(nick)s' удалён" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Это последний администратор, невозможно удалить пользователя" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Пользователь '%(nick)s' обновлён" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "не установлено" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Нет" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Невозможно открыть книгу. Файл не существует или недоступен" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "изменить метаданные" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s не допустимый язык" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "Запрещена загрузка файлов с расширением '%(ext)s'" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Загружаемый файл должен иметь расширение" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Ошибка при создании пути %(path)s (Доступ запрещён)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Не удалось сохранить файл %(file)s." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Формат файла %(ext)s добавлен в %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Метаданные обновлены" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Ошибка редактирования книги. Пожалуйста, проверьте лог-файл для дополнительной информации" - -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Загруженная книга, вероятно, существует в библиотеке, перед тем как загрузить новую, рассмотрите возможность изменения: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "Файл %(filename)s не удалось сохранить во временную папку" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" msgstr "" -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Файл %(file)s загружен" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Исходный или целевой формат для конвертирования отсутствует" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Книга успешно поставлена в очередь для конвертирования в %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Произошла ошибка при конвертирования этой книги: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Загруженная книга, вероятно, существует в библиотеке, перед тем как загрузить новую, рассмотрите возможность изменения: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s не допустимый язык" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Запрещена загрузка файлов с расширением '%(ext)s'" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Загружаемый файл должен иметь расширение" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Файл %(filename)s не удалось сохранить во временную папку" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "изменить метаданные" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Ошибка при создании пути %(path)s (Доступ запрещён)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Не удалось сохранить файл %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Формат файла %(ext)s добавлен в %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Настройка Google Drive не завершена, попробуйте деактивировать и снова активировать Google Drive" @@ -604,166 +661,179 @@ msgstr "Не удалось проверить домен обратного в msgid "%(format)s format not found for book id: %(book)d" msgstr "%(format)s форма не найден для книги с id: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s не найден на Google Drive: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s не найден: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Отправить на Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Это электронное письмо было отправлено через Caliber-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Тестовый e-mail для Calibre-Web" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Тестовый e-mail" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Начать работу с Calibre-Web" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Регистрационный e-mail для пользователя: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "Преобразовать %(orig)s в %(format)s и отправить в Kindle" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "Отправить %(format)s в Kindle" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Отправить на Kindle" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Запрашиваемый файл не может быть прочитан. Возможно у вас нет разрешения?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "Переименовывание заголовка с: '%(src)s' на '%(dest)s' не удалось из-за ошибки: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Не удалось переименовать файл по пути '%(src)s' to '%(dest)s' из-за ошибки: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Файл %(file)s не найден на Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Переименовывание заголовка с: '%(src)s' на '%(dest)s' не удалось из-за ошибки: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Путь книги %(path)s не найден на Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Этот адрес электронной почты уже зарегистрирован." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Это имя пользователя уже занято" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Не удалось создать путь для обложки." -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Только файлы в формате jpg / jpeg поддерживаются как файл обложки" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +msgid "Error executing UnRar" msgstr "" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Ожидание" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Обзор" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Неудачно" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "Начало" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Завершено" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Неизвестный статус" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Пожалуйста, подключитесь к Calibre-Web не с локального хоста, чтобы получить действительный api_endpoint для устройства Kobo" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Настройка Kobo" @@ -772,9 +842,9 @@ msgstr "Настройка Kobo" msgid "Register with %(provider)s" msgstr "Зарегистрируйтесь с %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "вы вошли как пользователь '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -833,507 +903,613 @@ msgstr "Ошибка Google Oauth, пожалуйста попробуйте п msgid "Google Oauth error: {}" msgstr "" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Логин" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Ключ не найден" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Ключ просрочен" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Успешно! Пожалуйста, проверьте свое устройство" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Книги" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Показывать недавние книги" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Популярные Книги" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Показывать популярные книги" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Книги с наилучшим рейтингом" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Показывать книги с наивысшим рейтингом" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Прочитанные Книги" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Показывать прочитанные и непрочитанные" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Непрочитанные Книги" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Показать непрочитанное" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Обзор" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Показывать Случайные Книги" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Категории" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Показывать выбор категории" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Серии" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Показывать выбор серии" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Авторы" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Показывать выбор автора" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Издатели" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Показать выбор издателя" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Языки" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Показывать выбор языка" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Рейтинги" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Показать выбор рейтинга" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Форматы файлов" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Показать выбор форматов файлов" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" -msgstr "" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "Показывать недавние книги" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Указана неверная полка" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Извините, но вам не разрешено добавлять книги на полку: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Книги уже размещены на полке: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Книга добавлена на книжную полку: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Вам не разрешено добавлять книгу на полку: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Книги уже размещены на полке: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Книги добавлены на полку: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Не удалось добавить книги на полку: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Книга удалена с полки: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Извините, вы не можете удалить книгу с полки: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Создать полку" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Извините, вы не можете удалить книгу с полки: %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Изменить полку" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Создана полка %(title)s" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Колка %(title)s изменена" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Произошла ошибка" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "Публичная полка с названием '%(title)s' уже существует." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "Приватная полка с названием '%(title)s' уже существует." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Изменить расположение полки '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Полка: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Ошибка открытия Полки. Полка не существует или недоступна" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Некорректные данные при чтении информации об обновлении" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Нет доступных обновлений. Вы используете последнюю версию" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Новое обновление доступно. Нажмите на кнопку ниже, чтобы обновить до последней версии." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Не удалось получить информацию об обновлении" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Нажмите на кнопку ниже для обновления до последней стабильной версии." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Новое обновление доступно. Нажмите на кнопку ниже, чтобы обновиться до версии: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Информация о выпуске недоступна" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Обзор (Случайные Книги)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Популярные книги (часто загружаемые)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Автор: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Издатель: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Серии: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Оценка: %(rating)s звезды(а)" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Формат файла: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Категория: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Язык: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Расширенный поиск" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Поиск" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Скачать" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Список рейтингов" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Список форматов файлов" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Задания" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Опубликовано после " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Опубликовано до " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Рейтинг <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Рейтинг >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Книга успешно поставлена в очередь для отправки на %(kindlemail)s" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Расширенный поиск" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Указана неверная полка" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Извините, но вам не разрешено добавлять книги на полку: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Книги уже размещены на полке: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Книга добавлена на книжную полку: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Книги уже размещены на полке: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Книги добавлены на полку: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Не удалось добавить книги на полку: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Книга удалена с полки: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Создать полку" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Извините, вы не можете удалить книгу с полки: %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Изменить полку" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Метаданные обновлены" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Изменить расположение полки '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Создана полка %(title)s" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Колка %(title)s изменена" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Произошла ошибка" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "Публичная полка с названием '%(title)s' уже существует." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "Приватная полка с названием '%(title)s' уже существует." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Полка: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Ошибка открытия Полки. Полка не существует или недоступна" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Задания" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Ожидание" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Неудачно" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Начало" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Завершено" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Неизвестный статус" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Некорректные данные при чтении информации об обновлении" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Нет доступных обновлений. Вы используете последнюю версию" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Новое обновление доступно. Нажмите на кнопку ниже, чтобы обновить до последней версии." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Не удалось получить информацию об обновлении" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Нажмите на кнопку ниже для обновления до последней стабильной версии." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Новое обновление доступно. Нажмите на кнопку ниже, чтобы обновиться до версии: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Информация о выпуске недоступна" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Обзор (Случайные Книги)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Популярные книги (часто загружаемые)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Автор: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Издатель: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Серии: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Оценка: %(rating)s звезды(а)" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Формат файла: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Категория: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Язык: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Скачать" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Список рейтингов" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Список форматов файлов" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Пожалуйста, сперва настройте параметры SMTP....." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Книга успешно поставлена в очередь для отправки на %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "При отправке этой книги произошла ошибка: %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "Пожалуйста, сначала настройте e-mail на вашем kindle..." -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "Сервер электронной почты не настроен, обратитесь к администратору !" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Зарегистрироваться" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Ваш e-mail не подходит для регистрации" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Письмо с подтверждением отправлено вам на e-mail." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "Не удается активировать LDAP аутентификацию" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "Резервный вход в систему как: '%(nickname)s', LDAP-сервер недоступен или пользователь не известен" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Не удалось войти: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Ошибка в имени пользователя или пароле" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "Новый пароль был отправлен на ваш адрес электронной почты" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Пожалуйста, введите действительное имя пользователя для сброса пароля" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Вы вошли как: '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "Профиль %(name)s's" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Профиль обновлён" +#: cps/web.py:1420 +#, fuzzy +msgid "Oops! An account already exists for this Email." +msgstr "Этот адрес электронной почты уже зарегистрирован." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Отправить на Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "Ошибка Ebook-конвертора: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "изменить метаданные" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Загрузить" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Список пользователей" @@ -1346,14 +1522,15 @@ msgstr "Имя пользователя" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "Адрес электронной почты" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Отправить на Kindle Адрес электронной почты" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Управление" @@ -1363,212 +1540,229 @@ msgstr "Управление" msgid "Password" msgstr "Пароль" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Загрузить" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Скачать" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Посмотреть электронные книги" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Редактировать" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Удалить" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Добавить нового пользователя" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "Импорт пользователей LDAP" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "Настройки SMTP-сервера" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "SMTP-сервер" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP-порт" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "SSL" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "SMTP-логин" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Отправитель" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Настройки сервера" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Расположение базы данных Calibre" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Уровень логирования" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Порт" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Количество книг на странице" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Загрузка на сервер" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Анонимный просмотр" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Публичная регистрация" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Удалённый логин" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "Логин обратного прокси" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Имя заголовка обратного прокси" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Изменить основные настройки" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Изменить основные настройки" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "Изменить настройки интерфейса" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Управление" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Просмотреть лог файл" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Пере подключиться к базе жанных Calibre" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Перезагрузить Calibre-Web" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Остановить Calibre-Web" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Обновление" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Версия" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Подробности" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Текущая версия" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Проверка обновлений" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Установить обновления" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Вы действительно хотите перезагрузить Calibre-Web?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "Ok" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Отмена" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Вы действительно хотите остановить Calibre-Web?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Установка обновлений, пожалуйста, не обновляйте страницу" @@ -1580,119 +1774,118 @@ msgstr "с помощью" msgid "In Library" msgstr "В библиотеке" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "уменьшить" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Ещё от" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Удалить книгу" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Удалить форматы:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Конвертировать формат книги:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Конвертировать из:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "выбрать вариант" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Конвертировать в:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Конвертировать книгу" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Название книги" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Автор" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Описание" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Теги" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "ID Серии" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Рейтинг" @@ -1704,82 +1897,83 @@ msgstr "URL обложки(jpg, обложка загружается и сох msgid "Upload Cover from Local Disk" msgstr "Загрузить обложку с диска" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Опубликовано" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Издатель" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Язык" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Да" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Нет" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Загружаемый формат" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Просмотреть книгу после сохранения" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Получить метаданные" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Сохранить" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Ключевое слово" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " Поиск по ключевому слову " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Нажмите на обложку, чтобы получить метаданные" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Загрузка..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Закрыть" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Источник" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Ошибка поиска!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Результат(ы) не найдены! Попробуйте другое ключевое слово." @@ -1871,27 +2065,36 @@ msgstr "Введите доменное имя" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Зарегистрироваться" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Вы действительно уверены?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "" @@ -1984,6 +2187,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Разрешить загрузку на сервер" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "" @@ -1997,7 +2204,7 @@ msgid "Enable Public Registration" msgstr "Разрешить публичную регистрацию" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "" #: cps/templates/config_edit.html:132 @@ -2064,11 +2271,6 @@ msgstr "Порт сервера LDAP" msgid "LDAP Encryption" msgstr "Шифрование LDAP" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Нет" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2204,7 +2406,7 @@ msgstr "Количество отображаемых случайных кни msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Количество авторов для отображения перед скрытием (0 = отключить скрытие)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Тема" @@ -2236,138 +2438,141 @@ msgstr "Регулярное выражение для сортировки за msgid "Default Settings for New Users" msgstr "Настройки по умолчанию для новых пользователей" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Управление сервером" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Разрешить скачивание с сервера" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Разрешить чтение книг" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Разрешить загрузку на сервер" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Разрешить редактирование книг" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "Разрешить удаление книг" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Разрешить смену пароля" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Разрешить редактирование публичных книжных полок" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Исключить языки" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Показать книги на языках" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Видимость для новых пользователей(по умолчанию)" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Показывать случайные книги при просмотре деталей" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "Добавить разрешенные / запрещенные теги" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "Добавить разрешенные / запрещенные значения индивидуальных столбцов" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Читать" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Прослушать в браузере" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Опубликованный" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Отметить как непрочитанное" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Отметить как прочитанное" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Прочесть" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Описание:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Добавить на книжную полку" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Публичная)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Редактировать метаданные" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "" +#, fuzzy +msgid "Gmail Account" +msgstr "Учетная запись" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 @@ -2391,10 +2596,11 @@ msgid "Attachment Size Limit" msgstr "" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Сохранить настройки и отправить тестовое письмо" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Назад" @@ -2420,46 +2626,63 @@ msgstr "Введите доменное имя" msgid "Denied Domains (Blacklist)" msgstr "Запрещенные домены (черный список)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Далее" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" msgstr "Откройте файл .kobo / Kobo eReader.conf в текстовом редакторе и добавьте (или отредактируйте):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Kobo Sync Token" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 #, fuzzy msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "Сервер электронной почты не настроен, обратитесь к администратору !" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Создать запись" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Вернуться на главную" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "" @@ -2523,7 +2746,7 @@ msgstr "Книги, упорядоченные по рейтингу" msgid "Books ordered by file formats" msgstr "Книги отсортированы по формату файла" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Полки" @@ -2532,63 +2755,67 @@ msgstr "Полки" msgid "Books organized in shelves" msgstr "Книги организованы на полках" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Главная" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Включить навигацию" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Поиск в библиотеке" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Загружается..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Ошибка" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Загрузка завершена, обработка, пожалуйста, подождите..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Настройки" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Учетная запись" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Выход" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Загружается..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Ошибка" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Загрузка завершена, обработка, пожалуйста, подождите..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Настройки" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Пожалуйста не обновляйте страницу" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Просмотр" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "О программе" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Предыдущий" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Подробнее о книге" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Запомнить меня" @@ -2597,7 +2824,7 @@ msgstr "Запомнить меня" msgid "Forgot Password?" msgstr "Забыли пароль ?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Войти через магическую ссылку" @@ -2693,7 +2920,7 @@ msgstr "" msgid "Select" msgstr "" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "Книга" @@ -2707,128 +2934,141 @@ msgstr "Каталог электронных книг Caliber-Web" msgid "epub Reader" msgstr "PDF reader" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Светлая" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Темная" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Назад" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Обновить размещение текста при открытии боковой панели." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "PDF reader" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Горячие клавиши" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Предыдущая страница" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Следующая страница" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Масштабировать до лучшего" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Масштабироваать по ширине" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Масштабировать по высоте" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Масштабировать до оригинала" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Повернуть Вправо" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Повернуть Влево" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Перевернуть изображение" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Светлая" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Темная" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Масштаб" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Лучшее" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Ширина" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Длина" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Оригинальный" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Повернуть" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Перевернуть" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Горизонтально" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Вертикально" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Направление" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Слева направо" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Справа налево" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "" @@ -2837,7 +3077,7 @@ msgstr "" msgid "DJVU Reader" msgstr "PDF reader" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "PDF reader" @@ -2856,7 +3096,7 @@ msgid "Choose a username" msgstr "Выберите имя пользователя" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Ваш email-адрес" #: cps/templates/remote_login.html:5 @@ -2875,15 +3115,19 @@ msgstr "После этого вы автоматически войдете в msgid "This verification link will expire in 10 minutes." msgstr "Срок действия ссылки истекает через 10 минут." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Результаты не найдены" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Выражение для поиска:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Результаты для:" @@ -2895,10 +3139,6 @@ msgstr "Опубликовано от" msgid "Published Date To" msgstr "Опубликовано до" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Исключить теги" @@ -2940,30 +3180,26 @@ msgstr "" msgid "To:" msgstr "" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Удалить эту книжную полку" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Книжная полка будет безвозвратно удалена для всех" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Сделать книжную полку доступной для всех ?" @@ -3005,8 +3241,8 @@ msgid "System Statistics" msgstr "" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Программа" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3032,9 +3268,17 @@ msgstr "Прогресс" msgid "Run Time" msgstr "Время выполнения" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Время начала" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3064,19 +3308,23 @@ msgstr "Kobo Sync Token" msgid "Create/View" msgstr "Создать/Просмотреть" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "Добавить разрешенные / запрещенные значения индивидуальных столбцов" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Удалить этого пользователя" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Создать Kobo Auth URL" @@ -3096,17 +3344,17 @@ msgstr "Выберите имя пользователя" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "Ваш email-адрес" +msgid "Enter Email" +msgstr "Тестовый e-mail" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Enter Kindle E-mail Address" +msgid "Enter eReader Email" msgstr "Отправить на Kindle Адрес электронной почты" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Kindle E-mail" +msgid "eReader Email" msgstr "Тестовый e-mail" #: cps/templates/user_table.html:137 @@ -3176,10 +3424,6 @@ msgstr "" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Показывать выбор серии" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Показывать случайные книги" - diff --git a/cps/translations/sv/LC_MESSAGES/messages.mo b/cps/translations/sv/LC_MESSAGES/messages.mo index 209d5f4ae..bf0691ced 100644 Binary files a/cps/translations/sv/LC_MESSAGES/messages.mo and b/cps/translations/sv/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/sv/LC_MESSAGES/messages.po b/cps/translations/sv/LC_MESSAGES/messages.po index a2e8c72fb..9cf3715e0 100644 --- a/cps/translations/sv/LC_MESSAGES/messages.po +++ b/cps/translations/sv/LC_MESSAGES/messages.po @@ -7,587 +7,643 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/Calibre-Web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2021-05-13 11:00+0000\n" "Last-Translator: Jonatan Nyberg \n" "Language: sv\n" "Language-Team: \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "inte installerad" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "installerad" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Statistik" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Server startas om, vänligen uppdatera sidan" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Stänger servern, vänligen stäng fönstret" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "Återanslutning lyckades" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "Okänt kommando" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "Boken är i kö för att skicka till %(eReadermail)s" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Okänd" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Administrationssida" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Grundläggande konfiguration" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Användargränssnitt konfiguration" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" msgstr "Redigera användare" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Alla" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "Användaren hittades inte" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "{} användare har tagits bort" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Visa alla" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "Felaktig begäran" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "Gästnamn kan inte ändras" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "Gäst kan inte ha den här rollen" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "Ingen administratörsanvändare kvar, kan inte ta bort administratörsrollen" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "Värdet måste vara sant eller falskt" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "Ogiltig roll" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "Gästen kan inte ha den här vyn" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "Ogiltig vy" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "Gästens språk bestäms automatiskt och kan inte ställas in" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "Inget giltigt språk anges" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "Inget giltigt bokspråk anges" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "Parameter hittades inte" -#: cps/admin.py:533 +#: cps/admin.py:565 #, fuzzy msgid "Invalid Read Column" msgstr "Ogiltig roll" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Calibre-Web konfiguration uppdaterad" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "Vill du verkligen ta bort Kobo-token?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "Vill du verkligen ta bort den här domänen?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "Vill du verkligen ta bort den här användaren?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Är du säker på att du vill ta bort hyllan?" -#: cps/admin.py:580 +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Är du säker på att du vill ändra språk för valda användare?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "Är du säker på att du vill ändra synliga bokspråk för valda användare?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "Är du säker på att du vill ändra den valda rollen för de valda användarna?" -#: cps/admin.py:586 +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Är du säker på att du vill ändra de valda begränsningarna för de valda användarna?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "Är du säker på att du vill ändra de valda synlighetsbegränsningarna för de valda användarna?" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Är du säker på att du vill ändra den valda rollen för de valda användarna?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "Är du säker på att du vill stoppa Calibre-Web?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "Taggen hittades inte" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "Ogiltig åtgärd" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "Förneka" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "Tillåt" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Taggen hittades inte" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Ogiltig åtgärd" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json är inte konfigurerad för webbapplikation" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "Loggfilens plats är inte giltig, vänligen ange rätt sökväg" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "Åtkomstloggplatsens plats är inte giltig, vänligen ange rätt sökväg" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "Vänligen ange en LDAP-leverantör, port, DN och användarobjektidentifierare" -#: cps/admin.py:1102 +#: cps/admin.py:1191 #, fuzzy msgid "Please Enter a LDAP Service Account and Password" msgstr "Ange giltigt användarnamn för att återställa lösenordet" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "LDAP-gruppobjektfilter måste ha en \"%s\"-formatidentifierare" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "LDAP-gruppobjektfilter har omatchande parentes" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "LDAP-användarobjektfilter måste ha en \"%s\"-formatidentifierare" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "LDAP-användarobjektfilter har omatchad parentes" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "Användarfilter för LDAP-medlemmar måste ha en \"%s\"-formatidentifierare" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "Användarfilter för LDAP-medlemmar har omatchad parentes" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "LDAP-certifikat, certifikat eller nyckelplats är inte giltigt, vänligen ange rätt sökväg" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "Inställningar för DB är inte skrivbara" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "DB-plats är inte giltig, vänligen ange rätt sökväg" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "DB är inte skrivbar" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "Keyfile-platsen är inte giltig, vänligen ange rätt sökväg" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "Certfile-platsen är inte giltig, vänligen ange rätt sökväg" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "E-postserverinställningar uppdaterade" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Funktion konfiguration" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Fyll i alla fält!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "E-posten är inte från giltig domän" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "Lägg till ny användare" -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Användaren '%(user)s' skapad" - -#: cps/admin.py:1369 -msgid "Found an existing account for this e-mail address or name." -msgstr "Hittade ett befintligt konto för den här e-postadressen eller namnet." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Användaren '%(nick)s' borttagen" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "Det går inte att ta bort gästanvändaren" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Ingen adminstratörsanvändare kvar, kan inte ta bort användaren" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Redigera användaren %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Användaren '%(nick)s' uppdaterad" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Ett okänt fel uppstod. Försök igen senare." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Ändra SMTP-inställningar" -#: cps/admin.py:1528 -#, fuzzy -msgid "Gmail Account Verification Successful" -msgstr "Verifiering av G-mail-kontot lyckades" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Databasfel: %(error)s." + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "Testa e-post i kö för att skicka till %(email)s, vänligen kontrollera Uppgifter för resultat" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Det gick inte att skicka Testmeddelandet: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Vänligen konfigurera din e-postadress först..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "E-postserverinställningar uppdaterade" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Ett okänt fel uppstod. Försök igen senare." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Redigera användaren %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "Lösenord för användaren %(user)s återställd" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Konfigurera SMTP-postinställningarna först..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Visaren för loggfil" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Begär uppdateringspaketet" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Hämtar uppdateringspaketet" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Packar upp uppdateringspaketet" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Ersätta filer" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Databasanslutningarna är stängda" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Stoppar server" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Uppdatering klar, tryck på okej och uppdatera sidan" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Uppdateringen misslyckades:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTP-fel" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Anslutningsfel" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Tiden ute när du etablerade anslutning" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Allmänt fel" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "Uppdateringsfilen kunde inte sparas i Temp Dir" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 #, fuzzy msgid "Failed to extract at least One LDAP User" msgstr "Det gick inte att skapa minst en LDAP-användare" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "Det gick inte att skapa minst en LDAP-användare" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "Fel: %(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "Fel: Ingen användare återges som svar på LDAP-servern" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "Minst en LDAP-användare hittades inte i databasen" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} användare har importerats" -#: cps/converter.py:30 -msgid "not configured" -msgstr "inte konfigurerad" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "DB-plats är inte giltig, vänligen ange rätt sökväg" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "DB är inte skrivbar" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "Keyfile-platsen är inte giltig, vänligen ange rätt sökväg" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "Certfile-platsen är inte giltig, vänligen ange rätt sökväg" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "E-postserverinställningar uppdaterade" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Funktion konfiguration" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Fyll i alla fält!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "E-posten är inte från giltig domän" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Lägg till ny användare" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Användaren '%(user)s' skapad" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "Hittade ett befintligt konto för den här e-postadressen eller namnet." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Användaren '%(nick)s' borttagen" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Det går inte att ta bort gästanvändaren" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Ingen adminstratörsanvändare kvar, kan inte ta bort användaren" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Användaren '%(nick)s' uppdaterad" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "inte installerad" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "Körningstillstånd saknas" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 -#, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, fuzzy, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "Anpassad kolumn n.%(column)d finns inte i calibre-databasen" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "Bokformat har tagits bort" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Ingen" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "Boken har tagits bort" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Hoppsan! Vald boktitel är inte tillgänglig. Filen finns inte eller är inte tillgänglig" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "redigera metadata" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s är inte ett giltigt språk" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "Filändelsen '%(ext)s' får inte laddas upp till den här servern" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Filen som ska laddas upp måste ha en ändelse" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "Det gick inte att skapa sökväg %(path)s (behörighet nekad)." - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "Det gick inte att lagra filen %(file)s." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "Databasfel: %(error)s." - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "Filformatet %(ext)s lades till %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "Identifierare är inte skiftlägeskänsliga, skriver över gammal identifierare" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Metadata uppdaterades" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Det gick inte att redigera boken, kontrollera loggfilen för mer information" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Uppladdad bok finns förmodligen i biblioteket, överväg att ändra innan du laddar upp nya: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "Filen %(filename)s kunde inte sparas i temp dir" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "Det gick inte att flytta omslagsfil %(file)s: %(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "Filen %(file)s uppladdad" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Källa eller målformat för konvertering saknas" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "Boken är i kö för konvertering till %(book_format)s" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Det gick inte att konvertera den här boken: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Uppladdad bok finns förmodligen i biblioteket, överväg att ändra innan du laddar upp nya: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s är inte ett giltigt språk" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "Filändelsen '%(ext)s' får inte laddas upp till den här servern" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Filen som ska laddas upp måste ha en ändelse" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "Filen %(filename)s kunde inte sparas i temp dir" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "Det gick inte att flytta omslagsfil %(file)s: %(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "Bokformat har tagits bort" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "Boken har tagits bort" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "redigera metadata" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "Det gick inte att skapa sökväg %(path)s (behörighet nekad)." + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Det gick inte att lagra filen %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "Filformatet %(ext)s lades till %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Installationen av Google Drive är inte klar, försök att inaktivera och aktivera Google Drive igen" @@ -601,165 +657,181 @@ msgstr "Återuppringningsdomänen är inte verifierad, följ stegen för att ver msgid "%(format)s format not found for book id: %(book)d" msgstr "%(format)s formatet hittades inte för bok-id: %(book)d" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(format)s hittades inte på Google Drive: %(fn)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s hittades inte: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Skicka till Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Detta e-postmeddelande har skickats via Calibre-Web." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Calibre-Web test e-post" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Test e-post" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Kom igång med Calibre-Web" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Registrera e-post för användare: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "Konvertera %(orig)s till %(format)s och skicka till Kindle" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "Skicka %(format)s till Kindle" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Skicka till Kindle" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "Den begärda filen kunde inte läsas. Kanske fel behörigheter?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "Borttagning av bokmapp för boken %(id)s misslyckades, sökvägen har undermappar: %(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "Borttagning av boken %(id)s misslyckades: %(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, fuzzy, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "Borttagning av boken %(id)s, boksökväg inte giltig: %(path)s" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "Byt namn på titel från: \"%(src)s\" till \"%(dest)s\" misslyckades med fel: %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Byt namn på fil i sökvägen '%(src)s' till '%(dest)s' misslyckades med fel: %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Filen %(file)s hittades inte på Google Drive" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Byt namn på titel från: \"%(src)s\" till \"%(dest)s\" misslyckades med fel: %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Boksökvägen %(path)s hittades inte på Google Drive" -#: cps/helper.py:507 cps/web.py:1654 -msgid "Found an existing account for this e-mail address" -msgstr "Hittade ett befintligt konto för den här e-postadressen" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Detta användarnamn är redan taget" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" msgstr "Ogiltigt e-postadressformat" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "Fel vid hämtning av omslaget" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "Fel på omslagsformat" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "Det gick inte att skapa sökväg för omslag" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "Omslagsfilen är inte en giltig bildfil eller kunde inte lagras" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "Endast jpg/jpeg/png/webp/bmp-filer stöds som omslagsfil" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "Endast jpg/jpeg-filer stöds som omslagsfil" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "Unrar binär fil hittades inte" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" msgstr "Fel vid körning av UnRar" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Väntar" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Upptäck" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Misslyckades" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "Startad" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Klar" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Okänd status" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "Vänligen få tillgång till calibre-web från icke localhost för att få giltig api_endpoint för Kobo-enhet" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Kobo-installation" @@ -768,9 +840,9 @@ msgstr "Kobo-installation" msgid "Register with %(provider)s" msgstr "Registrera dig med %(provider)s" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "du är nu inloggad som: \"%(nickname)s\"" #: cps/oauth_bb.py:148 @@ -829,507 +901,612 @@ msgstr "Google Oauth-fel, försök igen senare." msgid "Google Oauth error: {}" msgstr "Google Oauth-fel: {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "{} stjärnor" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Logga in" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Token hittades inte" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Token har löpt ut" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Lyckades! Vänligen återvänd till din enhet" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "Böcker" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Visa senaste böcker" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Heta böcker" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Visa heta böcker" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "Hämtade böcker" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "Visa hämtade böcker" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Bäst rankade böcker" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Visa böcker med bästa betyg" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Lästa böcker" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Visa lästa och olästa" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Olästa böcker" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Visa olästa" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Upptäck" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Visa slumpmässiga böcker" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Kategorier" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Visa kategorival" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Serier" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Visa serieval" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Författare" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Visa författarval" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Förlag" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Visa urval av förlag" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Språk" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Visa språkval" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Betyg" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Visa val av betyg" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Filformat" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Visa val av filformat" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "Arkiverade böcker" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" msgstr "Visa arkiverade böcker" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "Boklista" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "Visa boklista" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Ogiltig hylla specificerad" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Tyvärr får du inte lägga till en bok på hyllan: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "Boken är redan en del av hyllan: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Boken har lagts till i hyllan: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Du får inte lägga till en bok i hyllan: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "Böcker är redan en del av hyllan: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "Böcker har lagts till hyllan: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "Kunde inte lägga till böcker till hyllan: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Boken har tagits bort från hyllan: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Tyvärr har du inte rätt att ta bort en bok från den här hyllan: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Skapa en hylla" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Tyvärr har du inte rätt att ta bort en bok från den här hyllan: %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Redigera en hylla" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Hyllan %(title)s skapad" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Hyllan %(title)s ändrad" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Det fanns ett fel" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "En offentlig hylla med namnet \"%(title)s\" finns redan." - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "En privat hylla med namnet \"%(title)s\" finns redan." - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Ändra ordning på hyllan: '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Hylla: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Fel vid öppning av hyllan. Hylla finns inte eller är inte tillgänglig" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Oväntade data vid läsning av uppdateringsinformation" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Ingen uppdatering tillgänglig. Du har redan den senaste versionen installerad" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "En ny uppdatering är tillgänglig. Klicka på knappen nedan för att uppdatera till den senaste versionen." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Kunde inte hämta uppdateringsinformation" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Klicka på knappen nedan för att uppdatera till den senaste stabila versionen." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "En ny uppdatering är tillgänglig. Klicka på knappen nedan för att uppdatera till version: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Ingen versionsinformation tillgänglig" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Upptäck (slumpmässiga böcker)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Heta böcker (mest hämtade)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "Hämtade böcker av %(user)s" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Författare: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Förlag: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Serier: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Betyg: %(rating)s stars" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Filformat: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Kategori: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Språk: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Avancerad sökning" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Sök" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "Hämtningar" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Betygslista" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Lista över filformat" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Uppgifter" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Publicerad efter " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Publicerad före " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Betyg <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Betyg >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "Lässtatus = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "Boken är i kö för att skicka till %(kindlemail)s" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Avancerad sökning" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Ogiltig hylla specificerad" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Tyvärr får du inte lägga till en bok på hyllan: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "Boken är redan en del av hyllan: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Boken har lagts till i hyllan: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "Böcker är redan en del av hyllan: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "Böcker har lagts till hyllan: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "Kunde inte lägga till böcker till hyllan: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Boken har tagits bort från hyllan: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Skapa en hylla" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Tyvärr har du inte rätt att ta bort en bok från den här hyllan: %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Redigera en hylla" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Boken har tagits bort" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Ändra ordning på hyllan: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Hyllan %(title)s skapad" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Hyllan %(title)s ändrad" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Det fanns ett fel" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "En offentlig hylla med namnet \"%(title)s\" finns redan." + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "En privat hylla med namnet \"%(title)s\" finns redan." + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Hylla: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Fel vid öppning av hyllan. Hylla finns inte eller är inte tillgänglig" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Uppgifter" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Väntar" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Misslyckades" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Startad" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Klar" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Okänd status" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Oväntade data vid läsning av uppdateringsinformation" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Ingen uppdatering tillgänglig. Du har redan den senaste versionen installerad" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "En ny uppdatering är tillgänglig. Klicka på knappen nedan för att uppdatera till den senaste versionen." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Kunde inte hämta uppdateringsinformation" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Klicka på knappen nedan för att uppdatera till den senaste stabila versionen." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "En ny uppdatering är tillgänglig. Klicka på knappen nedan för att uppdatera till version: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Ingen versionsinformation tillgänglig" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Upptäck (slumpmässiga böcker)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Heta böcker (mest hämtade)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "Hämtade böcker av %(user)s" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Författare: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Förlag: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Serier: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Betyg: %(rating)s stars" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Filformat: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Kategori: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Språk: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Hämtningar" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Betygslista" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Lista över filformat" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Konfigurera SMTP-postinställningarna först..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "Boken är i kö för att skicka till %(eReadermail)s" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "Det gick inte att skicka den här boken: %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "Konfigurera din kindle-e-postadress först..." -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "E-postservern är inte konfigurerad, kontakta din administratör!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Registrera" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "Din e-post är inte tillåten att registrera" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Bekräftelsemail skickades till ditt e-postkonto." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "Det går inte att aktivera LDAP-autentisering" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "Det gick inte att logga in: %(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Fel användarnamn eller lösenord" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "Nytt lösenord skickades till din e-postadress" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Ange giltigt användarnamn för att återställa lösenordet" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Du är nu inloggad som: \"%(nickname)s\"" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)ss profil" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Profilen uppdaterad" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "Hittade ett befintligt konto för den här e-postadressen" + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "Hittade ingen giltig gmail.json-fil med OAuth-information" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Skicka till Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "calibre e-bokkonverterings %(tool)s hittades inte" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "%(format)s-format hittades inte på disken" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "E-bokkonverteraren misslyckades med okänt fel" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Kepubify-konverteraren misslyckades: %(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "Konverterad fil hittades inte eller mer än en fil i mappen %(folder)s" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "E-bokkonverteraren misslyckades: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "calibre misslyckades med fel: %(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "redigera metadata" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Ladda upp" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Användarlista" @@ -1342,14 +1519,15 @@ msgstr "Smeknamn" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "E-post" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Kindle" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Administratör" @@ -1359,212 +1537,230 @@ msgstr "Administratör" msgid "Password" msgstr "Lösenord" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Ladda upp" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Hämta" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "Visa e-böcker" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Redigera" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Ta bort" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "Publik hylla" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "Lägg till ny användare" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "Importera LDAP-användare" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "Inställningar för SMTP-e-postserver" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "SMTP-värdnamn" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP-port" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "SSL" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "SMTP-inloggning" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Från meddelande" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" msgstr "E-posttjänst" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "Gmail via Oauth2" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Konfiguration" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Calibre DB dir" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Loggnivå" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Port" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "Extern port" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Böcker per sida" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Laddar upp" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Anonym surfning" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Publik registrering" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "Fjärrinloggning" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "Omvänd proxy inloggning" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Omvänt proxy rubriknamn" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Redigera grundläggande konfiguration" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "Redigera grundläggande konfiguration" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "Redigera UI-konfiguration" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Administration" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "Hämta felsökningspaketet" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "Visa loggfiler" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Anslut till Calibre DB igen" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "Starta om Calibre-Web" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "Stoppa Calibre-Web" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Uppdatera" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Version" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Detaljer" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Aktuell version" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Sök efter uppdatering" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Utför uppdatering" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "Är du säker på att du vill starta om Calibre-Web?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "Ok" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "Avbryt" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "Är du säker på att du vill stoppa Calibre-Web?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Uppdaterar, vänligen uppdatera inte sidan" @@ -1576,119 +1772,118 @@ msgstr "via" msgid "In Library" msgstr "I biblioteket" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "Sortera efter bokdatum, nyast först" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "Sortera efter bokdatum, äldsta först" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "Sortera titel i alfabetisk ordning" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "Sortera titel i omvänd alfabetisk ordning" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "Sortera efter publiceringsdatum, nyast först" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "Sortera efter publiceringsdatum, äldsta först" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "minska" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Mer av" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Ta bort boken" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Ta bort format:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Konvertera bokformat:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Konvertera från:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "välj ett alternativ" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Konvertera till:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "Konvertera boken" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Boktitel" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Författare" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Beskrivning" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "Identifierare" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "Identifierartyp" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "Identifierarvärde" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "Ta bort" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "Lägg till identifierare" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Taggar" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "Serie-ID" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Betyg" @@ -1700,82 +1895,83 @@ msgstr "Omslagswebbadress (jpg, omslag hämtas och lagras i databasen, fältet msgid "Upload Cover from Local Disk" msgstr "Ladda upp omslag från lokal enhet" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Publiceringsdatum" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Förlag" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Språk" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Ja" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Nej" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Ladda upp format" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "Visa bok vid Spara" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Hämta metadata" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "Spara" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Sökord" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " Sök sökord " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Klicka på omslaget för att läsa in metadata till formuläret" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Läser in..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Stäng" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Källa" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Sökningsfel!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "Inga resultat hittades! Försök med ett annat sökord." @@ -1867,27 +2063,36 @@ msgstr "Ange domännamn" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Lässtatus" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Identifierare" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Är du verkligen säker?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "Böcker med titel slås samman från:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "I bok med titel:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "Slå samman" @@ -1980,6 +2185,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Aktivera uppladdning" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "Tillåtna filformat för uppladdning" @@ -1993,7 +2202,7 @@ msgid "Enable Public Registration" msgstr "Aktivera offentlig registrering" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "Använd e-post som användarnamn" #: cps/templates/config_edit.html:132 @@ -2060,11 +2269,6 @@ msgstr "LDAP-serverport" msgid "LDAP Encryption" msgstr "LDAP-kryptering" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Ingen" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS" @@ -2200,7 +2404,7 @@ msgstr "Antal slumpmässiga böcker att visa" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "Antal författare att visa innan de döljs (0 = inaktivera dölja)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Tema" @@ -2232,140 +2436,143 @@ msgstr "Reguljärt uttryck för titelsortering" msgid "Default Settings for New Users" msgstr "Standardinställningar för nya användare" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Adminstratör användare" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Tillåt Hämtningar" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "Tillåt bokvisare" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Tillåt Uppladdningar" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Tillåt Redigera" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "Tillåt borttagning av böcker" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Tillåt Ändra lösenord" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Tillåt Redigering av offentliga hyllor" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Uteslut språk" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Visa böcker med språk" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Standardvisibiliteter för nya användare" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Visa slumpmässiga böcker i detaljvyn" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "Lägg till tillåtna/avvisade taggar" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "Lägg till tillåtna/avvisade anpassade kolumnvärden" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Läs i webbläsaren" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "Lyssna i webbläsaren" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, fuzzy, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "Publicerad" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Markera som oläst" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Markera som läst" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Läst" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "Återställ från arkivet" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "Lägg till i arkivet" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "Arkiverad" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Beskrivning:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Lägg till hyllan" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(Publik)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Redigera metadata" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "Välj servertyp" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +#, fuzzy +msgid "Standard Email Account" msgstr "Använd standard e-postkonto" #: cps/templates/email_edit.html:16 #, fuzzy -msgid "Gmail Account with OAuth2 Verification" -msgstr "Gmail-konto med OAuth2-verifiering" +msgid "Gmail Account" +msgstr "Välj servertyp" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" -msgstr "Ställ in Gmail-kontot som e-postserver" +msgid "Setup Gmail Account" +msgstr "" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" @@ -2388,10 +2595,11 @@ msgid "Attachment Size Limit" msgstr "Gräns för bilagestorlek" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Spara inställningarna och skicka test-e-post" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Tillbaka" @@ -2417,46 +2625,63 @@ msgstr "Ange domännamn" msgid "Denied Domains (Blacklist)" msgstr "Avvisade domäner för registrering" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Nästa" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "Öppna filen .kobo/Kobo eReader.conf i en textredigerare och lägg till (eller redigera):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "Öppna filen .kobo/Kobo/Kobo eReader.conf i en textredigerare och lägg till (eller redigera):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Kobo Sync Token" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 #, fuzzy msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "E-postservern är inte konfigurerad, kontakta din administratör!" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "Skapa ärende" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "Tillbaka till hemmet" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "Sortera författare i alfabetisk ordning" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "Sortera författare i omvänd alfabetisk ordning" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "Sortera stigande enligt serieindex" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "Sortera fallande enligt serieindex" @@ -2520,7 +2745,7 @@ msgstr "Böcker sorterade efter Betyg" msgid "Books ordered by file formats" msgstr "Böcker ordnade av filformat" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "Hyllor" @@ -2529,63 +2754,67 @@ msgstr "Hyllor" msgid "Books organized in shelves" msgstr "Böcker organiserade i hyllor" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Hem" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Växla navigering" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "Sök i bibliotek" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Laddar upp..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Fel" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Uppladdning klar, bearbetning, vänligen vänta ..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Inställningar" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Konto" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Logga ut" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Laddar upp..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Fel" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Uppladdning klar, bearbetning, vänligen vänta ..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Inställningar" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "Vänligen uppdatera inte sidan" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Bläddra" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Om" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Föregående" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Bokdetaljer" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Kom ihåg mig" @@ -2594,7 +2823,7 @@ msgstr "Kom ihåg mig" msgid "Forgot Password?" msgstr "Glömt lösenord?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Logga in med magisk länk" @@ -2690,7 +2919,7 @@ msgstr "Föräldramapp" msgid "Select" msgstr "Välj" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 msgid "Ok" msgstr "Ok" @@ -2703,128 +2932,141 @@ msgstr "Calibre-Web e-bokkatalog" msgid "epub Reader" msgstr "PDF-läsare" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Ljust" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Mörkt" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Tillbaka" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Fyll i texten igen när sidofält är öppna." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "PDF-läsare" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Kortkommandon" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Föregående sida" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Nästa sida" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "Skala till bäst" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Skala till bredd" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Skala till höjd" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Skala till ursprunglig" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Rotera åt höger" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Rotera åt vänster" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Vänd bilden" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Ljust" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Mörkt" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Skala" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "Bäst" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Bredd" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Höjd" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Ursprunglig" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Rotera" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Vänd" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Horisontell" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Vertikal" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Riktning" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Vänster till höger" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Höger till vänster" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "" @@ -2833,7 +3075,7 @@ msgstr "" msgid "DJVU Reader" msgstr "PDF-läsare" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "PDF-läsare" @@ -2852,7 +3094,7 @@ msgid "Choose a username" msgstr "Välj ett användarnamn" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Din e-postadress" #: cps/templates/remote_login.html:5 @@ -2871,15 +3113,19 @@ msgstr "När du gör det kommer du automatiskt att logga in på den här enheten msgid "This verification link will expire in 10 minutes." msgstr "Länken går ut efter 10 minuter." -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "Inga resultat hittades" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "Sökterm:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Resultat för:" @@ -2891,10 +3137,6 @@ msgstr "Publiceringsdatum från" msgid "Published Date To" msgstr "Publiceringsdatum till" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "Lässtatus" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Uteslut taggar" @@ -2935,30 +3177,26 @@ msgstr "" msgid "To:" msgstr "" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Ta bort den här hyllan" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "Redigera hyllegenskaper" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "Ordna böcker manuellt" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "Inaktivera ändring av ordning" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "Aktivera ändring av ordning" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Hylla kommer att tas bort för alla användare" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "Dela med alla" @@ -3000,8 +3238,8 @@ msgid "System Statistics" msgstr "Systemstatistik" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Programbibliotek" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3027,9 +3265,17 @@ msgstr "Förlopp" msgid "Run Time" msgstr "Drifttid" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "Starttid" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3059,19 +3305,23 @@ msgstr "Kobo Sync Token" msgid "Create/View" msgstr "Skapa/Visa" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "Lägg till tillåtna/avvisade anpassade kolumnvärden" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Ta bort den här användaren" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "Skapa Kobo Auth URL" @@ -3088,16 +3338,19 @@ msgid "Enter Username" msgstr "Ange användarnamn" #: cps/templates/user_table.html:135 -msgid "Enter E-mail Address" -msgstr "Ange e-postadress" +#, fuzzy +msgid "Enter Email" +msgstr "Test e-post" #: cps/templates/user_table.html:136 -msgid "Enter Kindle E-mail Address" -msgstr "Ange Kindle e-postadress" +#, fuzzy +msgid "Enter eReader Email" +msgstr "Kindle" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" -msgstr "Kindle e-postadress" +#, fuzzy +msgid "eReader Email" +msgstr "Test e-post" #: cps/templates/user_table.html:137 msgid "Locale" @@ -3158,10 +3411,7 @@ msgid "Sync selected Shelves with Kobo" msgstr "" #: cps/templates/user_table.html:156 -msgid "Show read/unread selection" +#, fuzzy +msgid "Show Read/Unread Section" msgstr "Visa läst/oläst val" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Visa slumpmässiga böcker" - diff --git a/cps/translations/tr/LC_MESSAGES/messages.mo b/cps/translations/tr/LC_MESSAGES/messages.mo index 410fa7199..c724710fb 100644 Binary files a/cps/translations/tr/LC_MESSAGES/messages.mo and b/cps/translations/tr/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/tr/LC_MESSAGES/messages.po b/cps/translations/tr/LC_MESSAGES/messages.po index d108c2c36..52c93311a 100644 --- a/cps/translations/tr/LC_MESSAGES/messages.po +++ b/cps/translations/tr/LC_MESSAGES/messages.po @@ -7,583 +7,640 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2020-04-23 22:47+0300\n" "Last-Translator: iz \n" "Language: tr\n" "Language-Team: \n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "yüklü değil" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "yüklü" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "İstatistikler" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Sunucu yeniden başlatıldı, lütfen sayfayı yeniden yükleyin" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Sunucu kapatıyor, lütfen pencereyi kapatın" -#: cps/admin.py:154 -msgid "Reconnect successful" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "%(eReadermail)s'a gönderilmek üzere başarıyla sıraya alındı" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Bilinmeyen" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Yönetim sayfası" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Temel Ayarlar" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Arayüz Ayarları" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" msgstr "" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "Tümü" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Calibre-Web yapılandırması güncellendi" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "" -#: cps/admin.py:580 +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" msgstr "" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "" -#: cps/admin.py:586 +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:590 +#: cps/admin.py:622 msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "" -#: cps/admin.py:592 +#: cps/admin.py:624 msgid "Are you sure you want to change Calibre library location?" msgstr "" -#: cps/admin.py:741 -msgid "Tag not found" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "" -#: cps/admin.py:1102 +#: cps/admin.py:1191 #, fuzzy msgid "Please Enter a LDAP Service Account and Password" msgstr "Şifrenizi sıfırlayabilmek için lütfen geçerli bir kullanıcı adı giriniz" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "" -#: cps/admin.py:1192 -msgid "DB is not Writeable" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "E-posta sunucusu ayarları güncellendi" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Özellik Yapılandırması" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Lütfen tüm alanları doldurun!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "E-posta izin verilen bir servisten değil" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "Yeni kullanıcı ekle" - -#: cps/admin.py:1363 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 #, python-format -msgid "User '%(user)s' created" -msgstr "'%(user)s' kullanıcısı oluşturuldu" - -#: cps/admin.py:1369 -#, fuzzy -msgid "Found an existing account for this e-mail address or name." -msgstr "Bu e-posta adresi veya kullanıcı adı için zaten bir hesap var." - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Kullanıcı '%(nick)s' silindi" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" +msgid "Oops! Database Error: %(error)s." msgstr "" -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "Başka yönetici kullanıcı olmadığından silinemedi" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "%(nick)s kullanıcısını düzenle" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "'%(nick)s' kullanıcısı güncellendi" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "Bilinmeyen bir hata oluştu. Lütfen daha sonra tekrar deneyiniz." - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" -msgstr "" - -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "" - -#: cps/admin.py:1554 +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "Deneme e-postası gönderilirken bir hata oluştu: %(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "Lütfen önce e-posta adresinizi ayarlayın..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "E-posta sunucusu ayarları güncellendi" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Bilinmeyen bir hata oluştu. Lütfen daha sonra tekrar deneyiniz." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "%(nick)s kullanıcısını düzenle" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "%(user)s kullanıcısının şifresi sıfırlandı" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Lütfen önce SMTP e-posta ayarlarını ayarlayın..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "Log dosyası görüntüleyici" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Güncelleme paketi isteniyor" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Güncelleme paketi indiriliyor" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Güncelleme paketi ayıklanıyor" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "Dosyalar değiştiriliyor" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "Veritabanı bağlantıları kapalı" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "Sunucu durduruyor" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Güncelleme tamamlandı, sayfayı yenilemek için lütfen Tamam'a tıklayınız" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "Güncelleme başarısız:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTP Hatası" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "Bağlantı hatası" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "Bağlantı kurulmaya çalışırken zaman aşımına uğradı" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "Genel hata" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "%(filename)s dosyası geçici dizine kaydedilemedi" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" msgstr "" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "" -#: cps/converter.py:30 -msgid "not configured" -msgstr "ayarlanmadı" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "E-posta sunucusu ayarları güncellendi" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Özellik Yapılandırması" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Lütfen tüm alanları doldurun!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "E-posta izin verilen bir servisten değil" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Yeni kullanıcı ekle" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "'%(user)s' kullanıcısı oluşturuldu" + +#: cps/admin.py:1897 +#, fuzzy +msgid "Oops! An account already exists for this Email. or name." +msgstr "Bu e-posta adresi veya kullanıcı adı için zaten bir hesap var." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Kullanıcı '%(nick)s' silindi" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "Başka yönetici kullanıcı olmadığından silinemedi" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "'%(nick)s' kullanıcısı güncellendi" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "yüklü değil" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Hiçbiri" + +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" -msgstr "" - -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "metaveri düzenle" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s geçerli bir dil değil" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "'%(ext)s' uzantılı dosyaların bu sunucuya yüklenmesine izin verilmiyor" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Yüklenecek dosyanın mutlaka bir uzantısı olması gerekli" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "%(path)s dizini oluşturulamadı. (İzin reddedildi)" - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "%(file)s dosyası kaydedilemedi." - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "%(book)s kitabına %(ext)s dosya biçimi eklendi" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "Metaveri başarıyla güncellendi" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "eKitap düzenlenirken hata oluştu, detaylar için lütfen log dosyasını kontrol edin" - -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "Yüklenen eKitap muhtemelen kitaplıkta zaten var. Yenisini yüklemeden değiştirmeyi düşünün: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "%(filename)s dosyası geçici dizine kaydedilemedi" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" msgstr "" -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "%(file)s dosyası yüklendi" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "Dönüştürme için kaynak ya da hedef biçimi eksik" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "eKitap %(book_format)s formatlarına dönüştürülmek üzere başarıyla sıraya alındı" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "Bu eKitabı dönüştürürken bir hata oluştu: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "Yüklenen eKitap muhtemelen kitaplıkta zaten var. Yenisini yüklemeden değiştirmeyi düşünün: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s geçerli bir dil değil" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "'%(ext)s' uzantılı dosyaların bu sunucuya yüklenmesine izin verilmiyor" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Yüklenecek dosyanın mutlaka bir uzantısı olması gerekli" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "%(filename)s dosyası geçici dizine kaydedilemedi" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "metaveri düzenle" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "%(path)s dizini oluşturulamadı. (İzin reddedildi)" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "%(file)s dosyası kaydedilemedi." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "%(book)s kitabına %(ext)s dosya biçimi eklendi" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Google Drive kurulumu tamamlanmadı, Google Drive'ı devre dışı bırakmayı ve tekrar etkinleştirmeyi deneyin" @@ -597,166 +654,178 @@ msgstr "Geri yönlendirme alanı (callback domain) doğrulanamadı, lütfen Goog msgid "%(format)s format not found for book id: %(book)d" msgstr "%(book)d nolu kitap için %(format)s biçimi bulunamadı" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "%(fn)s eKitabı için %(format)s biçimi Google Drive'da bulunamadı" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "%(format)s bulunamadı: %(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Kindle'a gönder" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "Bu e-Posta Calibre-Web ile gönderilmiştir." -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Calibre-Web deneme e-Postası" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "Deneme e-Postası" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "Calibre-Web'i Kullanmaya Başlayın" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "Kullanıcı Kayıt e-Postası: %(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "%(orig)s'dan %(format)s biçimine çevir ve Kindle'a gönder" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "%(format)s biçimlerini Kindle'a gönder" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "Kindle'a gönder" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "İstenilen dosya okunamadı. Yanlış izinlerden kaynaklanabilir?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "Kitap adını değiştirme sırasında hata oluştu ('%(src)s' → '%(dest)s'): %(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "Dosya adını değiştirme sırasında hata oluştu ('%(src)s' → '%(dest)s'): %(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "%(file)s dosyası Google Drive'da bulunamadı" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "Kitap adını değiştirme sırasında hata oluştu ('%(src)s' → '%(dest)s'): %(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "eKitap yolu %(path)s Google Drive'da bulunamadı" -#: cps/helper.py:507 cps/web.py:1654 -#, fuzzy -msgid "Found an existing account for this e-mail address" -msgstr "Bu e-posta adresi için bir hesap mevcut." +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "Bu kullanıcı adı zaten alındı" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +msgid "Error executing UnRar" msgstr "" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "Bekleniyor" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Keşfet" -#: cps/helper.py:764 -msgid "Failed" -msgstr "Başarısız" - -#: cps/helper.py:766 -msgid "Started" -msgstr "Başladı" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "Bitti" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "Bilinmeyen Durum" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" msgstr "" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "" + +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "" @@ -765,9 +834,9 @@ msgstr "" msgid "Register with %(provider)s" msgstr "%(provider)s ile Kaydol" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "giriş yaptınız: '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -826,507 +895,612 @@ msgstr "Google Oauth hatası, lütfen tekrar deneyin." msgid "Google Oauth error: {}" msgstr "" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Giriş" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Token bulunamadı" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Token süresi doldu" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Başarılı! Lütfen cihazınıza dönün" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "eKitaplar" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Son eKitapları göster" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Popüler" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Okunanlar" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Okunan ve okunmayanları göster" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Okunmamışlar" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "Okunmamışları göster" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Keşfet" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Rastgele Kitap Göster" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Kategoriler" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Kategori seçimini göster" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Seriler" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Seri seçimini göster" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Yazarlar" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Yazar seçimini göster" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "Yayıncılar" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "Yayıncı seçimini göster" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Diller" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Dil seçimini göster" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "Değerlendirmeler" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "Değerlendirme seçimini göster" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "Biçimler" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "Dosya biçimi seçimini göster" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" -msgstr "" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "Son eKitapları göster" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "Geçersiz kitaplık seçildi" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Maalesef bu kitaplığa eKitap eklemenize izin verilmiyor: %(shelfname)s" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "eKitap zaten bu kitaplıkta bulunuyor: %(shelfname)s" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "eKitap kitaplığa eklendi: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "Bu kitaplığa eKitap eklemenize izin verilmiyor: %(name)s" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "eKitaplar zaten bu kitaplıkta bulunuyor: %(name)s" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "eKitaplar kitaplığa eklendi: %(sname)s" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "eKitaplar kitaplığa eklenemedi: %(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "eKitap kitaplıktan silindi: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Maalesef bu kitaplıktan eKitap silmenize izin verilmiyor: %(sname)s" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "Kitaplık oluştur" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Maalesef bu kitaplıktan eKitap silmenize izin verilmiyor: %(sname)s" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Kitaplığı düzenle" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "%(title)s kitaplığı oluşturuldu." - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "%(title)s kitaplığı değiştirildi" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Bir hata oluştu" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Kitaplık sıralamasını değiştir: '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Kitaplık: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Kitaplık açılırken hata oluştu. Kitaplık mevcut değil ya da erişilebilir değil" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "Güncelleme bilgileri okunurken beklenmeyen veri" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "Yeni güncelleme mevcut değil. Zaten en son sürüme sahipsiniz." - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "Yeni bir güncelleme mevcut. Son sürüme güncellemek için aşağıdaki düğmeye tıklayın." - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "Güncelleme bilgileri alınamadı" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "Son kararlı sürüme güncellemek için aşağıdaki düğmeye tıklayın." - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "Yeni bir güncelleme mevcut. Son sürüme güncellemek için aşağıdaki düğmeye tıklayın: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "Sürüm bilgisi mevcut değil" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Keşfet (Rastgele)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "Yazar: %(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "Yayınevi: %(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Seri: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "Değerlendirme: %(rating)s yıldız" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "Biçim: %(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Kategori: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Dil: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Gelişmiş Arama" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Ara" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "Değerlendirme listesi" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "Biçim listesi" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "Görevler" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "Yayınlanma (sonra)" -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "Yayınlanma (önce)" -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "Değerlendirme <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "Değerlendirme >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "%(kindlemail)s'a gönderilmek üzere başarıyla sıraya alındı" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Gelişmiş Arama" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "Geçersiz kitaplık seçildi" + +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Maalesef bu kitaplığa eKitap eklemenize izin verilmiyor: %(shelfname)s" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "eKitap zaten bu kitaplıkta bulunuyor: %(shelfname)s" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "eKitap kitaplığa eklendi: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" msgstr "" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "eKitaplar zaten bu kitaplıkta bulunuyor: %(name)s" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "eKitaplar kitaplığa eklendi: %(sname)s" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "eKitaplar kitaplığa eklenemedi: %(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "eKitap kitaplıktan silindi: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" msgstr "" -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Kitaplık oluştur" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Maalesef bu kitaplıktan eKitap silmenize izin verilmiyor: %(sname)s" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Kitaplığı düzenle" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "Metaveri başarıyla güncellendi" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Kitaplık sıralamasını değiştir: '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "%(title)s kitaplığı oluşturuldu." + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "%(title)s kitaplığı değiştirildi" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Bir hata oluştu" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Kitaplık: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Kitaplık açılırken hata oluştu. Kitaplık mevcut değil ya da erişilebilir değil" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Görevler" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Bekleniyor" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Başarısız" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Başladı" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Bitti" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Bilinmeyen Durum" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "Güncelleme bilgileri okunurken beklenmeyen veri" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "Yeni güncelleme mevcut değil. Zaten en son sürüme sahipsiniz." + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "Yeni bir güncelleme mevcut. Son sürüme güncellemek için aşağıdaki düğmeye tıklayın." + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "Güncelleme bilgileri alınamadı" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "Son kararlı sürüme güncellemek için aşağıdaki düğmeye tıklayın." + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "Yeni bir güncelleme mevcut. Son sürüme güncellemek için aşağıdaki düğmeye tıklayın: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "Sürüm bilgisi mevcut değil" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Keşfet (Rastgele)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "Yazar: %(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Yayınevi: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Seri: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Değerlendirme: %(rating)s yıldız" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Biçim: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Kategori: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Dil: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Değerlendirme listesi" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Biçim listesi" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Lütfen önce SMTP e-posta ayarlarını ayarlayın..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "%(eReadermail)s'a gönderilmek üzere başarıyla sıraya alındı" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "" + +#: cps/web.py:1213 +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "" + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "E-Posta sunucusu ayarlanmadı, lütfen yöneticinizle iletişime geçin!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Kayıt ol" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "E-posta adresinizle kaydolunmasına izin verilmiyor" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "Onay e-Postası hesabınıza gönderildi." -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "LDAP Kimlik Doğrulaması etkinleştirilemiyor" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Yanlış Kullanıcı adı ya da Şifre" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "Yeni şifre e-Posta adresinize gönderildi" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "Şifrenizi sıfırlayabilmek için lütfen geçerli bir kullanıcı adı giriniz" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "Giriş yaptınız: '%(nickname)s'" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)s Profili" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Profil güncellendi" +#: cps/web.py:1420 +#, fuzzy +msgid "Oops! An account already exists for this Email." +msgstr "Bu e-posta adresi için bir hesap mevcut." + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Kindle'a gönder" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "eKitap-Dönüştürücü hatası: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "metaveri düzenle" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Yükleme" + #: cps/templates/admin.html:9 msgid "Users" msgstr "" @@ -1339,14 +1513,15 @@ msgstr "Kullanıcı adı" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" -msgstr "" +#, fuzzy +msgid "Send to eReader Email" +msgstr "E-Posta adresiniz" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Yönetim" @@ -1356,212 +1531,229 @@ msgstr "Yönetim" msgid "Password" msgstr "Şifre" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Yükleme" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "İndirme" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Düzenleme" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Sil" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "Şifreleme" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Ayarlar" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "Log Seviyesi" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Port" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "Ters Proxy Header Adı" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Calibre-Web yapılandırması güncellendi" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "" -#: cps/templates/admin.html:160 -msgid "Administration" -msgstr "Yönetim" - -#: cps/templates/admin.html:161 -msgid "Download Debug Package" +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" msgstr "" -#: cps/templates/admin.html:162 -msgid "View Logs" +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" msgstr "" -#: cps/templates/admin.html:165 +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 msgid "Reconnect Calibre Database" msgstr "" -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 +msgid "Administration" +msgstr "Yönetim" + +#: cps/templates/admin.html:200 +msgid "Download Debug Package" +msgstr "" + +#: cps/templates/admin.html:201 +msgid "View Logs" +msgstr "" + +#: cps/templates/admin.html:207 msgid "Restart" msgstr "" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "Güncelleme" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "Sürüm" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "Detaylar" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "Geçerli sürüm" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Güncelle" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "" @@ -1573,119 +1765,118 @@ msgstr "ile" msgid "In Library" msgstr "Kitaplıkta" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "azalt" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "daha fazla" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "eKitabı Sil" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "Biçimleri Sil:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "Biçime dönüştür:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "Biçimden dönüştür:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "bir seçenek seçin" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "Dönüştür:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "eKitabı dönüştür" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Kitap Adı" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Yazar" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Açıklama" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Etiketler" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Değerlendirme" @@ -1697,82 +1888,83 @@ msgstr "" msgid "Upload Cover from Local Disk" msgstr "" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Yayınevi" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Dil" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Evet" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Hayır" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Anahtar Kelime" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr "Anahtar kelime ara" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Forma metaveri yüklemek için kapağa tıklayın" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Yükleniyor..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Kapak" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Kaynak" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Arama hatası!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "" @@ -1864,27 +2056,36 @@ msgstr "Servis adı girin" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Kayıt ol" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "Emin misiniz?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "" @@ -1976,6 +2177,10 @@ msgstr "" msgid "Enable Uploads" msgstr "" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "" @@ -1989,7 +2194,7 @@ msgid "Enable Public Registration" msgstr "" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "" #: cps/templates/config_edit.html:132 @@ -2056,11 +2261,6 @@ msgstr "LDAP Sunucu Portu" msgid "LDAP Encryption" msgstr "" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Hiçbiri" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "" @@ -2196,7 +2396,7 @@ msgstr "" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Tema" @@ -2228,137 +2428,140 @@ msgstr "" msgid "Default Settings for New Users" msgstr "" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "İndirmeye İzin Ver" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Yüklemeye izin ver" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Düzenlemeye İzin ver" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Şifre değiştirmeye izin ver" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Genel Kitaplıkları düzenlemeye izin ver" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Dilleri Hariç Tut" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 msgid "Default Visible Language of Books" msgstr "" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "Okunmadı olarak işaretle" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "Okundu olarak işaretle" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Okudum" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Açıklama:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Kitaplığa ekle" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "" +#, fuzzy +msgid "Gmail Account" +msgstr "Hesap" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 @@ -2382,10 +2585,10 @@ msgid "Attachment Size Limit" msgstr "" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +msgid "Save and Send Test Email" msgstr "" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Geri" @@ -2411,46 +2614,62 @@ msgstr "Servis adı girin" msgid "Denied Domains (Blacklist)" msgstr "" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Sonraki" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" msgstr "" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 #, fuzzy msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "E-Posta sunucusu ayarlanmadı, lütfen yöneticinizle iletişime geçin!" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "" @@ -2514,7 +2733,7 @@ msgstr "" msgid "Books ordered by file formats" msgstr "Biçime göre sıralanmış eKitaplar" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "" @@ -2523,63 +2742,67 @@ msgstr "" msgid "Books organized in shelves" msgstr "" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "Anasayfa" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Yükleniyor..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "Hata" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "Yükleme tamamlandı, işleniyor, lütfen bekleyin..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Ayarlar" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "Hesap" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Çıkış" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Yükleniyor..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Hata" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Yükleme tamamlandı, işleniyor, lütfen bekleyin..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Ayarlar" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Gözat" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Hakkında" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Önceki" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "eKitap Detayları" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "" @@ -2588,7 +2811,7 @@ msgstr "" msgid "Forgot Password?" msgstr "" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "" @@ -2684,7 +2907,7 @@ msgstr "" msgid "Select" msgstr "" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "Kitap" @@ -2698,128 +2921,141 @@ msgstr "" msgid "epub Reader" msgstr "PDF Okuyucu" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Açık" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Koyu" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Geri" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Kenar çubukları açıkken metni kaydır" +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 #, fuzzy msgid "Comic Reader" msgstr "PDF Okuyucu" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "Klavye Kısayolları" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "Önceki Sayfa" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "Sonraki Sayfa" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "En İyiye Ölçeklendir" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "Genişliğe Ölçeklendir" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "Yüksekliğe Ölçeklendir" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "Asıla göre ölçeklendir" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "Sağa çevir" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "Sola çevir" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "Resmi döndir" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "Açık" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "Koyu" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "Ölçeklendir" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "En İyi" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "Genişlik" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "Yükseklik" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "Asıl" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "Çevir" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "Döndür" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "Yatay" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "Dikey" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "Yön" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "Soldan Sağa" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "Sağdan Sola" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "" @@ -2828,7 +3064,7 @@ msgstr "" msgid "DJVU Reader" msgstr "PDF Okuyucu" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 #, fuzzy msgid "PDF Reader" msgstr "PDF Okuyucu" @@ -2847,7 +3083,7 @@ msgid "Choose a username" msgstr "Kullanıcı adı seç" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "E-Posta adresiniz" #: cps/templates/remote_login.html:5 @@ -2866,15 +3102,19 @@ msgstr "" msgid "This verification link will expire in 10 minutes." msgstr "" -#: cps/templates/search.html:5 -msgid "No Results Found" +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" msgstr "" #: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "" + +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Sonuçlar:" @@ -2886,10 +3126,6 @@ msgstr "" msgid "Published Date To" msgstr "" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Etiketleri Hariç Tut" @@ -2931,30 +3167,26 @@ msgstr "" msgid "To:" msgstr "" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Bu Kitaplığı sil" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "" @@ -2996,7 +3228,7 @@ msgid "System Statistics" msgstr "" #: cps/templates/stats.html:33 -msgid "Program Library" +msgid "Program" msgstr "" #: cps/templates/stats.html:34 @@ -3023,8 +3255,16 @@ msgstr "İlerleme" msgid "Run Time" msgstr "" -#: cps/templates/tasks.html:18 -msgid "Start Time" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." msgstr "" #: cps/templates/user_edit.html:20 @@ -3055,19 +3295,23 @@ msgstr "" msgid "Create/View" msgstr "" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "" @@ -3086,17 +3330,17 @@ msgstr "Kullanıcı adı seç" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" +msgid "Enter Email" +msgstr "Deneme e-Postası" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "Enter eReader Email" msgstr "E-Posta adresiniz" #: cps/templates/user_table.html:136 #, fuzzy -msgid "Enter Kindle E-mail Address" -msgstr "E-Posta adresiniz" - -#: cps/templates/user_table.html:136 -#, fuzzy -msgid "Kindle E-mail" +msgid "eReader Email" msgstr "Deneme e-Postası" #: cps/templates/user_table.html:137 @@ -3160,10 +3404,6 @@ msgstr "" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Seri seçimini göster" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Rastgele eKitap göster" - diff --git a/cps/translations/uk/LC_MESSAGES/messages.mo b/cps/translations/uk/LC_MESSAGES/messages.mo index 1e4731af8..7477286ac 100644 Binary files a/cps/translations/uk/LC_MESSAGES/messages.mo and b/cps/translations/uk/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/uk/LC_MESSAGES/messages.po b/cps/translations/uk/LC_MESSAGES/messages.po index 131da18fe..f01992806 100644 --- a/cps/translations/uk/LC_MESSAGES/messages.po +++ b/cps/translations/uk/LC_MESSAGES/messages.po @@ -6,585 +6,641 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-web\n" "Report-Msgid-Bugs-To: https://github.com/janeczku/calibre-web\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2017-04-30 00:47+0300\n" "Last-Translator: ABIS Team \n" "Language: uk\n" "Language-Team: \n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "не встановлено" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "Статистика" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "Сервер перезавантажено, будь-ласка, перезавантажте сторінку" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "Виконується зупинка серверу, будь-ласка, закрийте вікно" -#: cps/admin.py:154 -msgid "Reconnect successful" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" +msgstr "Невідома команда" + +#: cps/admin.py:167 +msgid "Success! Books queued for Metadata Backup" msgstr "" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "Невідомий" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "Сторінка адміністратора" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "Настройки сервера" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "Конфігурація інтерфейсу" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 #, fuzzy msgid "Edit Users" msgstr "Керування сервером" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" -msgstr "" +msgstr "Всі" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" -msgstr "" +msgstr "Користувача не знайдено" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" -msgstr "" +msgstr "{} користувачі видалені успішно" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "Показати всі" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" -msgstr "" +msgstr "Не правильна роль" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "Ви справді хочете видалити книжкову полицю?" -#: cps/admin.py:580 +#: cps/admin.py:611 #, fuzzy msgid "Are you sure you want to change locales of selected user(s)?" msgstr "Ви справді хочете видалити книжкову полицю?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "" -#: cps/admin.py:586 +#: cps/admin.py:617 #, fuzzy msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "Ви справді хочете видалити книжкову полицю?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:590 +#: cps/admin.py:622 #, fuzzy msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "Ви справді хочете видалити книжкову полицю?" -#: cps/admin.py:592 +#: cps/admin.py:624 #, fuzzy msgid "Are you sure you want to change Calibre library location?" msgstr "Ви справді хочете видалити книжкову полицю?" -#: cps/admin.py:741 -msgid "Tag not found" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" -msgstr "" +msgstr "Заборонити" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" +msgstr "Дозволити" + +#: cps/admin.py:915 +msgid "{} sync entries deleted" msgstr "" -#: cps/admin.py:1015 +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Тег не знайдено" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "З'єднання з базою даних закрите" - -#: cps/admin.py:1324 -#, fuzzy -msgid "Database Configuration" -msgstr "Особливі налаштування" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "Будь-ласка, заповніть всі поля!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "Додати користувача" - -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "Користувач '%(user)s' додан" - -#: cps/admin.py:1369 -msgid "Found an existing account for this e-mail address or name." -msgstr "" - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "Користувача '%(nick)s' видалено" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "Змінити користувача %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "Користувача '%(nick)s' оновлено" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "" - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "Змінити налаштування SMTP" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "" + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "" -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "" + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "Змінити користувача %(nick)s" + +#: cps/admin.py:1423 +#, python-format +msgid "Success! Password for user %(user)s reset" msgstr "" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "Будь-ласка, спочатку сконфігуруйте параметри SMTP" -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "Перевірка оновлень" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "Завантаження оновлень" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "Розпакування оновлення" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" -msgstr "" +msgstr "Заміна файлів" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "З'єднання з базою даних закрите" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" -msgstr "" +msgstr "Сервер зупиняється" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "Оновлення встановлені, натисніть ok і перезавантажте сторінку" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" -msgstr "" +msgstr "Оновлення неуспішне:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" -msgstr "" +msgstr "HTTP помилка" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" -msgstr "" +msgstr "Помилка зʼєднання" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" -msgstr "" +msgstr "Помилка" -#: cps/admin.py:1696 +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" msgstr "" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" msgstr "" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "" -#: cps/converter.py:30 -msgid "not configured" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" msgstr "" +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "З'єднання з базою даних закрите" + +#: cps/admin.py:1850 +#, fuzzy +msgid "Database Configuration" +msgstr "Особливі налаштування" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Будь-ласка, заповніть всі поля!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Додати користувача" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Користувач '%(user)s' додан" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "" + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Користувача '%(nick)s' видалено" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Користувача '%(nick)s' оновлено" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "не встановлено" + #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "Ні" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "Неможливо відкрити книгу. Файл не існує або немає доступу." -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "змінити метадані" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "Завантажувальний файл повинен мати розширення" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "" - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "" - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "Сталась помилка при редагуванні книги. Будь-ласка, перевірте лог-файл для деталей" - -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " +#: cps/editbooks.py:234 +msgid "Error editing book: {}" msgstr "" -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "" + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "Завантажувальний файл повинен мати розширення" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "змінити метадані" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "" + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "" @@ -598,165 +654,175 @@ msgstr "Домен зворотнього зв'язку не підтвердж msgid "%(format)s format not found for book id: %(book)d" msgstr "" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "Відправити на Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +msgid "This Email has been sent via Calibre-Web." msgstr "" -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +msgid "Calibre-Web Test Email" msgstr "" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +msgid "Test Email" msgstr "" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "" -#: cps/helper.py:135 +#: cps/helper.py:137 #, python-format -msgid "Registration e-mail for user: %(name)s" +msgid "Registration Email for user: %(name)s" msgstr "" -#: cps/helper.py:146 cps/helper.py:152 +#: cps/helper.py:148 cps/helper.py:154 #, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" -msgstr "" - -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 #, fuzzy, python-format -msgid "%(book)s send to Kindle" +msgid "Send %(format)s to eReader" +msgstr "Надіслати %(format)s до E-Reader" + +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" msgstr "Відправити на Kindle" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "" -#: cps/helper.py:388 +#: cps/helper.py:450 #, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "" -#: cps/helper.py:507 cps/web.py:1654 -msgid "Found an existing account for this e-mail address" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +msgid "Error executing UnRar" msgstr "" -#: cps/helper.py:762 -msgid "Waiting" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Огляд" + +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" msgstr "" -#: cps/helper.py:764 -msgid "Failed" +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" -msgstr "" - -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "" @@ -765,9 +831,9 @@ msgstr "" msgid "Register with %(provider)s" msgstr "" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "Ви увійшли як користувач: '%(nickname)s'" #: cps/oauth_bb.py:148 @@ -826,507 +892,610 @@ msgstr "" msgid "Google Oauth error: {}" msgstr "" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" -msgstr "" +msgstr "{} зірок" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "Ім'я користувача" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "Токен не знайдено" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Час дії токено вичерпано" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "Вдалося! Будь-ласка, поверніться до вашого пристрою" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" -msgstr "" +msgstr "Книжки" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "Показувати останні книги" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "Популярні книги" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "Показувати популярні книги" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "Книги з найкращим рейтингом" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "Показувати книги з найвищим рейтингом" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "Прочитані книги" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "Показувати прочитані та непрочитані книги" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "Непрочитані книги" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" -msgstr "" +msgstr "Показати не прочитані" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "Огляд" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "Показувати випадкові книги" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "Категорії" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "Показувати вибір категорії" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "Серії" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "Показувати вибір серії" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "Автори" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "Показувати вибір автора" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" -msgstr "" +msgstr "Видавництва" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" -msgstr "" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" +msgstr "Показувати вибір серії" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "Мови" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "Показувати вибір мови" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" -msgstr "" +msgstr "Рейтинги" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" -msgstr "" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "Показувати вибір серії" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" -msgstr "" +msgstr "Формати файлів" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" -msgstr "" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" +msgstr "Показувати вибір серії" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" -msgstr "" +msgstr "Архівні книжки" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" -msgstr "" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "Архівні книжки" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" -msgstr "" +msgstr "Список книжок" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "" - -#: cps/shelf.py:73 -#, fuzzy -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "Вибачте, але у вас немає дозволу для видалення книги з цієї полиці" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "Книга додана на книжкову полицю: %(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "Книга видалена з книжкової полиці: %(sname)s" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "Вибачте, але у вас немає дозволу для видалення книги з цієї полиці" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "створити книжкову полицю" - -#: cps/shelf.py:236 -#, fuzzy -msgid "Sorry you are not allowed to edit this shelf" -msgstr "Вибачте, але у вас немає дозволу для видалення книги з цієї полиці" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "Змінити книжкову полицю" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "Створена книжкова полиця %(title)s" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "Книжкова полиця %(title)s змінена" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "Сталась помилка" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "Змінити розташування книжкової полиці '%(name)s'" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "Книжкова полиця: '%(name)s'" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "Помилка при відкриванні полиці. Полиця не існує або до неї відсутній доступ" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "" - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "" - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "Огляд (випадкові книги)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "Популярні книги (найбільш завантажувані)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "Серії: %(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "Категорія: %(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "Мова: %(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "Розширений пошук" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "Пошук" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "DLS" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " -msgstr "" +msgstr "Опубліковані після " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " -msgstr "Опубліковано до" +msgstr "Опубліковано до " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" -msgstr "" +msgstr "Рейтинг <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" -msgstr "" +msgstr "Рейтинг >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Розширений пошук" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" msgstr "" -#: cps/web.py:1445 +#: cps/shelf.py:55 +#, fuzzy +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Вибачте, але у вас немає дозволу для видалення книги з цієї полиці" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Книга додана на книжкову полицю: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Книга видалена з книжкової полиці: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "створити книжкову полицю" + +#: cps/shelf.py:218 +#, fuzzy +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Вибачте, але у вас немає дозволу для видалення книги з цієї полиці" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Змінити книжкову полицю" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "Змінити розташування книжкової полиці '%(name)s'" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Створена книжкова полиця %(title)s" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Книжкова полиця %(title)s змінена" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Сталась помилка" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "Книжкова полиця: '%(name)s'" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "Помилка при відкриванні полиці. Полиця не існує або до неї відсутній доступ" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Завдання" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Очікує" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Розпочато" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Завершено" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "Закінчено" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "Відмінено" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Невідомий статус" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "" + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "" + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "Огляд (випадкові книги)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "Популярні книги (найбільш завантажувані)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "Видавництво: %(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "Серії: %(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "Рейтинг: Відсутній" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "Рейтинг: %(rating)s зірок" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "Формат файлу: %(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "Категорія: %(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "Мова: %(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Завантаження" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Список рейтингів" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Список форматів файлу" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "Будь-ласка, спочатку сконфігуруйте параметри SMTP" + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "Помилка при відправці книги: %(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "" -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "Зареєструватись" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "" -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "Помилка в імені користувача або паролі" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "Профіль %(name)s" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "Профіль оновлено" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "" + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "Відправити на Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "змінити метадані" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Додати нову книгу" + #: cps/templates/admin.html:9 msgid "Users" msgstr "Список користувачів" @@ -1339,14 +1508,15 @@ msgstr "Ім'я користувача" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "Kindle" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "Адмін" @@ -1356,212 +1526,229 @@ msgstr "Адмін" msgid "Password" msgstr "Пароль" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "Додати нову книгу" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "Завантажити" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "Редагувати" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "Видалити" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "SMTP-сервер" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP-порт" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "SSL" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "SMTP логін" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "Відправник" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "Налаштування сервера" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Папка Calibre DB" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" -msgstr "" +msgstr "Рівень логування" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "Порт" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" -msgstr "" +msgstr "Зовнішній порт" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "Кількість книг на сторінці" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "Загрузка на сервер" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "Анонімний перегляд" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "Публічна реєстрація" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 #, fuzzy msgid "Edit Calibre Database Configuration" msgstr "Папка Calibre DB" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "Заплановані завдання" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "Максимальний час завдання" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "Адміністрування" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" -msgstr "" +msgstr "Переглянути логи" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "Повторне підключення до БД Calibre" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" -msgstr "" +msgstr "Перезавантажити" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" -msgstr "" +msgstr "Вимкнути" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "Інформація про версію" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" -msgstr "" +msgstr "Версія" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" -msgstr "" +msgstr "Деталі" -#: cps/templates/admin.html:183 -msgid "Current version" -msgstr "" +#: cps/templates/admin.html:227 +msgid "Current Version" +msgstr "Поточна версія" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "Перевірка оновлень" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "Встановити оновлення" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" -msgstr "" +msgstr "Впевнені що хочете перезавантажити?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "Ok" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" -msgstr "" +msgstr "Скасувати" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "Встановлення оновлень, будь-ласка, не оновлюйте сторінку" @@ -1573,119 +1760,118 @@ msgstr "через" msgid "In Library" msgstr "У бібліотеці" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "Більше за" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "Видалити книгу" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" -msgstr "" +msgstr "Видалити формати:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" -msgstr "" +msgstr "Конвертувати з:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" -msgstr "" +msgstr "Конвертувати в:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" -msgstr "" +msgstr "Конвертувати книгу" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "Назва книги" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "Автор" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "Опис" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" -msgstr "" +msgstr "Ідентифікатори" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" -msgstr "" +msgstr "Видалити" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" -msgstr "" +msgstr "Додати ідентифікатор" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "Теги" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "Рейтинг" @@ -1697,82 +1883,83 @@ msgstr "" msgid "Upload Cover from Local Disk" msgstr "" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "Опубліковано" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "Видавець" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "Мова" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "Так" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "Ні" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "Формат завантаження" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "переглянути книгу після редагування" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "Отримати метадані" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" -msgstr "" +msgstr "Зберегти" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "Ключове слово" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " Пошук по ключовому слову" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "Натисніть на обкладинку, щоб отримати метадані" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "Завантаження..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "Закрити" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "Джерело" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "Помилка пошуку!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "" @@ -1849,7 +2036,7 @@ msgstr "" #: cps/templates/book_table.html:71 msgid "Publishing Date" -msgstr "" +msgstr "Дата публікації" #: cps/templates/book_table.html:72 msgid "Enter Publishers" @@ -1857,35 +2044,44 @@ msgstr "" #: cps/templates/book_table.html:73 msgid "Enter comments" -msgstr "" +msgstr "Введіть коментар" #: cps/templates/book_table.html:73 msgid "Comments" +msgstr "Коментарі" + +#: cps/templates/book_table.html:75 +msgid "Archive Status" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "Зареєструватись" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" -msgstr "" +msgstr "Обʼєднати" #: cps/templates/config_db.html:12 msgid "Location of Calibre Database" @@ -1933,19 +2129,19 @@ msgstr "Розташування ключових слів SSL (залиште #: cps/templates/config_edit.html:43 msgid "Update Channel" -msgstr "" +msgstr "Канал оновлення" #: cps/templates/config_edit.html:45 msgid "Stable" -msgstr "" +msgstr "Стабільний" #: cps/templates/config_edit.html:46 msgid "Nightly" -msgstr "" +msgstr "Нічний" #: cps/templates/config_edit.html:50 msgid "Trusted Hosts (Comma Separated)" -msgstr "" +msgstr "Довірені хости (розділені комою)" #: cps/templates/config_edit.html:61 msgid "Logfile Configuration" @@ -1975,6 +2171,10 @@ msgstr "" msgid "Enable Uploads" msgstr "Дозволити завантаження книг на сервер" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "" @@ -1988,7 +2188,7 @@ msgid "Enable Public Registration" msgstr "Дозволити публічну реєстрацію" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "" #: cps/templates/config_edit.html:132 @@ -2029,7 +2229,7 @@ msgstr "" #: cps/templates/config_edit.html:180 msgid "Login type" -msgstr "" +msgstr "Тип логіну" #: cps/templates/config_edit.html:182 msgid "Use Standard Authentication" @@ -2055,18 +2255,13 @@ msgstr "" msgid "LDAP Encryption" msgstr "" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "Ні" - #: cps/templates/config_edit.html:205 msgid "TLS" -msgstr "" +msgstr "TLS" #: cps/templates/config_edit.html:206 msgid "SSL" -msgstr "" +msgstr "SSL" #: cps/templates/config_edit.html:210 msgid "LDAP CACertificate Path (Only needed for Client Certificate Authentication)" @@ -2086,7 +2281,7 @@ msgstr "" #: cps/templates/config_edit.html:235 msgid "Anonymous" -msgstr "" +msgstr "Анонім" #: cps/templates/config_edit.html:236 msgid "Unauthenticated" @@ -2138,7 +2333,7 @@ msgstr "" #: cps/templates/config_edit.html:280 msgid "Autodetect" -msgstr "" +msgstr "Автовизначення" #: cps/templates/config_edit.html:281 msgid "Custom Filter" @@ -2195,7 +2390,7 @@ msgstr "Кількість показаних випадкових книг" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "Тема" @@ -2227,138 +2422,140 @@ msgstr "Regexp для сортування по назві" msgid "Default Settings for New Users" msgstr "Налаштування по замовчуванню для нових користувачів" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "Керування сервером" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "Дозволити завантажувати з сервера" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "Дозволити завантаження на сервер" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "Дозволити редагування книг" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "Дозволити зміну пароля" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "Дозволити редагування публічних книжкових полиць" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "Виключити мови" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "Показувати книги на мовах" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "Можливості за замовчуванням для нових користувачів" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "Показувати випадкові книги при перегляді деталей" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "Відкрити в браузері" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" -msgstr "" +msgstr "Прослухати в браузері" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" -msgstr "" +msgstr "Опубліковано" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" -msgstr "" +msgstr "Відмітити як не прочитане" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" -msgstr "" +msgstr "Відмітити як прочитане" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "Прочитано" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" -msgstr "" +msgstr "Відновити з архіву" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" -msgstr "" +msgstr "Додати в архів" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" -msgstr "" +msgstr "Заархівовано" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "Опис:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "Додати на книжкову полицю" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" -msgstr "" +msgstr "(Публічно)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "Редагувати метадані" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" +msgid "Gmail Account" msgstr "" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 @@ -2379,13 +2576,14 @@ msgstr "Пароль SMTP" #: cps/templates/email_edit.html:58 msgid "Attachment Size Limit" -msgstr "" +msgstr "Обмеження розміру вкладення" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "Зберегти налаштування і відправити тестове повідомлення" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "Назад" @@ -2396,60 +2594,76 @@ msgstr "" #: cps/templates/email_edit.html:78 cps/templates/email_edit.html:105 msgid "Add Domain" -msgstr "" +msgstr "Додати домен" #: cps/templates/email_edit.html:81 cps/templates/email_edit.html:108 #: cps/templates/user_table.html:27 msgid "Add" -msgstr "" +msgstr "Додати" #: cps/templates/email_edit.html:86 cps/templates/email_edit.html:96 msgid "Enter domainname" -msgstr "" +msgstr "Введіть домен" #: cps/templates/email_edit.html:92 msgid "Denied Domains (Blacklist)" -msgstr "" +msgstr "Заборонені домени (Чорний список)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "Далі" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" msgstr "" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "Список" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "" @@ -2513,7 +2727,7 @@ msgstr "" msgid "Books ordered by file formats" msgstr "" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "" @@ -2522,63 +2736,67 @@ msgstr "" msgid "Books organized in shelves" msgstr "" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "Включити навігацію" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "Завантаження..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "" - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "Налаштування" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "Вийти" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Завантаження..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Помилка" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "" + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Налаштування" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "Перегляд" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "Про програму" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "Попередній перегляд" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "Деталі" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "Запам'ятати мене" @@ -2587,7 +2805,7 @@ msgstr "Запам'ятати мене" msgid "Forgot Password?" msgstr "" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "Увійдіть в систему за допомогою magic link" @@ -2633,7 +2851,7 @@ msgstr "" #: cps/templates/modal_dialogs.html:15 msgid "Enter Tag" -msgstr "" +msgstr "Введіть тег" #: cps/templates/modal_dialogs.html:24 msgid "Add View Restriction" @@ -2661,7 +2879,7 @@ msgstr "" #: cps/templates/modal_dialogs.html:76 msgid "Choose File Location" -msgstr "" +msgstr "Оберіть розташування файлу" #: cps/templates/modal_dialogs.html:82 msgid "type" @@ -2683,7 +2901,7 @@ msgstr "" msgid "Select" msgstr "" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 #, fuzzy msgid "Ok" msgstr "Книга" @@ -2696,135 +2914,148 @@ msgstr "" msgid "epub Reader" msgstr "" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Назад" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "Переформатувати текст, коли відкриті бічні панелі." +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 msgid "Comic Reader" msgstr "" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "" -#: cps/templates/readcbr.html:125 -msgid "Best" -msgstr "" - -#: cps/templates/readcbr.html:126 -msgid "Width" -msgstr "" - -#: cps/templates/readcbr.html:127 -msgid "Height" -msgstr "" - #: cps/templates/readcbr.html:128 +msgid "Best" +msgstr "Краще" + +#: cps/templates/readcbr.html:129 +msgid "Width" +msgstr "Ширина" + +#: cps/templates/readcbr.html:130 +msgid "Height" +msgstr "Висота" + +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" -msgstr "" +msgstr "Повернути" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" -msgstr "" - -#: cps/templates/readcbr.html:153 -msgid "Direction" -msgstr "" +msgstr "Вертикально" #: cps/templates/readcbr.html:156 +msgid "Direction" +msgstr "Напрям" + +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" -msgstr "" +msgstr "Показати" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" -msgstr "" +msgstr "Сховати" #: cps/templates/readdjvu.html:5 msgid "DJVU Reader" msgstr "" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 msgid "PDF Reader" msgstr "" @@ -2842,7 +3073,7 @@ msgid "Choose a username" msgstr "Виберіть ім'я користувача" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "Ваш email-адрес" #: cps/templates/remote_login.html:5 @@ -2861,15 +3092,19 @@ msgstr "Після цього ви автоматично ввійдете в с msgid "This verification link will expire in 10 minutes." msgstr "" -#: cps/templates/search.html:5 -msgid "No Results Found" +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" msgstr "" #: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "" + +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "Результати для:" @@ -2881,10 +3116,6 @@ msgstr "Дата публікації з" msgid "Published Date To" msgstr "Дата публікації до" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "Виключити теги" @@ -2904,7 +3135,7 @@ msgstr "Виключити мови" #: cps/templates/search_form.html:126 msgid "Extensions" -msgstr "" +msgstr "Розширення" #: cps/templates/search_form.html:134 msgid "Exclude Extensions" @@ -2920,36 +3151,32 @@ msgstr "" #: cps/templates/search_form.html:180 msgid "From:" -msgstr "" +msgstr "Від:" #: cps/templates/search_form.html:190 msgid "To:" -msgstr "" +msgstr "До:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "Видалити цю книжкову полицю" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "Книжкова полиця буде остаточно видалена для всіх" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "зробити книжкову полицю доступною для всіх?" @@ -2988,11 +3215,11 @@ msgstr "Серій в цій бібліотеці" #: cps/templates/stats.html:29 msgid "System Statistics" -msgstr "" +msgstr "Статистика системи" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "Назва" +msgid "Program" +msgstr "Програма" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3000,31 +3227,39 @@ msgstr "Встановлена версія" #: cps/templates/tasks.html:12 msgid "User" -msgstr "" +msgstr "Користувач" #: cps/templates/tasks.html:14 msgid "Task" -msgstr "" +msgstr "Завдання" #: cps/templates/tasks.html:15 msgid "Status" -msgstr "" +msgstr "Статус" #: cps/templates/tasks.html:16 msgid "Progress" -msgstr "" +msgstr "Прогрес" #: cps/templates/tasks.html:17 msgid "Run Time" +msgstr "Тривалість" + +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "Дії" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." msgstr "" -#: cps/templates/tasks.html:18 -msgid "Start Time" +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" -msgstr "" +msgstr "Скинути пароль користувача" #: cps/templates/user_edit.html:43 msgid "Language of Books" @@ -3032,7 +3267,7 @@ msgstr "Показувати книги на мовах" #: cps/templates/user_edit.html:54 msgid "OAuth Settings" -msgstr "" +msgstr "Налаштування OAuth" #: cps/templates/user_edit.html:56 msgid "Link" @@ -3048,27 +3283,31 @@ msgstr "" #: cps/templates/user_edit.html:66 msgid "Create/View" +msgstr "Створити/Переглянути" + +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" msgstr "" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "Видалити цього користувача" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "" #: cps/templates/user_table.html:80 cps/templates/user_table.html:103 msgid "Select..." -msgstr "" +msgstr "Обрати..." #: cps/templates/user_table.html:131 #, fuzzy @@ -3082,21 +3321,22 @@ msgstr "Виберіть ім'я користувача" #: cps/templates/user_table.html:135 #, fuzzy -msgid "Enter E-mail Address" -msgstr "Ваш email-адрес" - -#: cps/templates/user_table.html:136 -#, fuzzy -msgid "Enter Kindle E-mail Address" +msgid "Enter Email" msgstr "Kindle" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" -msgstr "" +#, fuzzy +msgid "Enter eReader Email" +msgstr "Kindle" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "eReader Email" +msgstr "Kindle" #: cps/templates/user_table.html:137 msgid "Locale" -msgstr "" +msgstr "Локалізація" #: cps/templates/user_table.html:138 msgid "Visible Book Languages" @@ -3108,15 +3348,15 @@ msgstr "" #: cps/templates/user_table.html:139 msgid "Allowed Tags" -msgstr "" +msgstr "Дозволені теги" #: cps/templates/user_table.html:140 msgid "Edit Denied Tags" -msgstr "" +msgstr "Змінити заборонені теги" #: cps/templates/user_table.html:140 msgid "Denied Tags" -msgstr "" +msgstr "Заборонені теги" #: cps/templates/user_table.html:141 msgid "Edit Allowed Column Values" @@ -3141,7 +3381,7 @@ msgstr "Дозволити зміну пароля" #: cps/templates/user_table.html:147 msgid "View" -msgstr "" +msgstr "Показати" #: cps/templates/user_table.html:150 #, fuzzy @@ -3154,10 +3394,6 @@ msgstr "" #: cps/templates/user_table.html:156 #, fuzzy -msgid "Show read/unread selection" +msgid "Show Read/Unread Section" msgstr "Показувати вибір серії" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "Показувати випадкові книги" - diff --git a/cps/translations/vi/LC_MESSAGES/messages.mo b/cps/translations/vi/LC_MESSAGES/messages.mo new file mode 100644 index 000000000..193d77d11 Binary files /dev/null and b/cps/translations/vi/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/vi/LC_MESSAGES/messages.po b/cps/translations/vi/LC_MESSAGES/messages.po new file mode 100644 index 000000000..ba507e62e --- /dev/null +++ b/cps/translations/vi/LC_MESSAGES/messages.po @@ -0,0 +1,3391 @@ +# This file is distributed under the same license as the Calibre-web project +# Ha Link +msgid "" +msgstr "" +"Project-Id-Version: Calibre-web\n" +"Report-Msgid-Bugs-To: https://github.com/janeczku/calibre-web\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" +"PO-Revision-Date: 2022-09-20 21:36+0700\n" +"Last-Translator: Ha Link \n" +"Language: vi\n" +"Language-Team: \n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.10.3\n" + +#: cps/about.py:84 +msgid "Statistics" +msgstr "Thống kê" + +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." +msgstr "Máy chủ đã khởi động lại,hãy tải lại trang" + +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." +msgstr "Máy chủ đang được tắt, hãy đóng cửa sổ này" + +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" + +#: cps/admin.py:156 +msgid "Unknown command" +msgstr "Lệnh không tồn tại" + +#: cps/admin.py:167 +msgid "Success! Books queued for Metadata Backup" +msgstr "" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 +msgid "Unknown" +msgstr "Không rõ" + +#: cps/admin.py:225 +msgid "Admin page" +msgstr "Trang admin" + +#: cps/admin.py:245 +msgid "Basic Configuration" +msgstr "Thiết lập cơ bản" + +#: cps/admin.py:283 +msgid "UI Configuration" +msgstr "Thiết lập UI" + +#: cps/admin.py:317 cps/templates/admin.html:51 +msgid "Edit Users" +msgstr "Chỉnh sửa người dùng" + +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 +msgid "All" +msgstr "Tất cả" + +#: cps/admin.py:388 cps/admin.py:1392 +msgid "User not found" +msgstr "Không tìm thấy user" + +#: cps/admin.py:402 +msgid "{} users deleted successfully" +msgstr "{} người dung đã đươc xoá thành công" + +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 +#: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 +msgid "Show All" +msgstr "Hiển thị tất cả" + +#: cps/admin.py:446 cps/admin.py:452 +msgid "Malformed request" +msgstr "Yêu cầu không đúng định dạng" + +#: cps/admin.py:464 cps/admin.py:1993 +msgid "Guest Name can't be changed" +msgstr "Tên người dung khách không thể thay đổi" + +#: cps/admin.py:476 +msgid "Guest can't have this role" +msgstr "Khách không thể mang vai trò này" + +#: cps/admin.py:488 cps/admin.py:1948 +msgid "No admin user remaining, can't remove admin role" +msgstr "Không còn người dùng quản trị, không thể xoá vai trò admin" + +#: cps/admin.py:492 cps/admin.py:506 +msgid "Value has to be true or false" +msgstr "Giá trị phải là true hoặc false" + +#: cps/admin.py:494 +msgid "Invalid role" +msgstr "Vai trò không hợp lệ" + +#: cps/admin.py:498 +msgid "Guest can't have this view" +msgstr "Tài khoản khách không có màn hình này" + +#: cps/admin.py:508 +msgid "Invalid view" +msgstr "View không hợp lệ" + +#: cps/admin.py:511 +msgid "Guest's Locale is determined automatically and can't be set" +msgstr "Ngôn ngữ của khách được xác định tự động và không thể đặt được" + +#: cps/admin.py:515 +msgid "No Valid Locale Given" +msgstr "Địa chỉ cung cấp không hợp lệ" + +#: cps/admin.py:526 +msgid "No Valid Book Language Given" +msgstr "Ngôn ngữ sách không hợp lệ" + +#: cps/admin.py:528 cps/editbooks.py:442 +msgid "Parameter not found" +msgstr "Tham số không tồn tại" + +#: cps/admin.py:565 +msgid "Invalid Read Column" +msgstr "Cột đọc không hợp lệ" + +#: cps/admin.py:571 +msgid "Invalid Restricted Column" +msgstr "Cột bị hạn chế không hợp lệ" + +#: cps/admin.py:591 cps/admin.py:1819 +msgid "Calibre-Web configuration updated" +msgstr "Thiết lập Calibre-Web đã cập nhật" + +#: cps/admin.py:603 +msgid "Do you really want to delete the Kobo Token?" +msgstr "Bạn có thực sự muốn xóa Kobo Token không?" + +#: cps/admin.py:605 +msgid "Do you really want to delete this domain?" +msgstr "Bạn có thực sự muốn xóa miền này không?" + +#: cps/admin.py:607 +msgid "Do you really want to delete this user?" +msgstr "Bạn có thực sự muốn xóa người dùng này không?" + +#: cps/admin.py:609 +msgid "Are you sure you want to delete this shelf?" +msgstr "Bạn có chắc chắn muốn xóa giá này không?" + +#: cps/admin.py:611 +msgid "Are you sure you want to change locales of selected user(s)?" +msgstr "Bạn có chắc chắn muốn thay đổi ngôn ngữ của những người dùng đã chọn?" + +#: cps/admin.py:613 +msgid "Are you sure you want to change visible book languages for selected user(s)?" +msgstr "Bạn có chắc chắn muốn thay đổi ngôn ngữ sách hiển thị cho (những) người dùng đã chọn không?" + +#: cps/admin.py:615 +msgid "Are you sure you want to change the selected role for the selected user(s)?" +msgstr "Bạn có chắc chắn muốn thay đổi vai trò đã chọn cho (những) người dùng đã chọn không?" + +#: cps/admin.py:617 +msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" +msgstr "Bạn có chắc chắn muốn thay đổi những giới hạn đã chọn cho người dung?" + +#: cps/admin.py:619 +msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" +msgstr "Bạn có chắc chắn muốn thay đổi các giới hạn hiển thị đã chọn cho (những) người dùng đã chọn không?" + +#: cps/admin.py:622 +msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" +msgstr "Bạn có chắc chắn muốn thay đổi hành vi đồng bộ hóa giá cho (những) người dùng đã chọn không?" + +#: cps/admin.py:624 +msgid "Are you sure you want to change Calibre library location?" +msgstr "Bạn có chắc chắn muốn thay đổi vị trí thư viện Calibre không?" + +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "" + +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "Bạn có chắc chắn muốn xóa cơ sở dữ liệu đồng bộ của Calibre-Web để bắt buộc đồng bộ hóa hoàn toàn với Kobo Reader của mình không?" + +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 +#: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 +#: cps/templates/user_table.html:58 +msgid "Deny" +msgstr "Từ chối" + +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 +#: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 +#: cps/templates/user_table.html:61 +msgid "Allow" +msgstr "Cho phép" + +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{} mục nhập đồng bộ hóa đã bị xóa" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "Tag không tồn tại" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "Hành động không hợp lệ" + +#: cps/admin.py:1104 +msgid "client_secrets.json Is Not Configured For Web Application" +msgstr "" + +#: cps/admin.py:1149 +msgid "Logfile Location is not Valid, Please Enter Correct Path" +msgstr "Vị trí tệp nhật ký không hợp lệ, vui lòng nhập đường dẫn chính xác" + +#: cps/admin.py:1155 +msgid "Access Logfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1185 +msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" +msgstr "" + +#: cps/admin.py:1191 +msgid "Please Enter a LDAP Service Account and Password" +msgstr "" + +#: cps/admin.py:1194 +msgid "Please Enter a LDAP Service Account" +msgstr "" + +#: cps/admin.py:1199 +#, python-format +msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" +msgstr "" + +#: cps/admin.py:1201 +msgid "LDAP Group Object Filter Has Unmatched Parenthesis" +msgstr "" + +#: cps/admin.py:1205 +#, python-format +msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" +msgstr "" + +#: cps/admin.py:1207 +msgid "LDAP User Object Filter Has Unmatched Parenthesis" +msgstr "" + +#: cps/admin.py:1214 +#, python-format +msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" +msgstr "" + +#: cps/admin.py:1216 +msgid "LDAP Member User Filter Has Unmatched Parenthesis" +msgstr "" + +#: cps/admin.py:1223 +msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" +msgstr "Thêm người dùng mới" + +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" +msgstr "" + +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" + +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "Lỗi cơ sở dữ liệu: %(error)s." + +#: cps/admin.py:1311 +#, python-format +msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" +msgstr "" + +#: cps/admin.py:1314 +#, python-format +msgid "There was an error sending the Test e-mail: %(res)s" +msgstr "" + +#: cps/admin.py:1316 +msgid "Please configure your e-mail address first..." +msgstr "" + +#: cps/admin.py:1318 +msgid "Email Server Settings updated" +msgstr "" + +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +#, fuzzy +msgid "Scheduled tasks settings updated" +msgstr "Thiết lập cơ sở dữ lieu đã được cập nhật" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "Lỗi không xác định xảy ra. Xin hãy thử lại sau." + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 +#, python-format +msgid "Edit User %(nick)s" +msgstr "Chỉnh sửa người dùng %(nick)s" + +#: cps/admin.py:1423 +#, python-format +msgid "Success! Password for user %(user)s reset" +msgstr "" + +#: cps/admin.py:1429 +msgid "Oops! Please configure the SMTP mail settings." +msgstr "" + +#: cps/admin.py:1440 +msgid "Logfile viewer" +msgstr "" + +#: cps/admin.py:1506 +msgid "Requesting update package" +msgstr "" + +#: cps/admin.py:1507 +msgid "Downloading update package" +msgstr "" + +#: cps/admin.py:1508 +msgid "Unzipping update package" +msgstr "Đang giải nén tệp cập nhật" + +#: cps/admin.py:1509 +msgid "Replacing files" +msgstr "They thế tập tin" + +#: cps/admin.py:1510 +msgid "Database connections are closed" +msgstr "Liên kết cơ sở dữ liệu đã được đóng" + +#: cps/admin.py:1511 +msgid "Stopping server" +msgstr "Đang dừng server" + +#: cps/admin.py:1512 +msgid "Update finished, please press okay and reload page" +msgstr "Cập nhật hoàn tất, ấn okay và tải lại trang" + +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 +msgid "Update failed:" +msgstr "Cập nhật thất bại:" + +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 +msgid "HTTP Error" +msgstr "Lỗi HTTP" + +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 +msgid "Connection error" +msgstr "Lỗi kết nối" + +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 +msgid "Timeout while establishing connection" +msgstr "" + +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 +msgid "General error" +msgstr "Lỗi chung" + +#: cps/admin.py:1517 +msgid "Update file could not be saved in temp dir" +msgstr "File cập nhật không thể được lưu trong thư mục tạm thời" + +#: cps/admin.py:1518 +msgid "Files could not be replaced during update" +msgstr "" + +#: cps/admin.py:1542 +msgid "Failed to extract at least One LDAP User" +msgstr "" + +#: cps/admin.py:1587 +msgid "Failed to Create at Least One LDAP User" +msgstr "" + +#: cps/admin.py:1600 +#, python-format +msgid "Error: %(ldaperror)s" +msgstr "" + +#: cps/admin.py:1604 +msgid "Error: No user returned in response of LDAP server" +msgstr "" + +#: cps/admin.py:1637 +msgid "At Least One LDAP User Not Found in Database" +msgstr "" + +#: cps/admin.py:1639 +msgid "{} User Successfully Imported" +msgstr "" + +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "Thiết lập cơ sở dữ lieu đã được cập nhật" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "Thiết lập cơ sở dữ lieu :)))" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "Hãy điền hết các trường!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "Địa chỉ email không hợp lệ" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "Thêm người dùng mới" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "Người dùng '%(user)s' đã được tạo" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "Người dùng với địa chỉ email hoặc tên đã tồn tại." + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "Người dùng '%(nick)s' đã bị xoá" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "Không thể xoá người dùng khách" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "Người dùng '%(nick)s' đã được cập nhật" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "chưa cài đặt" + +#: cps/converter.py:32 +msgid "Execution permissions missing" +msgstr "" + +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" +msgstr "" + +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "None" + +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" +msgstr "" + +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "" + +#: cps/editbooks.py:174 cps/editbooks.py:716 +msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" +msgstr "" + +#: cps/editbooks.py:216 +msgid "Metadata successfully updated" +msgstr "Metadata đã được cập nhật thành công" + +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" + +#: cps/editbooks.py:291 +#, python-format +msgid "File %(file)s uploaded" +msgstr "File %(file)s đã được tải lên" + +#: cps/editbooks.py:318 +msgid "Source or destination format for conversion missing" +msgstr "Thiếu định dạng nguồn hoặc đích để convert" + +#: cps/editbooks.py:326 +#, python-format +msgid "Book successfully queued for converting to %(book_format)s" +msgstr "" + +#: cps/editbooks.py:330 +#, python-format +msgid "There was an error converting this book: %(res)s" +msgstr "Có lỗi xảy ra khi chuyển đổi định dạng cho sach: %(res)s" + +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "" + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s không phải là ngôn ngữ hợp lệ" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "Lưu file thất bại %(file)s." + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "" + +#: cps/gdrive.py:58 +msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" +msgstr "" + +#: cps/gdrive.py:95 +msgid "Callback domain is not verified, please follow steps to verify domain in google developer console" +msgstr "" + +#: cps/helper.py:80 +#, python-format +msgid "%(format)s format not found for book id: %(book)d" +msgstr "" + +#: cps/helper.py:87 cps/tasks/convert.py:75 +#, python-format +msgid "%(format)s not found on Google Drive: %(fn)s" +msgstr "" + +#: cps/helper.py:92 +#, python-format +msgid "%(format)s not found: %(fn)s" +msgstr "%(format)s không tìm thấy: %(fn)s" + +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" +msgstr "Gửi tới Kindle" + +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." +msgstr "E-mail này được gửi từ Calibre-Web." + +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" +msgstr "Calibre-Web test e-mail" + +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" +msgstr "Test e-mail" + +#: cps/helper.py:132 +msgid "Get Started with Calibre-Web" +msgstr "Bắt đầu với Calibre-Web" + +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" +msgstr "Email đăng ký cho người dùng: %(name)s" + +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "Chuyển đổi %(orig)s thành %(format)s và chuyển tới Kindle" + +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" +msgstr "Gửi %(format)s tới Kindle" + +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" +msgstr "%(book)s gửi tới Kindle" + +#: cps/helper.py:230 +msgid "The requested file could not be read. Maybe wrong permissions?" +msgstr "File được yêu cầu không thể đọc. Có thể do phân quyền bị sai?" + +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 +#, python-format +msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" +msgstr "Xoá thư mục cho sách %(id)s thất bại, đường dẫn có subfolders: %(path)s" + +#: cps/helper.py:374 +#, python-format +msgid "Deleting book %(id)s failed: %(message)s" +msgstr "Xoá sách %(id)s thất bại: %(message)s" + +#: cps/helper.py:385 +#, python-format +msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" +msgstr "" + +#: cps/helper.py:450 +#, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "" + +#: cps/helper.py:522 cps/helper.py:531 +#, python-format +msgid "File %(file)s not found on Google Drive" +msgstr "File %(file)s không tìm thấy trẻn Google Drive" + +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 +#, python-format +msgid "Book path %(path)s not found on Google Drive" +msgstr "Không tìm thấy được dẫn sách %(path)s trên Google Drive" + +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" + +#: cps/helper.py:652 +msgid "This username is already taken" +msgstr "Username này đã bị sử dụng" + +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" +msgstr "Định dạng email address không hợp lệ" + +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 +msgid "Error Downloading Cover" +msgstr "Lỗi tải xuống ảnh bìa" + +#: cps/helper.py:828 +msgid "Cover Format Error" +msgstr "Định dạng ảnh bìa lỗi" + +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 +msgid "Failed to create path for cover" +msgstr "Tạo đường dẫn cho ảnh bìa thất bại" + +#: cps/helper.py:857 +msgid "Cover-file is not a valid image file, or could not be stored" +msgstr "" + +#: cps/helper.py:868 +msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" +msgstr "" + +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 +msgid "Only jpg/jpeg files are supported as coverfile" +msgstr "" + +#: cps/helper.py:936 +msgid "Unrar binary file not found" +msgstr "" + +#: cps/helper.py:947 +msgid "Error executing UnRar" +msgstr "" + +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "Khám phá" + +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" + +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "" + +#: cps/kobo_auth.py:115 +msgid "Kobo Setup" +msgstr "Thiết lập Kobo" + +#: cps/oauth_bb.py:77 +#, python-format +msgid "Register with %(provider)s" +msgstr "" + +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 +#, python-format +msgid "Success! You are now logged in as: %(nickname)s" +msgstr "" + +#: cps/oauth_bb.py:148 +#, python-format +msgid "Link to %(oauth)s Succeeded" +msgstr "" + +#: cps/oauth_bb.py:155 +msgid "Login failed, No User Linked With OAuth Account" +msgstr "" + +#: cps/oauth_bb.py:197 +#, python-format +msgid "Unlink to %(oauth)s Succeeded" +msgstr "" + +#: cps/oauth_bb.py:202 +#, python-format +msgid "Unlink to %(oauth)s Failed" +msgstr "" + +#: cps/oauth_bb.py:205 +#, python-format +msgid "Not Linked to %(oauth)s" +msgstr "" + +#: cps/oauth_bb.py:261 +msgid "Failed to log in with GitHub." +msgstr "Đăng nhập với Github thất bại." + +#: cps/oauth_bb.py:267 +msgid "Failed to fetch user info from GitHub." +msgstr "Lấy thông tin user từ Github thất bại." + +#: cps/oauth_bb.py:279 +msgid "Failed to log in with Google." +msgstr "Đăng nhập với Google thất bại." + +#: cps/oauth_bb.py:285 +msgid "Failed to fetch user info from Google." +msgstr "Lấy thông tin người dùng từ Google thất bại." + +#: cps/oauth_bb.py:332 +msgid "GitHub Oauth error, please retry later." +msgstr "Oauth Github lỗi, xin thử lại sau." + +#: cps/oauth_bb.py:335 +msgid "GitHub Oauth error: {}" +msgstr "Github Oauth lỗi: {}" + +#: cps/oauth_bb.py:356 +msgid "Google Oauth error, please retry later." +msgstr "Google Oauth lỗi, làm ơn thử lại sau." + +#: cps/oauth_bb.py:359 +msgid "Google Oauth error: {}" +msgstr "Google Oauth lỗi: {}" + +#: cps/opds.py:273 +msgid "{} Stars" +msgstr "{} sao" + +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 +msgid "Login" +msgstr "Đăng nhập" + +#: cps/remotelogin.py:74 cps/remotelogin.py:108 +msgid "Token not found" +msgstr "Không tìm thấy token" + +#: cps/remotelogin.py:83 cps/remotelogin.py:116 +msgid "Token has expired" +msgstr "Token đã hết hạn" + +#: cps/remotelogin.py:92 +msgid "Success! Please return to your device" +msgstr "Thành công! Hãy quay lại thiết bị của bạn" + +#: cps/render_template.py:42 cps/web.py:410 +msgid "Books" +msgstr "Sách" + +#: cps/render_template.py:44 +msgid "Show recent books" +msgstr "Hiển thị sách gần đây" + +#: cps/render_template.py:45 cps/templates/index.xml:25 +msgid "Hot Books" +msgstr "Sách hot" + +#: cps/render_template.py:47 +msgid "Show Hot Books" +msgstr "Hiển thị sách hot" + +#: cps/render_template.py:49 cps/render_template.py:54 +msgid "Downloaded Books" +msgstr "Sách đã tải" + +#: cps/render_template.py:51 cps/render_template.py:56 +#: cps/templates/user_table.html:167 +msgid "Show Downloaded Books" +msgstr "Hiển thị sách đã tải" + +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 +msgid "Top Rated Books" +msgstr "Top sách được đánh giá cao" + +#: cps/render_template.py:61 cps/templates/user_table.html:161 +msgid "Show Top Rated Books" +msgstr "Hiện thị top những sách được đánh giá cao" + +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 +msgid "Read Books" +msgstr "Sách đã đọc" + +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" +msgstr "Hiển thị đã đọc và chưa đọc" + +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 +msgid "Unread Books" +msgstr "Sách chưa đọc" + +#: cps/render_template.py:68 +msgid "Show unread" +msgstr "Hiện thị sách chưa đọc" + +#: cps/render_template.py:69 +msgid "Discover" +msgstr "Khám phá" + +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 +msgid "Show Random Books" +msgstr "Hiển thị sách ngẫu nhiên" + +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 +msgid "Categories" +msgstr "Chủ đề" + +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" +msgstr "Hiển thị chọn chủ đề" + +#: cps/render_template.py:75 cps/templates/book_edit.html:91 +#: cps/templates/book_table.html:68 cps/templates/index.xml:90 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 +msgid "Series" +msgstr "Series" + +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" +msgstr "Hiển thị chọn series" + +#: cps/render_template.py:78 cps/templates/book_table.html:66 +#: cps/templates/index.xml:69 +msgid "Authors" +msgstr "Tác giả" + +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" +msgstr "Hiển thị chọn tác giả" + +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 +msgid "Publishers" +msgstr "Nhà phát hành" + +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" +msgstr "Hiển thị chọn nhà phát hành" + +#: cps/render_template.py:85 cps/templates/book_table.html:70 +#: cps/templates/index.xml:97 cps/templates/search_form.html:107 +#: cps/web.py:1078 +msgid "Languages" +msgstr "Ngôn ngữ" + +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" +msgstr "Hiển thị chọn ngôn ngữ" + +#: cps/render_template.py:89 cps/templates/index.xml:104 +msgid "Ratings" +msgstr "Đánh giá" + +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" +msgstr "Hiển thị chọn đánh giá" + +#: cps/render_template.py:92 cps/templates/index.xml:112 +msgid "File formats" +msgstr "Định dạng file" + +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" +msgstr "Hiển thị lựa chọn định dạng file" + +#: cps/render_template.py:96 cps/web.py:772 +msgid "Archived Books" +msgstr "Sách đã lưu trữ" + +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" +msgstr "Hiện thị sách trong kho" + +#: cps/render_template.py:101 cps/web.py:803 +msgid "Books List" +msgstr "Danh sách sách" + +#: cps/render_template.py:103 cps/templates/user_table.html:168 +msgid "Show Books List" +msgstr "Hiển thị danh sách sách" + +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 +msgid "Search" +msgstr "Tìm kiếm" + +#: cps/search.py:189 +msgid "Published after " +msgstr "Phát hành sau " + +#: cps/search.py:196 +msgid "Published before " +msgstr "Phát hành trước " + +#: cps/search.py:218 +#, python-format +msgid "Rating <= %(rating)s" +msgstr "Đánh giá <= %(rating)s" + +#: cps/search.py:220 +#, python-format +msgid "Rating >= %(rating)s" +msgstr "Đánh giá >= %(rating)s" + +#: cps/search.py:222 +#, python-format +msgid "Read Status = %(status)s" +msgstr "Trạng thái đọc = %(status)s" + +#: cps/search.py:324 +msgid "Error on search for custom columns, please restart Calibre-Web" +msgstr "" + +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "Tìm kiếm nâng cao" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "Xin lỗi bạn không có quyền thêm sách vào giá đó" + +#: cps/shelf.py:64 +#, python-format +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "Sách đã được thêm vào giá: %(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "Sách đã được xoá khỏi giá: %(sname)s" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "Xin lỗi bạn không có quyền xoá sách khỏi giá này" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "Tạo một giá sách" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "Xin lỗi bạn không có quyền chỉnh sửa giá sách này" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "Chỉnh sửa giá sách" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "Xin lỗi bạn không có quyền tạo một giá sách công khai" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "Giá sách %(title)s đã được tạo" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "Giá sách %(title)s đã được thay đổi" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "Có lỗi xảy ra" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "Nhiệm vụ" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "Đang chờ" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "Thất bại" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "Đã bắt đầu" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "Đã hoàn thành" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +#, fuzzy +msgid "Cancelled" +msgstr "Huỷ bỏ" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "Trạng thái không xác định" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "" + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "" + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "" + +#: cps/web.py:616 +#, fuzzy +msgid "Rating: None" +msgstr "Đánh giá cao hơn" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "Tải xuống" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "Danh sách đánh giá" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "Danh sách định dạng file" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "" + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "" + +#: cps/web.py:1213 +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "" + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "" + +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 +msgid "Register" +msgstr "Đăng ký" + +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." +msgstr "Email của bạn không được cho phép để đăng ký" + +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." +msgstr "" + +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" +msgstr "" + +#: cps/web.py:1303 +#, python-format +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" +msgstr "" + +#: cps/web.py:1309 +#, python-format +msgid "Oops! Login Failed: %(message)s" +msgstr "Không thể đăng nhập: %(message)s" + +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." +msgstr "Tên đăng nhập hoặc mật khẩu không đúng" + +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." +msgstr "Mật khẩu mới đã được gửi đến email của bạn" + +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" +msgstr "" + +#: cps/web.py:1400 cps/web.py:1449 +#, python-format +msgid "%(name)s's Profile" +msgstr "" + +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" +msgstr "Metadata đã được cập nhật thành công" + +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "Tìm thấy một tài khoản đã toàn tại cho địa chỉ email này" + +#: cps/services/gmail.py:58 +msgid "Found no valid gmail.json file with OAuth information" +msgstr "" + +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s gửi tới Kindle" + +#: cps/tasks/convert.py:153 +#, python-format +msgid "Calibre ebook-convert %(tool)s not found" +msgstr "" + +#: cps/tasks/convert.py:186 +#, python-format +msgid "%(format)s format not found on disk" +msgstr "" + +#: cps/tasks/convert.py:190 +msgid "Ebook converter failed with unknown error" +msgstr "" + +#: cps/tasks/convert.py:202 +#, python-format +msgid "Kepubify-converter failed: %(error)s" +msgstr "" + +#: cps/tasks/convert.py:224 +#, python-format +msgid "Converted file not found or more than one file in folder %(folder)s" +msgstr "" + +#: cps/tasks/convert.py:247 +#, python-format +msgid "Ebook-converter failed: %(error)s" +msgstr "" + +#: cps/tasks/convert.py:270 +#, python-format +msgid "Calibre failed with error: %(error)s" +msgstr "" + +#: cps/tasks/convert.py:275 +#, fuzzy +msgid "Convert" +msgstr "Khám phá" + +#: cps/tasks/database.py:28 +#, fuzzy +msgid "Reconnecting Calibre database" +msgstr "Kết nối lại với cơ sở dữ liệu Calibre" + +#: cps/tasks/mail.py:266 +#, fuzzy +msgid "E-mail" +msgstr "Test e-mail" + +#: cps/tasks/metadata_backup.py:47 +msgid "Backing up Metadata" +msgstr "" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "Tải lên" + +#: cps/templates/admin.html:9 +msgid "Users" +msgstr "Người dùng" + +#: cps/templates/admin.html:13 cps/templates/login.html:9 +#: cps/templates/login.html:10 cps/templates/register.html:9 +#: cps/templates/user_edit.html:10 cps/templates/user_table.html:134 +msgid "Username" +msgstr "Tên người dùng" + +#: cps/templates/admin.html:14 cps/templates/register.html:14 +#: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 +msgid "Email" +msgstr "Địa chỉ email" + +#: cps/templates/admin.html:15 cps/templates/user_edit.html:28 +#, fuzzy +msgid "Send to eReader Email" +msgstr "Kindle" + +#: cps/templates/admin.html:17 cps/templates/layout.html:92 +#: cps/templates/user_table.html:143 +msgid "Admin" +msgstr "Admin" + +#: cps/templates/admin.html:18 cps/templates/login.html:13 +#: cps/templates/login.html:14 cps/templates/user_edit.html:23 +msgid "Password" +msgstr "Mật khẩu" + +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 +#: cps/templates/user_table.html:146 +msgid "Download" +msgstr "Tải xuống" + +#: cps/templates/admin.html:23 +msgid "View Books" +msgstr "Xem sách" + +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 +#: cps/templates/user_table.html:148 +msgid "Edit" +msgstr "Chỉnh sửa" + +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 +#: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 +#: cps/templates/user_table.html:149 +msgid "Delete" +msgstr "Xoá" + +#: cps/templates/admin.html:26 +msgid "Public Shelf" +msgstr "Giá công khai" + +#: cps/templates/admin.html:55 +msgid "Import LDAP Users" +msgstr "" + +#: cps/templates/admin.html:62 +msgid "Email Server Settings" +msgstr "Thiết lập máy chủ email" + +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 +msgid "SMTP Hostname" +msgstr "SMTP Hostname" + +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 +msgid "SMTP Port" +msgstr "Cổng SMTP" + +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 +msgid "Encryption" +msgstr "SSL" + +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 +msgid "SMTP Login" +msgstr "Đăng nhập SMTP" + +#: cps/templates/admin.html:83 cps/templates/admin.html:94 +#: cps/templates/email_edit.html:55 +msgid "From Email" +msgstr "Từ E-mail" + +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" +msgstr "Dịch vụ E-Mail" + +#: cps/templates/admin.html:91 +msgid "Gmail via Oauth2" +msgstr "Gmail via Oauth2" + +#: cps/templates/admin.html:106 +msgid "Configuration" +msgstr "Thiết lập" + +#: cps/templates/admin.html:109 +msgid "Calibre Database Directory" +msgstr "Thư mục cơ sở dữ liệu Calibre" + +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 +msgid "Log Level" +msgstr "Log Level" + +#: cps/templates/admin.html:117 +msgid "Port" +msgstr "Cổng" + +#: cps/templates/admin.html:122 +msgid "External Port" +msgstr "" + +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 +msgid "Books per Page" +msgstr "Sách mỗi trang" + +#: cps/templates/admin.html:133 +msgid "Uploads" +msgstr "Tải lên" + +#: cps/templates/admin.html:137 +msgid "Anonymous Browsing" +msgstr "Ẩn danh" + +#: cps/templates/admin.html:141 +msgid "Public Registration" +msgstr "Đăng ký công khai" + +#: cps/templates/admin.html:145 +msgid "Magic Link Remote Login" +msgstr "Đăng nhập bằng Magic Link" + +#: cps/templates/admin.html:149 +msgid "Reverse Proxy Login" +msgstr "" + +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 +msgid "Reverse Proxy Header Name" +msgstr "" + +#: cps/templates/admin.html:159 +msgid "Edit Calibre Database Configuration" +msgstr "Chỉnh sửa thiết lập cơ sở dữ liệu Calibre" + +#: cps/templates/admin.html:160 +msgid "Edit Basic Configuration" +msgstr "Chỉnh sửa thiết lập cơ bản" + +#: cps/templates/admin.html:161 +msgid "Edit UI Configuration" +msgstr "Chỉnh sửa thiết lập UI" + +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +#, fuzzy +msgid "Reconnect Calibre Database" +msgstr "Kết nối lại với cơ sở dữ liệu Calibre" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 +msgid "Administration" +msgstr "Quản trị" + +#: cps/templates/admin.html:200 +msgid "Download Debug Package" +msgstr "Tải xuống package debug" + +#: cps/templates/admin.html:201 +msgid "View Logs" +msgstr "Xem logs" + +#: cps/templates/admin.html:207 +msgid "Restart" +msgstr "Khởi động lại" + +#: cps/templates/admin.html:208 +msgid "Shutdown" +msgstr "Tắt" + +#: cps/templates/admin.html:216 +#, fuzzy +msgid "Version Information" +msgstr "Thiết lập máy chủ" + +#: cps/templates/admin.html:220 +msgid "Version" +msgstr "Phiên bản" + +#: cps/templates/admin.html:221 +msgid "Details" +msgstr "Chi tiết" + +#: cps/templates/admin.html:227 +msgid "Current Version" +msgstr "Phiên bản hiện tại" + +#: cps/templates/admin.html:234 +msgid "Check for Update" +msgstr "Kiểm tra cập nhật" + +#: cps/templates/admin.html:235 +msgid "Perform Update" +msgstr "Bắt đầu cập nhật" + +#: cps/templates/admin.html:248 +msgid "Are you sure you want to restart?" +msgstr "Bạn có chắc chắn muốn khởi động lại?" + +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 +msgid "OK" +msgstr "Ok" + +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 +#: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 +#: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 +msgid "Cancel" +msgstr "Huỷ bỏ" + +#: cps/templates/admin.html:266 +msgid "Are you sure you want to shutdown?" +msgstr "Bạn có chắc muốn tắt?" + +#: cps/templates/admin.html:278 +msgid "Updating, please do not reload this page" +msgstr "Đang update, làm ơn đừng load lại trang này" + +#: cps/templates/author.html:15 +msgid "via" +msgstr "via" + +#: cps/templates/author.html:23 +msgid "In Library" +msgstr "Trong thư viện" + +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 +msgid "Sort according to book date, newest first" +msgstr "" + +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 +msgid "Sort according to book date, oldest first" +msgstr "" + +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 +msgid "Sort title in alphabetical order" +msgstr "" + +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 +msgid "Sort title in reverse alphabetical order" +msgstr "" + +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 +msgid "Sort according to publishing date, newest first" +msgstr "" + +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 +msgid "Sort according to publishing date, oldest first" +msgstr "" + +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 +msgid "reduce" +msgstr "" + +#: cps/templates/author.html:99 +msgid "More by" +msgstr "Cùng tác giả" + +#: cps/templates/book_edit.html:11 +msgid "Delete Book" +msgstr "Xoá sách" + +#: cps/templates/book_edit.html:14 +msgid "Delete formats:" +msgstr "Xoá định dạng:" + +#: cps/templates/book_edit.html:25 +msgid "Convert book format:" +msgstr "Chuyển đổi định dạng sách:" + +#: cps/templates/book_edit.html:30 +msgid "Convert from:" +msgstr "Chuyển đổi từ:" + +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 +msgid "select an option" +msgstr "chọn một lựa chọn" + +#: cps/templates/book_edit.html:37 +msgid "Convert to:" +msgstr "Chuyển đổi tới:" + +#: cps/templates/book_edit.html:46 +msgid "Convert book" +msgstr "Chuyển đổi sách" + +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 +msgid "Book Title" +msgstr "Tên sách" + +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 +msgid "Author" +msgstr "Tác giả" + +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 +msgid "Description" +msgstr "Mô tả" + +#: cps/templates/book_edit.html:73 +msgid "Identifiers" +msgstr "Nhận diện" + +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 +msgid "Identifier Type" +msgstr "Kiểu nhận diện" + +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 +msgid "Identifier Value" +msgstr "Giá trị nhận diện" + +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 +#: cps/templates/user_table.html:24 +msgid "Remove" +msgstr "Xoá" + +#: cps/templates/book_edit.html:83 +msgid "Add Identifier" +msgstr "Thêm nhận diện" + +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 +msgid "Tags" +msgstr "Đánh dấu" + +#: cps/templates/book_edit.html:95 +msgid "Series ID" +msgstr "Series ID" + +#: cps/templates/book_edit.html:99 +msgid "Rating" +msgstr "Đánh giá" + +#: cps/templates/book_edit.html:104 +msgid "Fetch Cover from URL (JPEG - Image will be downloaded and stored in database)" +msgstr "Lấy ảnh bìa từ URL (ảnh JPEG sẽ được tải xuống và lưu trong cơ sở dữ liệu)" + +#: cps/templates/book_edit.html:108 +msgid "Upload Cover from Local Disk" +msgstr "Tải ảnh bìa từ ổ cứng" + +#: cps/templates/book_edit.html:113 +msgid "Published Date" +msgstr "Ngày xuất bản" + +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 +msgid "Publisher" +msgstr "Nhà xuất bản" + +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 +msgid "Language" +msgstr "Ngôn ngữ" + +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 +#: cps/templates/search_form.html:164 +msgid "Yes" +msgstr "Có" + +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 +#: cps/templates/search_form.html:165 +msgid "No" +msgstr "Không" + +#: cps/templates/book_edit.html:201 +msgid "Upload Format" +msgstr "Định dạng tải lên" + +#: cps/templates/book_edit.html:209 +msgid "View Book on Save" +msgstr "Xem sách sau khi lưu" + +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 +msgid "Fetch Metadata" +msgstr "Fetch Metadata" + +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 +msgid "Save" +msgstr "Lưu" + +#: cps/templates/book_edit.html:233 +msgid "Keyword" +msgstr "Từ khoá" + +#: cps/templates/book_edit.html:234 +msgid "Search keyword" +msgstr "Tìm kiếm từ khoá" + +#: cps/templates/book_edit.html:240 +msgid "Click the cover to load metadata to the form" +msgstr "Ấn vào ảnh cover để tải metadata vào form" + +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 +msgid "Loading..." +msgstr "Đang tải..." + +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 +msgid "Close" +msgstr "Đóng" + +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 +msgid "Source" +msgstr "Nguồn" + +#: cps/templates/book_edit.html:287 +msgid "Search error!" +msgstr "Tìm kiếm lỗi!" + +#: cps/templates/book_edit.html:288 +msgid "No Result(s) found! Please try another keyword." +msgstr "Không tìm thấy kết quả! Hãy thử lại với từ khoá khác." + +#: cps/templates/book_table.html:12 cps/templates/book_table.html:69 +#: cps/templates/user_table.html:14 cps/templates/user_table.html:77 +#: cps/templates/user_table.html:100 +msgid "This Field is Required" +msgstr "Đây là trường bắt buộc" + +#: cps/templates/book_table.html:37 +msgid "Merge selected books" +msgstr "Gộp những sách đã chọn" + +#: cps/templates/book_table.html:38 cps/templates/user_table.html:124 +msgid "Remove Selections" +msgstr "Bỏ chọn" + +#: cps/templates/book_table.html:41 +msgid "Exchange author and title" +msgstr "Đổi tác giả và tên sách" + +#: cps/templates/book_table.html:47 +msgid "Update Title Sort automatically" +msgstr "Cập nhật sắp xếp theo tên tự động" + +#: cps/templates/book_table.html:51 +msgid "Update Author Sort automatically" +msgstr "Cập nhật sắp xếp theo tác giả tự động" + +#: cps/templates/book_table.html:63 cps/templates/book_table.html:69 +msgid "Enter Title" +msgstr "Nhập tên sách" + +#: cps/templates/book_table.html:63 cps/templates/config_view_edit.html:24 +#: cps/templates/shelf_edit.html:8 +msgid "Title" +msgstr "Tên" + +#: cps/templates/book_table.html:64 +msgid "Enter Title Sort" +msgstr "Nhập tên sách để sắp xếp" + +#: cps/templates/book_table.html:64 +msgid "Title Sort" +msgstr "Tên sắp xếp" + +#: cps/templates/book_table.html:65 +msgid "Enter Author Sort" +msgstr "Nhập tác giả sắp xếp" + +#: cps/templates/book_table.html:65 +msgid "Author Sort" +msgstr "Tên tác giả sắp xếp" + +#: cps/templates/book_table.html:66 +msgid "Enter Authors" +msgstr "Nhập tên tác giả" + +#: cps/templates/book_table.html:67 +msgid "Enter Categories" +msgstr "Nhập thể loại" + +#: cps/templates/book_table.html:68 +msgid "Enter Series" +msgstr "Nhập tên series" + +#: cps/templates/book_table.html:69 +msgid "Series Index" +msgstr "Chỉ số series" + +#: cps/templates/book_table.html:70 +msgid "Enter Languages" +msgstr "Nhập ngôn ngữ" + +#: cps/templates/book_table.html:71 +msgid "Publishing Date" +msgstr "Ngày phát hành" + +#: cps/templates/book_table.html:72 +msgid "Enter Publishers" +msgstr "Nhập tên nhà phát hành" + +#: cps/templates/book_table.html:73 +msgid "Enter comments" +msgstr "Nhập nhận xét" + +#: cps/templates/book_table.html:73 +msgid "Comments" +msgstr "Nhận xét" + +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "Read status" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 +msgid "Enter " +msgstr "Nhập " + +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 +msgid "Are you really sure?" +msgstr "Bạn có thực sự chắc chắn?" + +#: cps/templates/book_table.html:117 +msgid "Books with Title will be merged from:" +msgstr "" + +#: cps/templates/book_table.html:121 +msgid "Into Book with Title:" +msgstr "" + +#: cps/templates/book_table.html:126 +msgid "Merge" +msgstr "Trộn" + +#: cps/templates/config_db.html:12 +msgid "Location of Calibre Database" +msgstr "Vị trí cơ sở dữ liệu của Calibre" + +#: cps/templates/config_db.html:22 +msgid "Use Google Drive?" +msgstr "Dùng Google Drive?" + +#: cps/templates/config_db.html:27 +msgid "Authenticate Google Drive" +msgstr "Xác thực Google Drive" + +#: cps/templates/config_db.html:32 +msgid "Google Drive Calibre folder" +msgstr "Thư mục Calibre trên Google Drive" + +#: cps/templates/config_db.html:40 +msgid "Metadata Watch Channel ID" +msgstr "" + +#: cps/templates/config_db.html:43 +msgid "Revoke" +msgstr "Thu hồi" + +#: cps/templates/config_db.html:68 +msgid "New db location is invalid, please enter valid path" +msgstr "Đường dẫn DB mới không hợp lệ, xin hãy nhập đường dẫn hợp lệ" + +#: cps/templates/config_edit.html:18 +msgid "Server Configuration" +msgstr "Thiết lập máy chủ" + +#: cps/templates/config_edit.html:25 +msgid "Server Port" +msgstr "Cổng máy chủ" + +#: cps/templates/config_edit.html:28 +msgid "SSL certfile location (leave it empty for non-SSL Servers)" +msgstr "" + +#: cps/templates/config_edit.html:35 +msgid "SSL Keyfile location (leave it empty for non-SSL Servers)" +msgstr "" + +#: cps/templates/config_edit.html:43 +msgid "Update Channel" +msgstr "" + +#: cps/templates/config_edit.html:45 +msgid "Stable" +msgstr "" + +#: cps/templates/config_edit.html:46 +msgid "Nightly" +msgstr "" + +#: cps/templates/config_edit.html:50 +msgid "Trusted Hosts (Comma Separated)" +msgstr "" + +#: cps/templates/config_edit.html:61 +msgid "Logfile Configuration" +msgstr "" + +#: cps/templates/config_edit.html:77 +msgid "Location and name of logfile (calibre-web.log for no entry)" +msgstr "" + +#: cps/templates/config_edit.html:82 +msgid "Enable Access Log" +msgstr "" + +#: cps/templates/config_edit.html:85 +msgid "Location and name of access logfile (access.log for no entry)" +msgstr "" + +#: cps/templates/config_edit.html:96 +msgid "Feature Configuration" +msgstr "" + +#: cps/templates/config_edit.html:104 +msgid "Convert non-English characters in title and author while saving to disk" +msgstr "" + +#: cps/templates/config_edit.html:108 +msgid "Enable Uploads" +msgstr "" + +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + +#: cps/templates/config_edit.html:112 +msgid "Allowed Upload Fileformats" +msgstr "" + +#: cps/templates/config_edit.html:118 +msgid "Enable Anonymous Browsing" +msgstr "" + +#: cps/templates/config_edit.html:122 +msgid "Enable Public Registration" +msgstr "" + +#: cps/templates/config_edit.html:127 +msgid "Use Email as Username" +msgstr "" + +#: cps/templates/config_edit.html:132 +msgid "Enable Magic Link Remote Login" +msgstr "" + +#: cps/templates/config_edit.html:137 +msgid "Enable Kobo sync" +msgstr "" + +#: cps/templates/config_edit.html:142 +msgid "Proxy unknown requests to Kobo Store" +msgstr "" + +#: cps/templates/config_edit.html:145 +msgid "Server External Port (for port forwarded API calls)" +msgstr "" + +#: cps/templates/config_edit.html:153 +msgid "Use Goodreads" +msgstr "Sử dụng Goodreads" + +#: cps/templates/config_edit.html:154 +msgid "Create an API Key" +msgstr "Tạo API Key" + +#: cps/templates/config_edit.html:158 +msgid "Goodreads API Key" +msgstr "Goodreads API Key" + +#: cps/templates/config_edit.html:162 +msgid "Goodreads API Secret" +msgstr "Goodreads API Secret" + +#: cps/templates/config_edit.html:169 +msgid "Allow Reverse Proxy Authentication" +msgstr "" + +#: cps/templates/config_edit.html:180 +msgid "Login type" +msgstr "Kiểu đăng nhập" + +#: cps/templates/config_edit.html:182 +msgid "Use Standard Authentication" +msgstr "" + +#: cps/templates/config_edit.html:184 +msgid "Use LDAP Authentication" +msgstr "" + +#: cps/templates/config_edit.html:187 +msgid "Use OAuth" +msgstr "" + +#: cps/templates/config_edit.html:194 +msgid "LDAP Server Host Name or IP Address" +msgstr "" + +#: cps/templates/config_edit.html:198 +msgid "LDAP Server Port" +msgstr "" + +#: cps/templates/config_edit.html:202 +msgid "LDAP Encryption" +msgstr "" + +#: cps/templates/config_edit.html:205 +msgid "TLS" +msgstr "" + +#: cps/templates/config_edit.html:206 +msgid "SSL" +msgstr "" + +#: cps/templates/config_edit.html:210 +msgid "LDAP CACertificate Path (Only needed for Client Certificate Authentication)" +msgstr "" + +#: cps/templates/config_edit.html:217 +msgid "LDAP Certificate Path (Only needed for Client Certificate Authentication)" +msgstr "" + +#: cps/templates/config_edit.html:224 +msgid "LDAP Keyfile Path (Only needed for Client Certificate Authentication)" +msgstr "" + +#: cps/templates/config_edit.html:233 +msgid "LDAP Authentication" +msgstr "" + +#: cps/templates/config_edit.html:235 +msgid "Anonymous" +msgstr "" + +#: cps/templates/config_edit.html:236 +msgid "Unauthenticated" +msgstr "" + +#: cps/templates/config_edit.html:237 +msgid "Simple" +msgstr "" + +#: cps/templates/config_edit.html:242 +msgid "LDAP Administrator Username" +msgstr "" + +#: cps/templates/config_edit.html:248 +msgid "LDAP Administrator Password" +msgstr "" + +#: cps/templates/config_edit.html:253 +msgid "LDAP Distinguished Name (DN)" +msgstr "" + +#: cps/templates/config_edit.html:257 +msgid "LDAP User Object Filter" +msgstr "" + +#: cps/templates/config_edit.html:262 +msgid "LDAP Server is OpenLDAP?" +msgstr "" + +#: cps/templates/config_edit.html:264 +msgid "Following Settings are Needed For User Import" +msgstr "" + +#: cps/templates/config_edit.html:266 +msgid "LDAP Group Object Filter" +msgstr "" + +#: cps/templates/config_edit.html:270 +msgid "LDAP Group Name" +msgstr "" + +#: cps/templates/config_edit.html:274 +msgid "LDAP Group Members Field" +msgstr "" + +#: cps/templates/config_edit.html:278 +msgid "LDAP Member User Filter Detection" +msgstr "" + +#: cps/templates/config_edit.html:280 +msgid "Autodetect" +msgstr "" + +#: cps/templates/config_edit.html:281 +msgid "Custom Filter" +msgstr "" + +#: cps/templates/config_edit.html:286 +msgid "LDAP Member User Filter" +msgstr "" + +#: cps/templates/config_edit.html:297 +#, python-format +msgid "Obtain %(provider)s OAuth Credential" +msgstr "" + +#: cps/templates/config_edit.html:300 +#, python-format +msgid "%(provider)s OAuth Client Id" +msgstr "" + +#: cps/templates/config_edit.html:304 +#, python-format +msgid "%(provider)s OAuth Client Secret" +msgstr "" + +#: cps/templates/config_edit.html:320 +msgid "External binaries" +msgstr "" + +#: cps/templates/config_edit.html:326 +msgid "Path to Calibre E-Book Converter" +msgstr "" + +#: cps/templates/config_edit.html:334 +msgid "Calibre E-Book Converter Settings" +msgstr "" + +#: cps/templates/config_edit.html:337 +msgid "Path to Kepubify E-Book Converter" +msgstr "" + +#: cps/templates/config_edit.html:345 +msgid "Location of Unrar binary" +msgstr "" + +#: cps/templates/config_view_edit.html:17 +msgid "View Configuration" +msgstr "" + +#: cps/templates/config_view_edit.html:32 +msgid "No. of Random Books to Display" +msgstr "" + +#: cps/templates/config_view_edit.html:36 +msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" +msgstr "" + +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 +msgid "Theme" +msgstr "" + +#: cps/templates/config_view_edit.html:42 +msgid "Standard Theme" +msgstr "Chủ đề mặc định" + +#: cps/templates/config_view_edit.html:43 +msgid "caliBlur! Dark Theme" +msgstr "calibur! Theme tối" + +#: cps/templates/config_view_edit.html:47 +msgid "Regular Expression for Ignoring Columns" +msgstr "" + +#: cps/templates/config_view_edit.html:51 +msgid "Link Read/Unread Status to Calibre Column" +msgstr "" + +#: cps/templates/config_view_edit.html:60 +msgid "View Restrictions based on Calibre column" +msgstr "" + +#: cps/templates/config_view_edit.html:69 +msgid "Regular Expression for Title Sorting" +msgstr "" + +#: cps/templates/config_view_edit.html:80 +msgid "Default Settings for New Users" +msgstr "" + +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 +msgid "Admin User" +msgstr "Người dùng quản trị" + +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 +msgid "Allow Downloads" +msgstr "Cho phép tải xuống" + +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 +msgid "Allow eBook Viewer" +msgstr "Cho phép xem eBook" + +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 +msgid "Allow Uploads" +msgstr "Cho phép tải lên" + +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 +msgid "Allow Edit" +msgstr "Cho phép chỉnh sửa" + +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 +msgid "Allow Delete Books" +msgstr "Cho phép xoá sách" + +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 +msgid "Allow Changing Password" +msgstr "Cho phép thay đổi mật khẩu" + +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 +msgid "Allow Editing Public Shelves" +msgstr "Cho phép chỉnh sửa giá sách công khai" + +#: cps/templates/config_view_edit.html:123 +msgid "Default Language" +msgstr "Ngôn ngữ mặc định" + +#: cps/templates/config_view_edit.html:131 +msgid "Default Visible Language of Books" +msgstr "Ngôn ngữ hiển thị mặc định của sách" + +#: cps/templates/config_view_edit.html:147 +msgid "Default Visibilities for New Users" +msgstr "" + +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 +#: cps/templates/user_table.html:154 +msgid "Show Random Books in Detail View" +msgstr "Hiển thị sách ngẫu nhiên trong màn hình chi tiết" + +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 +msgid "Add Allowed/Denied Tags" +msgstr "" + +#: cps/templates/config_view_edit.html:167 +msgid "Add Allowed/Denied custom column values" +msgstr "Thêm cho phép/từ chối giá trị cột tuỳ biến" + +#: cps/templates/detail.html:62 cps/templates/detail.html:71 +msgid "Read in Browser" +msgstr "Đọc trên trình duyệt" + +#: cps/templates/detail.html:79 cps/templates/detail.html:96 +msgid "Listen in Browser" +msgstr "Nghe trên trình duyệt" + +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 +#, python-format +msgid "Book %(index)s of %(range)s" +msgstr "Sách %(index)s của %(range)s" + +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 +msgid "Published" +msgstr "Đã phát hành" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Unread" +msgstr "Đánh dấu chưa đọc" + +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 +msgid "Mark As Read" +msgstr "Đánh dấu đã đọc" + +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 +msgid "Read" +msgstr "Đọc" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Restore from archive" +msgstr "Khôi phục từ lưu trữ" + +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 +msgid "Add to archive" +msgstr "Thêm vào lưu trữ" + +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 +msgid "Archived" +msgstr "Lưu trữ" + +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 +msgid "Description:" +msgstr "Mô tả:" + +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 +msgid "Add to shelf" +msgstr "Thêm vào giá sách" + +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 +msgid "(Public)" +msgstr "(Công khai)" + +#: cps/templates/detail.html:300 +msgid "Edit Metadata" +msgstr "Chỉnh sửa Metadata" + +#: cps/templates/email_edit.html:13 +msgid "Email Account Type" +msgstr "Chọn kiểu server" + +#: cps/templates/email_edit.html:15 +#, fuzzy +msgid "Standard Email Account" +msgstr "Dùng tài khoản email tiêu chuẩn" + +#: cps/templates/email_edit.html:16 +#, fuzzy +msgid "Gmail Account" +msgstr "Chọn kiểu server" + +#: cps/templates/email_edit.html:22 +msgid "Setup Gmail Account" +msgstr "" + +#: cps/templates/email_edit.html:24 +msgid "Revoke Gmail Access" +msgstr "Thu hồi quyền truy cập Gmail" + +#: cps/templates/email_edit.html:42 +msgid "STARTTLS" +msgstr "STARTTLS" + +#: cps/templates/email_edit.html:43 +msgid "SSL/TLS" +msgstr "SSL/TLS" + +#: cps/templates/email_edit.html:51 +msgid "SMTP Password" +msgstr "Mật khẩu SMTP" + +#: cps/templates/email_edit.html:58 +msgid "Attachment Size Limit" +msgstr "Giới hạn kích thước file đính kèm" + +#: cps/templates/email_edit.html:66 +#, fuzzy +msgid "Save and Send Test Email" +msgstr "Lưu và gửi test E-mail" + +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 +#: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 +msgid "Back" +msgstr "Quay lại" + +#: cps/templates/email_edit.html:74 +msgid "Allowed Domains (Whitelist)" +msgstr "Domains được chấp nhận (Whitelist)" + +#: cps/templates/email_edit.html:78 cps/templates/email_edit.html:105 +msgid "Add Domain" +msgstr "Thêm domain" + +#: cps/templates/email_edit.html:81 cps/templates/email_edit.html:108 +#: cps/templates/user_table.html:27 +msgid "Add" +msgstr "Thêm" + +#: cps/templates/email_edit.html:86 cps/templates/email_edit.html:96 +msgid "Enter domainname" +msgstr "Nhập tên domain" + +#: cps/templates/email_edit.html:92 +msgid "Denied Domains (Blacklist)" +msgstr "Domain bị từ chối (Blacklist)" + +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 +msgid "Next" +msgstr "Tiếp tục" + +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "" + +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Token đồng bộ Kobo" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 +msgid "Calibre-Web Instance is unconfigured, please contact your administrator" +msgstr "" + +#: cps/templates/http_error.html:44 +msgid "Create Issue" +msgstr "" + +#: cps/templates/http_error.html:51 +msgid "Return to Home" +msgstr "Quay về trang chủ" + +#: cps/templates/http_error.html:53 +msgid "Logout User" +msgstr "" + +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 +msgid "Sort authors in alphabetical order" +msgstr "" + +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 +msgid "Sort authors in reverse alphabetical order" +msgstr "" + +#: cps/templates/index.html:83 +msgid "Sort ascending according to series index" +msgstr "" + +#: cps/templates/index.html:84 +msgid "Sort descending according to series index" +msgstr "" + +#: cps/templates/index.xml:6 +msgid "Start" +msgstr "Bắt đầu" + +#: cps/templates/index.xml:18 +msgid "Alphabetical Books" +msgstr "" + +#: cps/templates/index.xml:22 +msgid "Books sorted alphabetically" +msgstr "" + +#: cps/templates/index.xml:29 +msgid "Popular publications from this catalog based on Downloads." +msgstr "" + +#: cps/templates/index.xml:36 +msgid "Popular publications from this catalog based on Rating." +msgstr "" + +#: cps/templates/index.xml:39 +msgid "Recently added Books" +msgstr "Sách mới được thêm gần đây" + +#: cps/templates/index.xml:43 +msgid "The latest Books" +msgstr "Sách mới nhất" + +#: cps/templates/index.xml:46 +msgid "Random Books" +msgstr "Sách ngẫu nhiên" + +#: cps/templates/index.xml:73 +msgid "Books ordered by Author" +msgstr "Sách sắp xếp theo tác giả" + +#: cps/templates/index.xml:80 +msgid "Books ordered by publisher" +msgstr "Sách sắp xếp theo nhà phát hành" + +#: cps/templates/index.xml:87 +msgid "Books ordered by category" +msgstr "Sách sắp xếp theo thể loại" + +#: cps/templates/index.xml:94 +msgid "Books ordered by series" +msgstr "Sách sắp xếp theo series" + +#: cps/templates/index.xml:101 +msgid "Books ordered by Languages" +msgstr "Sách sắp xếp theo ngôn ngữ" + +#: cps/templates/index.xml:108 +msgid "Books ordered by Rating" +msgstr "Sách sắp xếp theo xếp hạng" + +#: cps/templates/index.xml:116 +msgid "Books ordered by file formats" +msgstr "Sách sắp xếp theo định dạng" + +#: cps/templates/index.xml:119 cps/templates/layout.html:153 +#: cps/templates/search_form.html:87 +msgid "Shelves" +msgstr "Giá sách" + +#: cps/templates/index.xml:123 +msgid "Books organized in shelves" +msgstr "Sách tổ chức theo giá sách" + +#: cps/templates/layout.html:26 cps/templates/login.html:30 +msgid "Home" +msgstr "Trang chủ" + +#: cps/templates/layout.html:32 +msgid "Toggle Navigation" +msgstr "" + +#: cps/templates/layout.html:48 +msgid "Search Library" +msgstr "Tìm kiếm thư viện" + +#: cps/templates/layout.html:66 cps/templates/layout.html:95 +msgid "Account" +msgstr "Tài khoản" + +#: cps/templates/layout.html:72 cps/templates/layout.html:97 +msgid "Logout" +msgstr "Đăng suất" + +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "Đang tải lên..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "Lỗi" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "Tải lên xong, đang xử lý, đợi chút ..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "Thiết lập" + +#: cps/templates/layout.html:136 +msgid "Please do not refresh the page" +msgstr "Làm ơn đừng load lại trang" + +#: cps/templates/layout.html:146 +msgid "Browse" +msgstr "Tìm kiếm" + +#: cps/templates/layout.html:159 cps/templates/stats.html:3 +msgid "About" +msgstr "About" + +#: cps/templates/layout.html:173 +msgid "Previous" +msgstr "Trước" + +#: cps/templates/layout.html:200 +msgid "Book Details" +msgstr "Chi tiết sách" + +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + +#: cps/templates/login.html:18 +msgid "Remember Me" +msgstr "Ghi nhớ tôi" + +#: cps/templates/login.html:23 +msgid "Forgot Password?" +msgstr "Quên mật khẩu?" + +#: cps/templates/login.html:34 +msgid "Log in with Magic Link" +msgstr "Đăng nhập với Magic Link" + +#: cps/templates/logviewer.html:6 +msgid "Show Calibre-Web Log: " +msgstr "Hiển thị Calibre-Web Log: " + +#: cps/templates/logviewer.html:8 +msgid "Calibre-Web Log: " +msgstr "Calibre-Web Log: " + +#: cps/templates/logviewer.html:8 +msgid "Stream output, can't be displayed" +msgstr "" + +#: cps/templates/logviewer.html:12 +msgid "Show Access Log: " +msgstr "Hiển thị log truy cập: " + +#: cps/templates/logviewer.html:18 +msgid "Download Calibre-Web Log" +msgstr "Tải xuống Calibre-Web Log" + +#: cps/templates/logviewer.html:21 +msgid "Download Access Log" +msgstr "Tải xuống log truy cập" + +#: cps/templates/modal_dialogs.html:6 +msgid "Select Allowed/Denied Tags" +msgstr "" + +#: cps/templates/modal_dialogs.html:7 +msgid "Select Allowed/Denied Custom Column Values" +msgstr "" + +#: cps/templates/modal_dialogs.html:8 +msgid "Select Allowed/Denied Tags of User" +msgstr "" + +#: cps/templates/modal_dialogs.html:9 +msgid "Select Allowed/Denied Custom Column Values of User" +msgstr "" + +#: cps/templates/modal_dialogs.html:15 +msgid "Enter Tag" +msgstr "Nhập Tag" + +#: cps/templates/modal_dialogs.html:24 +msgid "Add View Restriction" +msgstr "" + +#: cps/templates/modal_dialogs.html:50 +msgid "This book format will be permanently erased from database" +msgstr "" + +#: cps/templates/modal_dialogs.html:51 +msgid "This book will be permanently erased from database" +msgstr "" + +#: cps/templates/modal_dialogs.html:52 +msgid "and hard disk" +msgstr "" + +#: cps/templates/modal_dialogs.html:56 +msgid "Important Kobo Note: deleted books will remain on any paired Kobo device." +msgstr "" + +#: cps/templates/modal_dialogs.html:57 +msgid "Books must first be archived and the device synced before a book can safely be deleted." +msgstr "" + +#: cps/templates/modal_dialogs.html:76 +msgid "Choose File Location" +msgstr "Chọn file location" + +#: cps/templates/modal_dialogs.html:82 +msgid "type" +msgstr "kiểu" + +#: cps/templates/modal_dialogs.html:83 +msgid "name" +msgstr "tên" + +#: cps/templates/modal_dialogs.html:84 +msgid "size" +msgstr "kích thước" + +#: cps/templates/modal_dialogs.html:90 +msgid "Parent Directory" +msgstr "Thư mục cha" + +#: cps/templates/modal_dialogs.html:98 +msgid "Select" +msgstr "Chọn" + +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 +msgid "Ok" +msgstr "Ok" + +#: cps/templates/osd.xml:5 +msgid "Calibre-Web eBook Catalog" +msgstr "" + +#: cps/templates/read.html:6 +msgid "epub Reader" +msgstr "trình đọc epub" + +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "Sáng" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "Tối" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "Quay lại" + +#: cps/templates/read.html:88 +msgid "Reflow text when sidebars are open." +msgstr "" + +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + +#: cps/templates/readcbr.html:7 +msgid "Comic Reader" +msgstr "Trình đọc truyện tranh" + +#: cps/templates/readcbr.html:92 +msgid "Keyboard Shortcuts" +msgstr "Phím tắt" + +#: cps/templates/readcbr.html:95 +msgid "Previous Page" +msgstr "Trang trước" + +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 +msgid "Next Page" +msgstr "Trang tiếp theo" + +#: cps/templates/readcbr.html:97 +msgid "Scale to Best" +msgstr "" + +#: cps/templates/readcbr.html:98 +msgid "Scale to Width" +msgstr "" + +#: cps/templates/readcbr.html:99 +msgid "Scale to Height" +msgstr "" + +#: cps/templates/readcbr.html:100 +msgid "Scale to Native" +msgstr "" + +#: cps/templates/readcbr.html:101 +msgid "Rotate Right" +msgstr "Xoay phải" + +#: cps/templates/readcbr.html:102 +msgid "Rotate Left" +msgstr "Xoay trái" + +#: cps/templates/readcbr.html:103 +msgid "Flip Image" +msgstr "Lật ảnh" + +#: cps/templates/readcbr.html:125 +msgid "Scale" +msgstr "" + +#: cps/templates/readcbr.html:128 +msgid "Best" +msgstr "Tốt nhất" + +#: cps/templates/readcbr.html:129 +msgid "Width" +msgstr "Rộng" + +#: cps/templates/readcbr.html:130 +msgid "Height" +msgstr "Cao" + +#: cps/templates/readcbr.html:131 +msgid "Native" +msgstr "" + +#: cps/templates/readcbr.html:136 +msgid "Rotate" +msgstr "Xoay" + +#: cps/templates/readcbr.html:147 +msgid "Flip" +msgstr "Lật" + +#: cps/templates/readcbr.html:150 +msgid "Horizontal" +msgstr "Ngang" + +#: cps/templates/readcbr.html:151 +msgid "Vertical" +msgstr "Dọc" + +#: cps/templates/readcbr.html:156 +msgid "Direction" +msgstr "Hướng" + +#: cps/templates/readcbr.html:159 +msgid "Left to Right" +msgstr "Trái sang phải" + +#: cps/templates/readcbr.html:160 +msgid "Right to Left" +msgstr "Phải sang trái" + +#: cps/templates/readcbr.html:168 +msgid "Reset to Top" +msgstr "Quay lên trên" + +#: cps/templates/readcbr.html:169 +msgid "Remember Position" +msgstr "Ghi nhớ vị trí" + +#: cps/templates/readcbr.html:174 +msgid "Scrollbar" +msgstr "Thanh cuộn" + +#: cps/templates/readcbr.html:177 +msgid "Show" +msgstr "Hiện" + +#: cps/templates/readcbr.html:178 +msgid "Hide" +msgstr "Ẩn" + +#: cps/templates/readdjvu.html:5 +msgid "DJVU Reader" +msgstr "Trình đọc DJVU" + +#: cps/templates/readpdf.html:32 +msgid "PDF Reader" +msgstr "Trình đọc PDF" + +#: cps/templates/readtxt.html:6 +msgid "txt Reader" +msgstr "trình đọc txt" + +#: cps/templates/register.html:4 +msgid "Register New Account" +msgstr "Đăng ký tải khoản mới" + +#: cps/templates/register.html:10 +msgid "Choose a username" +msgstr "Chọn tên người dùng" + +#: cps/templates/register.html:15 +msgid "Your Email" +msgstr "Địa chỉ email của bạn" + +#: cps/templates/remote_login.html:5 +msgid "Magic Link - Authorise New Device" +msgstr "Magic Link - Xác thực thiết bị mới" + +#: cps/templates/remote_login.html:7 +msgid "On another device, login and visit:" +msgstr "Trên thiết bị khác, đăng nhập và thăm quan:" + +#: cps/templates/remote_login.html:11 +msgid "Once verified, you will automatically be logged in on this device." +msgstr "Một khi xác nhận, bạn sẽ tự động đăng nhập trên thiết bị này." + +#: cps/templates/remote_login.html:14 +msgid "This verification link will expire in 10 minutes." +msgstr "Link xác nhận này sẽ hết hạn trong 10 phút." + +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "Không tìm thấy kết quả" + +#: cps/templates/search.html:7 +msgid "Search Term:" +msgstr "Từ khoá tìm kiếm:" + +#: cps/templates/search.html:9 +msgid "Results for:" +msgstr "Kết quả cho:" + +#: cps/templates/search_form.html:21 +msgid "Published Date From" +msgstr "Ngày phát hành từ" + +#: cps/templates/search_form.html:31 +msgid "Published Date To" +msgstr "Ngày phát hành tới" + +#: cps/templates/search_form.html:59 +msgid "Exclude Tags" +msgstr "" + +#: cps/templates/search_form.html:77 +msgid "Exclude Series" +msgstr "" + +#: cps/templates/search_form.html:95 +msgid "Exclude Shelves" +msgstr "" + +#: cps/templates/search_form.html:115 +msgid "Exclude Languages" +msgstr "" + +#: cps/templates/search_form.html:126 +msgid "Extensions" +msgstr "" + +#: cps/templates/search_form.html:134 +msgid "Exclude Extensions" +msgstr "" + +#: cps/templates/search_form.html:144 +msgid "Rating Above" +msgstr "Đánh giá cao hơn" + +#: cps/templates/search_form.html:148 +msgid "Rating Below" +msgstr "Đánh giá thấp hơn" + +#: cps/templates/search_form.html:180 +msgid "From:" +msgstr "Từ:" + +#: cps/templates/search_form.html:190 +msgid "To:" +msgstr "Tới:" + +#: cps/templates/shelf.html:13 +msgid "Delete this Shelf" +msgstr "Xoá giá sách này" + +#: cps/templates/shelf.html:14 +msgid "Edit Shelf Properties" +msgstr "Chỉnh sửa thông tin giá sách" + +#: cps/templates/shelf.html:17 +msgid "Arrange books manually" +msgstr "Sắp xếp sách bằng tay" + +#: cps/templates/shelf.html:18 +msgid "Disable Change order" +msgstr "Khoá thay đổi thứ tự" + +#: cps/templates/shelf.html:18 +msgid "Enable Change order" +msgstr "Mở thay đổi thứ tự" + +#: cps/templates/shelf_edit.html:14 +msgid "Share with Everyone" +msgstr "Chia sửa với tất cả" + +#: cps/templates/shelf_edit.html:21 +msgid "Sync this shelf with Kobo device" +msgstr "Đồng bộ giá sách này với thiết bị Kobo" + +#: cps/templates/shelf_order.html:5 +msgid "Drag to Rearrange Order" +msgstr "Kéo để thay đổi lại thứ tự" + +#: cps/templates/shelf_order.html:33 +msgid "Hidden Book" +msgstr "Sách ẩn" + +#: cps/templates/stats.html:7 +msgid "Library Statistics" +msgstr "Thống kê thư viện" + +#: cps/templates/stats.html:12 +msgid "Books in this Library" +msgstr "Sách trong thư viện" + +#: cps/templates/stats.html:16 +msgid "Authors in this Library" +msgstr "Các tác giả trong thư viện" + +#: cps/templates/stats.html:20 +msgid "Categories in this Library" +msgstr "Các thể loại trong thư viện" + +#: cps/templates/stats.html:24 +msgid "Series in this Library" +msgstr "Các series trong thư viện" + +#: cps/templates/stats.html:29 +msgid "System Statistics" +msgstr "Thống kê hệ thống" + +#: cps/templates/stats.html:33 +msgid "Program" +msgstr "" + +#: cps/templates/stats.html:34 +msgid "Installed Version" +msgstr "Phiên bản đã cài đặt" + +#: cps/templates/tasks.html:12 +msgid "User" +msgstr "Người dùng" + +#: cps/templates/tasks.html:14 +msgid "Task" +msgstr "Nhiệm vụ" + +#: cps/templates/tasks.html:15 +msgid "Status" +msgstr "Trạng thái" + +#: cps/templates/tasks.html:16 +msgid "Progress" +msgstr "Tiến độ" + +#: cps/templates/tasks.html:17 +msgid "Run Time" +msgstr "Thời gian chạy" + +#: cps/templates/tasks.html:20 +#, fuzzy +msgid "Actions" +msgstr "Đánh giá" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" + +#: cps/templates/user_edit.html:20 +msgid "Reset user Password" +msgstr "Reset mật khẩu người dùng" + +#: cps/templates/user_edit.html:43 +msgid "Language of Books" +msgstr "Ngôn ngữ của sách" + +#: cps/templates/user_edit.html:54 +msgid "OAuth Settings" +msgstr "Thiết lập OAuth" + +#: cps/templates/user_edit.html:56 +msgid "Link" +msgstr "Link" + +#: cps/templates/user_edit.html:58 +msgid "Unlink" +msgstr "Unlink" + +#: cps/templates/user_edit.html:64 +msgid "Kobo Sync Token" +msgstr "Token đồng bộ Kobo" + +#: cps/templates/user_edit.html:66 +msgid "Create/View" +msgstr "Tạo/xem" + +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "Ép đồng bộ tất cả với Kobo" + +#: cps/templates/user_edit.html:88 +msgid "Add allowed/Denied Custom Column Values" +msgstr "" + +#: cps/templates/user_edit.html:137 +msgid "Sync only books in selected shelves with Kobo" +msgstr "Đồng bộ sách trên những giá được chọn với Kobo" + +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 +msgid "Delete User" +msgstr "Xoá người dùng" + +#: cps/templates/user_edit.html:159 +msgid "Generate Kobo Auth URL" +msgstr "" + +#: cps/templates/user_table.html:80 cps/templates/user_table.html:103 +msgid "Select..." +msgstr "Chọn..." + +#: cps/templates/user_table.html:131 +msgid "Edit User" +msgstr "Chỉnh sửa người dùng" + +#: cps/templates/user_table.html:134 +msgid "Enter Username" +msgstr "Nhập tên người dùng" + +#: cps/templates/user_table.html:135 +#, fuzzy +msgid "Enter Email" +msgstr "Test e-mail" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "Enter eReader Email" +msgstr "Kindle" + +#: cps/templates/user_table.html:136 +#, fuzzy +msgid "eReader Email" +msgstr "Test e-mail" + +#: cps/templates/user_table.html:137 +msgid "Locale" +msgstr "Ngôn ngữ" + +#: cps/templates/user_table.html:138 +msgid "Visible Book Languages" +msgstr "Những ngôn ngữ hiển thị cho sách" + +#: cps/templates/user_table.html:139 +msgid "Edit Allowed Tags" +msgstr "Chỉnh sửa những tags đươc cho phép" + +#: cps/templates/user_table.html:139 +msgid "Allowed Tags" +msgstr "Tags được cho phép" + +#: cps/templates/user_table.html:140 +msgid "Edit Denied Tags" +msgstr "Chỉnh sửa những tags bị từ chối" + +#: cps/templates/user_table.html:140 +msgid "Denied Tags" +msgstr "Tags bị từ chối" + +#: cps/templates/user_table.html:141 +msgid "Edit Allowed Column Values" +msgstr "Chỉnh sửa những giá trị cột được cho phép" + +#: cps/templates/user_table.html:141 +msgid "Allowed Column Values" +msgstr "Giá trị cột được cho phép" + +#: cps/templates/user_table.html:142 +msgid "Edit Denied Column Values" +msgstr "Chỉnh sửa những cột giá trị bị từ chối" + +#: cps/templates/user_table.html:142 +msgid "Denied Column Values" +msgstr "Những cột giá trị bị từ chối" + +#: cps/templates/user_table.html:144 +msgid "Change Password" +msgstr "Đổi mật khẩu" + +#: cps/templates/user_table.html:147 +msgid "View" +msgstr "Xem" + +#: cps/templates/user_table.html:150 +msgid "Edit Public Shelves" +msgstr "Chỉnh sửa giá sách công khai" + +#: cps/templates/user_table.html:152 +msgid "Sync selected Shelves with Kobo" +msgstr "Đồng bộ những giá sách đã chọn với Kobo" + +#: cps/templates/user_table.html:156 +#, fuzzy +msgid "Show Read/Unread Section" +msgstr "Hiển thị đã đọc và chưa đọc" + diff --git a/cps/translations/zh_Hans_CN/LC_MESSAGES/messages.mo b/cps/translations/zh_Hans_CN/LC_MESSAGES/messages.mo index b529a3588..cc36da236 100644 Binary files a/cps/translations/zh_Hans_CN/LC_MESSAGES/messages.mo and b/cps/translations/zh_Hans_CN/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po b/cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po index bf46df41e..21fd7c1ed 100644 --- a/cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po +++ b/cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po @@ -7,752 +7,811 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2020-09-27 22:18+0800\n" "Last-Translator: xlivevil \n" "Language: zh_CN\n" "Language-Team: zh_Hans_CN \n" -"Plural-Forms: nplurals=1; plural=0\n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "未安装" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "已安装" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "统计" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +msgid "Server restarted, please reload page." msgstr "服务器已重启,请刷新页面" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +msgid "Performing Server shutdown, please close window." msgstr "正在关闭服务器,请关闭窗口" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "重新连接成功" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "数据库重新连接成功" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "未知命令" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +msgid "Success! Books queued for Metadata Backup" +msgstr "书籍成功加入元数据备份队列" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "未知" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "管理页" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "基本配置" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "界面配置" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" msgstr "管理用户" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "全部" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "找不到用户" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "成功删除 {} 个用户" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "显示全部" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "格式错误的请求" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "访客名称无法更改" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "游客无法拥有此角色" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" -msgstr "理员账户不存在,无法删除管理员角色" +msgstr "没有其余管理员账户,无法删除管理员角色" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" -msgstr "值必须是 true 或 false" +msgstr "值必须为 true 或 false" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "无效角色" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" -msgstr "游客无法拥有此视图" +msgstr "游客无法查看此页面" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" -msgstr "无效视图" +msgstr "无效页面" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" -msgstr "游客的本地化是自动侦测而无法设置的" +msgstr "无法设置游客的本地化,该项设置的值将自动检测" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "无可用本地化" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "无有效书籍语言" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "参数未找到" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" -msgstr "无效的阅读列" +msgstr "无效的阅读栏目" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" -msgstr "无效的限制列" +msgstr "无效的限制栏目" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" -msgstr "Calibre-Web配置已更新" +msgstr "Calibre-Web 配置已更新" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" -msgstr "您确定删除Kobo Token吗?" +msgstr "您确定删除 Kobo 令牌吗?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "您确定要删除此域吗?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "您确定要删除此用户吗?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "您确定要删除此书架吗?" -#: cps/admin.py:580 +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" msgstr "您确定要修改选定用户的本地化设置吗?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "您确定要修改选定用户的可见书籍语言吗?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "您确定要修改选定用户的选定角色吗?" -#: cps/admin.py:586 +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "您确定要修改选定用户的选定限制吗?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "您确定要修改选定用户的选定可视化限制吗?" -#: cps/admin.py:590 +#: cps/admin.py:622 msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "您确定要更改所选用户的书架同步行为吗?" -#: cps/admin.py:592 +#: cps/admin.py:624 msgid "Are you sure you want to change Calibre library location?" msgstr "您确定要更改 Calibre 库位置吗?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "标签未找到" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "Calibre-Web 将搜索更新封面,并更新缩略图,这可能需要一段时间" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "无效的动作" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "您确定要删除 Calibre-Web 的同步数据库以强制与您的 Kobo Reader 进行完全同步吗" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "拒绝" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "允许" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "{} 同步项目被删除" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "标签未找到" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "无效的动作" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json 未为 Web 应用程序配置" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "日志文件路径无效,请输入正确的路径" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "访问日志路径无效,请输入正确的路径" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" -msgstr "请输入LDAP主机、端口、DN和用户对象标识符" +msgstr "请输入 LDAP 主机、端口、DN 和用户对象标识符" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" -msgstr "请输入一个LDAP服务账号和密码 " +msgstr "请输入一个 LDAP 服务账号和密码 " -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" -msgstr "请输入一个LDAP服务账号" +msgstr "请输入一个 LDAP 服务账号" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" -msgstr "LDAP组对象过滤器需要一个具有“%s”格式标识符" +msgstr "LDAP 组对象过滤器需要一个具有“%s”格式标识符" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" -msgstr "LDAP组对象过滤器的括号不匹配" +msgstr "LDAP 组对象过滤器的括号不匹配" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" -msgstr "LDAP用户对象过滤器需要一个具有“%s”格式标识符" +msgstr "LDAP 用户对象过滤器需要一个具有“%s”格式标识符" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" -msgstr "LDAP用户对象过滤器的括号不匹配" +msgstr "LDAP 用户对象过滤器的括号不匹配" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" -msgstr "LDAP成员用户过滤器需要有一个“%s”格式标识符" +msgstr "LDAP 成员用户过滤器需要有一个“%s”格式标识符" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" -msgstr "LDAP成员用户过滤器中有不匹配的括号" +msgstr "LDAP 成员用户过滤器中有不匹配的括号" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "LDAP CA证书、证书或密钥位置无效,请输入正确的路径" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "设置数据库不可写入" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "数据库路径无效,请输入正确的路径" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "数据库不可写入" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "密钥文件路径无效,请输入正确的路径" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "证书文件路径无效,请输入正确的路径" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "邮件服务器设置已更新" - -#: cps/admin.py:1324 -msgid "Database Configuration" -msgstr "数据库配置" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "请填写所有字段!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "邮箱不在有效域中" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "添加新用户" -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "用户“%(user)s”已创建" - -#: cps/admin.py:1369 -msgid "Found an existing account for this e-mail address or name." -msgstr "使用此邮箱或用户名的账号已经存在。" - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "用户“%(nick)s”已删除" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "无法删除游客用户" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "管理员账户不存在,无法删除用户" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "编辑用户 %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "用户“%(nick)s”已更新" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "发生一个未知错误,请稍后再试。" - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "编辑邮件服务器设置" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "G-Mail账号校验成功" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "Gmail 账户验证成功" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "数据库错误:%(error)s" + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" -msgstr "发送给%(email)s的测试邮件已进入队列。请检查任务结果" +msgstr "发送给 %(email)s 的测试邮件已加入队列。请检查任务结果" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "发送测试邮件时出错:%(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "请先配置您的邮箱地址..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "邮件服务器设置已更新" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "编辑计划任务设置" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "指定任务的开始时间无效" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "指定任务的持续时间无效" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "已更新计划任务设置" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "发生一个未知错误,请稍后再试" + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "设置数据库不可写" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "编辑用户 %(nick)s" + +#: cps/admin.py:1423 +#, python-format +msgid "Success! Password for user %(user)s reset" msgstr "用户 %(user)s 的密码已重置" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." -msgstr "请先配置SMTP邮箱设置..." +#: cps/admin.py:1429 +msgid "Oops! Please configure the SMTP mail settings." +msgstr "请先配置 SMTP 邮箱设置..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "日志文件查看器" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "正在请求更新包" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "正在下载更新包" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "正在解压更新包" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "正在替换文件" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "数据库连接已关闭" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "正在停止服务器" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "更新完成,请点击确定并刷新页面" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "更新失败:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" -msgstr "HTTP错误" +msgstr "HTTP 错误" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "连接错误" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "建立连接超时" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "一般错误" -#: cps/admin.py:1696 -#, fuzzy +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" msgstr "更新文件无法保存在临时目录中" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" -msgstr "" +msgstr "更新期间无法替换文件" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" -msgstr "未能提取至少一个LDAP用户" +msgstr "未能获得任何 LDAP 用户" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" -msgstr "未能创建至少一个LDAP用户" +msgstr "未能创建任何 LDAP 用户" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "错误:%(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" -msgstr "错误:在LDAP服务器的响应中没有返回用户" +msgstr "错误:在 LDAP 服务器的响应中没有返回用户" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" -msgstr "数据库中没有找到至少一个LDAP用户" +msgstr "数据库中没有找到任何 LDAP 用户" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} 用户被成功导入" -#: cps/converter.py:30 -msgid "not configured" -msgstr "未配置" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "数据库路径无效,请输入正确的路径" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "数据库不可写入" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "密钥文件路径无效,请输入正确的路径" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "证书文件路径无效,请输入正确的路径" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "数据库设置已更新" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "数据库配置" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "请填写所有字段!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "邮箱不在有效域中" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "添加新用户" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "用户“%(user)s”已创建" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "使用此邮箱或用户名的账号已经存在" + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "用户“%(nick)s”已删除" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "无法删除游客用户" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "管理员账户不存在,无法删除用户" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "电子邮件地址不能为空,并且必须是有效的电子邮件" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "用户“%(nick)s”已更新" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "未安装" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "缺少执行权限" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" -msgstr "自定义列号:%(column)d在Calibre数据库中不存在" +msgid "Custom Column No.%(column)d does not exist in calibre database" +msgstr "自定义列号:%(column)d 在 Calibre 数据库中不存在" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "书籍格式已成功删除" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "无" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "书籍已成功删除" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "糟糕!选择书名无法打开。文件不存在或者文件不可访问" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "编辑元数据" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "用户没有权限上传封面" -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "%(seriesindex)s 不是一个有效的数值,忽略" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s 不是一种有效语言" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "不能上传文件扩展名为“%(ext)s”的文件到此服务器" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "要上传的文件必须具有扩展名" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "创建路径 %(path)s 失败(权限拒绝)。" - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "保存文件 %(file)s 失败。" - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "数据库错误:%(error)s。" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "已添加 %(ext)s 格式到 %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "标识符不区分大小写,覆盖旧标识符" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "已成功更新元数据" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "编辑书籍出错,请检查日志文件以获取详细信息" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "编辑书籍时出错: {}" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "上传的书籍可能已经存在,建议修改后重新上传: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "文件 %(filename)s 无法保存到临时目录" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "移动封面文件失败 %(file)s:%(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "文件 %(file)s 已上传" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" -msgstr "转换的源或目的格式缺失" +msgstr "转换的源格式或目的格式缺失" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" -msgstr "书籍已经被成功加入到 %(book_format)s 格式转换队列" +msgstr "书籍已经被成功加入 %(book_format)s 格式转换队列" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "转换此书籍时出现错误: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "上传的书籍可能已经存在,建议修改后重新上传: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "'%(langname)s' 不是一种有效语言" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "不能上传文件扩展名为“%(ext)s”的文件到此服务器" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "要上传的文件必须具有扩展名" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "文件 %(filename)s 无法保存到临时目录" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "移动封面文件失败 %(file)s:%(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "书籍的此格式副本已成功删除" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "书籍已成功删除" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "您没有删除书籍的权限" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "编辑元数据" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s 不是一个有效的数值,忽略" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "用户没有权限上传其他文件格式" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "创建路径 %(path)s 失败 (权限不足)" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "保存文件 %(file)s 失败" + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "已添加 %(ext)s 格式到 %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" -msgstr "Google Drive 设置未完成,请尝试停用并再次激活Google云端硬盘" +msgstr "Google Drive 设置未完成,请尝试停用并再次激活 Google 云端硬盘" #: cps/gdrive.py:95 msgid "Callback domain is not verified, please follow steps to verify domain in google developer console" -msgstr "回调域名尚未被校验,请在google开发者控制台按步骤校验域名" +msgstr "回调域名尚未被校验,请在 Google 开发者控制台按步骤校验域名" #: cps/helper.py:80 #, python-format msgid "%(format)s format not found for book id: %(book)d" -msgstr "找不到id为 %(book)d 的书籍的 %(format)s 格式" +msgstr "找不到 ID 为 %(book)d 的书籍的 %(format)s 格式" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "Google Drive %(fn)s 上找不到 %(format)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "找不到 %(format)s:%(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" -msgstr "发送到Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +msgid "Send to eReader" +msgstr "发送到电子阅读器" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." -msgstr "此邮件已经通过Calibre-Web发送。" +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +msgid "This Email has been sent via Calibre-Web." +msgstr "此邮件已经通过 Calibre-Web 发送" -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" -msgstr "Calibre-Web测试邮件" +#: cps/helper.py:114 +msgid "Calibre-Web Test Email" +msgstr "Calibre-Web 测试邮件" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +msgid "Test Email" msgstr "测试邮件" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" -msgstr "开启Calibre-Web之旅" +msgstr "开启 Calibre-Web 之旅" -#: cps/helper.py:135 +#: cps/helper.py:137 #, python-format -msgid "Registration e-mail for user: %(name)s" +msgid "Registration Email for user: %(name)s" msgstr "用户注册电子邮件:%(name)s" -#: cps/helper.py:146 cps/helper.py:152 +#: cps/helper.py:148 cps/helper.py:154 #, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" -msgstr "转换 %(orig)s 到 %(format)s 并发送到Kindle" +msgid "Convert %(orig)s to %(format)s and send to eReader" +msgstr "转换 %(orig)s 到 %(format)s 并发送到电子阅读器" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 #, python-format -msgid "Send %(format)s to Kindle" -msgstr "发送 %(format)s 到Kindle" +msgid "Send %(format)s to eReader" +msgstr "发送 %(format)s 到电子阅读器" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, python-format -msgid "%(book)s send to Kindle" -msgstr "%(book)s发送到Kindle" +msgid "%(book)s send to eReader" +msgstr "%(book)s 发送到电子阅读器" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "无法读取请求的文件。可能有错误的权限设置?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "阅读状态无法设置: {}" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" -msgstr "删除书的文件夹%(id)s失败,路径有子文件夹:%(path)s" +msgstr "删除书的文件夹 %(id)s 失败,路径有子文件夹:%(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" -msgstr "删除书籍 %(id)s失败:%(message)s" +msgstr "删除书籍 %(id)s 失败:%(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "仅从数据库中删除书籍 %(id)s,数据库中的书籍路径无效: %(path)s" -#: cps/helper.py:388 +#: cps/helper.py:450 +#, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "将作者从“%(src)s”改为“%(dest)s”时失败,出错信息:%(error)s" + +#: cps/helper.py:522 cps/helper.py:531 +#, python-format +msgid "File %(file)s not found on Google Drive" +msgstr "Google Drive 上找不到文件 %(file)s" + +#: cps/helper.py:565 #, python-format msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "将标题从“%(src)s”改为“%(dest)s”时失败,出错信息:%(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "从“%(src)s”重命名为“%(dest)s”失败,出错信息:%(error)s" +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "重命名此路径: {}文件时出错" -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 -#, python-format -msgid "File %(file)s not found on Google Drive" -msgstr "Google Drive上找不到文件 %(file)s" - -#: cps/helper.py:467 +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" -msgstr "Google Drive上找不到书籍路径 %(path)s" +msgstr "Google Drive 上找不到书籍路径 %(path)s" -#: cps/helper.py:507 cps/web.py:1654 -msgid "Found an existing account for this e-mail address" -msgstr "使用此邮箱的账号已经存在。" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "已存在使用此邮箱的账户" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "此用户名已被使用" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" -msgstr "无效的邮件地址格式" +#: cps/helper.py:664 +msgid "Invalid Email address format" +msgstr "无效的邮箱格式" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "上传封面所需的 Python 模块 'advocate' 未安装" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "下载封面时出错" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "封面格式出错" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "您没有访问本地主机或本地网络进行封面上传" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "创建封面路径失败" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" -msgstr "封面文件不是有效的图片文件,或者无法存储" +msgstr "封面文件不是有效的图片文件,或者无法存储它" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" -msgstr "封面文件只支持jpg/jpeg/png/webp/bmp文件" +msgstr "封面文件只支持 jpg、jpeg、png、webp、bmp 文件" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "封面文件内容无效" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" -msgstr "仅将jpg、jpeg文件作为封面文件" +msgstr "仅将 jpg、jpeg 文件作为封面文件" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" -msgstr "找不到Unrar执行文件" +msgstr "找不到 Unrar 执行文件" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" -msgstr "执行UnRar时出错" +#: cps/helper.py:947 +msgid "Error executing UnRar" +msgstr "执行 UnRar 时出错" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "等待中" +#: cps/helper.py:1040 +msgid "Cover" +msgstr "封面" -#: cps/helper.py:764 -msgid "Failed" -msgstr "失败" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "将所有书籍加入元数据备份队列" -#: cps/helper.py:766 -msgid "Started" -msgstr "已开始" +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" +msgstr "请不要从 localhost 访问 Calibre-Web,以便 Kobo 设备能获取有效的 api_endpoint" -#: cps/helper.py:768 -msgid "Finished" -msgstr "已完成" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "未知状态" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" -msgstr "请不要使用localhost访问Calibre-Web,以便Kobo设备能获取有效的api_endpoint" - -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Kobo 设置" @@ -761,54 +820,54 @@ msgstr "Kobo 设置" msgid "Register with %(provider)s" msgstr "使用 %(provider)s 注册" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "您现在已以“%(nickname)s”身份登录" #: cps/oauth_bb.py:148 #, python-format msgid "Link to %(oauth)s Succeeded" -msgstr "链接到%(oauth)s成功" +msgstr "链接到 %(oauth)s 成功" #: cps/oauth_bb.py:155 msgid "Login failed, No User Linked With OAuth Account" -msgstr "登录失败,没有用户与OAuth帐户关联" +msgstr "登录失败,没有用户与 OAuth 帐户关联" #: cps/oauth_bb.py:197 #, python-format msgid "Unlink to %(oauth)s Succeeded" -msgstr "取消链接到%(oauth)s成功" +msgstr "取消链接到 %(oauth)s 成功" #: cps/oauth_bb.py:202 #, python-format msgid "Unlink to %(oauth)s Failed" -msgstr "取消链接到%(oauth)s失败" +msgstr "取消链接到 %(oauth)s 失败" #: cps/oauth_bb.py:205 #, python-format msgid "Not Linked to %(oauth)s" -msgstr "为连接到%(oauth)s" +msgstr "未连接到 %(oauth)s" #: cps/oauth_bb.py:261 msgid "Failed to log in with GitHub." -msgstr "使用Github登录失败。" +msgstr "使用 Github 登录失败" #: cps/oauth_bb.py:267 msgid "Failed to fetch user info from GitHub." -msgstr "从Github获取用户信息失败。" +msgstr "从 Github 获取用户信息失败" #: cps/oauth_bb.py:279 msgid "Failed to log in with Google." -msgstr "使用Google登录失败。" +msgstr "使用 Google 登录失败" #: cps/oauth_bb.py:285 msgid "Failed to fetch user info from Google." -msgstr "从Google获取用户信息失败。" +msgstr "从 Google 获取用户信息失败" #: cps/oauth_bb.py:332 msgid "GitHub Oauth error, please retry later." -msgstr "GitHub Oauth 错误,请重试。" +msgstr "GitHub Oauth 错误,请重试" #: cps/oauth_bb.py:335 msgid "GitHub Oauth error: {}" @@ -816,511 +875,603 @@ msgstr "GitHub Oauth 错误: {}" #: cps/oauth_bb.py:356 msgid "Google Oauth error, please retry later." -msgstr "Google Oauth 错误,请重试。" +msgstr "Google Oauth 错误,请重试" #: cps/oauth_bb.py:359 msgid "Google Oauth error: {}" msgstr "Google Oauth 错误: {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "{} 星" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "登录" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" -msgstr "找不到Token" +msgstr "找不到令牌" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" -msgstr "Token已过期" +msgstr "令牌已过期" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "成功!请返回您的设备" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "书籍" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" -msgstr "显示最近书籍" +msgstr "显示最近查看的书籍" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "热门书籍" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "显示热门书籍" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" -msgstr "下载历史" +msgstr "已下载书籍" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "显示下载过的书籍" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "最高评分书籍" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "显示最高评分书籍" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "已读书籍" -#: cps/render_template.py:61 -msgid "Show read and unread" -msgstr "显示阅读状态" +#: cps/render_template.py:64 +msgid "Show Read and Unread" +msgstr "显示已读或未读状态" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "未读书籍" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "显示未读" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "发现" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "显示随机书籍" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "分类" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" -msgstr "显示分类选择" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +msgid "Show Category Section" +msgstr "显示分类栏目" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "丛书" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" -msgstr "显示丛书选择" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +msgid "Show Series Section" +msgstr "显示丛书栏目" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "作者" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" -msgstr "显示作者选择" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +msgid "Show Author Section" +msgstr "显示作者栏目" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "出版社" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" -msgstr "显示出版社选择" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +msgid "Show Publisher Section" +msgstr "显示出版社栏目" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "语言" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" -msgstr "显示语言选择" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +msgid "Show Language Section" +msgstr "显示语言栏目" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "评分" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" -msgstr "显示评分选择" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +msgid "Show Ratings Section" +msgstr "显示评分栏目" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "文件格式" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" -msgstr "显示文件格式选择" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +msgid "Show File Formats Section" +msgstr "显示文件格式栏目" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "归档书籍" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +msgid "Show Archived Books" msgstr "显示归档书籍" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "书籍列表" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "显示书籍列表" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "指定的书架无效" - -#: cps/shelf.py:73 -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "对不起,您没有添加书籍到这个书架的权限" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "此书籍已经是书架 %(shelfname)s 的一部分" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "此书籍已被添加到书架:%(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "您没有添加书籍到书架 %(name)s 的权限" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "书籍已经在书架 %(name)s 中了" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "书籍已经被添加到书架 %(sname)s 中" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "无法添加书籍到书架:%(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "此书已从书架 %(sname)s 中删除" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "对不起,您没有从书架 %(sname)s 中删除书籍的权限" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "创建书架" - -#: cps/shelf.py:236 -msgid "Sorry you are not allowed to edit this shelf" -msgstr "对不起,您没有编辑这个书架的权限" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "编辑书架" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "书架 %(title)s 已创建" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "书架 %(title)s 已修改" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "发生错误" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "公共书架:%(title)s已经存在已经存在。" - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "私有书架:%(title)s已经存在已经存在。" - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "修改书架 %(name)s 顺序" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "书架:%(name)s" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "打开书架出错。书架不存在或不可访问" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "读取更新信息时出现意外数据" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "无可用更新。您已经安装了最新版本" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "有新的更新。单击下面的按钮以更新到最新版本。" - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "无法获取更新信息" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "点击下面按钮更新到最新稳定版本。" - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "有新的更新。单击下面的按钮以更新到版本: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "无可用发布信息" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "发现(随机书籍)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "热门书籍(最多下载)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "%(user)s 下载过的书籍" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "作者:%(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "出版社:%(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "丛书:%(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "评分:%(rating)s 星" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "文件格式:%(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "分类:%(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "语言:%(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "高级搜索" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "搜索" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "下载次数" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "评分列表" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "文件格式列表" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "任务列表" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "出版时间晚于 " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "出版时间早于 " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "评分 <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "评分 >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "阅读状态 = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" -msgstr "搜索自定义列时出错,请重启 Calibre-Web" +msgstr "搜索自定义栏目时出错,请重启 Calibre-Web" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "书籍已经成功加入 %(kindlemail)s 的发送队列" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "高级搜索" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "指定的书架无效" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "对不起,您没有添加书籍到这个书架的权限" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "此书籍已经是书架 %(shelfname)s 的一部分" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "此书籍已被添加到书架:%(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "您没有向书架添加书籍的权限" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "书籍已经在书架 %(name)s 中了" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "书籍已经被添加到书架 %(sname)s 中" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "无法添加书籍到书架:%(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "此书已从书架 %(sname)s 中删除" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "抱歉,您没有从这个书架删除书籍的权限" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "创建书架" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "对不起,您没有编辑这个书架的权限" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "编辑书架" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "删除书架时出错" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "书架已成功删除" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "修改书架 %(name)s 顺序" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "抱歉,您没有创建公开书架的权限" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "书架 %(title)s 已创建" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "书架 %(title)s 已修改" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "发生错误" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "公共书架:%(title)s 已经存在已经存在" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "私有书架:%(title)s 已经存在已经存在" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "书架:%(name)s" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "打开书架出错。书架不存在或不可访问" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "任务列表" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "等待中" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "失败" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "已开始" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "已完成" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "已结束" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "已取消" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "未知状态" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "读取更新信息时出现异常数据" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "无可用更新。您已经安装了最新版本" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "有新的更新。单击下面的按钮以更新到最新版本" + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "无法获取更新信息" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "点击下面按钮更新到最新稳定版本" + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "有新的更新。单击下面的按钮以更新到版本: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "无可用发布信息" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "发现 (随机书籍)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "热门书籍(最多下载)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "%(user)s 下载过的书籍" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "作者:%(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "出版社:%(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "丛书:%(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "评分:无" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "评分:%(rating)s 星" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "文件格式:%(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "分类:%(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "语言:%(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "下载次数" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "评分列表" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "文件格式列表" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "请先配置 SMTP 邮箱设置..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "书籍已经成功加入 %(eReadermail)s 的发送队列" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "糟糕!发送这本书籍的时候出现错误:%(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." -msgstr "请先配置您的kindle邮箱。" +#: cps/web.py:1213 +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "请先配置您的 Kindle 邮箱" -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "邮件服务未配置,请联系网站管理员!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "注册" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "您的电子邮件不允许注册" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." -msgstr "确认邮件已经发送到您的邮箱。" +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." +msgstr "确认邮件已经发送到您的邮箱" -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" -msgstr "无法激活LDAP认证" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" +msgstr "无法激活 LDAP 认证" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" -msgstr "后备登录“%(nickname)s”:无法访问LDAP服务器,或用户未知" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" +msgstr "后备登录“%(nickname)s”:无法访问 LDAP 服务器,或用户未知" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "无法登录:%(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "用户名或密码错误" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "新密码已发送到您的邮箱" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "请输入有效的用户名进行密码重置" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "您现在已以“%(nickname)s”登录" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)s 的用户配置" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +msgid "Success! Profile Updated" msgstr "资料已更新" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "使用此邮箱的账号已经存在" + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "找不到包含 OAuth 信息的有效 gmail.json 文件" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s 发送到电子阅读器" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" -msgstr "Calibre 电子书转换器%(tool)s没有发现" +msgstr "Calibre 电子书转换器 %(tool)s 没有发现" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "硬盘上找不到 %(format)s 格式" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "发生未知错误,书籍转换失败" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Kepubify 转换失败:%(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" -msgstr "找不到转换后的文件或文件夹%(folder)s中有多个文件" +msgstr "找不到转换后的文件或文件夹 %(folder)s 中有多个文件" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "电子书转换器失败: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "Calibre 运行失败,错误信息:%(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "转换" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "正在重新连接到 Calibre 数据库" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "电子邮件" + +#: cps/tasks/metadata_backup.py:47 +msgid "Backing up Metadata" +msgstr "正在备份元数据" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "生成了 %(count)s 个封面缩略图" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "封面缩略图" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "生成了 %(count)s 个丛书缩略图" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "正在清理封面缩略图缓存" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "上传书籍" + #: cps/templates/admin.html:9 msgid "Users" msgstr "用户列表" @@ -1333,14 +1484,14 @@ msgstr "用户名" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "邮箱地址" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" -msgstr "接收书籍的Kindle邮箱地址" +msgid "Send to eReader Email" +msgstr "接收书籍的电子阅读器邮箱地址" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "管理权限" @@ -1350,211 +1501,228 @@ msgstr "管理权限" msgid "Password" msgstr "密码" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "上传书籍" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "下载书籍" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "查看书籍" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "编辑书籍" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "删除数据" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "公共书架" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "添加新用户" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" -msgstr "导入LDAP用户" +msgstr "导入 LDAP 用户" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" -msgstr "SMTP邮件服务器设置" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" +msgstr "SMTP 邮件服务器设置" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" -msgstr "SMTP主机名" +msgstr "SMTP 主机名" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" -msgstr "SMTP端口" +msgstr "SMTP 端口" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "加密" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" -msgstr "SMTP用户名" +msgstr "SMTP 用户名" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "发件人邮箱" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "电子邮件服务" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" -msgstr "通过Oauth2的Gmail" +msgstr "使用 Oauth2 的 Gmail" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "配置" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Calibre 数据库路径" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "日志级别" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "端口" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "扩展端口" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "每页书籍数" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "上传" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "匿名浏览" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "开放注册" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "魔法链接远程登录" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "反向代理登录" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "反向代理头部名称" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 msgid "Edit Calibre Database Configuration" -msgstr "编辑Calibre数据库配置" +msgstr "编辑 Calibre 数据库配置" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "编辑基本配置" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "编辑界面配置" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "计划任务" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "任务开始运行的时间" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "最长任务持续时间" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "生成书籍封面缩略图" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "生成丛书封面缩略图" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "重新连接到 Calibre 库" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "刷新封面缩略图缓存" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "管理" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" -msgstr "下载Debug包" +msgstr "下载 Debug 包" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "查看日志文件" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "重新连接到Calibre数据库" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "重启" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "停止" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "更新" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "版本信息" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "版本" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "详情" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "当前版本" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "检查更新" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "执行更新" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "您确定要重启吗?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "确定" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "取消" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "您确定要关闭吗?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "正在更新,请不要刷新页面" @@ -1566,208 +1734,207 @@ msgstr "通过" msgid "In Library" msgstr "在书库" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "按图书日期排序,最新优先" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "按图书日期排序,最旧优先" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "按标题按字母顺序排序" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "按标题逆字母顺序排序" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "按出版日期排序,最新优先" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "按出版日期排序,最旧优先" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "减少" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "更多" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "删除书籍" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "删除格式:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" -msgstr "转换书籍格式:" +msgstr "书籍格式转换:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "转换从:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "选择一个选项" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "转换到:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "转换书籍" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "书名" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "作者" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "简介" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "书号" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "书号类型" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "书号编号" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "移除" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "添加书号" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "标签" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "丛书编号" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "评分" #: cps/templates/book_edit.html:104 msgid "Fetch Cover from URL (JPEG - Image will be downloaded and stored in database)" -msgstr "从URL获取封面(JPEG - 图片将下载并存储在数据库中)" +msgstr "从 URL 获取封面(JPEG - 图片将下载并存储在数据库中)" #: cps/templates/book_edit.html:108 msgid "Upload Cover from Local Disk" msgstr "从本地磁盘上传封面" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "出版日期" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "出版社" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "语言" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "确认" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "没有" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "上传格式" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "查看保存书籍" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "获取元数据" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "保存" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "关键字" -#: cps/templates/book_edit.html:237 -#, fuzzy +#: cps/templates/book_edit.html:234 msgid "Search keyword" msgstr " 搜索关键字 " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "单击封面将元数据加载到表单" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "加载中..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "关闭" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "源" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "搜索错误!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." -msgstr "无搜索结果!请尝试另一个关键字。" +msgstr "无搜索结果!请尝试另一个关键字" #: cps/templates/book_table.html:12 cps/templates/book_table.html:69 #: cps/templates/user_table.html:14 cps/templates/user_table.html:77 @@ -1849,35 +2016,42 @@ msgid "Enter Publishers" msgstr "输入出版社" #: cps/templates/book_table.html:73 -#, fuzzy msgid "Enter comments" -msgstr "输入域名" +msgstr "输入简介" #: cps/templates/book_table.html:73 msgid "Comments" -msgstr "" +msgstr "简介" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 -#, fuzzy +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "存档状态" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "阅读状态" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 msgid "Enter " -msgstr "书号" +msgstr "输入" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "您真的确认?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "这本书籍将被合并:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "合并到这本书籍:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "合并" @@ -1887,7 +2061,7 @@ msgstr "Calibre 数据库路径" #: cps/templates/config_db.html:22 msgid "Use Google Drive?" -msgstr "是否使用Google Drive?" +msgstr "是否使用 Google Drive?" #: cps/templates/config_db.html:27 msgid "Authenticate Google Drive" @@ -1899,7 +2073,7 @@ msgstr "Google Drive Calibre 路径" #: cps/templates/config_db.html:40 msgid "Metadata Watch Channel ID" -msgstr "元数据监视通道ID" +msgstr "元数据监视通道 ID" #: cps/templates/config_db.html:43 msgid "Revoke" @@ -1919,11 +2093,11 @@ msgstr "服务器端口" #: cps/templates/config_edit.html:28 msgid "SSL certfile location (leave it empty for non-SSL Servers)" -msgstr "SSL 证书文件路径(非SSL服务器请留空)" +msgstr "SSL 证书文件路径 (非 SSL 服务器请留空)" #: cps/templates/config_edit.html:35 msgid "SSL Keyfile location (leave it empty for non-SSL Servers)" -msgstr "SSL 密钥文件路径(非SSL服务器请留空)" +msgstr "SSL 密钥文件路径 (非 SSL 服务器请留空)" #: cps/templates/config_edit.html:43 msgid "Update Channel" @@ -1939,7 +2113,7 @@ msgstr "夜间版" #: cps/templates/config_edit.html:50 msgid "Trusted Hosts (Comma Separated)" -msgstr "" +msgstr "可信主机(用逗号分隔)" #: cps/templates/config_edit.html:61 msgid "Logfile Configuration" @@ -1947,7 +2121,7 @@ msgstr "日志文件配置" #: cps/templates/config_edit.html:77 msgid "Location and name of logfile (calibre-web.log for no entry)" -msgstr "日志文件路径和名称(默认为calibre-web.log)" +msgstr "日志文件路径和名称 (默认为 calibre-web.log)" #: cps/templates/config_edit.html:82 msgid "Enable Access Log" @@ -1955,7 +2129,7 @@ msgstr "启用访问日志" #: cps/templates/config_edit.html:85 msgid "Location and name of access logfile (access.log for no entry)" -msgstr "访问日志路径和名称(默认为access.log)" +msgstr "访问日志路径和名称 (默认为 access.log)" #: cps/templates/config_edit.html:96 msgid "Feature Configuration" @@ -1963,12 +2137,16 @@ msgstr "功能配置" #: cps/templates/config_edit.html:104 msgid "Convert non-English characters in title and author while saving to disk" -msgstr "" +msgstr "保存到磁盘时转换标题和作者中的非英文字符" #: cps/templates/config_edit.html:108 msgid "Enable Uploads" msgstr "启用上传" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "(请确保用户也有上传权限)" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "允许上传的文件格式" @@ -1982,7 +2160,7 @@ msgid "Enable Public Registration" msgstr "启用注册" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "使用邮箱或用户名" #: cps/templates/config_edit.html:132 @@ -1991,23 +2169,23 @@ msgstr "启用魔法链接远程登录" #: cps/templates/config_edit.html:137 msgid "Enable Kobo sync" -msgstr "启用Kobo同步" +msgstr "启用 Kobo 同步" #: cps/templates/config_edit.html:142 msgid "Proxy unknown requests to Kobo Store" -msgstr "代理未知请求到Kobo商店" +msgstr "代理未知请求到 Kobo 商店" #: cps/templates/config_edit.html:145 msgid "Server External Port (for port forwarded API calls)" -msgstr "服务器扩展端口(用于转发的API调用的端口)" +msgstr "服务器扩展端口 (用于转发的 API 调用的端口)" #: cps/templates/config_edit.html:153 msgid "Use Goodreads" -msgstr "使用Goodreads" +msgstr "使用 Goodreads" #: cps/templates/config_edit.html:154 msgid "Create an API Key" -msgstr "创建API Key" +msgstr "创建 API Key" #: cps/templates/config_edit.html:158 msgid "Goodreads API Key" @@ -2031,48 +2209,43 @@ msgstr "使用标准认证" #: cps/templates/config_edit.html:184 msgid "Use LDAP Authentication" -msgstr "使用LDAP认证" +msgstr "使用 LDAP 认证" #: cps/templates/config_edit.html:187 msgid "Use OAuth" -msgstr "使用OAuth认证" +msgstr "使用 OAuth 认证" #: cps/templates/config_edit.html:194 msgid "LDAP Server Host Name or IP Address" -msgstr "LDAP服务器主机名或IP地址" +msgstr "LDAP 服务器主机名或 IP 地址" #: cps/templates/config_edit.html:198 msgid "LDAP Server Port" -msgstr "LDAP服务器端口" +msgstr "LDAP 服务器端口" #: cps/templates/config_edit.html:202 msgid "LDAP Encryption" msgstr "LDAP 加密" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "无" - #: cps/templates/config_edit.html:205 msgid "TLS" -msgstr "TLS协议" +msgstr "TLS 协议" #: cps/templates/config_edit.html:206 msgid "SSL" -msgstr "SSL协议" +msgstr "SSL 协议" #: cps/templates/config_edit.html:210 msgid "LDAP CACertificate Path (Only needed for Client Certificate Authentication)" -msgstr "LDAP CA证书路径(仅用于客户端证书认证)" +msgstr "LDAP CA证书路径 (仅用于客户端证书认证)" #: cps/templates/config_edit.html:217 msgid "LDAP Certificate Path (Only needed for Client Certificate Authentication)" -msgstr "LDAP 证书路径(仅用于客户端证书认证)" +msgstr "LDAP 证书路径 (仅用于客户端证书认证)" #: cps/templates/config_edit.html:224 msgid "LDAP Keyfile Path (Only needed for Client Certificate Authentication)" -msgstr "LDAP密钥文件路径(仅用于客户端证书认证)" +msgstr "LDAP 密钥文件路径 (仅用于客户端证书认证)" #: cps/templates/config_edit.html:233 msgid "LDAP Authentication" @@ -2092,23 +2265,23 @@ msgstr "简单" #: cps/templates/config_edit.html:242 msgid "LDAP Administrator Username" -msgstr "LDAP管理员用户名" +msgstr "LDAP 管理员用户名" #: cps/templates/config_edit.html:248 msgid "LDAP Administrator Password" -msgstr "LDAP管理员密码" +msgstr "LDAP 管理员密码" #: cps/templates/config_edit.html:253 msgid "LDAP Distinguished Name (DN)" -msgstr "LDAP专有名称(DN)" +msgstr "LDAP 专有名称(DN)" #: cps/templates/config_edit.html:257 msgid "LDAP User Object Filter" -msgstr "LDAP用户对象过滤器" +msgstr "LDAP 用户对象过滤器" #: cps/templates/config_edit.html:262 msgid "LDAP Server is OpenLDAP?" -msgstr "LDAP服务器是 OpenLDAP?" +msgstr "LDAP 服务器为 OpenLDAP?" #: cps/templates/config_edit.html:264 msgid "Following Settings are Needed For User Import" @@ -2116,19 +2289,19 @@ msgstr "用户导入需要以下设置" #: cps/templates/config_edit.html:266 msgid "LDAP Group Object Filter" -msgstr "LDAP组对象过滤器" +msgstr "LDAP 组对象过滤器" #: cps/templates/config_edit.html:270 msgid "LDAP Group Name" -msgstr "LDAP组名" +msgstr "LDAP 组名" #: cps/templates/config_edit.html:274 msgid "LDAP Group Members Field" -msgstr "LDAP组成员字段" +msgstr "LDAP 组成员字段" #: cps/templates/config_edit.html:278 msgid "LDAP Member User Filter Detection" -msgstr "LDAP成员用户过滤器探测" +msgstr "LDAP 成员用户过滤器探测" #: cps/templates/config_edit.html:280 msgid "Autodetect" @@ -2140,12 +2313,12 @@ msgstr "自定义过滤器" #: cps/templates/config_edit.html:286 msgid "LDAP Member User Filter" -msgstr "LDAP成员用户过滤器" +msgstr "LDAP 成员用户过滤器" #: cps/templates/config_edit.html:297 #, python-format msgid "Obtain %(provider)s OAuth Credential" -msgstr "获取 %(provider)s OAuth凭证" +msgstr "获取 %(provider)s OAuth 凭证" #: cps/templates/config_edit.html:300 #, python-format @@ -2175,7 +2348,7 @@ msgstr "KEpubify 电子书转换器路径" #: cps/templates/config_edit.html:345 msgid "Location of Unrar binary" -msgstr "Unrar程序路径" +msgstr "Unrar 程序路径" #: cps/templates/config_view_edit.html:17 msgid "View Configuration" @@ -2189,7 +2362,7 @@ msgstr "随机书籍显示数量" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "主页中书籍作者的最大显示数量(0=不隐藏)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "主题" @@ -2221,139 +2394,139 @@ msgstr "按规则提取书名后排序(正则表达式)" msgid "Default Settings for New Users" msgstr "新用户默认权限设置" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "管理员用户" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "允许下载书籍" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "允许在线阅读" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "允许上传书籍" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "允许编辑书籍" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "允许删除书籍" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "允许修改密码" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "允许编辑公共书架" -#: cps/templates/config_view_edit.html:119 -#, fuzzy +#: cps/templates/config_view_edit.html:123 msgid "Default Language" -msgstr "排除语言" +msgstr "默认语言" -#: cps/templates/config_view_edit.html:127 -#, fuzzy +#: cps/templates/config_view_edit.html:131 msgid "Default Visible Language of Books" -msgstr "按语言显示书籍" +msgstr "默认显示书籍语言" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "新用户默认显示权限" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "在主页显示随机书籍" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "添加显示或隐藏书籍的标签值" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "添加显示或隐藏书籍的自定义栏目值" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "在线阅读" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "在线听书" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" -msgstr "%(range)s 第%(index)s册" +msgstr "%(range)s 第 %(index)s 册" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "出版日期" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "标为未读" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "标为已读" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "已读" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "从档案还原" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "添加到归档" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "归档" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "简介:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "添加到书架" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(公共)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "编辑元数据" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "选择服务器类型" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" -msgstr "使用标准电子邮件账号" +msgid "Standard Email Account" +msgstr "标准电子邮件" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "使用Gmail账号" +msgid "Gmail Account" +msgstr "Gmail 账户" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" -msgstr "设置Gmail账号作为电子邮件服务" +msgid "Setup Gmail Account" +msgstr "设置 Gmail 账户" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" @@ -2361,25 +2534,25 @@ msgstr "撤消 Gmail 访问权限" #: cps/templates/email_edit.html:42 msgid "STARTTLS" -msgstr "STARTTLS协议" +msgstr "STARTTLS 协议" #: cps/templates/email_edit.html:43 msgid "SSL/TLS" -msgstr "SSL/TLS协议" +msgstr "SSL/TLS 协议" #: cps/templates/email_edit.html:51 msgid "SMTP Password" -msgstr "SMTP密码" +msgstr "SMTP 密码" #: cps/templates/email_edit.html:58 msgid "Attachment Size Limit" msgstr "附件大小限制" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +msgid "Save and Send Test Email" msgstr "保存设置并发送测试邮件" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "后退" @@ -2405,45 +2578,61 @@ msgstr "输入域名" msgid "Denied Domains (Blacklist)" msgstr "禁止注册的域名(黑名单)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "下一个" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "在文本编辑器中打开.kobo/Kobo eReader.conf,添加(或编辑):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "在文本编辑器中打开 .kobo/Kobo/Kobo eReader.conf,添加(或编辑):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "Kobo Token:" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "列表" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "Calibre-Web 实例未配置,请联系您的管理员!" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "创建问题" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "回到首页" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "登出账号" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "按下载数排序" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "按下载数逆序排序" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "按作者字母顺序排序" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "按作者逆字母顺序排序" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "按丛书编号排序" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "按丛书编号逆排序" @@ -2461,11 +2650,11 @@ msgstr "按字母排序的书籍" #: cps/templates/index.xml:29 msgid "Popular publications from this catalog based on Downloads." -msgstr "基于下载数的热门书籍。" +msgstr "基于下载数的热门书籍" #: cps/templates/index.xml:36 msgid "Popular publications from this catalog based on Rating." -msgstr "基于评分的热门书籍。" +msgstr "基于评分的热门书籍" #: cps/templates/index.xml:39 msgid "Recently added Books" @@ -2507,7 +2696,7 @@ msgstr "书籍按评分排序" msgid "Books ordered by file formats" msgstr "书籍按文件格式排序" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "书架列表" @@ -2516,63 +2705,67 @@ msgstr "书架列表" msgid "Books organized in shelves" msgstr "书架上的书" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "首页" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "切换导航" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "搜索书库" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "正在上传..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "错误" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "上传完成,正在处理,请稍候..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "设置" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "账号" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "注销" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "正在上传..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "错误" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "上传完成,正在处理,请稍候..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "设置" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "请不要刷新页面" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "按条件浏览" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "关于" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "上一个" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "书籍详情" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "网格" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "记住我" @@ -2581,13 +2774,13 @@ msgstr "记住我" msgid "Forgot Password?" msgstr "忘记密码?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "通过魔法链接登录" #: cps/templates/logviewer.html:6 msgid "Show Calibre-Web Log: " -msgstr "显示Calibre-Web日志: " +msgstr "显示 Calibre-Web 日志: " #: cps/templates/logviewer.html:8 msgid "Calibre-Web Log: " @@ -2603,7 +2796,7 @@ msgstr "显示访问日志: " #: cps/templates/logviewer.html:18 msgid "Download Calibre-Web Log" -msgstr "下载Calibre-Web日志" +msgstr "下载 Calibre-Web 日志" #: cps/templates/logviewer.html:21 msgid "Download Access Log" @@ -2611,19 +2804,19 @@ msgstr "下载访问日志" #: cps/templates/modal_dialogs.html:6 msgid "Select Allowed/Denied Tags" -msgstr "选择标签值显示或隐藏书籍" +msgstr "选择显示的与隐藏的标签" #: cps/templates/modal_dialogs.html:7 msgid "Select Allowed/Denied Custom Column Values" -msgstr "选择自定义栏目值显示或隐藏本用户书籍" +msgstr "选择显示的自定义栏目值与隐藏的自定义栏目值" #: cps/templates/modal_dialogs.html:8 msgid "Select Allowed/Denied Tags of User" -msgstr "选择标签值显示或隐藏书籍" +msgstr "选择此用户显示的标签与隐藏的标签" #: cps/templates/modal_dialogs.html:9 msgid "Select Allowed/Denied Custom Column Values of User" -msgstr "选择自定义栏目值显示或隐藏本用户书籍" +msgstr "选择此用户显示的自定义栏目值与隐藏的自定义栏目值" #: cps/templates/modal_dialogs.html:15 msgid "Enter Tag" @@ -2635,7 +2828,7 @@ msgstr "添加显示或隐藏书籍的值" #: cps/templates/modal_dialogs.html:50 msgid "This book format will be permanently erased from database" -msgstr "此书籍格式将从数据库中永久删除" +msgstr "书籍的此格式副本将从数据库中永久删除" #: cps/templates/modal_dialogs.html:51 msgid "This book will be permanently erased from database" @@ -2647,11 +2840,11 @@ msgstr ",包括从硬盘中" #: cps/templates/modal_dialogs.html:56 msgid "Important Kobo Note: deleted books will remain on any paired Kobo device." -msgstr "Kobo 重要说明:被删除的书籍将保留在任何配对的 Kobo 设备上。" +msgstr "Kobo 重要提示:被删除的书籍将保留在任何配对的 Kobo 设备上" #: cps/templates/modal_dialogs.html:57 msgid "Books must first be archived and the device synced before a book can safely be deleted." -msgstr "必须先将书籍存档并同步设备,然后才能安全地删除书籍。" +msgstr "在安全删除图书之前,必须先将图书归档并与设备同步" #: cps/templates/modal_dialogs.html:76 msgid "Choose File Location" @@ -2677,153 +2870,165 @@ msgstr "父目录" msgid "Select" msgstr "选择" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 msgid "Ok" msgstr "完成" #: cps/templates/osd.xml:5 msgid "Calibre-Web eBook Catalog" -msgstr "Caliebre-Web电子书路径" +msgstr "Caliebre-Web 电子书路径" #: cps/templates/read.html:6 msgid "epub Reader" -msgstr "epub阅读器" +msgstr "epub 阅读器" -#: cps/templates/read.html:74 -msgid "Reflow text when sidebars are open." -msgstr "打开侧栏时重排文本。" - -#: cps/templates/readcbr.html:7 -msgid "Comic Reader" -msgstr "Comic阅读器" - -#: cps/templates/readcbr.html:89 -msgid "Keyboard Shortcuts" -msgstr "快捷键" - -#: cps/templates/readcbr.html:92 -msgid "Previous Page" -msgstr "上一页" - -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 -msgid "Next Page" -msgstr "下一页" - -#: cps/templates/readcbr.html:94 -msgid "Scale to Best" -msgstr "缩放到最佳" - -#: cps/templates/readcbr.html:95 -msgid "Scale to Width" -msgstr "按宽度缩放" - -#: cps/templates/readcbr.html:96 -msgid "Scale to Height" -msgstr "按高度缩放" - -#: cps/templates/readcbr.html:97 -msgid "Scale to Native" -msgstr "缩放到原始大小" - -#: cps/templates/readcbr.html:98 -msgid "Rotate Right" -msgstr "向右旋转" - -#: cps/templates/readcbr.html:99 -msgid "Rotate Left" -msgstr "向左旋转" - -#: cps/templates/readcbr.html:100 -msgid "Flip Image" -msgstr "翻转图片" - -#: cps/templates/readcbr.html:116 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 msgid "Light" msgstr "浅色" -#: cps/templates/readcbr.html:117 +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 msgid "Dark" msgstr "深色" -#: cps/templates/readcbr.html:122 +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "棕色" + +#: cps/templates/read.html:84 +msgid "Black" +msgstr "黑色" + +#: cps/templates/read.html:88 +msgid "Reflow text when sidebars are open." +msgstr "打开侧栏时重排文本" + +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "字体大小" + +#: cps/templates/readcbr.html:7 +msgid "Comic Reader" +msgstr "Comic 阅读器" + +#: cps/templates/readcbr.html:92 +msgid "Keyboard Shortcuts" +msgstr "快捷键" + +#: cps/templates/readcbr.html:95 +msgid "Previous Page" +msgstr "上一页" + +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 +msgid "Next Page" +msgstr "下一页" + +#: cps/templates/readcbr.html:97 +msgid "Scale to Best" +msgstr "缩放到最佳" + +#: cps/templates/readcbr.html:98 +msgid "Scale to Width" +msgstr "按宽度缩放" + +#: cps/templates/readcbr.html:99 +msgid "Scale to Height" +msgstr "按高度缩放" + +#: cps/templates/readcbr.html:100 +msgid "Scale to Native" +msgstr "缩放到原始大小" + +#: cps/templates/readcbr.html:101 +msgid "Rotate Right" +msgstr "向右旋转" + +#: cps/templates/readcbr.html:102 +msgid "Rotate Left" +msgstr "向左旋转" + +#: cps/templates/readcbr.html:103 +msgid "Flip Image" +msgstr "翻转图片" + +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "缩放" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "最佳" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "宽度" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "高度" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "原始" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "旋转" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "翻转" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "水平" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "垂直" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "方向" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "从左到右" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "从右到左" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "重置为顶部" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "记住位置" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "工具栏" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "显示" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "隐藏" #: cps/templates/readdjvu.html:5 msgid "DJVU Reader" -msgstr "DJVU阅读器" +msgstr "DJVU 阅读器" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 msgid "PDF Reader" -msgstr "PDF阅读器" +msgstr "PDF 阅读器" #: cps/templates/readtxt.html:6 msgid "txt Reader" -msgstr "txt阅读器" +msgstr "txt 阅读器" #: cps/templates/register.html:4 msgid "Register New Account" @@ -2834,7 +3039,7 @@ msgid "Choose a username" msgstr "选择一个用户名" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "您的邮箱地址" #: cps/templates/remote_login.html:5 @@ -2847,21 +3052,25 @@ msgstr "在另一个设备上,登录并访问:" #: cps/templates/remote_login.html:11 msgid "Once verified, you will automatically be logged in on this device." -msgstr "验证后,您将自动在新设备上登录。" +msgstr "验证后,您将自动在新设备上登录" #: cps/templates/remote_login.html:14 msgid "This verification link will expire in 10 minutes." -msgstr "此验证链接将在10分钟后失效。" +msgstr "此验证链接将在10分钟后失效" -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "生成丛书封面缩略图" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "无搜索结果" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "搜索项:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "结果:" @@ -2873,10 +3082,6 @@ msgstr "出版日期从" msgid "Published Date To" msgstr "出版日期到" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "阅读状态" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "排除标签" @@ -2917,30 +3122,26 @@ msgstr "从:" msgid "To:" msgstr "到:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "删除此书架" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "编辑书架属性" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "手动排列书籍排列顺序" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "禁止改变顺序" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "允许改变顺序" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "书架将会从所有用户中删除" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "书架将被公开" @@ -2982,8 +3183,8 @@ msgid "System Statistics" msgstr "系统统计" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "程序名称" +msgid "Program" +msgstr "程序" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3009,9 +3210,17 @@ msgstr "任务进度" msgid "Run Time" msgstr "运行时间" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "开始时间" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "活动" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "这个任务将被取消。此任务所有的更改都将被保存" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "如果这是计划任务,则将在下一个计划的时间内重新运行" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3023,7 +3232,7 @@ msgstr "按语言显示书籍" #: cps/templates/user_edit.html:54 msgid "OAuth Settings" -msgstr "OAuth设置" +msgstr "OAuth 设置" #: cps/templates/user_edit.html:56 msgid "Link" @@ -3041,21 +3250,25 @@ msgstr "Kobo 同步 Token" msgid "Create/View" msgstr "新建或查看" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "强制与 Kobo 完全同步" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "添加显示或隐藏书籍的自定义栏目值" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "仅同步所选书架中的书籍到 Kobo" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "删除此用户" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" -msgstr "生成Kobo Auth 地址" +msgstr "生成 Kobo Auth 地址" #: cps/templates/user_table.html:80 cps/templates/user_table.html:103 msgid "Select..." @@ -3070,16 +3283,16 @@ msgid "Enter Username" msgstr "输入用户名" #: cps/templates/user_table.html:135 -msgid "Enter E-mail Address" -msgstr "输入邮箱地址" +msgid "Enter Email" +msgstr "输入邮箱" #: cps/templates/user_table.html:136 -msgid "Enter Kindle E-mail Address" -msgstr "输入Kindle邮箱地址" +msgid "Enter eReader Email" +msgstr "接收书籍的电子阅读器邮箱" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" -msgstr "Kindle邮箱" +msgid "eReader Email" +msgstr "电子阅读器邮箱" #: cps/templates/user_table.html:137 msgid "Locale" @@ -3087,7 +3300,7 @@ msgstr "本地化" #: cps/templates/user_table.html:138 msgid "Visible Book Languages" -msgstr "可见数据语言" +msgstr "可见书籍语言" #: cps/templates/user_table.html:139 msgid "Edit Allowed Tags" @@ -3099,11 +3312,11 @@ msgstr "允许标签" #: cps/templates/user_table.html:140 msgid "Edit Denied Tags" -msgstr "编辑拒绝标签" +msgstr "编辑被拒绝标签" #: cps/templates/user_table.html:140 msgid "Denied Tags" -msgstr "拒绝标签" +msgstr "被拒绝标签" #: cps/templates/user_table.html:141 msgid "Edit Allowed Column Values" @@ -3138,10 +3351,6 @@ msgid "Sync selected Shelves with Kobo" msgstr "同步所选书架到 Kobo" #: cps/templates/user_table.html:156 -msgid "Show read/unread selection" -msgstr "显示已读/未读选择" - -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "显示随机书籍" +msgid "Show Read/Unread Section" +msgstr "显示已读、未读栏目" diff --git a/cps/translations/zh_Hant_TW/LC_MESSAGES/messages.mo b/cps/translations/zh_Hant_TW/LC_MESSAGES/messages.mo index c3dea789f..8fbed7cfc 100644 Binary files a/cps/translations/zh_Hant_TW/LC_MESSAGES/messages.mo and b/cps/translations/zh_Hant_TW/LC_MESSAGES/messages.mo differ diff --git a/cps/translations/zh_Hant_TW/LC_MESSAGES/messages.po b/cps/translations/zh_Hant_TW/LC_MESSAGES/messages.po index 85ba820d6..16b841bb1 100644 --- a/cps/translations/zh_Hant_TW/LC_MESSAGES/messages.po +++ b/cps/translations/zh_Hant_TW/LC_MESSAGES/messages.po @@ -7,580 +7,637 @@ msgid "" msgstr "" "Project-Id-Version: Calibre-Web\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: 2020-09-27 22:18+0800\n" "Last-Translator: xlivevil \n" "Language: zh_TW\n" "Language-Team: zh_Hans_CN \n" -"Plural-Forms: nplurals=1; plural=0\n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "未安裝" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "已安裝" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "統計" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +#, fuzzy +msgid "Server restarted, please reload page." msgstr "服務器已重啟,請刷新頁面" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +#, fuzzy +msgid "Performing Server shutdown, please close window." msgstr "正在關閉服務器,請關閉窗口" -#: cps/admin.py:154 -msgid "Reconnect successful" -msgstr "重新連接成功" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" +msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "未知命令" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +#, fuzzy +msgid "Success! Books queued for Metadata Backup" +msgstr "書籍已經成功加入 %(eReadermail)s 的發送隊列" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "未知" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "管理頁" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "基本配置" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "界面配置" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" msgstr "管理用戶" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "全部" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "找不到用戶" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "成功刪除 {} 個用戶" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "顯示全部" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "格式錯誤的請求" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "訪客名稱無法更改" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "遊客無法擁有此角色" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "管理員賬戶不存在,無法刪除管理員角色" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "值必須是 true 或 false" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "無效角色" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "遊客無法擁有此視圖" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "無效視圖" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "訪客的本地化是自動偵測而無法設置的" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "無可用本地化" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "無有效書籍語言" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "參數未找到" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "無效的閱讀列" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "無效的限制列" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "Calibre-Web配置已更新" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "您確定刪除Kobo Token嗎?" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "您確定要刪除此網域嗎?" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "您確定要刪除此用戶嗎?" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "您確定要刪除此書架嗎?" -#: cps/admin.py:580 +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" msgstr "您確定要修改選定用戶的本地化設置嗎?" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "您確定要修改選定用戶的可見書籍語言嗎?" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "您確定要修改選定用戶的選定角色嗎?" -#: cps/admin.py:586 +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "您確定要修改選定用戶的選定限制嗎?" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "您確定要修改選定用戶的選定可視化限制嗎?" -#: cps/admin.py:590 +#: cps/admin.py:622 msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "您確定要更改所選用戶的書架同步行為嗎?" -#: cps/admin.py:592 +#: cps/admin.py:624 msgid "Are you sure you want to change Calibre library location?" msgstr "您確定要更改 Calibre 庫位置嗎?" -#: cps/admin.py:741 -msgid "Tag not found" -msgstr "標籤未找到" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" +msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" -msgstr "無效的動作" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" +msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "拒絕" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "允許" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "標籤未找到" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "無效的動作" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "client_secrets.json 未為 Web 應用程序配置" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "日誌文件路徑無效,請輸入正確的路徑" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "訪問日誌路徑無效,請輸入正確的路徑" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "請輸入LDAP主機、端口、DN和用戶對象標識符" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "請輸入一個LDAP服務賬號和密碼 " -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "請輸入一個LDAP服務賬號" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "LDAP群組對象過濾器需要一個具有“%s”格式標識符號" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "LDAP群組對象過濾器的括號不匹配" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "LDAP用戶對象過濾器需要一個具有“%s”格式標識符" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "LDAP用戶對象過濾器的括號不匹配" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "LDAP成員用戶過濾器需要有一個“%s”格式標識符號" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "LDAP成員用戶過濾器中有不匹配的括號" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "LDAP CA證書、證書或密鑰位置無效,請輸入正確的路徑" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" -msgstr "設置數據庫不可寫入" - -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" -msgstr "數據庫路徑無效,請輸入正確的路徑" - -#: cps/admin.py:1192 -msgid "DB is not Writeable" -msgstr "數據庫不可寫入" - -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "密鑰文件路徑無效,請輸入正確的路徑" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "證書文件路徑無效,請輸入正確的路徑" - -#: cps/admin.py:1316 -#, fuzzy -msgid "Database Settings updated" -msgstr "郵件服務器設置已更新" - -#: cps/admin.py:1324 -msgid "Database Configuration" -msgstr "數據庫配置" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "請填寫所有欄位!" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "郵箱不在有效網域中" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "添加新用戶" -#: cps/admin.py:1363 -#, python-format -msgid "User '%(user)s' created" -msgstr "用戶“%(user)s”已創建" - -#: cps/admin.py:1369 -msgid "Found an existing account for this e-mail address or name." -msgstr "使用此郵箱或用戶名的賬號已經存在。" - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "用戶“%(nick)s”已刪除" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "無法刪除訪客用戶" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "管理員賬戶不存在,無法刪除用戶" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "編輯用戶 %(nick)s" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "用戶“%(nick)s”已更新" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "發生一個未知錯誤,請稍後再試。" - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "編輯郵件服務器設置" -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "G-Mail賬號驗證成功" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." +msgstr "" -#: cps/admin.py:1554 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 +#, python-format +msgid "Oops! Database Error: %(error)s." +msgstr "數據庫錯誤:%(error)s。" + +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "發送給%(email)s的測試郵件已進入隊列。請檢查任務結果" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "發送測試郵件時出錯:%(res)s" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "請先配置您的郵箱地址..." -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "郵件服務器設置已更新" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "發生一個未知錯誤,請稍後再試。" + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" +msgstr "編輯用戶 %(nick)s" + +#: cps/admin.py:1423 +#, fuzzy, python-format +msgid "Success! Password for user %(user)s reset" msgstr "用戶 %(user)s 的密碼已重置" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1429 +#, fuzzy +msgid "Oops! Please configure the SMTP mail settings." msgstr "請先配置SMTP郵箱設置..." -#: cps/admin.py:1619 +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "日誌文件查看器" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "正在請求更新包" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "正在下載更新包" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "正在解壓更新包" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "正在替換文件" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "數據庫連接已關閉" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "正在停止服務器" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "更新完成,請點擊確定並刷新頁面" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "更新失敗:" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "HTTP錯誤" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "連接錯誤" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "建立連接超時" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "一般錯誤" -#: cps/admin.py:1696 +#: cps/admin.py:1517 #, fuzzy msgid "Update file could not be saved in temp dir" msgstr "更新文件無法保存在臨時目錄中" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "更新時檔案無法替換變更" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" msgstr "未能提取至少一個LDAP用戶" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "未能創建至少一個LDAP用戶" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "錯誤:%(ldaperror)s" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "錯誤:在LDAP服務器的響應中沒有返回用戶" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "數據庫中沒有找到至少一個LDAP用戶" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "{} 用戶被成功導入" -#: cps/converter.py:30 -msgid "not configured" -msgstr "未配置" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "數據庫路徑無效,請輸入正確的路徑" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "數據庫不可寫入" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "密鑰文件路徑無效,請輸入正確的路徑" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "證書文件路徑無效,請輸入正確的路徑" + +#: cps/admin.py:1842 +#, fuzzy +msgid "Database Settings updated" +msgstr "郵件服務器設置已更新" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "數據庫配置" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "請填寫所有欄位!" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "郵箱不在有效網域中" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "添加新用戶" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "用戶“%(user)s”已創建" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "使用此郵箱或用戶名的賬號已經存在。" + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "用戶“%(nick)s”已刪除" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "無法刪除訪客用戶" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "管理員賬戶不存在,無法刪除用戶" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "用戶“%(nick)s”已更新" + +#: cps/converter.py:31 +msgid "not installed" +msgstr "未安裝" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "缺少執行權限" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 -#, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 +#, fuzzy, python-format +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "自定義列號:%(column)d在Calibre數據庫中不存在" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" -msgstr "書籍格式已成功刪除" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" +msgstr "無" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" -msgstr "書籍已成功刪除" - -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "糟糕!選擇書名無法打開。文件不存在或者文件不可訪問" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "編輯元數據" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" +msgstr "" -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "%(seriesindex)s 不是一個有效的數值,忽略" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "%(langname)s 不是一種有效語言" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "不能上傳文件附檔名為“%(ext)s”的文件到此服務器" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "要上傳的文件必須具有附檔名" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "創建路徑 %(path)s 失敗(權限拒絕)。" - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "保存文件 %(file)s 失敗。" - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "數據庫錯誤:%(error)s。" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "已添加 %(ext)s 格式到 %(book)s" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "標識符不區分大小寫,覆蓋舊標識符" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "已成功更新元數據" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" -msgstr "編輯書籍出錯,請檢查日誌文件以獲取詳細信息" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" +msgstr "" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "上傳的書籍可能已經存在,建議修改後重新上傳: " - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "文件 %(filename)s 無法保存到臨時目錄" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "移動封面文件失敗 %(file)s:%(error)s" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "文件 %(file)s 已上傳" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "轉換的來源或目的格式不存在" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "書籍已經被成功加入到 %(book_format)s 格式轉換隊列" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "轉換此書籍時出現錯誤: %(res)s" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "上傳的書籍可能已經存在,建議修改後重新上傳: " + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, fuzzy, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "%(langname)s 不是一種有效語言" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "不能上傳文件附檔名為“%(ext)s”的文件到此服務器" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "要上傳的文件必須具有附檔名" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "文件 %(filename)s 無法保存到臨時目錄" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "移動封面文件失敗 %(file)s:%(error)s" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "書籍格式已成功刪除" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "書籍已成功刪除" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "編輯元數據" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "%(seriesindex)s 不是一個有效的數值,忽略" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "創建路徑 %(path)s 失敗(權限拒絕)。" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "保存文件 %(file)s 失敗。" + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "已添加 %(ext)s 格式到 %(book)s" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "Google Drive 設置未完成,請嘗試停用並再次激活Google雲端硬碟" @@ -594,165 +651,181 @@ msgstr "回調網域名稱尚未被驗證,請在google開發者控制台按步 msgid "%(format)s format not found for book id: %(book)d" msgstr "找不到id為 %(book)d 的書籍的 %(format)s 格式" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "Google Drive %(fn)s 上找不到 %(format)s" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "找不到 %(format)s:%(fn)s" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +#, fuzzy +msgid "Send to eReader" msgstr "發送到Kindle" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +#, fuzzy +msgid "This Email has been sent via Calibre-Web." msgstr "此郵件已經通過Calibre-Web發送。" -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +#, fuzzy +msgid "Calibre-Web Test Email" msgstr "Calibre-Web測試郵件" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +#, fuzzy +msgid "Test Email" msgstr "測試郵件" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "開啟Calibre-Web之旅" -#: cps/helper.py:135 -#, python-format -msgid "Registration e-mail for user: %(name)s" +#: cps/helper.py:137 +#, fuzzy, python-format +msgid "Registration Email for user: %(name)s" msgstr "用戶註冊電子郵件:%(name)s" -#: cps/helper.py:146 cps/helper.py:152 -#, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +#: cps/helper.py:148 cps/helper.py:154 +#, fuzzy, python-format +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "轉換 %(orig)s 到 %(format)s 並發送到Kindle" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 -#, python-format -msgid "Send %(format)s to Kindle" +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 +#, fuzzy, python-format +msgid "Send %(format)s to eReader" msgstr "發送 %(format)s 到Kindle" -#: cps/helper.py:219 cps/tasks/convert.py:90 -#, python-format -msgid "%(book)s send to Kindle" +#: cps/helper.py:225 +#, fuzzy, python-format +msgid "%(book)s send to eReader" msgstr "%(book)s發送到Kindle" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "無法讀取請求的文件。可能有錯誤的權限設置?" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "刪除書的文件夾%(id)s失敗,路徑有子文件夾:%(path)s" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "刪除書籍 %(id)s失敗:%(message)s" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "僅從數據庫中刪除書籍 %(id)s,數據庫中的書籍路徑無效: %(path)s" -#: cps/helper.py:388 -#, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +#: cps/helper.py:450 +#, fuzzy, python-format +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "將標題從“%(src)s”改為“%(dest)s”時失敗,錯誤錯信息:%(error)s" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "從“%(src)s”重命名為“%(dest)s”失敗,錯誤信息:%(error)s" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "Google Drive上找不到文件 %(file)s" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "將標題從“%(src)s”改為“%(dest)s”時失敗,錯誤錯信息:%(error)s" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "Google Drive上找不到書籍路徑 %(path)s" -#: cps/helper.py:507 cps/web.py:1654 -msgid "Found an existing account for this e-mail address" -msgstr "使用此郵箱的賬號已經存在。" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" +msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "此用戶名已被使用" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +#, fuzzy +msgid "Invalid Email address format" msgstr "無效的郵件地址格式" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "下載封面時出錯" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "封面格式出錯" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "創建封面路徑失敗" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "封面文件不是有效的圖片文件,或者無法儲存" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "封面文件只支持jpg/jpeg/png/webp/bmp格式文件" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "僅將jpg、jpeg文件作為封面文件" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "找不到Unrar執行文件" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +#, fuzzy +msgid "Error executing UnRar" msgstr "執行UnRar時出錯" -#: cps/helper.py:762 -msgid "Waiting" -msgstr "等待中" +#: cps/helper.py:1040 +#, fuzzy +msgid "Cover" +msgstr "發現" -#: cps/helper.py:764 -msgid "Failed" -msgstr "失敗" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" +msgstr "" -#: cps/helper.py:766 -msgid "Started" -msgstr "已開始" - -#: cps/helper.py:768 -msgid "Finished" -msgstr "已完成" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "未知狀態" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" +#: cps/kobo_auth.py:89 +#, fuzzy +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "請不要使用localhost訪問Calibre-Web,以便Kobo設備能獲取有效的api_endpoint" -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "Kobo 設置" @@ -761,9 +834,9 @@ msgstr "Kobo 設置" msgid "Register with %(provider)s" msgstr "使用 %(provider)s 註冊" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "您現在已以“%(nickname)s”身份登入" #: cps/oauth_bb.py:148 @@ -822,505 +895,610 @@ msgstr "Google Oauth 錯誤,請重試。" msgid "Google Oauth error: {}" msgstr "Google Oauth 錯誤: {}" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "{} 星" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "登入" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "找不到Token" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "Token已過期" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "成功!請返回您的設備" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "書籍" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "顯示最近書籍" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "熱門書籍" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "顯示熱門書籍" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "已下載書籍" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "顯示下載過的書籍" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "最高評分書籍" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "顯示最高評分書籍" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "已讀書籍" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +#, fuzzy +msgid "Show Read and Unread" msgstr "顯示閱讀狀態" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "未讀書籍" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "顯示未讀" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "發現" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "隨機顯示書籍" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "分類" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +#, fuzzy +msgid "Show Category Section" msgstr "顯示分類選擇" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "叢書" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +#, fuzzy +msgid "Show Series Section" msgstr "顯示叢書選擇" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "作者" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +#, fuzzy +msgid "Show Author Section" msgstr "顯示作者選擇" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "出版社" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +#, fuzzy +msgid "Show Publisher Section" msgstr "顯示出版社選擇" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "語言" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +#, fuzzy +msgid "Show Language Section" msgstr "顯示語言選擇" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "評分" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +#, fuzzy +msgid "Show Ratings Section" msgstr "顯示評分選擇" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "文件格式" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +#, fuzzy +msgid "Show File Formats Section" msgstr "顯示文件格式選擇" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "歸檔書籍" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +#, fuzzy +msgid "Show Archived Books" msgstr "顯示歸檔書籍" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "書籍列表" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "顯示書籍列表" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "指定的書架無效" - -#: cps/shelf.py:73 -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "對不起,您沒有添加書籍到這個書架的權限" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "此書籍已經是書架 %(shelfname)s 的一部分" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "此書籍已被添加到書架:%(sname)s" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "您沒有添加書籍到書架 %(name)s 的權限" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "書籍已經在書架 %(name)s 中了" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "書籍已經被添加到書架 %(sname)s 中" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "無法添加書籍到書架:%(sname)s" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "此書已從書架 %(sname)s 中刪除" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "對不起,您沒有從書架 %(sname)s 中刪除書籍的權限" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "創建書架" - -#: cps/shelf.py:236 -msgid "Sorry you are not allowed to edit this shelf" -msgstr "對不起,您沒有編輯這個書架的權限" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "編輯書架" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "書架 %(title)s 已創建" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "書架 %(title)s 已修改" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "發生錯誤" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "公共書架:%(title)s已經存在已經存在。" - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "私有書架:%(title)s已經存在。" - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "修改書架 %(name)s 順序" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "書架:%(name)s" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "打開書架出錯。書架不存在或不可訪問" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "讀取更新信息時出現未預期數據" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "無可用更新。您已經安裝了最新版本" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "有新的更新。單擊下面的按鈕以更新到最新版本。" - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "無法獲取更新信息" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "點擊下面按鈕更新到最新穩定版本。" - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "有新的更新。單擊下面的按鈕以更新到版本: %(version)s" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "無可用發佈信息" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "發現(隨機書籍)" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "熱門書籍(最多下載)" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "%(user)s 下載過的書籍" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "作者:%(name)s" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "出版社:%(name)s" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "叢書:%(serie)s" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "評分:%(rating)s 星" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "文件格式:%(format)s" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "分類:%(name)s" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "語言:%(name)s" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "進階搜尋" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "搜尋" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "下載次數" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "評分列表" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "文件格式列表" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "任務列表" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "出版時間晚於 " -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "出版時間早於 " -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "評分 <= %(rating)s" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "評分 >= %(rating)s" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "閱讀狀態 = %(status)s" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "搜詢自定義欄位時出錯,請重啟 Calibre-Web" -#: cps/web.py:1441 -#, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" -msgstr "書籍已經成功加入 %(kindlemail)s 的發送隊列" +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "進階搜尋" -#: cps/web.py:1445 +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "指定的書架無效" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "對不起,您沒有添加書籍到這個書架的權限" + +#: cps/shelf.py:64 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book is already part of the shelf: %(shelfname)s" +msgstr "此書籍已經是書架 %(shelfname)s 的一部分" + +#: cps/shelf.py:89 +#, python-format +msgid "Book has been added to shelf: %(sname)s" +msgstr "此書籍已被添加到書架:%(sname)s" + +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" +msgstr "" + +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" +msgstr "書籍已經在書架 %(name)s 中了" + +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "書籍已經被添加到書架 %(sname)s 中" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "無法添加書籍到書架:%(sname)s" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "此書已從書架 %(sname)s 中刪除" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "創建書架" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "對不起,您沒有編輯這個書架的權限" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "編輯書架" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +#, fuzzy +msgid "Shelf successfully deleted" +msgstr "書籍已成功刪除" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "修改書架 %(name)s 順序" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "書架 %(title)s 已創建" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "書架 %(title)s 已修改" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "發生錯誤" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "公共書架:%(title)s已經存在已經存在。" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "私有書架:%(title)s已經存在。" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "書架:%(name)s" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "打開書架出錯。書架不存在或不可訪問" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "任務列表" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "等待中" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "失敗" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "已開始" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "已完成" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "未知狀態" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "讀取更新信息時出現未預期數據" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "無可用更新。您已經安裝了最新版本" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "有新的更新。單擊下面的按鈕以更新到最新版本。" + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "無法獲取更新信息" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "點擊下面按鈕更新到最新穩定版本。" + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "有新的更新。單擊下面的按鈕以更新到版本: %(version)s" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "無可用發佈信息" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "發現(隨機書籍)" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "熱門書籍(最多下載)" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "%(user)s 下載過的書籍" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "作者:%(name)s" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "出版社:%(name)s" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "叢書:%(serie)s" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "評分:%(rating)s 星" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "文件格式:%(format)s" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "分類:%(name)s" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "語言:%(name)s" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "下載次數" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "評分列表" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "文件格式列表" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "請先配置SMTP郵箱設置..." + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "書籍已經成功加入 %(eReadermail)s 的發送隊列" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" msgstr "糟糕!發送這本書籍的時候出現錯誤:%(res)s" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/web.py:1213 +#, fuzzy +msgid "Oops! Please update your profile with a valid eReader Email." msgstr "請先設置您的kindle郵箱。" -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." msgstr "郵件服務未配置,請聯繫網站管理員!" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "註冊" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "您的電子郵件不允許註冊" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "確認郵件已經發送到您的郵箱。" -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "無法激活LDAP認證" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "備援登入“%(nickname)s”:無法訪問LDAP伺服器,或用戶未知" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "無法登入:%(message)s" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "用戶名或密碼錯誤" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "新密碼已發送到您的郵箱" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "請輸入有效的用戶名進行密碼重置" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" -msgstr "您現在已以“%(nickname)s”登入" - -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +msgid "%(name)s's Profile" msgstr "%(name)s 的用戶配置" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1416 +#, fuzzy +msgid "Success! Profile Updated" msgstr "資料已更新" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." +msgstr "使用此郵箱的賬號已經存在。" + #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "找不到包含 OAuth 信息的有效 gmail.json 文件" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, fuzzy, python-format +msgid "%(book)s send to E-Reader" +msgstr "%(book)s發送到Kindle" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "沒有發現Calibre 電子書轉換器%(tool)s" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "硬碟上找不到 %(format)s 格式" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "發生未知錯誤,書籍轉換失敗" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "Kepubify 轉換失敗:%(error)s" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "找不到轉換後的文件或文件夾%(folder)s中有多個文件" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "電子書轉換器失敗: %(error)s" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "Calibre 運行失敗,錯誤信息:%(error)s" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +#, fuzzy +msgid "Backing up Metadata" +msgstr "編輯元數據" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "上傳書籍" + #: cps/templates/admin.html:9 msgid "Users" msgstr "用戶列表" @@ -1333,14 +1511,15 @@ msgstr "用戶名" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "郵箱地址" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +#, fuzzy +msgid "Send to eReader Email" msgstr "接收書籍的Kindle郵箱地址" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "管理權限" @@ -1350,211 +1529,229 @@ msgstr "管理權限" msgid "Password" msgstr "密碼" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "上傳書籍" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "下載書籍" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "查看書籍" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "編輯書籍" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "刪除數據" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "公共書架" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "添加新用戶" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "導入LDAP用戶" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "SMTP郵件服務器設置" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "SMTP主機名" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "SMTP端口" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "加密" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "SMTP用戶名" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "發信人郵箱" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +#, fuzzy +msgid "Email Service" msgstr "電子郵件服務" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "通過Oauth2的Gmail" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "配置" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "Calibre 數據庫路徑" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "日誌級別" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "端口" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "擴展端口" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "每頁書籍數" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "上傳" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "匿名瀏覽" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "開放註冊" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "魔法連接遠程登錄" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "反向代理登入" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "反向代理標頭名稱" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 msgid "Edit Calibre Database Configuration" msgstr "編輯Calibre數據庫配置" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "編輯基本配置" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "編輯界面配置" -#: cps/templates/admin.html:160 +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" +msgstr "" + +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" +msgstr "" + +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" +msgstr "" + +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 +msgid "Reconnect Calibre Database" +msgstr "" + +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 msgid "Administration" msgstr "管理" -#: cps/templates/admin.html:161 +#: cps/templates/admin.html:200 msgid "Download Debug Package" msgstr "下載除錯包" -#: cps/templates/admin.html:162 +#: cps/templates/admin.html:201 msgid "View Logs" msgstr "查看日誌文件" -#: cps/templates/admin.html:165 -msgid "Reconnect Calibre Database" -msgstr "重新連接到Calibre數據庫" - -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:207 msgid "Restart" msgstr "重啟" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "停止" -#: cps/templates/admin.html:172 -msgid "Update" -msgstr "更新" +#: cps/templates/admin.html:216 +msgid "Version Information" +msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "版本" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "詳情" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "當前版本" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "檢查更新" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "執行更新" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "您確定要重啟嗎?" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "確定" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "取消" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "您確定要關閉嗎?" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "正在更新,請不要刷新頁面" @@ -1566,119 +1763,118 @@ msgstr "通過" msgid "In Library" msgstr "在書庫" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "按圖書日期排序,最新優先" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "按圖書日期排序,最舊優先" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "按標題按字母順序排序" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "按標題逆字母順序排序" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "按出版日期排序,最新優先" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "按出版日期排序,最舊優先" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "減少" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "更多" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "刪除書籍" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "刪除格式:" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "轉換書籍格式:" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "轉換從:" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "選擇一個選項" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "轉換到:" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "轉換書籍" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "書名" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "作者" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "簡介" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "書號" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "書號類型" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "書號編號" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "移除" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "添加書號" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "標籤" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "叢書編號" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "評分" @@ -1690,82 +1886,83 @@ msgstr "從URL獲取封面(JPEG - 圖片將下載並存儲在數據庫中)" msgid "Upload Cover from Local Disk" msgstr "從本地硬碟上傳封面" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "出版日期" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "出版社" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "語言" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "確認" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "沒有" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "上傳格式" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "查看保存書籍" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "獲取元數據" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "儲存" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "關鍵字" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 #, fuzzy msgid "Search keyword" msgstr " 搜索關鍵字 " -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "單擊封面將元數據加載到表單" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "加載中..." -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "關閉" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "來源" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "搜索錯誤!" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "無搜索結果!請嘗試另一個關鍵字。" @@ -1857,27 +2054,36 @@ msgstr "輸入網域名" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "閱讀狀態" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 #, fuzzy msgid "Enter " msgstr "書號" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "您真的確認?" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "這本書籍將被合併:" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "合併到這本書籍:" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "合併" @@ -1969,6 +2175,10 @@ msgstr "儲存到硬碟時同步轉換書名與作者中的非英語字元" msgid "Enable Uploads" msgstr "啟用上傳" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "允許上傳的文件格式" @@ -1982,7 +2192,7 @@ msgid "Enable Public Registration" msgstr "啟用註冊" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "使用郵箱或用戶名" #: cps/templates/config_edit.html:132 @@ -2049,11 +2259,6 @@ msgstr "LDAP伺服器端口" msgid "LDAP Encryption" msgstr "LDAP 加密" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "無" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "TLS協議" @@ -2189,7 +2394,7 @@ msgstr "隨機書籍顯示數量" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "主頁中書籍作者的最大顯示數量(0=不隱藏)" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "主題" @@ -2221,139 +2426,143 @@ msgstr "按規則提取書名後排序(正則表達式)" msgid "Default Settings for New Users" msgstr "新用戶默認權限設置" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "管理員用戶" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "允許下載書籍" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "允許在線閱讀" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "允許上傳書籍" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "允許編輯書籍" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "允許刪除書籍" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "允許修改密碼" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "允許編輯公共書架" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 #, fuzzy msgid "Default Language" msgstr "預設語言" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 #, fuzzy msgid "Default Visible Language of Books" msgstr "按預設語言顯示書籍" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "新用戶默認顯示權限" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "在主頁顯示隨機書籍" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "添加顯示或隱藏書籍的標籤值" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "添加顯示或隱藏書籍的自定義欄位值" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "在線閱讀" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "在線聽書" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "%(range)s 第%(index)s冊" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "出版日期" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "標為未讀" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "標為已讀" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "已讀" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "從歸檔檔案還原" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "添加到歸檔" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "歸檔" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "簡介:" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "添加到書架" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "(公共)" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "編輯元數據" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "選擇伺服器類型" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +#, fuzzy +msgid "Standard Email Account" msgstr "使用標準電子郵件賬號" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" -msgstr "使用Gmail賬號" +#, fuzzy +msgid "Gmail Account" +msgstr "選擇伺服器類型" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" -msgstr "設置Gmail賬號作為電子郵件服務" +msgid "Setup Gmail Account" +msgstr "" #: cps/templates/email_edit.html:24 msgid "Revoke Gmail Access" @@ -2376,10 +2585,11 @@ msgid "Attachment Size Limit" msgstr "附件大小限制" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +#, fuzzy +msgid "Save and Send Test Email" msgstr "保存設置並發送測試郵件" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "後退" @@ -2405,45 +2615,62 @@ msgstr "輸入網域名" msgid "Denied Domains (Blacklist)" msgstr "禁止註冊的網域名(黑名單)" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "下一個" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" -msgstr "在文本編輯器中打開.kobo/Kobo eReader.conf,添加(或編輯):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" +msgstr "在文本編輯器中打開.kobo/Kobo/Kobo eReader.conf,添加(或編輯):" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +#, fuzzy +msgid "Kobo Token:" +msgstr "Kobo 同步 Token" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "Calibre-Web 實例未配置,請聯繫您的系統管理員!" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "創建問題" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "回到首頁" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "登出賬號" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "按作者字母順序排序" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "按作者逆字母順序排序" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "按叢書編號排序" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "按叢書編號逆排序" @@ -2507,7 +2734,7 @@ msgstr "書籍按評分排序" msgid "Books ordered by file formats" msgstr "書籍按文件格式排序" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "書架列表" @@ -2516,63 +2743,67 @@ msgstr "書架列表" msgid "Books organized in shelves" msgstr "書架上的書" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "首頁" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "切換導航" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "搜索書庫" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "正在上傳..." - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "錯誤" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "上傳完成,正在處理中,請稍候..." - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "設置" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "賬號" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "登出" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "正在上傳..." + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "錯誤" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "上傳完成,正在處理中,請稍候..." + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "設置" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "請不要刷新頁面" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "瀏覽" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "關於" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "上一個" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "書籍詳情" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "記住我" @@ -2581,7 +2812,7 @@ msgstr "記住我" msgid "Forgot Password?" msgstr "忘記密碼?" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "通過魔法連接登入" @@ -2677,7 +2908,7 @@ msgstr "父目錄" msgid "Select" msgstr "選擇" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 msgid "Ok" msgstr "完成" @@ -2689,127 +2920,140 @@ msgstr "Caliebre-Web電子書路徑" msgid "epub Reader" msgstr "epub閱讀器" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "淺色" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "深色" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +#, fuzzy +msgid "Black" +msgstr "後退" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "打開側欄時重排文本。" +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 msgid "Comic Reader" msgstr "Comic閱讀器" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "快捷鍵" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "上一頁" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "下一頁" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "縮放到最佳" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "按寬度縮放" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "按高度縮放" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "縮放到原始大小" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "向右旋轉" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "向左旋轉" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "翻轉圖片" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "淺色" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "深色" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "縮放" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "最佳" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "寬度" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "高度" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "原始" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "旋轉" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "翻轉" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "水平" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "垂直" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "方向" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "從左到右" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "從右到左" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "重置為頂部" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "記住位置" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "工具欄" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "顯示" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "隱藏" @@ -2817,7 +3061,7 @@ msgstr "隱藏" msgid "DJVU Reader" msgstr "DJVU閱讀器" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 msgid "PDF Reader" msgstr "PDF閱讀器" @@ -2834,7 +3078,7 @@ msgid "Choose a username" msgstr "選擇一個用戶名" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "您的郵箱地址" #: cps/templates/remote_login.html:5 @@ -2853,15 +3097,19 @@ msgstr "驗證後,您將自動在新設備上登入。" msgid "This verification link will expire in 10 minutes." msgstr "此驗證連接將在10分鐘後失效。" -#: cps/templates/search.html:5 +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" +msgstr "" + +#: cps/templates/search.html:6 msgid "No Results Found" msgstr "無搜索結果" -#: cps/templates/search.html:6 +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "搜索項:" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "結果:" @@ -2873,10 +3121,6 @@ msgstr "出版日期從" msgid "Published Date To" msgstr "出版日期到" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "閱讀狀態" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "排除標籤" @@ -2917,30 +3161,26 @@ msgstr "從:" msgid "To:" msgstr "到:" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "刪除此書架" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "編輯書架屬性" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "手動排列書籍排列順序" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "禁止改變順序" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "允許改變順序" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "書架將會從所有用戶中刪除" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "書架將被公開" @@ -2982,8 +3222,8 @@ msgid "System Statistics" msgstr "系統統計" #: cps/templates/stats.html:33 -msgid "Program Library" -msgstr "程式名稱" +msgid "Program" +msgstr "" #: cps/templates/stats.html:34 msgid "Installed Version" @@ -3009,9 +3249,17 @@ msgstr "任務進度" msgid "Run Time" msgstr "運行時間" -#: cps/templates/tasks.html:18 -msgid "Start Time" -msgstr "開始時間" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." +msgstr "" #: cps/templates/user_edit.html:20 msgid "Reset user Password" @@ -3041,19 +3289,23 @@ msgstr "Kobo 同步 Token" msgid "Create/View" msgstr "新建或查看" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "添加顯示或隱藏書籍的自定義欄位值" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "僅同步所選書架中的書籍到 Kobo" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "刪除此用戶" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "生成Kobo Auth 地址" @@ -3070,16 +3322,19 @@ msgid "Enter Username" msgstr "輸入用戶名" #: cps/templates/user_table.html:135 -msgid "Enter E-mail Address" -msgstr "輸入郵箱地址" +#, fuzzy +msgid "Enter Email" +msgstr "測試郵件" #: cps/templates/user_table.html:136 -msgid "Enter Kindle E-mail Address" -msgstr "輸入Kindle郵箱地址" +#, fuzzy +msgid "Enter eReader Email" +msgstr "接收書籍的Kindle郵箱地址" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" -msgstr "Kindle郵箱" +#, fuzzy +msgid "eReader Email" +msgstr "測試郵件" #: cps/templates/user_table.html:137 msgid "Locale" @@ -3138,10 +3393,7 @@ msgid "Sync selected Shelves with Kobo" msgstr "同步所選書架到 Kobo" #: cps/templates/user_table.html:156 -msgid "Show read/unread selection" +#, fuzzy +msgid "Show Read/Unread Section" msgstr "顯示已讀/未讀選擇" -#: cps/templates/user_table.html:159 -msgid "Show random books" -msgstr "顯示隨機書籍" - diff --git a/cps/ub.py b/cps/ub.py index 69ea55f6c..fd0278e5b 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import atexit import os import sys import datetime @@ -37,6 +38,7 @@ except ImportError as e: from flask_dance.consumer.storage.sqla import OAuthConsumerMixin oauth_support = True except ImportError as e: + OAuthConsumerMixin = BaseException oauth_support = False from sqlalchemy import create_engine, exc, exists, event, text from sqlalchemy import Column, ForeignKey @@ -51,7 +53,7 @@ except ImportError: from sqlalchemy.orm import backref, relationship, sessionmaker, Session, scoped_session from werkzeug.security import generate_password_hash -from . import constants, logger, cli +from . import constants, logger log = logger.create() @@ -62,27 +64,14 @@ searched_ids = {} logged_in = dict() -def store_user_session(): - if flask_session.get('_user_id', ""): - if logged_in.get(flask_session.get('_user_id', "")): - logged_in[flask_session.get('_user_id', "")].append(flask_session.get('_id', "")) - else: - logged_in[flask_session.get('_user_id', "")] = [flask_session.get('_id', "")] - log.info(flask_session.get('_id', "")) - -def delete_user_session(user_id, session_key): - try: - logged_in.get(str(user_id), []).remove(session_key) - except ValueError: - pass - -def check_user_session(user_id, session_key): - return session_key in logged_in.get(str(user_id), []) def signal_store_user_session(object, user): store_user_session() + def store_user_session(): + if flask_session.get('user_id', ""): + flask_session['_user_id'] = flask_session.get('user_id', "") if flask_session.get('_user_id', ""): try: if not check_user_session(flask_session.get('_user_id', ""), flask_session.get('_id', "")): @@ -98,15 +87,16 @@ def store_user_session(): else: log.error("No user id in session") + def delete_user_session(user_id, session_key): try: log.debug("Deleted session_key: " + session_key) - session.query(User_Sessions).filter(User_Sessions.user_id==user_id, - User_Sessions.session_key==session_key).delete() + session.query(User_Sessions).filter(User_Sessions.user_id == user_id, + User_Sessions.session_key == session_key).delete() session.commit() - except (exc.OperationalError, exc.InvalidRequestError): + except (exc.OperationalError, exc.InvalidRequestError) as ex: session.rollback() - log.exception(e) + log.exception(ex) def check_user_session(user_id, session_key): @@ -126,6 +116,12 @@ def store_ids(result): ids.append(element.id) searched_ids[current_user.id] = ids +def store_combo_ids(result): + ids = list() + for element in result: + ids.append(element[0].id) + searched_ids[current_user.id] = ids + class UserBase: @@ -216,9 +212,9 @@ class UserBase: pass try: session.commit() - except (exc.OperationalError, exc.InvalidRequestError): + except (exc.OperationalError, exc.InvalidRequestError) as e: session.rollback() - # ToDo: Error message + log.error_or_exception(e) def __repr__(self): return '' % self.name @@ -267,7 +263,7 @@ class OAuthProvider(Base): active = Column(Boolean) -# Class for anonymous user is derived from User base and completly overrides methods and properties for the +# Class for anonymous user is derived from User base and completely overrides methods and properties for the # anonymous user class Anonymous(AnonymousUserMixin, UserBase): def __init__(self): @@ -314,11 +310,11 @@ class Anonymous(AnonymousUserMixin, UserBase): return None def set_view_property(self, page, prop, value): - if 'view' in flask_session: - if not flask_session['view'].get(page): - flask_session['view'][page] = dict() - flask_session['view'][page][prop] = value - return None + if not 'view' in flask_session: + flask_session['view'] = dict() + if not flask_session['view'].get(page): + flask_session['view'][page] = dict() + flask_session['view'][page][prop] = value class User_Sessions(Base): __tablename__ = 'user_session' @@ -435,8 +431,8 @@ class KoboReadingState(Base): book_id = Column(Integer) last_modified = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow) priority_timestamp = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow) - current_bookmark = relationship("KoboBookmark", uselist=False, backref="kobo_reading_state", cascade="all") - statistics = relationship("KoboStatistics", uselist=False, backref="kobo_reading_state", cascade="all") + current_bookmark = relationship("KoboBookmark", uselist=False, backref="kobo_reading_state", cascade="all, delete") + statistics = relationship("KoboStatistics", uselist=False, backref="kobo_reading_state", cascade="all, delete") class KoboBookmark(Base): @@ -496,7 +492,7 @@ class Registration(Base): allow = Column(Integer) def __repr__(self): - return u"".format(self.domain) + return "".format(self.domain) class RemoteAuthToken(Base): @@ -517,8 +513,30 @@ class RemoteAuthToken(Base): return '' % self.id +def filename(context): + file_format = context.get_current_parameters()['format'] + if file_format == 'jpeg': + return context.get_current_parameters()['uuid'] + '.jpg' + else: + return context.get_current_parameters()['uuid'] + '.' + file_format + + +class Thumbnail(Base): + __tablename__ = 'thumbnail' + + id = Column(Integer, primary_key=True) + entity_id = Column(Integer) + uuid = Column(String, default=lambda: str(uuid.uuid4()), unique=True) + format = Column(String, default='jpeg') + type = Column(SmallInteger, default=constants.THUMBNAIL_TYPE_COVER) + resolution = Column(SmallInteger, default=constants.COVER_THUMBNAIL_SMALL) + filename = Column(String, default=filename) + generated_at = Column(DateTime, default=lambda: datetime.datetime.utcnow()) + expiration = Column(DateTime, nullable=True) + + # Add missing tables during migration of database -def add_missing_tables(engine, session): +def add_missing_tables(engine, _session): if not engine.dialect.has_table(engine.connect(), "book_read_link"): ReadBook.__table__.create(bind=engine) if not engine.dialect.has_table(engine.connect(), "bookmark"): @@ -531,30 +549,32 @@ def add_missing_tables(engine, session): KoboStatistics.__table__.create(bind=engine) if not engine.dialect.has_table(engine.connect(), "archived_book"): ArchivedBook.__table__.create(bind=engine) + if not engine.dialect.has_table(engine.connect(), "thumbnail"): + Thumbnail.__table__.create(bind=engine) if not engine.dialect.has_table(engine.connect(), "registration"): Registration.__table__.create(bind=engine) with engine.connect() as conn: conn.execute("insert into registration (domain, allow) values('%.%',1)") - session.commit() + _session.commit() # migrate all settings missing in registration table -def migrate_registration_table(engine, session): +def migrate_registration_table(engine, _session): try: - session.query(exists().where(Registration.allow)).scalar() - session.commit() + _session.query(exists().where(Registration.allow)).scalar() + _session.commit() except exc.OperationalError: # Database is not compatible, some columns are missing with engine.connect() as conn: conn.execute("ALTER TABLE registration ADD column 'allow' INTEGER") conn.execute("update registration set 'allow' = 1") - session.commit() + _session.commit() try: # Handle table exists, but no content - cnt = session.query(Registration).count() + cnt = _session.query(Registration).count() if not cnt: with engine.connect() as conn: conn.execute("insert into registration (domain, allow) values('%.%',1)") - session.commit() + _session.commit() except exc.OperationalError: # Database is not writeable print('Settings database is not writeable. Exiting...') sys.exit(2) @@ -572,9 +592,9 @@ def migrate_guest_password(engine): sys.exit(2) -def migrate_shelfs(engine, session): +def migrate_shelfs(engine, _session): try: - session.query(exists().where(Shelf.uuid)).scalar() + _session.query(exists().where(Shelf.uuid)).scalar() except exc.OperationalError: with engine.connect() as conn: conn.execute("ALTER TABLE shelf ADD column 'uuid' STRING") @@ -582,33 +602,33 @@ def migrate_shelfs(engine, session): conn.execute("ALTER TABLE shelf ADD column 'last_modified' DATETIME") conn.execute("ALTER TABLE book_shelf_link ADD column 'date_added' DATETIME") conn.execute("ALTER TABLE shelf ADD column 'kobo_sync' BOOLEAN DEFAULT false") - for shelf in session.query(Shelf).all(): + for shelf in _session.query(Shelf).all(): shelf.uuid = str(uuid.uuid4()) shelf.created = datetime.datetime.now() shelf.last_modified = datetime.datetime.now() - for book_shelf in session.query(BookShelf).all(): + for book_shelf in _session.query(BookShelf).all(): book_shelf.date_added = datetime.datetime.now() - session.commit() + _session.commit() try: - session.query(exists().where(Shelf.kobo_sync)).scalar() + _session.query(exists().where(Shelf.kobo_sync)).scalar() except exc.OperationalError: with engine.connect() as conn: conn.execute("ALTER TABLE shelf ADD column 'kobo_sync' BOOLEAN DEFAULT false") - session.commit() + _session.commit() try: - session.query(exists().where(BookShelf.order)).scalar() + _session.query(exists().where(BookShelf.order)).scalar() except exc.OperationalError: # Database is not compatible, some columns are missing with engine.connect() as conn: conn.execute("ALTER TABLE book_shelf_link ADD column 'order' INTEGER DEFAULT 1") - session.commit() + _session.commit() -def migrate_readBook(engine, session): +def migrate_readBook(engine, _session): try: - session.query(exists().where(ReadBook.read_status)).scalar() + _session.query(exists().where(ReadBook.read_status)).scalar() except exc.OperationalError: with engine.connect() as conn: conn.execute("ALTER TABLE book_read_link ADD column 'read_status' INTEGER DEFAULT 0") @@ -616,46 +636,46 @@ def migrate_readBook(engine, session): conn.execute("ALTER TABLE book_read_link ADD column 'last_modified' DATETIME") conn.execute("ALTER TABLE book_read_link ADD column 'last_time_started_reading' DATETIME") conn.execute("ALTER TABLE book_read_link ADD column 'times_started_reading' INTEGER DEFAULT 0") - session.commit() - test = session.query(ReadBook).filter(ReadBook.last_modified == None).all() + _session.commit() + test = _session.query(ReadBook).filter(ReadBook.last_modified == None).all() for book in test: book.last_modified = datetime.datetime.utcnow() - session.commit() + _session.commit() -def migrate_remoteAuthToken(engine, session): +def migrate_remoteAuthToken(engine, _session): try: - session.query(exists().where(RemoteAuthToken.token_type)).scalar() - session.commit() + _session.query(exists().where(RemoteAuthToken.token_type)).scalar() + _session.commit() except exc.OperationalError: # Database is not compatible, some columns are missing with engine.connect() as conn: conn.execute("ALTER TABLE remote_auth_token ADD column 'token_type' INTEGER DEFAULT 0") conn.execute("update remote_auth_token set 'token_type' = 0") - session.commit() + _session.commit() # Migrate database to current version, has to be updated after every database change. Currently migration from # everywhere to current should work. Migration is done by checking if relevant columns are existing, and than adding # rows with SQL commands -def migrate_Database(session): - engine = session.bind - add_missing_tables(engine, session) - migrate_registration_table(engine, session) - migrate_readBook(engine, session) - migrate_remoteAuthToken(engine, session) - migrate_shelfs(engine, session) +def migrate_Database(_session): + engine = _session.bind + add_missing_tables(engine, _session) + migrate_registration_table(engine, _session) + migrate_readBook(engine, _session) + migrate_remoteAuthToken(engine, _session) + migrate_shelfs(engine, _session) try: create = False - session.query(exists().where(User.sidebar_view)).scalar() + _session.query(exists().where(User.sidebar_view)).scalar() except exc.OperationalError: # Database is not compatible, some columns are missing with engine.connect() as conn: conn.execute("ALTER TABLE user ADD column `sidebar_view` Integer DEFAULT 1") - session.commit() + _session.commit() create = True try: if create: with engine.connect() as conn: conn.execute("SELECT language_books FROM user") - session.commit() + _session.commit() except exc.OperationalError: with engine.connect() as conn: conn.execute("UPDATE user SET 'sidebar_view' = (random_books* :side_random + language_books * :side_lang " @@ -665,32 +685,32 @@ def migrate_Database(session): 'side_series': constants.SIDEBAR_SERIES, 'side_category': constants.SIDEBAR_CATEGORY, 'side_hot': constants.SIDEBAR_HOT, 'side_autor': constants.SIDEBAR_AUTHOR, 'detail_random': constants.DETAIL_RANDOM}) - session.commit() + _session.commit() try: - session.query(exists().where(User.denied_tags)).scalar() + _session.query(exists().where(User.denied_tags)).scalar() except exc.OperationalError: # Database is not compatible, some columns are missing with engine.connect() as conn: conn.execute("ALTER TABLE user ADD column `denied_tags` String DEFAULT ''") conn.execute("ALTER TABLE user ADD column `allowed_tags` String DEFAULT ''") conn.execute("ALTER TABLE user ADD column `denied_column_value` String DEFAULT ''") conn.execute("ALTER TABLE user ADD column `allowed_column_value` String DEFAULT ''") - session.commit() + _session.commit() try: - session.query(exists().where(User.view_settings)).scalar() + _session.query(exists().where(User.view_settings)).scalar() except exc.OperationalError: with engine.connect() as conn: conn.execute("ALTER TABLE user ADD column `view_settings` VARCHAR(10) DEFAULT '{}'") - session.commit() + _session.commit() try: - session.query(exists().where(User.kobo_only_shelves_sync)).scalar() + _session.query(exists().where(User.kobo_only_shelves_sync)).scalar() except exc.OperationalError: with engine.connect() as conn: conn.execute("ALTER TABLE user ADD column `kobo_only_shelves_sync` SMALLINT DEFAULT 0") - session.commit() + _session.commit() try: # check if name is in User table instead of nickname - session.query(exists().where(User.name)).scalar() + _session.query(exists().where(User.name)).scalar() except exc.OperationalError: # Create new table user_id and copy contents of table user into it with engine.connect() as conn: @@ -720,20 +740,20 @@ def migrate_Database(session): # delete old user table and rename new user_id table to user: conn.execute(text("DROP TABLE user")) conn.execute(text("ALTER TABLE user_id RENAME TO user")) - session.commit() - if session.query(User).filter(User.role.op('&')(constants.ROLE_ANONYMOUS) == constants.ROLE_ANONYMOUS).first() \ + _session.commit() + if _session.query(User).filter(User.role.op('&')(constants.ROLE_ANONYMOUS) == constants.ROLE_ANONYMOUS).first() \ is None: - create_anonymous_user(session) + create_anonymous_user(_session) migrate_guest_password(engine) -def clean_database(session): +def clean_database(_session): # Remove expired remote login tokens now = datetime.datetime.now() - session.query(RemoteAuthToken).filter(now > RemoteAuthToken.expiration).\ + _session.query(RemoteAuthToken).filter(now > RemoteAuthToken.expiration).\ filter(RemoteAuthToken.token_type != 1).delete() - session.commit() + _session.commit() # Save downloaded books per user in calibre-web's own database @@ -749,7 +769,7 @@ def update_download(book_id, user_id): session.rollback() -# Delete non exisiting downloaded books in calibre-web's own database +# Delete non existing downloaded books in calibre-web's own database def delete_download(book_id): session.query(Downloads).filter(book_id == Downloads.book_id).delete() try: @@ -758,43 +778,52 @@ def delete_download(book_id): session.rollback() # Generate user Guest (translated text), as anonymous user, no rights -def create_anonymous_user(session): +def create_anonymous_user(_session): user = User() user.name = "Guest" user.email = 'no@email' user.role = constants.ROLE_ANONYMOUS user.password = '' - session.add(user) + _session.add(user) try: - session.commit() + _session.commit() except Exception: - session.rollback() + _session.rollback() # Generate User admin with admin123 password, and access to everything -def create_admin_user(session): +def create_admin_user(_session): user = User() user.name = "admin" + user.email = "admin@example.org" user.role = constants.ADMIN_USER_ROLES user.sidebar_view = constants.ADMIN_USER_SIDEBAR user.password = generate_password_hash(constants.DEFAULT_PASSWORD) - session.add(user) + _session.add(user) try: - session.commit() + _session.commit() except Exception: - session.rollback() + _session.rollback() + +def init_db_thread(): + global app_DB_path + engine = create_engine('sqlite:///{0}'.format(app_DB_path), echo=False) + + Session = scoped_session(sessionmaker()) + Session.configure(bind=engine) + return Session() -def init_db(app_db_path): +def init_db(app_db_path, user_credentials=None): # Open session for database connection global session global app_DB_path app_DB_path = app_db_path - engine = create_engine(u'sqlite:///{0}'.format(app_db_path), echo=False) + engine = create_engine('sqlite:///{0}'.format(app_db_path), echo=False) Session = scoped_session(sessionmaker()) Session.configure(bind=engine) @@ -809,8 +838,8 @@ def init_db(app_db_path): create_admin_user(session) create_anonymous_user(session) - if cli.user_credentials: - username, password = cli.user_credentials.split(':', 1) + if user_credentials: + username, password = user_credentials.split(':', 1) user = session.query(User).filter(func.lower(User.name) == username.lower()).first() if user: if not password: @@ -828,6 +857,16 @@ def init_db(app_db_path): sys.exit(3) +def get_new_session_instance(): + new_engine = create_engine('sqlite:///{0}'.format(app_DB_path), echo=False) + new_session = scoped_session(sessionmaker()) + new_session.configure(bind=new_engine) + + atexit.register(lambda: new_session.remove() if new_session else True) + + return new_session + + def dispose(): global session @@ -844,12 +883,13 @@ def dispose(): except Exception: pass -def session_commit(success=None): +def session_commit(success=None, _session=None): + s = _session if _session else session try: - session.commit() + s.commit() if success: log.info(success) except (exc.OperationalError, exc.InvalidRequestError) as e: - session.rollback() - log.debug_or_exception(e) + s.rollback() + log.error_or_exception(e) return "" diff --git a/cps/updater.py b/cps/updater.py index 9090263fb..282677898 100644 --- a/cps/updater.py +++ b/cps/updater.py @@ -28,10 +28,10 @@ from io import BytesIO from tempfile import gettempdir import requests -from babel.dates import format_datetime +from flask_babel import format_datetime from flask_babel import gettext as _ -from . import constants, logger, config, web_server +from . import constants, logger # config, web_server log = logger.create() @@ -53,51 +53,53 @@ class Updater(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.paused = False - # self.pause_cond = threading.Condition(threading.Lock()) self.can_run = threading.Event() self.pause() self.status = -1 self.updateIndex = None - # self.run() + + def init_updater(self, config, web_server): + self.config = config + self.web_server = web_server def get_current_version_info(self): - if config.config_updatechannel == constants.UPDATE_STABLE: + if self.config.config_updatechannel == constants.UPDATE_STABLE: return self._stable_version_info() return self._nightly_version_info() - def get_available_updates(self, request_method, locale): - if config.config_updatechannel == constants.UPDATE_STABLE: + def get_available_updates(self, request_method): + if self.config.config_updatechannel == constants.UPDATE_STABLE: return self._stable_available_updates(request_method) - return self._nightly_available_updates(request_method, locale) + return self._nightly_available_updates(request_method) def do_work(self): try: self.status = 1 - log.debug(u'Download update file') + log.debug('Download update file') headers = {'Accept': 'application/vnd.github.v3+json'} r = requests.get(self._get_request_path(), stream=True, headers=headers, timeout=(10, 600)) r.raise_for_status() self.status = 2 - log.debug(u'Opening zipfile') + log.debug('Opening zipfile') z = zipfile.ZipFile(BytesIO(r.content)) self.status = 3 - log.debug(u'Extracting zipfile') + log.debug('Extracting zipfile') tmp_dir = gettempdir() z.extractall(tmp_dir) - foldername = os.path.join(tmp_dir, z.namelist()[0])[:-1] - if not os.path.isdir(foldername): + folder_name = os.path.join(tmp_dir, z.namelist()[0])[:-1] + if not os.path.isdir(folder_name): self.status = 11 - log.info(u'Extracted contents of zipfile not found in temp folder') + log.info('Extracted contents of zipfile not found in temp folder') self.pause() return False self.status = 4 - log.debug(u'Replacing files') - if self.update_source(foldername, constants.BASE_DIR): + log.debug('Replacing files') + if self.update_source(folder_name, constants.BASE_DIR): self.status = 6 - log.debug(u'Preparing restart of server') + log.debug('Preparing restart of server') time.sleep(2) - web_server.stop(True) + self.web_server.stop(True) self.status = 7 time.sleep(2) return True @@ -105,21 +107,21 @@ class Updater(threading.Thread): self.status = 13 except requests.exceptions.HTTPError as ex: - log.error(u'HTTP Error %s', ex) + log.error('HTTP Error %s', ex) self.status = 8 except requests.exceptions.ConnectionError: - log.error(u'Connection error') + log.error('Connection error') self.status = 9 except requests.exceptions.Timeout: - log.error(u'Timeout while establishing connection') + log.error('Timeout while establishing connection') self.status = 10 except (requests.exceptions.RequestException, zipfile.BadZipFile): self.status = 11 - log.error(u'General error') + log.error('General error') except (IOError, OSError) as ex: self.status = 12 - log.error(u'Possible Reason for error: update file could not be saved in temp dir') - log.debug_or_exception(ex) + log.error('Possible Reason for error: update file could not be saved in temp dir') + log.error_or_exception(ex) self.pause() return False @@ -184,29 +186,30 @@ class Updater(threading.Thread): return rf @classmethod - def check_permissions(cls, root_src_dir, root_dst_dir): + def check_permissions(cls, root_src_dir, root_dst_dir, log_function): access = True remove_path = len(root_src_dir) + 1 for src_dir, __, files in os.walk(root_src_dir): root_dir = os.path.join(root_dst_dir, src_dir[remove_path:]) - # Skip non existing folders on check - if not os.path.isdir(root_dir): # root_dir.lstrip(os.sep).startswith('.') or + # Skip non-existing folders on check + if not os.path.isdir(root_dir): continue - if not os.access(root_dir, os.R_OK|os.W_OK): - log.debug("Missing permissions for {}".format(root_dir)) + if not os.access(root_dir, os.R_OK | os.W_OK): + log_function("Missing permissions for {}".format(root_dir)) access = False for file_ in files: curr_file = os.path.join(root_dir, file_) - # Skip non existing files on check - if not os.path.isfile(curr_file): # or curr_file.startswith('.'): + # Skip non-existing files on check + if not os.path.isfile(curr_file): # or curr_file.startswith('.'): continue - if not os.access(curr_file, os.R_OK|os.W_OK): - log.debug("Missing permissions for {}".format(curr_file)) + if not os.access(curr_file, os.R_OK | os.W_OK): + log_function("Missing permissions for {}".format(curr_file)) access = False return access @classmethod - def moveallfiles(cls, root_src_dir, root_dst_dir): + def move_all_files(cls, root_src_dir, root_dst_dir): + permission = None new_permissions = os.stat(root_dst_dir) log.debug('Performing Update on OS-System: %s', sys.platform) change_permissions = not (sys.platform == "win32" or sys.platform == "darwin") @@ -215,7 +218,7 @@ class Updater(threading.Thread): if not os.path.exists(dst_dir): try: os.makedirs(dst_dir) - log.debug('Create directory: {}', dst_dir) + log.debug('Create directory: {}'.format(dst_dir)) except OSError as e: log.error('Failed creating folder: {} with error {}'.format(dst_dir, e)) if change_permissions: @@ -234,7 +237,7 @@ class Updater(threading.Thread): permission = os.stat(dst_file) try: os.remove(dst_file) - log.debug('Remove file before copy: %s', dst_file) + log.debug('Remove file before copy: {}'.format(dst_file)) except OSError as e: log.error('Failed removing file: {} with error {}'.format(dst_file, e)) else: @@ -258,20 +261,14 @@ class Updater(threading.Thread): def update_source(self, source, destination): # destination files old_list = list() - exclude = ( - os.sep + 'app.db', os.sep + 'calibre-web.log1', os.sep + 'calibre-web.log2', os.sep + 'gdrive.db', - os.sep + 'vendor', os.sep + 'calibre-web.log', os.sep + '.git', os.sep + 'client_secrets.json', - os.sep + 'gdrive_credentials', os.sep + 'settings.yaml', os.sep + 'venv', os.sep + 'virtualenv', - os.sep + 'access.log', os.sep + 'access.log1', os.sep + 'access.log2', - os.sep + '.calibre-web.log.swp', os.sep + '_sqlite3.so', os.sep + 'cps' + os.sep + '.HOMEDIR', - os.sep + 'gmail.json' - ) + exclude = self._add_excluded_files(log.info) additional_path = self.is_venv() if additional_path: - exclude = exclude + (additional_path,) - - # check if we are in a package, rename cps.py to __init__.py + exclude.append(additional_path) + exclude = tuple(exclude) + # check if we are in a package, rename cps.py to __init__.py and __main__.py if constants.HOME_CONFIG: + shutil.copy(os.path.join(source, 'cps.py'), os.path.join(source, '__main__.py')) shutil.move(os.path.join(source, 'cps.py'), os.path.join(source, '__init__.py')) for root, dirs, files in os.walk(destination, topdown=True): @@ -293,8 +290,8 @@ class Updater(threading.Thread): remove_items = self.reduce_dirs(rf, new_list) - if self.check_permissions(source, destination): - self.moveallfiles(source, destination) + if self.check_permissions(source, destination, log.debug): + self.move_all_files(source, destination) for item in remove_items: item_path = os.path.join(destination, item[1:]) @@ -330,16 +327,23 @@ class Updater(threading.Thread): @classmethod def _stable_version_info(cls): log.debug("Stable version: {}".format(constants.STABLE_VERSION)) - return constants.STABLE_VERSION # Current version + return constants.STABLE_VERSION # Current Version + + @classmethod + def dry_run(cls): + cls._add_excluded_files(print) + cls.check_permissions(constants.BASE_DIR, constants.BASE_DIR, print) + print("\n*** Finished ***") @staticmethod - def _populate_parent_commits(update_data, status, locale, tz, parents): + def _populate_parent_commits(update_data, status, tz, parents): try: parent_commit = update_data['parents'][0] # limit the maximum search depth remaining_parents_cnt = 10 except (IndexError, KeyError): remaining_parents_cnt = None + parent_commit = None if remaining_parents_cnt is not None: while True: @@ -357,7 +361,7 @@ class Updater(threading.Thread): parent_commit_date = datetime.datetime.strptime( parent_data['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz parent_commit_date = format_datetime( - parent_commit_date, format='short', locale=locale) + parent_commit_date, format='short') parents.append([parent_commit_date, parent_data['message'].replace('\r\n', '

      ').replace('\n', '

      ')]) @@ -382,16 +386,40 @@ class Updater(threading.Thread): r.raise_for_status() update_data = r.json() except requests.exceptions.HTTPError as e: - status['message'] = _(u'HTTP Error') + ' ' + str(e) + status['message'] = _('HTTP Error') + ' ' + str(e) except requests.exceptions.ConnectionError: - status['message'] = _(u'Connection error') + status['message'] = _('Connection error') except requests.exceptions.Timeout: - status['message'] = _(u'Timeout while establishing connection') + status['message'] = _('Timeout while establishing connection') except (requests.exceptions.RequestException, ValueError): - status['message'] = _(u'General error') + status['message'] = _('General error') return status, update_data - def _nightly_available_updates(self, request_method, locale): + @staticmethod + def _add_excluded_files(log_function): + excluded_files = [ + os.sep + 'app.db', os.sep + 'calibre-web.log1', os.sep + 'calibre-web.log2', os.sep + 'gdrive.db', + os.sep + 'vendor', os.sep + 'calibre-web.log', os.sep + '.git', os.sep + 'client_secrets.json', + os.sep + 'gdrive_credentials', os.sep + 'settings.yaml', os.sep + 'venv', os.sep + 'virtualenv', + os.sep + 'access.log', os.sep + 'access.log1', os.sep + 'access.log2', + os.sep + '.calibre-web.log.swp', os.sep + '_sqlite3.so', os.sep + 'cps' + os.sep + '.HOMEDIR', + os.sep + 'gmail.json', os.sep + 'exclude.txt', os.sep + 'cps' + os.sep + 'cache' + ] + try: + with open(os.path.join(constants.BASE_DIR, "exclude.txt"), "r") as f: + lines = f.readlines() + for line in lines: + processed_line = line.strip("\n\r ").strip("\"'").lstrip("\\/ ").\ + replace("\\", os.sep).replace("/", os.sep) + if os.path.exists(os.path.join(constants.BASE_DIR, processed_line)): + excluded_files.append(os.sep + processed_line) + else: + log_function("File list for updater: {} not found".format(line)) + except (PermissionError, FileNotFoundError): + log_function("Excluded file list for updater not found, or not accessible") + return excluded_files + + def _nightly_available_updates(self, request_method): tz = datetime.timedelta(seconds=time.timezone if (time.localtime().tm_isdst == 0) else time.altzone) if request_method == "GET": repository_url = _REPOSITORY_API_URL @@ -400,18 +428,18 @@ class Updater(threading.Thread): if status['message'] != '': return json.dumps(status) if 'object' not in commit or 'url' not in commit['object']: - status['message'] = _(u'Unexpected data while reading update information') + status['message'] = _('Unexpected data while reading update information') return json.dumps(status) try: if commit['object']['sha'] == status['current_commit_hash']: status.update({ 'update': False, 'success': True, - 'message': _(u'No update available. You already have the latest version installed') + 'message': _('No update available. You already have the latest version installed') }) return json.dumps(status) except (TypeError, KeyError): - status['message'] = _(u'Unexpected data while reading update information') + status['message'] = _('Unexpected data while reading update information') return json.dumps(status) # a new update is available @@ -426,44 +454,44 @@ class Updater(threading.Thread): log.debug("A new update is available.") status['success'] = True status['message'] = _( - u'A new update is available. Click on the button below to update to the latest version.') + 'A new update is available. Click on the button below to update to the latest version.') new_commit_date = datetime.datetime.strptime( update_data['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz parents.append( [ - format_datetime(new_commit_date, format='short', locale=locale), + format_datetime(new_commit_date, format='short'), update_data['message'], update_data['sha'] ] ) # it only makes sense to analyze the parents if we know the current commit hash if status['current_commit_hash'] != '': - parents = self._populate_parent_commits(update_data, status, locale, tz, parents) + parents = self._populate_parent_commits(update_data, status, tz, parents) status['history'] = parents[::-1] except (IndexError, KeyError): status['success'] = False - status['message'] = _(u'Could not fetch update information') + status['message'] = _('Could not fetch update information') log.error("Could not fetch update information") return json.dumps(status) return '' def _stable_updater_set_status(self, i, newer, status, parents, commit): - if i == -1 and newer == False: + if i == -1 and newer is False: status.update({ 'update': True, 'success': True, 'message': _( - u'Click on the button below to update to the latest stable version.'), + 'Click on the button below to update to the latest stable version.'), 'history': parents }) self.updateFile = commit[0]['zipball_url'] - elif i == -1 and newer == True: + elif i == -1 and newer is True: status.update({ 'update': True, 'success': True, - 'message': _(u'A new update is available. Click on the button below to ' - u'update to version: %(version)s', version=commit[0]['tag_name']), + 'message': _('A new update is available. Click on the button below to ' + 'update to version: %(version)s', version=commit[0]['tag_name']), 'history': parents }) self.updateFile = commit[0]['zipball_url'] @@ -495,6 +523,7 @@ class Updater(threading.Thread): return status, parents def _stable_available_updates(self, request_method): + status = None if request_method == "GET": parents = [] # repository_url = 'https://api.github.com/repos/flatpak/flatpak/releases' # test URL @@ -539,7 +568,7 @@ class Updater(threading.Thread): except ValueError: current_version[2] = int(current_version[2].split(' ')[0])-1 - # Check if major versions are identical search for newest non equal commit and update to this one + # Check if major versions are identical search for newest non-equal commit and update to this one if major_version_update == current_version[0]: if (minor_version_update == current_version[1] and patch_version_update > current_version[2]) or \ @@ -552,7 +581,7 @@ class Updater(threading.Thread): i -= 1 continue if major_version_update > current_version[0]: - # found update update to last version before major update, unless current version is on last version + # found update to last version before major update, unless current version is on last version # before major update if i == (len(commit) - 1): i -= 1 @@ -567,7 +596,7 @@ class Updater(threading.Thread): return json.dumps(status) def _get_request_path(self): - if config.config_updatechannel == constants.UPDATE_STABLE: + if self.config.config_updatechannel == constants.UPDATE_STABLE: return self.updateFile return _REPOSITORY_API_URL + '/zipball/master' @@ -595,7 +624,7 @@ class Updater(threading.Thread): status['message'] = _(u'HTTP Error') + ': ' + commit['message'] else: status['message'] = _(u'HTTP Error') + ': ' + str(e) - except requests.exceptions.ConnectionError: + except requests.exceptions.ConnectionError as e: status['message'] = _(u'Connection error') except requests.exceptions.Timeout: status['message'] = _(u'Timeout while establishing connection') diff --git a/cps/uploader.py b/cps/uploader.py index f238b89df..3cd7b21aa 100644 --- a/cps/uploader.py +++ b/cps/uploader.py @@ -27,12 +27,6 @@ from .helper import split_authors log = logger.create() - -try: - from lxml.etree import LXML_VERSION as lxmlversion -except ImportError: - lxmlversion = None - try: from wand.image import Image, Color from wand import version as ImageVersion @@ -43,17 +37,22 @@ except (ImportError, RuntimeError) as e: use_generic_pdf_cover = True try: - from PyPDF3 import PdfFileReader - from PyPDF3 import __version__ as PyPdfVersion + from pypdf import PdfReader use_pdf_meta = True except ImportError as ex: + log.debug('PyPDF is recommended for best performance in metadata extracting from pdf files: %s', ex) try: - from PyPDF2 import PdfFileReader - from PyPDF2 import __version__ as PyPdfVersion + from PyPDF2 import PdfReader use_pdf_meta = True - except ImportError as e: - log.debug('Cannot import PyPDF3/PyPDF2, extracting pdf metadata will not work: %s / %s', ex, e) - use_pdf_meta = False + except ImportError as ex: + log.debug('PyPDF is recommended for best performance in metadata extracting from pdf files: %s', ex) + log.debug('PyPdf2 is also possible for metadata extracting from pdf files, but not recommended anymore') + try: + from PyPDF3 import PdfFileReader as PdfReader + use_pdf_meta = True + except ImportError as e: + log.debug('Cannot import PyPDF3/PyPDF2, extracting pdf metadata will not work: %s / %s', e) + use_pdf_meta = False try: from . import epub @@ -71,7 +70,7 @@ except ImportError as e: def process(tmp_file_path, original_file_name, original_file_extension, rarExecutable): - meta = None + meta = default_meta(tmp_file_path, original_file_name, original_file_extension) extension_upper = original_file_extension.upper() try: if ".PDF" == extension_upper: @@ -88,11 +87,11 @@ def process(tmp_file_path, original_file_name, original_file_extension, rarExecu except Exception as ex: log.warning('cannot parse metadata, using default: %s', ex) - if meta and meta.title.strip() and meta.author.strip(): - if meta.author.lower() == 'unknown': - meta = meta._replace(author=_(u'Unknown')) - return meta - return default_meta(tmp_file_path, original_file_name, original_file_extension) + if not meta.title.strip(): + meta = original_file_name + if not meta.author.strip() or meta.author.lower() == 'unknown': + meta = meta._replace(author=_('Unknown')) + return meta def default_meta(tmp_file_path, original_file_name, original_file_extension): @@ -100,14 +99,17 @@ def default_meta(tmp_file_path, original_file_name, original_file_extension): file_path=tmp_file_path, extension=original_file_extension, title=original_file_name, - author=_(u'Unknown'), - cover=None, #pdf_preview(tmp_file_path, original_file_name), + author=_('Unknown'), + cover=None, description="", tags="", series="", series_id="", languages="", - publisher="") + publisher="", + pubdate="", + identifiers=[] + ) def parse_xmp(pdf_file): @@ -115,54 +117,9 @@ def parse_xmp(pdf_file): Parse XMP Metadata and prepare for BookMeta object """ try: - xmp_info = pdf_file.getXmpMetadata() + xmp_info = pdf_file.xmp_metadata except Exception as ex: - log.debug('Can not read XMP metadata {}'.format(ex)) - return None - - if xmp_info: - try: - xmp_author = xmp_info.dc_creator # list - except AttributeError: - xmp_author = [''] - - if xmp_info.dc_title: - xmp_title = xmp_info.dc_title['x-default'] - else: - xmp_title = '' - - if xmp_info.dc_description: - xmp_description = xmp_info.dc_description['x-default'] - else: - xmp_description = '' - - languages = [] - try: - for i in xmp_info.dc_language: - #calibre-web currently only takes one language. - languages.append(isoLanguages.get_lang3(i)) - except AttributeError: - languages.append('') - - xmp_tags = ', '.join(xmp_info.dc_subject) - xmp_publisher = ', '.join(xmp_info.dc_publisher) - - return {'author': xmp_author, - 'title': xmp_title, - 'subject': xmp_description, - 'tags': xmp_tags, 'languages': languages, - 'publisher': xmp_publisher - } - - -def parse_xmp(pdf_file): - """ - Parse XMP Metadata and prepare for BookMeta object - """ - try: - xmp_info = pdf_file.getXmpMetadata() - except Exception as ex: - log.debug('Can not read XMP metadata {}'.format(ex)) + log.debug('Can not read PDF XMP metadata {}'.format(ex)) return None if xmp_info: @@ -206,8 +163,11 @@ def pdf_meta(tmp_file_path, original_file_name, original_file_extension): if use_pdf_meta: with open(tmp_file_path, 'rb') as f: - pdf_file = PdfFileReader(f) - doc_info = pdf_file.getDocumentInfo() + pdf_file = PdfReader(f) + try: + doc_info = pdf_file.metadata + except Exception as exc: + log.debug('Can not read PDF DocumentInfo {}'.format(exc)) xmp_info = parse_xmp(pdf_file) if xmp_info: @@ -218,7 +178,7 @@ def pdf_meta(tmp_file_path, original_file_name, original_file_extension): languages = xmp_info['languages'] publisher = xmp_info['publisher'] else: - author = u'Unknown' + author = 'Unknown' title = '' languages = [""] publisher = "" @@ -227,13 +187,16 @@ def pdf_meta(tmp_file_path, original_file_name, original_file_extension): if doc_info: if author == '': - author = ' & '.join(split_authors([doc_info.author])) if doc_info.author else u'Unknown' + author = ' & '.join(split_authors([doc_info.author])) if doc_info.author else 'Unknown' if title == '': title = doc_info.title if doc_info.title else original_file_name if subject == '': - subject = doc_info.subject + subject = doc_info.subject or "" if tags == '' and '/Keywords' in doc_info: - tags = doc_info['/Keywords'] + if isinstance(doc_info['/Keywords'], bytes): + tags = doc_info['/Keywords'].decode('utf-8') + else: + tags = doc_info['/Keywords'] else: title = original_file_name @@ -248,7 +211,9 @@ def pdf_meta(tmp_file_path, original_file_name, original_file_extension): series="", series_id="", languages=','.join(languages), - publisher=publisher) + publisher=publisher, + pubdate="", + identifiers=[]) def pdf_preview(tmp_file_path, tmp_dir): @@ -274,29 +239,12 @@ def pdf_preview(tmp_file_path, tmp_dir): return None -def get_versions(all=True): +def get_magick_version(): ret = dict() if not use_generic_pdf_cover: ret['Image Magick'] = ImageVersion.MAGICK_VERSION else: - ret['Image Magick'] = u'not installed' - if all: - if not use_generic_pdf_cover: - ret['Wand'] = ImageVersion.VERSION - else: - ret['Wand'] = u'not installed' - if use_pdf_meta: - ret['PyPdf'] = PyPdfVersion - else: - ret['PyPdf'] = u'not installed' - if lxmlversion: - ret['lxml'] = '.'.join(map(str, lxmlversion)) - else: - ret['lxml'] = u'not installed' - if comic.use_comic_meta: - ret['Comic_API'] = comic.comic_version or u'installed' - else: - ret['Comic_API'] = u'not installed' + ret['Image Magick'] = 'not installed' return ret diff --git a/cps/usermanagement.py b/cps/usermanagement.py index 71da7701c..d0d1494ca 100644 --- a/cps/usermanagement.py +++ b/cps/usermanagement.py @@ -16,19 +16,16 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import base64 -import binascii +from functools import wraps from sqlalchemy.sql.expression import func from werkzeug.security import check_password_hash from flask_login import login_required, login_user +from flask import request, Response -from . import lm, ub, config, constants, services +from . import lm, ub, config, constants, services, logger -try: - from functools import wraps -except ImportError: - pass # We're not using Python 3 +log = logger.create() def login_required_if_no_ano(func): @wraps(func) @@ -39,6 +36,51 @@ def login_required_if_no_ano(func): return decorated_view +def requires_basic_auth_if_no_ano(f): + @wraps(f) + def decorated(*args, **kwargs): + auth = request.authorization + if not auth or auth.type != 'basic': + if config.config_anonbrowse != 1: + user = load_user_from_reverse_proxy_header(request) + if user: + return f(*args, **kwargs) + return _authenticate() + else: + return f(*args, **kwargs) + if config.config_login_type == constants.LOGIN_LDAP and services.ldap: + login_result, error = services.ldap.bind_user(auth.username, auth.password) + if login_result: + user = _fetch_user_by_name(auth.username) + login_user(user) + return f(*args, **kwargs) + elif login_result is not None: + log.error(error) + return _authenticate() + user = _load_user_from_auth_header(auth.username, auth.password) + if not user: + return _authenticate() + return f(*args, **kwargs) + return decorated + + +def _load_user_from_auth_header(username, password): + user = _fetch_user_by_name(username) + if bool(user and check_password_hash(str(user.password), password)): + login_user(user) + return user + else: + ip_address = request.headers.get('X-Forwarded-For', request.remote_addr) + log.warning('OPDS Login failed for user "%s" IP-address: %s', username, ip_address) + return None + + +def _authenticate(): + return Response( + 'Could not verify your access level for that URL.\n' + 'You have to login with proper credentials', 401, + {'WWW-Authenticate': 'Basic realm="Login Required"'}) + def _fetch_user_by_name(username): return ub.session.query(ub.User).filter(func.lower(ub.User.name) == username.lower()).first() @@ -46,45 +88,20 @@ def _fetch_user_by_name(username): @lm.user_loader def load_user(user_id): - return ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first() + user = ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first() + return user @lm.request_loader -def load_user_from_request(request): +def load_user_from_reverse_proxy_header(req): if config.config_allow_reverse_proxy_header_login: rp_header_name = config.config_reverse_proxy_login_header_name if rp_header_name: - rp_header_username = request.headers.get(rp_header_name) + rp_header_username = req.headers.get(rp_header_name) if rp_header_username: user = _fetch_user_by_name(rp_header_username) if user: login_user(user) return user + return None - auth_header = request.headers.get("Authorization") - if auth_header: - user = load_user_from_auth_header(auth_header) - if user: - return user - - return - - -def load_user_from_auth_header(header_val): - if header_val.startswith('Basic '): - header_val = header_val.replace('Basic ', '', 1) - basic_username = basic_password = '' # nosec - try: - header_val = base64.b64decode(header_val).decode('utf-8') - # Users with colon are invalid: rfc7617 page 4 - basic_username = header_val.split(':', 1)[0] - basic_password = header_val.split(':', 1)[1] - except (TypeError, UnicodeDecodeError, binascii.Error): - pass - user = _fetch_user_by_name(basic_username) - if user and config.config_login_type == constants.LOGIN_LDAP and services.ldap: - if services.ldap.bind_user(str(user.password), basic_password): - return user - if user and check_password_hash(str(user.password), basic_password): - return user - return diff --git a/cps/web.py b/cps/web.py index ea6faf197..8445196f9 100644 --- a/cps/web.py +++ b/cps/web.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web) # Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11, # andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh, @@ -21,40 +19,43 @@ # along with this program. If not, see . import os -from datetime import datetime import json import mimetypes import chardet # dependency of requests import copy -from babel.dates import format_date -from babel import Locale as LC from flask import Blueprint, jsonify from flask import request, redirect, send_from_directory, make_response, flash, abort, url_for from flask import session as flask_session from flask_babel import gettext as _ +from flask_babel import get_locale from flask_login import login_user, logout_user, login_required, current_user from sqlalchemy.exc import IntegrityError, InvalidRequestError, OperationalError from sqlalchemy.sql.expression import text, func, false, not_, and_, or_ from sqlalchemy.orm.attributes import flag_modified from sqlalchemy.sql.functions import coalesce -from .services.worker import WorkerThread - from werkzeug.datastructures import Headers from werkzeug.security import generate_password_hash, check_password_hash from . import constants, logger, isoLanguages, services -from . import babel, db, ub, config, get_locale, app +from . import db, ub, config, app from . import calibre_db, kobo_sync_status +from .search import render_search_results, render_adv_search_results from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download -from .helper import check_valid_domain, render_task_status, check_email, check_username, \ - get_cc_columns, get_book_cover, get_download_link, send_mail, generate_random_password, \ - send_registration_mail, check_send_to_kindle, check_read_formats, tags_filters, reset_password, valid_email +from .helper import check_valid_domain, check_email, check_username, \ + get_book_cover, get_series_cover_thumbnail, get_download_link, send_mail, generate_random_password, \ + send_registration_mail, check_send_to_ereader, check_read_formats, tags_filters, reset_password, valid_email, \ + edit_book_read_status from .pagination import Pagination from .redirect import redirect_back +from .babel import get_available_locale from .usermanagement import login_required_if_no_ano +from .kobo_sync_status import remove_synced_book from .render_template import render_title_template +from .kobo_sync_status import change_archived_books +from .services.worker import WorkerThread +from .tasks_status import render_task_status feature_support = { 'ldap': bool(services.ldap), @@ -64,15 +65,14 @@ feature_support = { try: from .oauth_bb import oauth_check, register_user_with_oauth, logout_oauth_user, get_oauth_status + feature_support['oauth'] = True except ImportError: feature_support['oauth'] = False oauth_check = {} + register_user_with_oauth = logout_oauth_user = get_oauth_status = None -try: - from functools import wraps -except ImportError: - pass # We're not using Python 3 +from functools import wraps try: from natsort import natsorted as sort @@ -82,18 +82,29 @@ except ImportError: @app.after_request def add_security_headers(resp): - resp.headers['Content-Security-Policy'] = "default-src 'self'" + ''.join([' '+host for host in config.config_trustedhosts.strip().split(',')]) + " 'unsafe-inline' 'unsafe-eval'; font-src 'self' data:; img-src 'self' data:" - if request.endpoint == "editbook.edit_book" or config.config_use_google_drive: - resp.headers['Content-Security-Policy'] += " *" + csp = "default-src 'self'" + csp += ''.join([' ' + host for host in config.config_trustedhosts.strip().split(',')]) + csp += " 'unsafe-inline' 'unsafe-eval'; font-src 'self' data:; img-src 'self'" + if request.path.startswith("/author/") and config.config_use_goodreads: + csp += " images.gr-assets.com i.gr-assets.com s.gr-assets.com" + csp += " data:" + if request.endpoint == "edit-book.show_edit_book" or config.config_use_google_drive: + csp += " *;" elif request.endpoint == "web.read_book": - resp.headers['Content-Security-Policy'] += " blob:;style-src-elem 'self' blob: 'unsafe-inline';" + csp += " blob:; style-src-elem 'self' blob: 'unsafe-inline';" + else: + csp += ";" + csp += " object-src 'none';" + resp.headers['Content-Security-Policy'] = csp resp.headers['X-Content-Type-Options'] = 'nosniff' resp.headers['X-Frame-Options'] = 'SAMEORIGIN' resp.headers['X-XSS-Protection'] = '1; mode=block' resp.headers['Strict-Transport-Security'] = 'max-age=31536000;' return resp + web = Blueprint('web', __name__) + log = logger.create() @@ -119,19 +130,20 @@ def viewer_required(f): return inner + # ################################### data provider functions ######################################################### @web.route("/ajax/emailstat") @login_required def get_email_status_json(): - tasks = WorkerThread.getInstance().tasks + tasks = WorkerThread.get_instance().tasks return jsonify(render_task_status(tasks)) @web.route("/ajax/bookmark//", methods=['POST']) @login_required -def bookmark(book_id, book_format): +def set_bookmark(book_id, book_format): bookmark_key = request.form["bookmark"] ub.session.query(ub.Bookmark).filter(and_(ub.Bookmark.user_id == int(current_user.id), ub.Bookmark.book_id == book_id, @@ -140,11 +152,11 @@ def bookmark(book_id, book_format): ub.session_commit() return "", 204 - lbookmark = ub.Bookmark(user_id=current_user.id, - book_id=book_id, - format=book_format, - bookmark_key=bookmark_key) - ub.session.merge(lbookmark) + l_bookmark = ub.Bookmark(user_id=current_user.id, + book_id=book_id, + format=book_format, + bookmark_key=bookmark_key) + ub.session.merge(l_bookmark) ub.session_commit("Bookmark for user {} in book {} created".format(current_user.id, book_id)) return "", 201 @@ -152,60 +164,19 @@ def bookmark(book_id, book_format): @web.route("/ajax/toggleread/", methods=['POST']) @login_required def toggle_read(book_id): - if not config.config_read_column: - book = ub.session.query(ub.ReadBook).filter(and_(ub.ReadBook.user_id == int(current_user.id), - ub.ReadBook.book_id == book_id)).first() - if book: - if book.read_status == ub.ReadBook.STATUS_FINISHED: - book.read_status = ub.ReadBook.STATUS_UNREAD - else: - book.read_status = ub.ReadBook.STATUS_FINISHED - else: - readBook = ub.ReadBook(user_id=current_user.id, book_id = book_id) - readBook.read_status = ub.ReadBook.STATUS_FINISHED - book = readBook - if not book.kobo_reading_state: - kobo_reading_state = ub.KoboReadingState(user_id=current_user.id, book_id=book_id) - kobo_reading_state.current_bookmark = ub.KoboBookmark() - kobo_reading_state.statistics = ub.KoboStatistics() - book.kobo_reading_state = kobo_reading_state - ub.session.merge(book) - ub.session_commit("Book {} readbit toggled".format(book_id)) + message = edit_book_read_status(book_id) + if message: + return message, 400 else: - try: - calibre_db.update_title_sort(config) - book = calibre_db.get_filtered_book(book_id) - read_status = getattr(book, 'custom_column_' + str(config.config_read_column)) - if len(read_status): - read_status[0].value = not read_status[0].value - calibre_db.session.commit() - else: - cc_class = db.cc_classes[config.config_read_column] - new_cc = cc_class(value=1, book=book_id) - calibre_db.session.add(new_cc) - calibre_db.session.commit() - except (KeyError, AttributeError): - log.error(u"Custom Column No.%d is not existing in calibre database", config.config_read_column) - return "Custom Column No.{} is not existing in calibre database".format(config.config_read_column), 400 - except (OperationalError, InvalidRequestError) as e: - calibre_db.session.rollback() - log.error(u"Read status could not set: %e", e) - return "Read status could not set: {}".format(e), 400 - return "" + return message + @web.route("/ajax/togglearchived/", methods=['POST']) @login_required def toggle_archived(book_id): - archived_book = ub.session.query(ub.ArchivedBook).filter(and_(ub.ArchivedBook.user_id == int(current_user.id), - ub.ArchivedBook.book_id == book_id)).first() - if archived_book: - archived_book.is_archived = not archived_book.is_archived - archived_book.last_modified = datetime.utcnow() - else: - archived_book = ub.ArchivedBook(user_id=current_user.id, book_id=book_id) - archived_book.is_archived = True - ub.session.merge(archived_book) - ub.session_commit("Book {} archivebit toggled".format(book_id)) + is_archived = change_archived_books(book_id, message="Book {} archive bit toggled".format(book_id)) + if is_archived: + remove_synced_book(book_id) return "" @@ -271,6 +242,7 @@ def get_comic_book(book_id, book_format, page): return "", 204 ''' + # ################################### Typeahead ################################################################## @@ -338,47 +310,63 @@ def get_matching_tags(): return json_dumps -def get_sort_function(sort, data): +def generate_char_list(entries): # data_colum, db_link): + char_list = list() + for entry in entries: + upper_char = entry[0].name[0].upper() + if upper_char not in char_list: + char_list.append(upper_char) + return char_list + + +def query_char_list(data_colum, db_link): + results = (calibre_db.session.query(func.upper(func.substr(data_colum, 1, 1)).label('char')) + .join(db_link).join(db.Books).filter(calibre_db.common_filters()) + .group_by(func.upper(func.substr(data_colum, 1, 1))).all()) + return results + + +def get_sort_function(sort_param, data): order = [db.Books.timestamp.desc()] - if sort == 'stored': - sort = current_user.get_view_property(data, 'stored') + if sort_param == 'stored': + sort_param = current_user.get_view_property(data, 'stored') else: - current_user.set_view_property(data, 'stored', sort) - if sort == 'pubnew': + current_user.set_view_property(data, 'stored', sort_param) + if sort_param == 'pubnew': order = [db.Books.pubdate.desc()] - if sort == 'pubold': + if sort_param == 'pubold': order = [db.Books.pubdate] - if sort == 'abc': + if sort_param == 'abc': order = [db.Books.sort] - if sort == 'zyx': + if sort_param == 'zyx': order = [db.Books.sort.desc()] - if sort == 'new': + if sort_param == 'new': order = [db.Books.timestamp.desc()] - if sort == 'old': + if sort_param == 'old': order = [db.Books.timestamp] - if sort == 'authaz': + if sort_param == 'authaz': order = [db.Books.author_sort.asc(), db.Series.name, db.Books.series_index] - if sort == 'authza': + if sort_param == 'authza': order = [db.Books.author_sort.desc(), db.Series.name.desc(), db.Books.series_index.desc()] - if sort == 'seriesasc': + if sort_param == 'seriesasc': order = [db.Books.series_index.asc()] - if sort == 'seriesdesc': + if sort_param == 'seriesdesc': order = [db.Books.series_index.desc()] - if sort == 'hotdesc': + if sort_param == 'hotdesc': order = [func.count(ub.Downloads.book_id).desc()] - if sort == 'hotasc': + if sort_param == 'hotasc': order = [func.count(ub.Downloads.book_id).asc()] - if sort is None: - sort = "new" - return order, sort + if sort_param is None: + sort_param = "new" + return order, sort_param -def render_books_list(data, sort, book_id, page): - order = get_sort_function(sort, data) +def render_books_list(data, sort_param, book_id, page): + order = get_sort_function(sort_param, data) if data == "rated": return render_rated_books(page, book_id, order=order) elif data == "discover": - return render_discover_books(page, book_id) + return render_discover_books(book_id) elif data == "unread": return render_read_books(page, False, order=order) elif data == "read": @@ -404,21 +392,22 @@ def render_books_list(data, sort, book_id, page): elif data == "archived": return render_archived_books(page, order) elif data == "search": - term = (request.args.get('query') or '') + term = json.loads(flask_session.get('query', '')) offset = int(int(config.config_books_per_page) * (page - 1)) return render_search_results(term, offset, order, config.config_books_per_page) elif data == "advsearch": - term = json.loads(flask_session['query']) + term = json.loads(flask_session.get('query', '{}')) offset = int(int(config.config_books_per_page) * (page - 1)) return render_adv_search_results(term, offset, order, config.config_books_per_page) else: website = data or "newest" entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, True, order[0], + True, config.config_read_column, db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series) return render_title_template('index.html', random=random, entries=entries, pagination=pagination, - title=_(u"Books"), page=website, order=order[1]) + title=_("Books"), page=website, order=order[1]) def render_rated_books(page, book_id, order): @@ -427,53 +416,61 @@ def render_rated_books(page, book_id, order): db.Books, db.Books.ratings.any(db.Ratings.rating > 9), order[0], + True, config.config_read_column, db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series) return render_title_template('index.html', random=random, entries=entries, pagination=pagination, - id=book_id, title=_(u"Top Rated Books"), page="rated", order=order[1]) + id=book_id, title=_("Top Rated Books"), page="rated", order=order[1]) else: abort(404) -def render_discover_books(page, book_id): +def render_discover_books(book_id): if current_user.check_visibility(constants.SIDEBAR_RANDOM): - entries, __, pagination = calibre_db.fill_indexpage(page, 0, db.Books, True, [func.randomblob(2)]) + entries, __, ___ = calibre_db.fill_indexpage(1, 0, db.Books, True, [func.randomblob(2)], + join_archive_read=True, + config_read_column=config.config_read_column) pagination = Pagination(1, config.config_books_per_page, config.config_books_per_page) - return render_title_template('discover.html', entries=entries, pagination=pagination, id=book_id, - title=_(u"Discover (Random Books)"), page="discover") + return render_title_template('index.html', random=false(), entries=entries, pagination=pagination, id=book_id, + title=_("Discover (Random Books)"), page="discover") else: abort(404) + def render_hot_books(page, order): if current_user.check_visibility(constants.SIDEBAR_HOT): if order[1] not in ['hotasc', 'hotdesc']: - # Unary expression comparsion only working (for this expression) in sqlalchemy 1.4+ - #if not (order[0][0].compare(func.count(ub.Downloads.book_id).desc()) or - # order[0][0].compare(func.count(ub.Downloads.book_id).asc())): + # Unary expression comparison only working (for this expression) in sqlalchemy 1.4+ + # if not (order[0][0].compare(func.count(ub.Downloads.book_id).desc()) or + # order[0][0].compare(func.count(ub.Downloads.book_id).asc())): order = [func.count(ub.Downloads.book_id).desc()], 'hotdesc' if current_user.show_detail_random(): - random = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()) \ - .order_by(func.random()).limit(config.config_random_books) + random_query = calibre_db.generate_linked_query(config.config_read_column, db.Books) + random = (random_query.filter(calibre_db.common_filters()) + .order_by(func.random()) + .limit(config.config_random_books).all()) else: random = false() + off = int(int(config.config_books_per_page) * (page - 1)) - all_books = ub.session.query(ub.Downloads, func.count(ub.Downloads.book_id))\ + all_books = ub.session.query(ub.Downloads, func.count(ub.Downloads.book_id)) \ .order_by(*order[0]).group_by(ub.Downloads.book_id) hot_books = all_books.offset(off).limit(config.config_books_per_page) entries = list() for book in hot_books: - downloadBook = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()).filter( - db.Books.id == book.Downloads.book_id).first() - if downloadBook: - entries.append(downloadBook) + query = calibre_db.generate_linked_query(config.config_read_column, db.Books) + download_book = query.filter(calibre_db.common_filters()).filter( + book.Downloads.book_id == db.Books.id).first() + if download_book: + entries.append(download_book) else: ub.delete_download(book.Downloads.book_id) - numBooks = entries.__len__() - pagination = Pagination(page, config.config_books_per_page, numBooks) + num_books = entries.__len__() + pagination = Pagination(page, config.config_books_per_page, num_books) return render_title_template('index.html', random=random, entries=entries, pagination=pagination, - title=_(u"Hot Books (Most Downloaded)"), page="hot", order=order[1]) + title=_("Hot Books (Most Downloaded)"), page="hot", order=order[1]) else: abort(404) @@ -484,32 +481,27 @@ def render_downloaded_books(page, order, user_id): else: user_id = current_user.id if current_user.check_visibility(constants.SIDEBAR_DOWNLOAD): - if current_user.show_detail_random(): - random = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()) \ - .order_by(func.random()).limit(config.config_random_books) - else: - random = false() - - entries, __, pagination = calibre_db.fill_indexpage(page, + entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, ub.Downloads.user_id == user_id, order[0], + True, config.config_read_column, db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series, ub.Downloads, db.Books.id == ub.Downloads.book_id) for book in entries: - if not calibre_db.session.query(db.Books).filter(calibre_db.common_filters()) \ - .filter(db.Books.id == book.id).first(): - ub.delete_download(book.id) + if not (calibre_db.session.query(db.Books).filter(calibre_db.common_filters()) + .filter(db.Books.id == book.Books.id).first()): + ub.delete_download(book.Books.id) user = ub.session.query(ub.User).filter(ub.User.id == user_id).first() return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=user_id, - title=_(u"Downloaded books by %(user)s",user=user.name), + title=_("Downloaded books by %(user)s", user=user.name), page="download", order=order[1]) else: @@ -521,11 +513,12 @@ def render_author_books(page, author_id, order): db.Books, db.Books.authors.any(db.Authors.id == author_id), [order[0][0], db.Series.name, db.Books.series_index], + True, config.config_read_column, db.books_series_link, - db.Books.id == db.books_series_link.c.book, + db.books_series_link.c.book == db.Books.id, db.Series) if entries is None or not len(entries): - flash(_(u"Oops! Selected book title is unavailable. File does not exist or is not accessible"), + flash(_("Oops! Selected book is unavailable. File does not exist or is not accessible"), category="error") return redirect(url_for("web.index")) if constants.sqlalchemy_version2: @@ -538,55 +531,102 @@ def render_author_books(page, author_id, order): other_books = [] if services.goodreads_support and config.config_use_goodreads: author_info = services.goodreads_support.get_author_info(author_name) - other_books = services.goodreads_support.get_other_books(author_info, entries) - + book_entries = [entry.Books for entry in entries] + other_books = services.goodreads_support.get_other_books(author_info, book_entries) return render_title_template('author.html', entries=entries, pagination=pagination, id=author_id, - title=_(u"Author: %(name)s", name=author_name), author=author_info, + title=_("Author: %(name)s", name=author_name), author=author_info, other_books=other_books, page="author", order=order[1]) def render_publisher_books(page, book_id, order): - publisher = calibre_db.session.query(db.Publishers).filter(db.Publishers.id == book_id).first() - if publisher: + if book_id == '-1': entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, - db.Books.publishers.any(db.Publishers.id == book_id), + db.Publishers.name == None, [db.Series.name, order[0][0], db.Books.series_index], + True, config.config_read_column, + db.books_publishers_link, + db.Books.id == db.books_publishers_link.c.book, + db.Publishers, db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series) - return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id, - title=_(u"Publisher: %(name)s", name=publisher.name), - page="publisher", - order=order[1]) + publisher = _("None") else: - abort(404) + publisher = calibre_db.session.query(db.Publishers).filter(db.Publishers.id == book_id).first() + if publisher: + entries, random, pagination = calibre_db.fill_indexpage(page, 0, + db.Books, + db.Books.publishers.any( + db.Publishers.id == book_id), + [db.Series.name, order[0][0], + db.Books.series_index], + True, config.config_read_column, + db.books_series_link, + db.Books.id == db.books_series_link.c.book, + db.Series) + publisher = publisher.name + else: + abort(404) + + return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id, + title=_("Publisher: %(name)s", name=publisher), + page="publisher", + order=order[1]) def render_series_books(page, book_id, order): - name = calibre_db.session.query(db.Series).filter(db.Series.id == book_id).first() - if name: + if book_id == '-1': entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, - db.Books.series.any(db.Series.id == book_id), - [order[0][0]]) - return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id, - title=_(u"Series: %(serie)s", serie=name.name), page="series", order=order[1]) + db.Series.name == None, + [order[0][0]], + True, config.config_read_column, + db.books_series_link, + db.Books.id == db.books_series_link.c.book, + db.Series) + series_name = _("None") else: - abort(404) + series_name = calibre_db.session.query(db.Series).filter(db.Series.id == book_id).first() + if series_name: + entries, random, pagination = calibre_db.fill_indexpage(page, 0, + db.Books, + db.Books.series.any(db.Series.id == book_id), + [order[0][0]], + True, config.config_read_column) + series_name = series_name.name + else: + abort(404) + return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id, + title=_("Series: %(serie)s", serie=series_name), page="series", order=order[1]) def render_ratings_books(page, book_id, order): - name = calibre_db.session.query(db.Ratings).filter(db.Ratings.id == book_id).first() - entries, random, pagination = calibre_db.fill_indexpage(page, 0, - db.Books, - db.Books.ratings.any(db.Ratings.id == book_id), - [order[0][0]]) - if name and name.rating <= 10: + if book_id == '-1': + db_filter = coalesce(db.Ratings.rating, 0) < 1 + entries, random, pagination = calibre_db.fill_indexpage(page, 0, + db.Books, + db_filter, + [order[0][0]], + True, config.config_read_column, + db.books_series_link, + db.Books.id == db.books_series_link.c.book, + db.Series, + db.books_ratings_link, db.Ratings) + title = _("Rating: None") + rating = -1 + else: + name = calibre_db.session.query(db.Ratings).filter(db.Ratings.id == book_id).first() + entries, random, pagination = calibre_db.fill_indexpage(page, 0, + db.Books, + db.Books.ratings.any(db.Ratings.id == book_id), + [order[0][0]], + True, config.config_read_column) + title = _("Rating: %(rating)s stars", rating=int(name.rating / 2)) + rating = name.rating + if title and rating <= 10: return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id, - title=_(u"Rating: %(rating)s stars", rating=int(name.rating / 2)), - page="ratings", - order=order[1]) + title=title, page="ratings", order=order[1]) else: abort(404) @@ -597,9 +637,10 @@ def render_formats_books(page, book_id, order): entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, db.Books.data.any(db.Data.format == book_id.upper()), - [order[0][0]]) + [order[0][0]], + True, config.config_read_column) return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id, - title=_(u"File format: %(format)s", format=name.format), + title=_("File format: %(format)s", format=name.format), page="formats", order=order[1]) else: @@ -607,154 +648,131 @@ def render_formats_books(page, book_id, order): def render_category_books(page, book_id, order): - name = calibre_db.session.query(db.Tags).filter(db.Tags.id == book_id).first() - if name: + if book_id == '-1': entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, - db.Books.tags.any(db.Tags.id == book_id), + db.Tags.name == None, [order[0][0], db.Series.name, db.Books.series_index], + True, config.config_read_column, + db.books_tags_link, + db.Books.id == db.books_tags_link.c.book, + db.Tags, db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series) - return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id, - title=_(u"Category: %(name)s", name=name.name), page="category", order=order[1]) + tagsname = _("None") else: - abort(404) + tagsname = calibre_db.session.query(db.Tags).filter(db.Tags.id == book_id).first() + if tagsname: + entries, random, pagination = calibre_db.fill_indexpage(page, 0, + db.Books, + db.Books.tags.any(db.Tags.id == book_id), + [order[0][0], db.Series.name, + db.Books.series_index], + True, config.config_read_column, + db.books_series_link, + db.Books.id == db.books_series_link.c.book, + db.Series) + tagsname = tagsname.name + else: + abort(404) + return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id, + title=_("Category: %(name)s", name=tagsname), page="category", order=order[1]) def render_language_books(page, name, order): try: - lang_name = isoLanguages.get_language_name(get_locale(), name) + if name.lower() != "none": + lang_name = isoLanguages.get_language_name(get_locale(), name) + else: + lang_name = _("None") except KeyError: abort(404) - - entries, random, pagination = calibre_db.fill_indexpage(page, 0, - db.Books, - db.Books.languages.any(db.Languages.lang_code == name), - [order[0][0]]) + if name == "none": + entries, random, pagination = calibre_db.fill_indexpage(page, 0, + db.Books, + db.Languages.lang_code == None, + [order[0][0]], + True, config.config_read_column, + db.books_languages_link, + db.Books.id == db.books_languages_link.c.book, + db.Languages) + else: + entries, random, pagination = calibre_db.fill_indexpage(page, 0, + db.Books, + db.Books.languages.any(db.Languages.lang_code == name), + [order[0][0]], + True, config.config_read_column) return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=name, - title=_(u"Language: %(name)s", name=lang_name), page="language", order=order[1]) + title=_("Language: %(name)s", name=lang_name), page="language", order=order[1]) def render_read_books(page, are_read, as_xml=False, order=None): - sort = order[0] if order else [] + sort_param = order[0] if order else [] if not config.config_read_column: if are_read: db_filter = and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED) else: db_filter = coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED - entries, random, pagination = calibre_db.fill_indexpage(page, 0, - db.Books, - db_filter, - sort, - db.books_series_link, - db.Books.id == db.books_series_link.c.book, - db.Series, - ub.ReadBook, db.Books.id == ub.ReadBook.book_id) else: try: if are_read: db_filter = db.cc_classes[config.config_read_column].value == True else: db_filter = coalesce(db.cc_classes[config.config_read_column].value, False) != True - entries, random, pagination = calibre_db.fill_indexpage(page, 0, - db.Books, - db_filter, - sort, - db.books_series_link, - db.Books.id == db.books_series_link.c.book, - db.Series, - db.cc_classes[config.config_read_column]) - except (KeyError, AttributeError): - log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column) + except (KeyError, AttributeError, IndexError): + log.error("Custom Column No.{} does not exist in calibre database".format(config.config_read_column)) if not as_xml: - flash(_("Custom Column No.%(column)d is not existing in calibre database", + flash(_("Custom Column No.%(column)d does not exist in calibre database", column=config.config_read_column), category="error") return redirect(url_for("web.index")) - # ToDo: Handle error Case for opds + return [] # ToDo: Handle error Case for opds + + entries, random, pagination = calibre_db.fill_indexpage(page, 0, + db.Books, + db_filter, + sort_param, + True, config.config_read_column, + db.books_series_link, + db.Books.id == db.books_series_link.c.book, + db.Series) + if as_xml: return entries, pagination else: if are_read: - name = _(u'Read Books') + ' (' + str(pagination.total_count) + ')' - pagename = "read" + name = _('Read Books') + ' (' + str(pagination.total_count) + ')' + page_name = "read" else: - name = _(u'Unread Books') + ' (' + str(pagination.total_count) + ')' - pagename = "unread" + name = _('Unread Books') + ' (' + str(pagination.total_count) + ')' + page_name = "unread" return render_title_template('index.html', random=random, entries=entries, pagination=pagination, - title=name, page=pagename, order=order[1]) + title=name, page=page_name, order=order[1]) -def render_archived_books(page, sort): - order = sort[0] or [] - archived_books = ( - ub.session.query(ub.ArchivedBook) - .filter(ub.ArchivedBook.user_id == int(current_user.id)) - .filter(ub.ArchivedBook.is_archived == True) - .all() - ) +def render_archived_books(page, sort_param): + order = sort_param[0] or [] + archived_books = (ub.session.query(ub.ArchivedBook) + .filter(ub.ArchivedBook.user_id == int(current_user.id)) + .filter(ub.ArchivedBook.is_archived == True) + .all()) archived_book_ids = [archived_book.book_id for archived_book in archived_books] archived_filter = db.Books.id.in_(archived_book_ids) - entries, random, pagination = calibre_db.fill_indexpage_with_archived_books(page, 0, - db.Books, + entries, random, pagination = calibre_db.fill_indexpage_with_archived_books(page, db.Books, + 0, archived_filter, order, - allow_show_archived=True) + True, + True, config.config_read_column) - name = _(u'Archived Books') + ' (' + str(len(archived_book_ids)) + ')' - pagename = "archived" + name = _('Archived Books') + ' (' + str(len(archived_book_ids)) + ')' + page_name = "archived" return render_title_template('index.html', random=random, entries=entries, pagination=pagination, - title=name, page=pagename, order=sort[1]) - - -def render_prepare_search_form(cc): - # prepare data for search-form - tags = calibre_db.session.query(db.Tags)\ - .join(db.books_tags_link)\ - .join(db.Books)\ - .filter(calibre_db.common_filters()) \ - .group_by(text('books_tags_link.tag'))\ - .order_by(db.Tags.name).all() - series = calibre_db.session.query(db.Series)\ - .join(db.books_series_link)\ - .join(db.Books)\ - .filter(calibre_db.common_filters()) \ - .group_by(text('books_series_link.series'))\ - .order_by(db.Series.name)\ - .filter(calibre_db.common_filters()).all() - shelves = ub.session.query(ub.Shelf)\ - .filter(or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == int(current_user.id)))\ - .order_by(ub.Shelf.name).all() - extensions = calibre_db.session.query(db.Data)\ - .join(db.Books)\ - .filter(calibre_db.common_filters()) \ - .group_by(db.Data.format)\ - .order_by(db.Data.format).all() - if current_user.filter_language() == u"all": - languages = calibre_db.speaking_language() - else: - languages = None - return render_title_template('search_form.html', tags=tags, languages=languages, extensions=extensions, - series=series,shelves=shelves, title=_(u"Advanced Search"), cc=cc, page="advsearch") - - -def render_search_results(term, offset=None, order=None, limit=None): - join = db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series - entries, result_count, pagination = calibre_db.get_search_results(term, offset, order, limit, *join) - return render_title_template('search.html', - searchterm=term, - pagination=pagination, - query=term, - adv_searchterm=term, - entries=entries, - result_count=result_count, - title=_(u"Search"), - page="search", - order=order[1]) + title=name, page=page_name, order=sort_param[1]) # ################################### View Books list ################################################################## @@ -781,76 +799,95 @@ def books_list(data, sort_param, book_id, page): @login_required def books_table(): visibility = current_user.view_settings.get('table', {}) - cc = get_cc_columns(filter_config_custom_read=True) - return render_title_template('book_table.html', title=_(u"Books List"), cc=cc, page="book_table", + cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True) + return render_title_template('book_table.html', title=_("Books List"), cc=cc, page="book_table", visiblility=visibility) + @web.route("/ajax/listbooks") @login_required def list_books(): off = int(request.args.get("offset") or 0) limit = int(request.args.get("limit") or config.config_books_per_page) - search = request.args.get("search") - sort = request.args.get("sort", "id") + search_param = request.args.get("search") + sort_param = request.args.get("sort", "id") order = request.args.get("order", "").lower() state = None join = tuple() - if sort == "state": + if sort_param == "state": state = json.loads(request.args.get("state", "[]")) - # order = [db.Books.timestamp.asc()] if order == "asc" else [db.Books.timestamp.desc()] # ToDo wrong: sort ticked - elif sort == "tags": + elif sort_param == "tags": order = [db.Tags.name.asc()] if order == "asc" else [db.Tags.name.desc()] - join = db.books_tags_link,db.Books.id == db.books_tags_link.c.book, db.Tags - elif sort == "series": + join = db.books_tags_link, db.Books.id == db.books_tags_link.c.book, db.Tags + elif sort_param == "series": order = [db.Series.name.asc()] if order == "asc" else [db.Series.name.desc()] - join = db.books_series_link,db.Books.id == db.books_series_link.c.book, db.Series - elif sort == "publishers": + join = db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series + elif sort_param == "publishers": order = [db.Publishers.name.asc()] if order == "asc" else [db.Publishers.name.desc()] - join = db.books_publishers_link,db.Books.id == db.books_publishers_link.c.book, db.Publishers - elif sort == "authors": + join = db.books_publishers_link, db.Books.id == db.books_publishers_link.c.book, db.Publishers + elif sort_param == "authors": order = [db.Authors.name.asc(), db.Series.name, db.Books.series_index] if order == "asc" \ else [db.Authors.name.desc(), db.Series.name.desc(), db.Books.series_index.desc()] - join = db.books_authors_link, db.Books.id == db.books_authors_link.c.book, db.Authors, \ - db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series - elif sort == "languages": + join = db.books_authors_link, db.Books.id == db.books_authors_link.c.book, db.Authors, db.books_series_link, \ + db.Books.id == db.books_series_link.c.book, db.Series + elif sort_param == "languages": order = [db.Languages.lang_code.asc()] if order == "asc" else [db.Languages.lang_code.desc()] join = db.books_languages_link, db.Books.id == db.books_languages_link.c.book, db.Languages - elif order and sort in ["sort", "title", "authors_sort", "series_index"]: - order = [text(sort + " " + order)] + elif order and sort_param in ["sort", "title", "authors_sort", "series_index"]: + order = [text(sort_param + " " + order)] elif not state: order = [db.Books.timestamp.desc()] - total_count = filtered_count = calibre_db.session.query(db.Books).filter(calibre_db.common_filters(False)).count() - + total_count = filtered_count = calibre_db.session.query(db.Books).filter( + calibre_db.common_filters(allow_show_archived=True)).count() if state is not None: - if search: - books = calibre_db.search_query(search).all() + if search_param: + books = calibre_db.search_query(search_param, config).all() filtered_count = len(books) else: - books = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()).all() - entries = calibre_db.get_checkbox_sorted(books, state, off, limit, order) - elif search: - entries, filtered_count, __ = calibre_db.get_search_results(search, off, order, limit, *join) + query = calibre_db.generate_linked_query(config.config_read_column, db.Books) + books = query.filter(calibre_db.common_filters(allow_show_archived=True)).all() + entries = calibre_db.get_checkbox_sorted(books, state, off, limit, order, True) + elif search_param: + entries, filtered_count, __ = calibre_db.get_search_results(search_param, + config, + off, + [order, ''], + limit, + *join) else: - entries, __, __ = calibre_db.fill_indexpage((int(off) / (int(limit)) + 1), limit, db.Books, True, order, *join) + entries, __, __ = calibre_db.fill_indexpage_with_archived_books((int(off) / (int(limit)) + 1), + db.Books, + limit, + True, + order, + True, + True, + config.config_read_column, + *join) + result = list() for entry in entries: - for index in range(0, len(entry.languages)): - entry.languages[index].language_name = isoLanguages.get_language_name(get_locale(), entry.languages[ - index].lang_code) - table_entries = {'totalNotFiltered': total_count, 'total': filtered_count, "rows": entries} + val = entry[0] + val.is_archived = entry[1] is True + val.read_status = entry[2] == ub.ReadBook.STATUS_FINISHED + for lang_index in range(0, len(val.languages)): + val.languages[lang_index].language_name = isoLanguages.get_language_name(get_locale(), val.languages[ + lang_index].lang_code) + result.append(val) + + table_entries = {'totalNotFiltered': total_count, 'total': filtered_count, "rows": result} js_list = json.dumps(table_entries, cls=db.AlchemyEncoder) response = make_response(js_list) response.headers["Content-Type"] = "application/json; charset=utf-8" return response + @web.route("/ajax/table_settings", methods=['POST']) @login_required def update_table_settings(): - # vals = request.get_json() - # ToDo: Save table settings current_user.view_settings['table'] = json.loads(request.data) try: try: @@ -877,19 +914,18 @@ def author_list(): entries = calibre_db.session.query(db.Authors, func.count('books_authors_link.book').label('count')) \ .join(db.books_authors_link).join(db.Books).filter(calibre_db.common_filters()) \ .group_by(text('books_authors_link.author')).order_by(order).all() - charlist = calibre_db.session.query(func.upper(func.substr(db.Authors.sort, 1, 1)).label('char')) \ - .join(db.books_authors_link).join(db.Books).filter(calibre_db.common_filters()) \ - .group_by(func.upper(func.substr(db.Authors.sort, 1, 1))).all() + char_list = query_char_list(db.Authors.sort, db.books_authors_link) # If not creating a copy, readonly databases can not display authornames with "|" in it as changing the name # starts a change session - autor_copy = copy.deepcopy(entries) - for entry in autor_copy: + author_copy = copy.deepcopy(entries) + for entry in author_copy: entry.Authors.name = entry.Authors.name.replace('|', ',') - return render_title_template('list.html', entries=autor_copy, folder='web.books_list', charlist=charlist, - title=u"Authors", page="authorlist", data='author', order=order_no) + return render_title_template('list.html', entries=author_copy, folder='web.books_list', charlist=char_list, + title="Authors", page="authorlist", data='author', order=order_no) else: abort(404) + @web.route("/downloadlist") @login_required_if_no_ano def download_list(): @@ -900,13 +936,13 @@ def download_list(): order = ub.User.name.asc() order_no = 1 if current_user.check_visibility(constants.SIDEBAR_DOWNLOAD) and current_user.role_admin(): - entries = ub.session.query(ub.User, func.count(ub.Downloads.book_id).label('count'))\ + entries = ub.session.query(ub.User, func.count(ub.Downloads.book_id).label('count')) \ .join(ub.Downloads).group_by(ub.Downloads.user_id).order_by(order).all() - charlist = ub.session.query(func.upper(func.substr(ub.User.name, 1, 1)).label('char')) \ + char_list = ub.session.query(func.upper(func.substr(ub.User.name, 1, 1)).label('char')) \ .filter(ub.User.role.op('&')(constants.ROLE_ANONYMOUS) != constants.ROLE_ANONYMOUS) \ .group_by(func.upper(func.substr(ub.User.name, 1, 1))).all() - return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist, - title=_(u"Downloads"), page="downloadlist", data="download", order=order_no) + return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=char_list, + title=_("Downloads"), page="downloadlist", data="download", order=order_no) else: abort(404) @@ -924,11 +960,17 @@ def publisher_list(): entries = calibre_db.session.query(db.Publishers, func.count('books_publishers_link.book').label('count')) \ .join(db.books_publishers_link).join(db.Books).filter(calibre_db.common_filters()) \ .group_by(text('books_publishers_link.publisher')).order_by(order).all() - charlist = calibre_db.session.query(func.upper(func.substr(db.Publishers.name, 1, 1)).label('char')) \ - .join(db.books_publishers_link).join(db.Books).filter(calibre_db.common_filters()) \ - .group_by(func.upper(func.substr(db.Publishers.name, 1, 1))).all() - return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist, - title=_(u"Publishers"), page="publisherlist", data="publisher", order=order_no) + no_publisher_count = (calibre_db.session.query(db.Books) + .outerjoin(db.books_publishers_link).outerjoin(db.Publishers) + .filter(db.Publishers.name == None) + .filter(calibre_db.common_filters()) + .count()) + if no_publisher_count: + entries.append([db.Category(_("None"), "-1"), no_publisher_count]) + entries = sorted(entries, key=lambda x: x[0].name.lower(), reverse=not order_no) + char_list = generate_char_list(entries) + return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=char_list, + title=_("Publishers"), page="publisherlist", data="publisher", order=order_no) else: abort(404) @@ -943,26 +985,28 @@ def series_list(): else: order = db.Series.sort.asc() order_no = 1 + char_list = query_char_list(db.Series.sort, db.books_series_link) if current_user.get_view_property('series', 'series_view') == 'list': entries = calibre_db.session.query(db.Series, func.count('books_series_link.book').label('count')) \ .join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters()) \ .group_by(text('books_series_link.series')).order_by(order).all() - charlist = calibre_db.session.query(func.upper(func.substr(db.Series.sort, 1, 1)).label('char')) \ - .join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters()) \ - .group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all() - return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist, - title=_(u"Series"), page="serieslist", data="series", order=order_no) + no_series_count = (calibre_db.session.query(db.Books) + .outerjoin(db.books_series_link).outerjoin(db.Series) + .filter(db.Series.name == None) + .filter(calibre_db.common_filters()) + .count()) + if no_series_count: + entries.append([db.Category(_("None"), "-1"), no_series_count]) + entries = sorted(entries, key=lambda x: x[0].name.lower(), reverse=not order_no) + return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=char_list, + title=_("Series"), page="serieslist", data="series", order=order_no) else: entries = calibre_db.session.query(db.Books, func.count('books_series_link').label('count'), func.max(db.Books.series_index), db.Books.id) \ - .join(db.books_series_link).join(db.Series).filter(calibre_db.common_filters())\ + .join(db.books_series_link).join(db.Series).filter(calibre_db.common_filters()) \ .group_by(text('books_series_link.series')).order_by(order).all() - charlist = calibre_db.session.query(func.upper(func.substr(db.Series.sort, 1, 1)).label('char')) \ - .join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters()) \ - .group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all() - - return render_title_template('grid.html', entries=entries, folder='web.books_list', charlist=charlist, - title=_(u"Series"), page="serieslist", data="series", bodyClass="grid-view", + return render_title_template('grid.html', entries=entries, folder='web.books_list', charlist=char_list, + title=_("Series"), page="serieslist", data="series", bodyClass="grid-view", order=order_no) else: abort(404) @@ -979,11 +1023,19 @@ def ratings_list(): order = db.Ratings.rating.asc() order_no = 1 entries = calibre_db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'), - (db.Ratings.rating / 2).label('name')) \ + (db.Ratings.rating / 2).label('name')) \ .join(db.books_ratings_link).join(db.Books).filter(calibre_db.common_filters()) \ + .filter(db.Ratings.rating > 0) \ .group_by(text('books_ratings_link.rating')).order_by(order).all() + no_rating_count = (calibre_db.session.query(db.Books) + .outerjoin(db.books_ratings_link).outerjoin(db.Ratings) + .filter(or_(db.Ratings.rating == None, db.Ratings.rating == 0)) + .filter(calibre_db.common_filters()) + .count()) + entries.append([db.Category(_("None"), "-1", -1), no_rating_count]) + entries = sorted(entries, key=lambda x: x[0].rating, reverse=not order_no) return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=list(), - title=_(u"Ratings list"), page="ratingslist", data="ratings", order=order_no) + title=_("Ratings list"), page="ratingslist", data="ratings", order=order_no) else: abort(404) @@ -1003,8 +1055,14 @@ def formats_list(): db.Data.format.label('format')) \ .join(db.Books).filter(calibre_db.common_filters()) \ .group_by(db.Data.format).order_by(order).all() + no_format_count = (calibre_db.session.query(db.Books).outerjoin(db.Data) + .filter(db.Data.format == None) + .filter(calibre_db.common_filters()) + .count()) + if no_format_count: + entries.append([db.Category(_("None"), "-1"), no_format_count]) return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=list(), - title=_(u"File formats list"), page="formatslist", data="formats", order=order_no) + title=_("File formats list"), page="formatslist", data="formats", order=order_no) else: abort(404) @@ -1012,30 +1070,12 @@ def formats_list(): @web.route("/language") @login_required_if_no_ano def language_overview(): - if current_user.check_visibility(constants.SIDEBAR_LANGUAGE): - charlist = list() - if current_user.filter_language() == u"all": - languages = calibre_db.speaking_language() - # ToDo: generate first character list for languages - else: - #try: - # cur_l = LC.parse(current_user.filter_language()) - #except UnknownLocaleError: - # cur_l = None - - languages = calibre_db.session.query(db.Languages).filter( - db.Languages.lang_code == current_user.filter_language()).all() - languages[0].name = isoLanguages.get_language_name(get_locale(), languages[0].name.lang_code) - #if cur_l: - # languages[0].name = cur_l.get_language_name(get_locale()) - #else: - # languages[0].name = _(isoLanguages.get(part3=languages[0].lang_code).name) - lang_counter = calibre_db.session.query(db.books_languages_link, - func.count('books_languages_link.book').label('bookcount')).group_by( - text('books_languages_link.lang_code')).all() - return render_title_template('languages.html', languages=languages, lang_counter=lang_counter, - charlist=charlist, title=_(u"Languages"), page="langlist", - data="language") + if current_user.check_visibility(constants.SIDEBAR_LANGUAGE) and current_user.filter_language() == "all": + order_no = 0 if current_user.get_view_property('language', 'dir') == 'desc' else 1 + languages = calibre_db.speaking_language(reverse_order=not order_no, with_count=True) + char_list = generate_char_list(languages) + return render_title_template('list.html', entries=languages, folder='web.books_list', charlist=char_list, + title=_("Languages"), page="langlist", data="language", order=order_no) else: abort(404) @@ -1052,364 +1092,64 @@ def category_list(): order_no = 1 entries = calibre_db.session.query(db.Tags, func.count('books_tags_link.book').label('count')) \ .join(db.books_tags_link).join(db.Books).order_by(order).filter(calibre_db.common_filters()) \ - .group_by(text('books_tags_link.tag')).all() - charlist = calibre_db.session.query(func.upper(func.substr(db.Tags.name, 1, 1)).label('char')) \ - .join(db.books_tags_link).join(db.Books).filter(calibre_db.common_filters()) \ - .group_by(func.upper(func.substr(db.Tags.name, 1, 1))).all() - return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist, - title=_(u"Categories"), page="catlist", data="category", order=order_no) + .group_by(db.Tags.id).all() + no_tag_count = (calibre_db.session.query(db.Books) + .outerjoin(db.books_tags_link).outerjoin(db.Tags) + .filter(db.Tags.name == None) + .filter(calibre_db.common_filters()) + .count()) + if no_tag_count: + entries.append([db.Category(_("None"), "-1"), no_tag_count]) + entries = sorted(entries, key=lambda x: x[0].name.lower(), reverse=not order_no) + char_list = generate_char_list(entries) + return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=char_list, + title=_("Categories"), page="catlist", data="category", order=order_no) else: abort(404) -# ################################### Task functions ################################################################ - - -@web.route("/tasks") -@login_required -def get_tasks_status(): - # if current user admin, show all email, otherwise only own emails - tasks = WorkerThread.getInstance().tasks - answer = render_task_status(tasks) - return render_title_template('tasks.html', entries=answer, title=_(u"Tasks"), page="tasks") - - -@app.route("/reconnect") -def reconnect(): - calibre_db.reconnect_db(config, ub.app_DB_path) - return json.dumps({}) - - -# ################################### Search functions ################################################################ - -@web.route("/search", methods=["GET"]) -@login_required_if_no_ano -def search(): - term = request.args.get("query") - if term: - return redirect(url_for('web.books_list', data="search", sort_param='stored', query=term)) - else: - return render_title_template('search.html', - searchterm="", - result_count=0, - title=_(u"Search"), - page="search") - - -@web.route("/advsearch", methods=['POST']) -@login_required_if_no_ano -def advanced_search(): - values = dict(request.form) - params = ['include_tag', 'exclude_tag', 'include_serie', 'exclude_serie', 'include_shelf', 'exclude_shelf', - 'include_language', 'exclude_language', 'include_extension', 'exclude_extension'] - for param in params: - values[param] = list(request.form.getlist(param)) - flask_session['query'] = json.dumps(values) - return redirect(url_for('web.books_list', data="advsearch", sort_param='stored', query="")) - - -def adv_search_custom_columns(cc, term, q): - for c in cc: - if c.datatype == "datetime": - custom_start = term.get('custom_column_' + str(c.id) + '_start') - custom_end = term.get('custom_column_' + str(c.id) + '_end') - if custom_start: - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - func.datetime(db.cc_classes[c.id].value) >= func.datetime(custom_start))) - if custom_end: - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - func.datetime(db.cc_classes[c.id].value) <= func.datetime(custom_end))) - else: - custom_query = term.get('custom_column_' + str(c.id)) - if custom_query != '' and custom_query is not None: - if c.datatype == 'bool': - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - db.cc_classes[c.id].value == (custom_query == "True"))) - elif c.datatype == 'int' or c.datatype == 'float': - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - db.cc_classes[c.id].value == custom_query)) - elif c.datatype == 'rating': - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - db.cc_classes[c.id].value == int(float(custom_query) * 2))) - else: - q = q.filter(getattr(db.Books, 'custom_column_' + str(c.id)).any( - func.lower(db.cc_classes[c.id].value).ilike("%" + custom_query + "%"))) - return q - - -def adv_search_language(q, include_languages_inputs, exclude_languages_inputs): - if current_user.filter_language() != "all": - q = q.filter(db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())) - else: - for language in include_languages_inputs: - q = q.filter(db.Books.languages.any(db.Languages.id == language)) - for language in exclude_languages_inputs: - q = q.filter(not_(db.Books.series.any(db.Languages.id == language))) - return q - - -def adv_search_ratings(q, rating_high, rating_low): - if rating_high: - rating_high = int(rating_high) * 2 - q = q.filter(db.Books.ratings.any(db.Ratings.rating <= rating_high)) - if rating_low: - rating_low = int(rating_low) * 2 - q = q.filter(db.Books.ratings.any(db.Ratings.rating >= rating_low)) - return q - - -def adv_search_read_status(q, read_status): - if read_status: - if config.config_read_column: - try: - if read_status == "True": - q = q.join(db.cc_classes[config.config_read_column], isouter=True) \ - .filter(db.cc_classes[config.config_read_column].value == True) - else: - q = q.join(db.cc_classes[config.config_read_column], isouter=True) \ - .filter(coalesce(db.cc_classes[config.config_read_column].value, False) != True) - except (KeyError, AttributeError): - log.error(u"Custom Column No.%d is not existing in calibre database", config.config_read_column) - flash(_("Custom Column No.%(column)d is not existing in calibre database", - column=config.config_read_column), - category="error") - return q - else: - if read_status == "True": - q = q.join(ub.ReadBook, db.Books.id == ub.ReadBook.book_id, isouter=True) \ - .filter(ub.ReadBook.user_id == int(current_user.id), - ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED) - else: - q = q.join(ub.ReadBook, db.Books.id == ub.ReadBook.book_id, isouter=True) \ - .filter(ub.ReadBook.user_id == int(current_user.id), - coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED) - return q - - -def adv_search_extension(q, include_extension_inputs, exclude_extension_inputs): - for extension in include_extension_inputs: - q = q.filter(db.Books.data.any(db.Data.format == extension)) - for extension in exclude_extension_inputs: - q = q.filter(not_(db.Books.data.any(db.Data.format == extension))) - return q - - -def adv_search_tag(q, include_tag_inputs, exclude_tag_inputs): - for tag in include_tag_inputs: - q = q.filter(db.Books.tags.any(db.Tags.id == tag)) - for tag in exclude_tag_inputs: - q = q.filter(not_(db.Books.tags.any(db.Tags.id == tag))) - return q - - -def adv_search_serie(q, include_series_inputs, exclude_series_inputs): - for serie in include_series_inputs: - q = q.filter(db.Books.series.any(db.Series.id == serie)) - for serie in exclude_series_inputs: - q = q.filter(not_(db.Books.series.any(db.Series.id == serie))) - return q - -def adv_search_shelf(q, include_shelf_inputs, exclude_shelf_inputs): - q = q.outerjoin(ub.BookShelf, db.Books.id == ub.BookShelf.book_id)\ - .filter(or_(ub.BookShelf.shelf == None, ub.BookShelf.shelf.notin_(exclude_shelf_inputs))) - if len(include_shelf_inputs) > 0: - q = q.filter(ub.BookShelf.shelf.in_(include_shelf_inputs)) - return q - -def extend_search_term(searchterm, - author_name, - book_title, - publisher, - pub_start, - pub_end, - tags, - rating_high, - rating_low, - read_status, - ): - searchterm.extend((author_name.replace('|', ','), book_title, publisher)) - if pub_start: - try: - searchterm.extend([_(u"Published after ") + - format_date(datetime.strptime(pub_start, "%Y-%m-%d"), - format='medium', locale=get_locale())]) - except ValueError: - pub_start = u"" - if pub_end: - try: - searchterm.extend([_(u"Published before ") + - format_date(datetime.strptime(pub_end, "%Y-%m-%d"), - format='medium', locale=get_locale())]) - except ValueError: - pub_end = u"" - elements = {'tag': db.Tags, 'serie':db.Series, 'shelf':ub.Shelf} - for key, db_element in elements.items(): - tag_names = calibre_db.session.query(db_element).filter(db_element.id.in_(tags['include_' + key])).all() - searchterm.extend(tag.name for tag in tag_names) - tag_names = calibre_db.session.query(db_element).filter(db_element.id.in_(tags['exclude_' + key])).all() - searchterm.extend(tag.name for tag in tag_names) - language_names = calibre_db.session.query(db.Languages). \ - filter(db.Languages.id.in_(tags['include_language'])).all() - if language_names: - language_names = calibre_db.speaking_language(language_names) - searchterm.extend(language.name for language in language_names) - language_names = calibre_db.session.query(db.Languages). \ - filter(db.Languages.id.in_(tags['exclude_language'])).all() - if language_names: - language_names = calibre_db.speaking_language(language_names) - searchterm.extend(language.name for language in language_names) - if rating_high: - searchterm.extend([_(u"Rating <= %(rating)s", rating=rating_high)]) - if rating_low: - searchterm.extend([_(u"Rating >= %(rating)s", rating=rating_low)]) - if read_status: - searchterm.extend([_(u"Read Status = %(status)s", status=read_status)]) - searchterm.extend(ext for ext in tags['include_extension']) - searchterm.extend(ext for ext in tags['exclude_extension']) - # handle custom columns - searchterm = " + ".join(filter(None, searchterm)) - return searchterm, pub_start, pub_end - - -def render_adv_search_results(term, offset=None, order=None, limit=None): - sort = order[0] if order else [db.Books.sort] - pagination = None - - cc = get_cc_columns(filter_config_custom_read=True) - calibre_db.session.connection().connection.connection.create_function("lower", 1, db.lcase) - q = calibre_db.session.query(db.Books).outerjoin(db.books_series_link, db.Books.id == db.books_series_link.c.book)\ - .outerjoin(db.Series)\ - .filter(calibre_db.common_filters(True)) - - # parse multiselects to a complete dict - tags = dict() - elements = ['tag', 'serie', 'shelf', 'language', 'extension'] - for element in elements: - tags['include_' + element] = term.get('include_' + element) - tags['exclude_' + element] = term.get('exclude_' + element) - - author_name = term.get("author_name") - book_title = term.get("book_title") - publisher = term.get("publisher") - pub_start = term.get("publishstart") - pub_end = term.get("publishend") - rating_low = term.get("ratinghigh") - rating_high = term.get("ratinglow") - description = term.get("comment") - read_status = term.get("read_status") - if author_name: - author_name = author_name.strip().lower().replace(',', '|') - if book_title: - book_title = book_title.strip().lower() - if publisher: - publisher = publisher.strip().lower() - - searchterm = [] - cc_present = False - for c in cc: - if c.datatype == "datetime": - column_start = term.get('custom_column_' + str(c.id) + '_start') - column_end = term.get('custom_column_' + str(c.id) + '_end') - if column_start: - searchterm.extend([u"{} >= {}".format(c.name, - format_date(datetime.strptime(column_start, "%Y-%m-%d").date(), - format='medium', - locale=get_locale()) - )]) - cc_present = True - if column_end: - searchterm.extend([u"{} <= {}".format(c.name, - format_date(datetime.strptime(column_end, "%Y-%m-%d").date(), - format='medium', - locale=get_locale()) - )]) - cc_present = True - elif term.get('custom_column_' + str(c.id)): - searchterm.extend([(u"{}: {}".format(c.name, term.get('custom_column_' + str(c.id))))]) - cc_present = True - - - if any(tags.values()) or author_name or book_title or publisher or pub_start or pub_end or rating_low \ - or rating_high or description or cc_present or read_status: - searchterm, pub_start, pub_end = extend_search_term(searchterm, - author_name, - book_title, - publisher, - pub_start, - pub_end, - tags, - rating_high, - rating_low, - read_status) - q = q.filter() - if author_name: - q = q.filter(db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + author_name + "%"))) - if book_title: - q = q.filter(func.lower(db.Books.title).ilike("%" + book_title + "%")) - if pub_start: - q = q.filter(func.datetime(db.Books.pubdate) > func.datetime(pub_start)) - if pub_end: - q = q.filter(func.datetime(db.Books.pubdate) < func.datetime(pub_end)) - q = adv_search_read_status(q, read_status) - if publisher: - q = q.filter(db.Books.publishers.any(func.lower(db.Publishers.name).ilike("%" + publisher + "%"))) - q = adv_search_tag(q, tags['include_tag'], tags['exclude_tag']) - q = adv_search_serie(q, tags['include_serie'], tags['exclude_serie']) - q = adv_search_shelf(q, tags['include_shelf'], tags['exclude_shelf']) - q = adv_search_extension(q, tags['include_extension'], tags['exclude_extension']) - q = adv_search_language(q, tags['include_language'], tags['exclude_language']) - q = adv_search_ratings(q, rating_high, rating_low) - - if description: - q = q.filter(db.Books.comments.any(func.lower(db.Comments.text).ilike("%" + description + "%"))) - - # search custom culumns - try: - q = adv_search_custom_columns(cc, term, q) - except AttributeError as ex: - log.debug_or_exception(ex) - flash(_("Error on search for custom columns, please restart Calibre-Web"), category="error") - - q = q.order_by(*sort).all() - flask_session['query'] = json.dumps(term) - ub.store_ids(q) - result_count = len(q) - if offset is not None and limit is not None: - offset = int(offset) - limit_all = offset + int(limit) - pagination = Pagination((offset / (int(limit)) + 1), limit, result_count) - else: - offset = 0 - limit_all = result_count - return render_title_template('search.html', - adv_searchterm=searchterm, - pagination=pagination, - entries=q[offset:limit_all], - result_count=result_count, - title=_(u"Advanced Search"), page="advsearch", - order=order[1]) - - - -@web.route("/advsearch", methods=['GET']) -@login_required_if_no_ano -def advanced_search_form(): - # Build custom columns names - cc = get_cc_columns(filter_config_custom_read=True) - return render_prepare_search_form(cc) # ################################### Download/Send ################################################################## @web.route("/cover/") +@web.route("/cover//") @login_required_if_no_ano -def get_cover(book_id): - return get_book_cover(book_id) +def get_cover(book_id, resolution=None): + resolutions = { + 'og': constants.COVER_THUMBNAIL_ORIGINAL, + 'sm': constants.COVER_THUMBNAIL_SMALL, + 'md': constants.COVER_THUMBNAIL_MEDIUM, + 'lg': constants.COVER_THUMBNAIL_LARGE, + } + cover_resolution = resolutions.get(resolution, None) + return get_book_cover(book_id, cover_resolution) + + +@web.route("/series_cover/") +@web.route("/series_cover//") +@login_required_if_no_ano +def get_series_cover(series_id, resolution=None): + resolutions = { + 'og': constants.COVER_THUMBNAIL_ORIGINAL, + 'sm': constants.COVER_THUMBNAIL_SMALL, + 'md': constants.COVER_THUMBNAIL_MEDIUM, + 'lg': constants.COVER_THUMBNAIL_LARGE, + } + cover_resolution = resolutions.get(resolution, None) + return get_series_cover_thumbnail(series_id, cover_resolution) + + @web.route("/robots.txt") def get_robots(): - return send_from_directory(constants.STATIC_DIR, "robots.txt") + try: + return send_from_directory(constants.STATIC_DIR, "robots.txt") + except PermissionError: + log.error("No permission to access robots.txt file.") + abort(403) + @web.route("/show//", defaults={'anyname': 'None'}) @web.route("/show///") @@ -1429,7 +1169,7 @@ def serve_book(book_id, book_format, anyname): df = getFileFromEbooksFolder(book.path, data.name + "." + book_format) return do_gdrive_download(df, headers, (book_format.upper() == 'TXT')) except AttributeError as ex: - log.debug_or_exception(ex) + log.error_or_exception(ex) return "File Not Found" else: if book_format.upper() == 'TXT': @@ -1454,23 +1194,23 @@ def download_link(book_id, book_format, anyname): return get_download_link(book_id, book_format, client) -@web.route('/send///') -@login_required +@web.route('/send///', methods=["POST"]) +@login_required_if_no_ano @download_required -def send_to_kindle(book_id, book_format, convert): +def send_to_ereader(book_id, book_format, convert): if not config.get_mail_server_configured(): - flash(_(u"Please configure the SMTP mail settings first..."), category="error") + flash(_("Please configure the SMTP mail settings first."), category="error") elif current_user.kindle_mail: result = send_mail(book_id, book_format, convert, current_user.kindle_mail, config.config_calibre_dir, current_user.name) if result is None: - flash(_(u"Book successfully queued for sending to %(kindlemail)s", kindlemail=current_user.kindle_mail), + flash(_("Success! Book queued for sending to %(eReadermail)s", eReadermail=current_user.kindle_mail), category="success") ub.update_download(book_id, int(current_user.id)) else: - flash(_(u"Oops! There was an error sending this book: %(res)s", res=result), category="error") + flash(_("Oops! There was an error sending book: %(res)s", res=result), category="error") else: - flash(_(u"Please update your profile with a valid Send to Kindle E-mail Address."), category="error") + flash(_("Oops! Please update your profile with a valid eReader Email."), category="error") if "HTTP_REFERER" in request.environ: return redirect(request.environ["HTTP_REFERER"]) else: @@ -1487,18 +1227,18 @@ def register(): if current_user is not None and current_user.is_authenticated: return redirect(url_for('web.index')) if not config.get_mail_server_configured(): - flash(_(u"E-Mail server is not configured, please contact your administrator!"), category="error") + flash(_("Oops! Email server is not configured, please contact your administrator."), category="error") return render_title_template('register.html', title=_("Register"), page="register") if request.method == "POST": to_save = request.form.to_dict() - nickname = to_save["email"].strip() if config.config_register_email else to_save.get('name') + nickname = to_save.get("email", "").strip() if config.config_register_email else to_save.get('name') if not nickname or not to_save.get("email"): - flash(_(u"Please fill out all fields!"), category="error") + flash(_("Oops! Please complete all fields."), category="error") return render_title_template('register.html', title=_("Register"), page="register") try: nickname = check_username(nickname) - email = check_email(to_save["email"]) + email = check_email(to_save.get("email", "")) except Exception as ex: flash(str(ex), category="error") return render_title_template('register.html', title=_("Register"), page="register") @@ -1510,22 +1250,24 @@ def register(): password = generate_random_password() content.password = generate_password_hash(password) content.role = config.config_default_role + content.locale = config.config_default_locale content.sidebar_view = config.config_default_show try: ub.session.add(content) ub.session.commit() if feature_support['oauth']: register_user_with_oauth(content) - send_registration_mail(to_save["email"].strip(), nickname, password) + send_registration_mail(to_save.get("email", "").strip(), nickname, password) except Exception: ub.session.rollback() - flash(_(u"An unknown error occurred. Please try again later."), category="error") + flash(_("Oops! An unknown error occurred. Please try again later."), category="error") return render_title_template('register.html', title=_("Register"), page="register") else: - flash(_(u"Your e-mail is not allowed to register"), category="error") - log.warning('Registering failed for user "%s" e-mail address: %s', nickname, to_save["email"]) + flash(_("Oops! Your Email is not allowed."), category="error") + log.warning('Registering failed for user "{}" Email: {}'.format(nickname, + to_save.get("email",""))) return render_title_template('register.html', title=_("Register"), page="register") - flash(_(u"Confirmation e-mail was send to your e-mail account."), category="success") + flash(_("Success! Confirmation Email has been sent."), category="success") return redirect(url_for('web.login')) if feature_support['oauth']: @@ -1535,14 +1277,11 @@ def register(): @web.route('/login', methods=['GET', 'POST']) def login(): - #if not config.db_configured: - # log.debug(u"Redirect to initial configuration") - # return redirect(url_for('admin.basic_configuration')) if current_user is not None and current_user.is_authenticated: return redirect(url_for('web.index')) if config.config_login_type == constants.LOGIN_LDAP and not services.ldap: - log.error(u"Cannot activate LDAP authentication") - flash(_(u"Cannot activate LDAP authentication"), category="error") + log.error("Cannot activate LDAP authentication") + flash(_("Oops! Cannot activate LDAP authentication"), category="error") if request.method == "POST": form = request.form.to_dict() user = ub.session.query(ub.User).filter(func.lower(ub.User.name) == form['username'].strip().lower()) \ @@ -1552,57 +1291,57 @@ def login(): if login_result: login_user(user, remember=bool(form.get('remember_me'))) ub.store_user_session() - log.debug(u"You are now logged in as: '%s'", user.name) - flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.name), + log.debug("You are now logged in as: '{}'".format(user.name)) + flash(_("Success! You are now logged in as: %(nickname)s", nickname=user.name), category="success") return redirect_back(url_for("web.index")) elif login_result is None and user and check_password_hash(str(user.password), form['password']) \ - and user.name != "Guest": + and user.name != "Guest": login_user(user, remember=bool(form.get('remember_me'))) ub.store_user_session() - log.info("Local Fallback Login as: '%s'", user.name) - flash(_(u"Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known", + log.info("Local Fallback Login as: '{}'".format(user.name)) + flash(_("Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known", nickname=user.name), category="warning") return redirect_back(url_for("web.index")) elif login_result is None: log.info(error) - flash(_(u"Could not login: %(message)s", message=error), category="error") + flash(_("Oops! Login Failed: %(message)s", message=error), category="error") else: - ip_Address = request.headers.get('X-Forwarded-For', request.remote_addr) - log.warning('LDAP Login failed for user "%s" IP-address: %s', form['username'], ip_Address) - flash(_(u"Wrong Username or Password"), category="error") + ip_address = request.headers.get('X-Forwarded-For', request.remote_addr) + log.warning('LDAP Login failed for user "%s" IP-address: %s', form['username'], ip_address) + flash(_("Oops! Invalid Username or Password."), category="error") else: - ip_Address = request.headers.get('X-Forwarded-For', request.remote_addr) - if 'forgot' in form and form['forgot'] == 'forgot': + ip_address = request.headers.get('X-Forwarded-For', request.remote_addr) + if form.get('forgot', "") == 'forgot': if user is not None and user.name != "Guest": ret, __ = reset_password(user.id) if ret == 1: - flash(_(u"New Password was send to your email address"), category="info") - log.info('Password reset for user "%s" IP-address: %s', form['username'], ip_Address) + flash(_("Success! New Password was sent to your Email."), category="info") + log.info('Password reset for user "%s" IP-address: %s', form['username'], ip_address) else: - log.error(u"An unknown error occurred. Please try again later") - flash(_(u"An unknown error occurred. Please try again later."), category="error") + log.error("An unknown error occurred. Please try again later") + flash(_("Oops! An unknown error occurred. Please try again later."), category="error") else: - flash(_(u"Please enter valid username to reset password"), category="error") - log.warning('Username missing for password reset IP-address: %s', ip_Address) + flash(_("Oops! Please enter a valid username to reset password"), category="error") + log.warning('Username missing for password reset IP-address: %s', ip_address) else: if user and check_password_hash(str(user.password), form['password']) and user.name != "Guest": login_user(user, remember=bool(form.get('remember_me'))) ub.store_user_session() - log.debug(u"You are now logged in as: '%s'", user.name) - flash(_(u"You are now logged in as: '%(nickname)s'", nickname=user.name), category="success") + log.debug("You are now logged in as: '%s'", user.name) + flash(_("Success! You are now logged in as: %(nickname)s", nickname=user.name), category="success") config.config_is_initial = False return redirect_back(url_for("web.index")) else: - log.warning('Login failed for user "%s" IP-address: %s', form['username'], ip_Address) - flash(_(u"Wrong Username or Password"), category="error") + log.warning('Login failed for user "{}" IP-address: {}'.format(form['username'], ip_address)) + flash(_("Oops! Invalid Username or Password."), category="error") next_url = request.args.get('next', default=url_for("web.index"), type=str) if url_for("web.logout") == next_url: next_url = url_for("web.index") return render_title_template('login.html', - title=_(u"Login"), + title=_("Login"), next_url=next_url, config=config, oauth_check=oauth_check, @@ -1613,11 +1352,11 @@ def login(): @login_required def logout(): if current_user is not None and current_user.is_authenticated: - ub.delete_user_session(current_user.id, flask_session.get('_id',"")) + ub.delete_user_session(current_user.id, flask_session.get('_id', "")) logout_user() if feature_support['oauth'] and (config.config_login_type == 2 or config.config_login_type == 3): logout_oauth_user() - log.debug(u"User logged out") + log.debug("User logged out") return redirect(url_for('web.login')) @@ -1627,21 +1366,22 @@ def change_profile(kobo_support, local_oauth_check, oauth_status, translations, current_user.random_books = 0 if current_user.role_passwd() or current_user.role_admin(): if to_save.get("password"): - current_user.password = generate_password_hash(to_save["password"]) + current_user.password = generate_password_hash(to_save.get("password")) try: - if to_save.get("kindle_mail", current_user.kindle_mail) != current_user.kindle_mail: - current_user.kindle_mail = valid_email(to_save["kindle_mail"]) - if to_save.get("email", current_user.email) != current_user.email: - current_user.email = check_email(to_save["email"]) + if to_save.get("eReader_mail", current_user.kindle_mail) != current_user.kindle_mail: + current_user.kindle_mail = valid_email(to_save.get("eReader_mail")) + new_email = valid_email(to_save.get("email", current_user.email)) + if not new_email: + raise Exception(_("Email can't be empty and has to be a valid Email")) + if new_email != current_user.email: + current_user.email = check_email(new_email) if current_user.role_admin(): if to_save.get("name", current_user.name) != current_user.name: - # Query User name, if not existing, change - current_user.name = check_username(to_save["name"]) + # Query username, if not existing, change + current_user.name = check_username(to_save.get("name")) current_user.random_books = 1 if to_save.get("show_random") == "on" else 0 - if to_save.get("default_language"): - current_user.default_language = to_save["default_language"] - if to_save.get("locale"): - current_user.locale = to_save["locale"] + current_user.default_language = to_save.get("default_language", "all") + current_user.locale = to_save.get("locale", "en") old_state = current_user.kobo_only_shelves_sync # 1 -> 0: nothing has to be done # 0 -> 1: all synced books have to be added to archived books, + currently synced shelfs which @@ -1657,7 +1397,7 @@ def change_profile(kobo_support, local_oauth_check, oauth_status, translations, translations=translations, profile=1, languages=languages, - title=_(u"%(name)s's profile", name=current_user.name), + title=_("%(name)s's Profile", name=current_user.name), page="me", kobo_support=kobo_support, registered_oauth=local_oauth_check, @@ -1673,23 +1413,23 @@ def change_profile(kobo_support, local_oauth_check, oauth_status, translations, try: ub.session.commit() - flash(_(u"Profile updated"), category="success") - log.debug(u"Profile updated") + flash(_("Success! Profile Updated"), category="success") + log.debug("Profile updated") except IntegrityError: ub.session.rollback() - flash(_(u"Found an existing account for this e-mail address"), category="error") - log.debug(u"Found an existing account for this e-mail address") + flash(_("Oops! An account already exists for this Email."), category="error") + log.debug("Found an existing account for this Email") except OperationalError as e: ub.session.rollback() log.error("Database error: %s", e) - flash(_(u"Database error: %(error)s.", error=e), category="error") + flash(_("Oops! Database Error: %(error)s.", error=e), category="error") @web.route("/me", methods=["GET", "POST"]) @login_required def profile(): languages = calibre_db.speaking_language() - translations = babel.list_translations() + [LC('en')] + translations = get_available_locale() kobo_support = feature_support['kobo'] and config.config_kobo_sync if feature_support['oauth'] and config.config_login_type == 2: oauth_status = get_oauth_status() @@ -1706,7 +1446,7 @@ def profile(): languages=languages, content=current_user, kobo_support=kobo_support, - title=_(u"%(name)s's profile", name=current_user.name), + title=_("%(name)s's Profile", name=current_user.name), page="me", registered_oauth=local_oauth_check, oauth_status=oauth_status) @@ -1720,34 +1460,37 @@ def profile(): @viewer_required def read_book(book_id, book_format): book = calibre_db.get_filtered_book(book_id) + book.ordered_authors = calibre_db.order_authors([book], False) + if not book: - flash(_(u"Oops! Selected book title is unavailable. File does not exist or is not accessible"), category="error") - log.debug(u"Oops! Selected book title is unavailable. File does not exist or is not accessible") + flash(_("Oops! Selected book is unavailable. File does not exist or is not accessible"), + category="error") + log.debug("Selected book is unavailable. File does not exist or is not accessible") return redirect(url_for("web.index")) - # check if book has bookmark + # check if book has a bookmark bookmark = None if current_user.is_authenticated: bookmark = ub.session.query(ub.Bookmark).filter(and_(ub.Bookmark.user_id == int(current_user.id), ub.Bookmark.book_id == book_id, ub.Bookmark.format == book_format.upper())).first() if book_format.lower() == "epub": - log.debug(u"Start epub reader for %d", book_id) + log.debug("Start epub reader for %d", book_id) return render_title_template('read.html', bookid=book_id, title=book.title, bookmark=bookmark) elif book_format.lower() == "pdf": - log.debug(u"Start pdf reader for %d", book_id) + log.debug("Start pdf reader for %d", book_id) return render_title_template('readpdf.html', pdffile=book_id, title=book.title) elif book_format.lower() == "txt": - log.debug(u"Start txt reader for %d", book_id) + log.debug("Start txt reader for %d", book_id) return render_title_template('readtxt.html', txtfile=book_id, title=book.title) elif book_format.lower() == "djvu": - log.debug(u"Start djvu reader for %d", book_id) + log.debug("Start djvu reader for %d", book_id) return render_title_template('readdjvu.html', djvufile=book_id, title=book.title) else: for fileExt in constants.EXTENSIONS_AUDIO: if book_format.lower() == fileExt: entries = calibre_db.get_filtered_book(book_id) - log.debug(u"Start mp3 listening for %d", book_id) + log.debug("Start mp3 listening for %d", book_id) return render_title_template('listenmp3.html', mp3file=book_id, audioformat=book_format.lower(), entry=entries, bookmark=bookmark) for fileExt in ["cbr", "cbt", "cbz"]: @@ -1758,77 +1501,55 @@ def read_book(book_id, book_format): title = title + " - " + book.series[0].name if book.series_index: title = title + " #" + '{0:.2f}'.format(book.series_index).rstrip('0').rstrip('.') - log.debug(u"Start comic reader for %d", book_id) + log.debug("Start comic reader for %d", book_id) return render_title_template('readcbr.html', comicfile=all_name, title=title, extension=fileExt) - log.debug(u"Oops! Selected book title is unavailable. File does not exist or is not accessible") - flash(_(u"Oops! Selected book title is unavailable. File does not exist or is not accessible"), category="error") + log.debug("Selected book is unavailable. File does not exist or is not accessible") + flash(_("Oops! Selected book is unavailable. File does not exist or is not accessible"), + category="error") return redirect(url_for("web.index")) @web.route("/book/") @login_required_if_no_ano def show_book(book_id): - entries = calibre_db.get_filtered_book(book_id, allow_show_archived=True) + entries = calibre_db.get_book_read_archived(book_id, config.config_read_column, allow_show_archived=True) if entries: - for index in range(0, len(entries.languages)): - entries.languages[index].language_name = isoLanguages.get_language_name(get_locale(), entries.languages[ - index].lang_code) - cc = get_cc_columns(filter_config_custom_read=True) - book_in_shelfs = [] - shelfs = ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).all() - for entry in shelfs: - book_in_shelfs.append(entry.shelf) + read_book = entries[1] + archived_book = entries[2] + entry = entries[0] + entry.read_status = read_book == ub.ReadBook.STATUS_FINISHED + entry.is_archived = archived_book + for lang_index in range(0, len(entry.languages)): + entry.languages[lang_index].language_name = isoLanguages.get_language_name(get_locale(), entry.languages[ + lang_index].lang_code) + cc = calibre_db.get_cc_columns(config, filter_config_custom_read=True) + book_in_shelves = [] + shelves = ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).all() + for sh in shelves: + book_in_shelves.append(sh.shelf) - if not current_user.is_anonymous: - if not config.config_read_column: - matching_have_read_book = ub.session.query(ub.ReadBook). \ - filter(and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == book_id)).all() - have_read = len( - matching_have_read_book) > 0 and matching_have_read_book[0].read_status == ub.ReadBook.STATUS_FINISHED - else: - try: - matching_have_read_book = getattr(entries, 'custom_column_' + str(config.config_read_column)) - have_read = len(matching_have_read_book) > 0 and matching_have_read_book[0].value - except (KeyError, AttributeError): - log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column) - have_read = None + entry.tags = sort(entry.tags, key=lambda tag: tag.name) - archived_book = ub.session.query(ub.ArchivedBook).\ - filter(and_(ub.ArchivedBook.user_id == int(current_user.id), - ub.ArchivedBook.book_id == book_id)).first() - is_archived = archived_book and archived_book.is_archived + entry.ordered_authors = calibre_db.order_authors([entry]) - else: - have_read = None - is_archived = None + entry.email_share_list = check_send_to_ereader(entry) + entry.reader_list = check_read_formats(entry) - entries.tags = sort(entries.tags, key=lambda tag: tag.name) - - entries = calibre_db.order_authors(entries) - - kindle_list = check_send_to_kindle(entries) - reader_list = check_read_formats(entries) - - audioentries = [] - for media_format in entries.data: + entry.audio_entries = [] + for media_format in entry.data: if media_format.format.lower() in constants.EXTENSIONS_AUDIO: - audioentries.append(media_format.format.lower()) + entry.audio_entries.append(media_format.format.lower()) return render_title_template('detail.html', - entry=entries, - audioentries=audioentries, + entry=entry, cc=cc, - is_xhr=request.headers.get('X-Requested-With')=='XMLHttpRequest', - title=entries.title, - books_shelfs=book_in_shelfs, - have_read=have_read, - is_archived=is_archived, - kindle_list=kindle_list, - reader_list=reader_list, + is_xhr=request.headers.get('X-Requested-With') == 'XMLHttpRequest', + title=entry.title, + books_shelfs=book_in_shelves, page="book") else: - log.debug(u"Oops! Selected book title is unavailable. File does not exist or is not accessible") - flash(_(u"Oops! Selected book title is unavailable. File does not exist or is not accessible"), + log.debug("Selected book is unavailable. File does not exist or is not accessible") + flash(_("Oops! Selected book is unavailable. File does not exist or is not accessible"), category="error") return redirect(url_for("web.index")) diff --git a/exclude.txt b/exclude.txt new file mode 100644 index 000000000..e69de29bb diff --git a/library/metadata.db b/library/metadata.db new file mode 100644 index 000000000..fc0d5d315 Binary files /dev/null and b/library/metadata.db differ diff --git a/messages.pot b/messages.pot index b180986a2..a44d8d255 100644 --- a/messages.pot +++ b/messages.pot @@ -1,583 +1,636 @@ # Translations template for PROJECT. -# Copyright (C) 2021 ORGANIZATION +# Copyright (C) 2023 ORGANIZATION # This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2021. +# FIRST AUTHOR , 2023. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-11-20 11:24+0100\n" +"POT-Creation-Date: 2023-02-06 19:00+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.0\n" +"Generated-By: Babel 2.10.3\n" -#: cps/about.py:34 cps/about.py:48 cps/about.py:64 cps/converter.py:31 -msgid "not installed" -msgstr "" - -#: cps/about.py:46 cps/about.py:62 -msgid "installed" -msgstr "" - -#: cps/about.py:117 +#: cps/about.py:84 msgid "Statistics" msgstr "" -#: cps/admin.py:144 -msgid "Server restarted, please reload page" +#: cps/admin.py:143 +msgid "Server restarted, please reload page." msgstr "" -#: cps/admin.py:146 -msgid "Performing shutdown of server, please close window" +#: cps/admin.py:145 +msgid "Performing Server shutdown, please close window." msgstr "" -#: cps/admin.py:154 -msgid "Reconnect successful" +#: cps/admin.py:153 +msgid "Success! Database Reconnected" msgstr "" -#: cps/admin.py:157 +#: cps/admin.py:156 msgid "Unknown command" msgstr "" -#: cps/admin.py:167 cps/editbooks.py:704 cps/editbooks.py:718 -#: cps/editbooks.py:859 cps/editbooks.py:861 cps/editbooks.py:888 -#: cps/editbooks.py:904 cps/updater.py:584 cps/uploader.py:93 -#: cps/uploader.py:103 +#: cps/admin.py:167 +msgid "Success! Books queued for Metadata Backup" +msgstr "" + +#: cps/admin.py:200 cps/editbooks.py:576 cps/editbooks.py:578 +#: cps/editbooks.py:614 cps/editbooks.py:631 cps/editbooks.py:1238 +#: cps/updater.py:613 cps/uploader.py:93 cps/uploader.py:102 msgid "Unknown" msgstr "" -#: cps/admin.py:188 +#: cps/admin.py:225 msgid "Admin page" msgstr "" -#: cps/admin.py:207 +#: cps/admin.py:245 msgid "Basic Configuration" msgstr "" -#: cps/admin.py:244 +#: cps/admin.py:283 msgid "UI Configuration" msgstr "" -#: cps/admin.py:277 cps/templates/admin.html:46 +#: cps/admin.py:317 cps/templates/admin.html:51 msgid "Edit Users" msgstr "" -#: cps/admin.py:318 cps/opds.py:109 cps/opds.py:198 cps/opds.py:275 -#: cps/opds.py:327 cps/templates/grid.html:14 cps/templates/list.html:14 +#: cps/admin.py:361 cps/opds.py:494 cps/templates/grid.html:14 +#: cps/templates/list.html:13 msgid "All" msgstr "" -#: cps/admin.py:343 cps/admin.py:1572 +#: cps/admin.py:388 cps/admin.py:1392 msgid "User not found" msgstr "" -#: cps/admin.py:357 +#: cps/admin.py:402 msgid "{} users deleted successfully" msgstr "" -#: cps/admin.py:379 cps/templates/config_view_edit.html:129 +#: cps/admin.py:425 cps/templates/config_view_edit.html:133 #: cps/templates/user_edit.html:45 cps/templates/user_table.html:81 msgid "Show All" msgstr "" -#: cps/admin.py:400 cps/admin.py:406 +#: cps/admin.py:446 cps/admin.py:452 msgid "Malformed request" msgstr "" -#: cps/admin.py:418 cps/admin.py:1452 +#: cps/admin.py:464 cps/admin.py:1993 msgid "Guest Name can't be changed" msgstr "" -#: cps/admin.py:430 +#: cps/admin.py:476 msgid "Guest can't have this role" msgstr "" -#: cps/admin.py:442 cps/admin.py:1410 +#: cps/admin.py:488 cps/admin.py:1948 msgid "No admin user remaining, can't remove admin role" msgstr "" -#: cps/admin.py:446 cps/admin.py:460 +#: cps/admin.py:492 cps/admin.py:506 msgid "Value has to be true or false" msgstr "" -#: cps/admin.py:448 +#: cps/admin.py:494 msgid "Invalid role" msgstr "" -#: cps/admin.py:452 +#: cps/admin.py:498 msgid "Guest can't have this view" msgstr "" -#: cps/admin.py:462 +#: cps/admin.py:508 msgid "Invalid view" msgstr "" -#: cps/admin.py:465 +#: cps/admin.py:511 msgid "Guest's Locale is determined automatically and can't be set" msgstr "" -#: cps/admin.py:469 +#: cps/admin.py:515 msgid "No Valid Locale Given" msgstr "" -#: cps/admin.py:480 +#: cps/admin.py:526 msgid "No Valid Book Language Given" msgstr "" -#: cps/admin.py:482 +#: cps/admin.py:528 cps/editbooks.py:442 msgid "Parameter not found" msgstr "" -#: cps/admin.py:533 +#: cps/admin.py:565 msgid "Invalid Read Column" msgstr "" -#: cps/admin.py:539 +#: cps/admin.py:571 msgid "Invalid Restricted Column" msgstr "" -#: cps/admin.py:560 cps/admin.py:1293 +#: cps/admin.py:591 cps/admin.py:1819 msgid "Calibre-Web configuration updated" msgstr "" -#: cps/admin.py:572 +#: cps/admin.py:603 msgid "Do you really want to delete the Kobo Token?" msgstr "" -#: cps/admin.py:574 +#: cps/admin.py:605 msgid "Do you really want to delete this domain?" msgstr "" -#: cps/admin.py:576 +#: cps/admin.py:607 msgid "Do you really want to delete this user?" msgstr "" -#: cps/admin.py:578 cps/templates/shelf.html:91 +#: cps/admin.py:609 msgid "Are you sure you want to delete this shelf?" msgstr "" -#: cps/admin.py:580 +#: cps/admin.py:611 msgid "Are you sure you want to change locales of selected user(s)?" msgstr "" -#: cps/admin.py:582 +#: cps/admin.py:613 msgid "Are you sure you want to change visible book languages for selected user(s)?" msgstr "" -#: cps/admin.py:584 +#: cps/admin.py:615 msgid "Are you sure you want to change the selected role for the selected user(s)?" msgstr "" -#: cps/admin.py:586 +#: cps/admin.py:617 msgid "Are you sure you want to change the selected restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:588 +#: cps/admin.py:619 msgid "Are you sure you want to change the selected visibility restrictions for the selected user(s)?" msgstr "" -#: cps/admin.py:590 +#: cps/admin.py:622 msgid "Are you sure you want to change shelf sync behavior for the selected user(s)?" msgstr "" -#: cps/admin.py:592 +#: cps/admin.py:624 msgid "Are you sure you want to change Calibre library location?" msgstr "" -#: cps/admin.py:741 -msgid "Tag not found" +#: cps/admin.py:626 +msgid "Calibre-Web will search for updated Covers and update Cover Thumbnails, this may take a while?" msgstr "" -#: cps/admin.py:753 -msgid "Invalid Action" +#: cps/admin.py:629 +msgid "Are you sure you want delete Calibre-Web's sync database to force a full sync with your Kobo Reader?" msgstr "" -#: cps/admin.py:858 cps/admin.py:864 cps/admin.py:874 cps/admin.py:884 +#: cps/admin.py:872 cps/admin.py:878 cps/admin.py:888 cps/admin.py:898 #: cps/templates/modal_dialogs.html:29 cps/templates/user_table.html:41 #: cps/templates/user_table.html:58 msgid "Deny" msgstr "" -#: cps/admin.py:860 cps/admin.py:866 cps/admin.py:876 cps/admin.py:886 +#: cps/admin.py:874 cps/admin.py:880 cps/admin.py:890 cps/admin.py:900 #: cps/templates/modal_dialogs.html:28 cps/templates/user_table.html:44 #: cps/templates/user_table.html:61 msgid "Allow" msgstr "" -#: cps/admin.py:1015 +#: cps/admin.py:915 +msgid "{} sync entries deleted" +msgstr "" + +#: cps/admin.py:963 +msgid "Tag not found" +msgstr "" + +#: cps/admin.py:975 +msgid "Invalid Action" +msgstr "" + +#: cps/admin.py:1104 msgid "client_secrets.json Is Not Configured For Web Application" msgstr "" -#: cps/admin.py:1060 +#: cps/admin.py:1149 msgid "Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1066 +#: cps/admin.py:1155 msgid "Access Logfile Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1096 +#: cps/admin.py:1185 msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier" msgstr "" -#: cps/admin.py:1102 +#: cps/admin.py:1191 msgid "Please Enter a LDAP Service Account and Password" msgstr "" -#: cps/admin.py:1105 +#: cps/admin.py:1194 msgid "Please Enter a LDAP Service Account" msgstr "" -#: cps/admin.py:1110 +#: cps/admin.py:1199 #, python-format msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1112 +#: cps/admin.py:1201 msgid "LDAP Group Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1116 +#: cps/admin.py:1205 #, python-format msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1118 +#: cps/admin.py:1207 msgid "LDAP User Object Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1125 +#: cps/admin.py:1214 #, python-format msgid "LDAP Member User Filter needs to Have One \"%s\" Format Identifier" msgstr "" -#: cps/admin.py:1127 +#: cps/admin.py:1216 msgid "LDAP Member User Filter Has Unmatched Parenthesis" msgstr "" -#: cps/admin.py:1134 +#: cps/admin.py:1223 msgid "LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path" msgstr "" -#: cps/admin.py:1176 cps/admin.py:1278 cps/admin.py:1373 cps/admin.py:1479 -#: cps/admin.py:1547 cps/shelf.py:100 cps/shelf.py:160 cps/shelf.py:203 -#: cps/shelf.py:270 cps/shelf.py:331 cps/shelf.py:366 cps/shelf.py:441 -msgid "Settings DB is not Writeable" +#: cps/admin.py:1254 cps/templates/admin.html:53 +msgid "Add New User" msgstr "" -#: cps/admin.py:1187 -msgid "DB Location is not Valid, Please Enter Correct Path" +#: cps/admin.py:1263 cps/templates/admin.html:100 +msgid "Edit Email Server Settings" msgstr "" -#: cps/admin.py:1192 -msgid "DB is not Writeable" +#: cps/admin.py:1282 +msgid "Success! Gmail Account Verified." msgstr "" -#: cps/admin.py:1205 -msgid "Keyfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1209 -msgid "Certfile Location is not Valid, Please Enter Correct Path" -msgstr "" - -#: cps/admin.py:1316 -msgid "Database Settings updated" -msgstr "" - -#: cps/admin.py:1324 -msgid "Database Configuration" -msgstr "" - -#: cps/admin.py:1340 cps/web.py:1471 -msgid "Please fill out all fields!" -msgstr "" - -#: cps/admin.py:1348 -msgid "E-mail is not from valid domain" -msgstr "" - -#: cps/admin.py:1352 cps/admin.py:1500 -msgid "Add new user" -msgstr "" - -#: cps/admin.py:1363 +#: cps/admin.py:1301 cps/admin.py:1304 cps/admin.py:1685 cps/admin.py:1803 +#: cps/admin.py:1901 cps/admin.py:2021 cps/editbooks.py:229 +#: cps/editbooks.py:305 cps/editbooks.py:1201 cps/shelf.py:82 cps/shelf.py:142 +#: cps/shelf.py:185 cps/shelf.py:235 cps/shelf.py:272 cps/shelf.py:343 +#: cps/shelf.py:457 cps/tasks/convert.py:136 cps/web.py:1425 #, python-format -msgid "User '%(user)s' created" +msgid "Oops! Database Error: %(error)s." msgstr "" -#: cps/admin.py:1369 -msgid "Found an existing account for this e-mail address or name." -msgstr "" - -#: cps/admin.py:1389 -#, python-format -msgid "User '%(nick)s' deleted" -msgstr "" - -#: cps/admin.py:1391 cps/admin.py:1392 -msgid "Can't delete Guest User" -msgstr "" - -#: cps/admin.py:1395 -msgid "No admin user remaining, can't delete user" -msgstr "" - -#: cps/admin.py:1467 cps/admin.py:1590 -#, python-format -msgid "Edit User %(nick)s" -msgstr "" - -#: cps/admin.py:1471 -#, python-format -msgid "User '%(nick)s' updated" -msgstr "" - -#: cps/admin.py:1475 cps/admin.py:1605 cps/web.py:1496 cps/web.py:1559 -msgid "An unknown error occurred. Please try again later." -msgstr "" - -#: cps/admin.py:1509 cps/templates/admin.html:94 -msgid "Edit E-mail Server Settings" -msgstr "" - -#: cps/admin.py:1528 -msgid "Gmail Account Verification Successful" -msgstr "" - -#: cps/admin.py:1554 +#: cps/admin.py:1311 #, python-format msgid "Test e-mail queued for sending to %(email)s, please check Tasks for result" msgstr "" -#: cps/admin.py:1557 +#: cps/admin.py:1314 #, python-format msgid "There was an error sending the Test e-mail: %(res)s" msgstr "" -#: cps/admin.py:1559 +#: cps/admin.py:1316 msgid "Please configure your e-mail address first..." msgstr "" -#: cps/admin.py:1561 -msgid "E-mail server settings updated" +#: cps/admin.py:1318 +msgid "Email Server Settings updated" msgstr "" -#: cps/admin.py:1602 +#: cps/admin.py:1341 cps/templates/admin.html:191 +msgid "Edit Scheduled Tasks Settings" +msgstr "" + +#: cps/admin.py:1353 +msgid "Invalid start time for task specified" +msgstr "" + +#: cps/admin.py:1358 +msgid "Invalid duration for task specified" +msgstr "" + +#: cps/admin.py:1367 +msgid "Scheduled tasks settings updated" +msgstr "" + +#: cps/admin.py:1377 cps/admin.py:1426 cps/admin.py:2017 cps/web.py:1263 +#: cps/web.py:1324 +msgid "Oops! An unknown error occurred. Please try again later." +msgstr "" + +#: cps/admin.py:1381 +msgid "Settings DB is not Writeable" +msgstr "" + +#: cps/admin.py:1411 cps/admin.py:2009 #, python-format -msgid "Password for user %(user)s reset" +msgid "Edit User %(nick)s" msgstr "" -#: cps/admin.py:1608 cps/web.py:1436 -msgid "Please configure the SMTP mail settings first..." +#: cps/admin.py:1423 +#, python-format +msgid "Success! Password for user %(user)s reset" msgstr "" -#: cps/admin.py:1619 +#: cps/admin.py:1429 +msgid "Oops! Please configure the SMTP mail settings." +msgstr "" + +#: cps/admin.py:1440 msgid "Logfile viewer" msgstr "" -#: cps/admin.py:1685 +#: cps/admin.py:1506 msgid "Requesting update package" msgstr "" -#: cps/admin.py:1686 +#: cps/admin.py:1507 msgid "Downloading update package" msgstr "" -#: cps/admin.py:1687 +#: cps/admin.py:1508 msgid "Unzipping update package" msgstr "" -#: cps/admin.py:1688 +#: cps/admin.py:1509 msgid "Replacing files" msgstr "" -#: cps/admin.py:1689 +#: cps/admin.py:1510 msgid "Database connections are closed" msgstr "" -#: cps/admin.py:1690 +#: cps/admin.py:1511 msgid "Stopping server" msgstr "" -#: cps/admin.py:1691 +#: cps/admin.py:1512 msgid "Update finished, please press okay and reload page" msgstr "" -#: cps/admin.py:1692 cps/admin.py:1693 cps/admin.py:1694 cps/admin.py:1695 -#: cps/admin.py:1696 cps/admin.py:1697 +#: cps/admin.py:1513 cps/admin.py:1514 cps/admin.py:1515 cps/admin.py:1516 +#: cps/admin.py:1517 cps/admin.py:1518 msgid "Update failed:" msgstr "" -#: cps/admin.py:1692 cps/updater.py:385 cps/updater.py:595 cps/updater.py:597 +#: cps/admin.py:1513 cps/updater.py:389 cps/updater.py:624 cps/updater.py:626 msgid "HTTP Error" msgstr "" -#: cps/admin.py:1693 cps/updater.py:387 cps/updater.py:599 +#: cps/admin.py:1514 cps/updater.py:391 cps/updater.py:628 msgid "Connection error" msgstr "" -#: cps/admin.py:1694 cps/updater.py:389 cps/updater.py:601 +#: cps/admin.py:1515 cps/updater.py:393 cps/updater.py:630 msgid "Timeout while establishing connection" msgstr "" -#: cps/admin.py:1695 cps/updater.py:391 cps/updater.py:603 +#: cps/admin.py:1516 cps/updater.py:395 cps/updater.py:632 msgid "General error" msgstr "" -#: cps/admin.py:1696 +#: cps/admin.py:1517 msgid "Update file could not be saved in temp dir" msgstr "" -#: cps/admin.py:1697 +#: cps/admin.py:1518 msgid "Files could not be replaced during update" msgstr "" -#: cps/admin.py:1721 +#: cps/admin.py:1542 msgid "Failed to extract at least One LDAP User" msgstr "" -#: cps/admin.py:1766 +#: cps/admin.py:1587 msgid "Failed to Create at Least One LDAP User" msgstr "" -#: cps/admin.py:1779 +#: cps/admin.py:1600 #, python-format msgid "Error: %(ldaperror)s" msgstr "" -#: cps/admin.py:1783 +#: cps/admin.py:1604 msgid "Error: No user returned in response of LDAP server" msgstr "" -#: cps/admin.py:1816 +#: cps/admin.py:1637 msgid "At Least One LDAP User Not Found in Database" msgstr "" -#: cps/admin.py:1818 +#: cps/admin.py:1639 msgid "{} User Successfully Imported" msgstr "" -#: cps/converter.py:30 -msgid "not configured" +#: cps/admin.py:1697 +msgid "DB Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1717 +msgid "DB is not Writeable" +msgstr "" + +#: cps/admin.py:1730 +msgid "Keyfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1734 +msgid "Certfile Location is not Valid, Please Enter Correct Path" +msgstr "" + +#: cps/admin.py:1842 +msgid "Database Settings updated" +msgstr "" + +#: cps/admin.py:1850 +msgid "Database Configuration" +msgstr "" + +#: cps/admin.py:1866 cps/web.py:1237 +msgid "Oops! Please complete all fields." +msgstr "" + +#: cps/admin.py:1874 +msgid "E-mail is not from valid domain" +msgstr "" + +#: cps/admin.py:1880 +msgid "Add new user" +msgstr "" + +#: cps/admin.py:1891 +#, python-format +msgid "User '%(user)s' created" +msgstr "" + +#: cps/admin.py:1897 +msgid "Oops! An account already exists for this Email. or name." +msgstr "" + +#: cps/admin.py:1927 +#, python-format +msgid "User '%(nick)s' deleted" +msgstr "" + +#: cps/admin.py:1929 cps/admin.py:1930 +msgid "Can't delete Guest User" +msgstr "" + +#: cps/admin.py:1933 +msgid "No admin user remaining, can't delete user" +msgstr "" + +#: cps/admin.py:1987 cps/web.py:1375 +msgid "Email can't be empty and has to be a valid Email" +msgstr "" + +#: cps/admin.py:2013 +#, python-format +msgid "User '%(nick)s' updated" +msgstr "" + +#: cps/converter.py:31 +msgid "not installed" msgstr "" #: cps/converter.py:32 msgid "Execution permissions missing" msgstr "" -#: cps/db.py:651 cps/web.py:649 cps/web.py:1148 +#: cps/db.py:728 cps/search.py:138 cps/web.py:727 #, python-format -msgid "Custom Column No.%(column)d is not existing in calibre database" +msgid "Custom Column No.%(column)d does not exist in calibre database" msgstr "" -#: cps/editbooks.py:306 cps/editbooks.py:308 -msgid "Book Format Successfully Deleted" +#: cps/db.py:971 cps/templates/config_edit.html:204 +#: cps/templates/config_view_edit.html:62 cps/templates/email_edit.html:41 +#: cps/web.py:554 cps/web.py:588 cps/web.py:663 cps/web.py:688 cps/web.py:969 +#: cps/web.py:999 cps/web.py:1035 cps/web.py:1063 cps/web.py:1102 +msgid "None" msgstr "" -#: cps/editbooks.py:315 cps/editbooks.py:317 -msgid "Book Successfully Deleted" +#: cps/editbooks.py:110 cps/editbooks.py:895 cps/web.py:521 cps/web.py:1466 +#: cps/web.py:1508 cps/web.py:1553 +msgid "Oops! Selected book is unavailable. File does not exist or is not accessible" msgstr "" -#: cps/editbooks.py:373 cps/editbooks.py:760 cps/web.py:511 cps/web.py:1698 -#: cps/web.py:1739 cps/web.py:1806 -msgid "Oops! Selected book title is unavailable. File does not exist or is not accessible" +#: cps/editbooks.py:154 cps/editbooks.py:1221 +msgid "User has no rights to upload cover" msgstr "" -#: cps/editbooks.py:407 -msgid "edit metadata" -msgstr "" - -#: cps/editbooks.py:455 -#, python-format -msgid "%(seriesindex)s is not a valid number, skipping" -msgstr "" - -#: cps/editbooks.py:491 -#, python-format -msgid "%(langname)s is not a valid language" -msgstr "" - -#: cps/editbooks.py:631 cps/editbooks.py:974 -#, python-format -msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" -msgstr "" - -#: cps/editbooks.py:635 cps/editbooks.py:978 -msgid "File to be uploaded must have an extension" -msgstr "" - -#: cps/editbooks.py:647 -#, python-format -msgid "Failed to create path %(path)s (Permission denied)." -msgstr "" - -#: cps/editbooks.py:652 -#, python-format -msgid "Failed to store file %(file)s." -msgstr "" - -#: cps/editbooks.py:670 cps/editbooks.py:1065 cps/web.py:1659 -#, python-format -msgid "Database error: %(error)s." -msgstr "" - -#: cps/editbooks.py:675 -#, python-format -msgid "File format %(ext)s added to %(book)s" -msgstr "" - -#: cps/editbooks.py:811 +#: cps/editbooks.py:174 cps/editbooks.py:716 msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier" msgstr "" -#: cps/editbooks.py:845 +#: cps/editbooks.py:216 msgid "Metadata successfully updated" msgstr "" -#: cps/editbooks.py:854 -msgid "Error editing book, please check logfile for details" +#: cps/editbooks.py:234 +msgid "Error editing book: {}" msgstr "" -#: cps/editbooks.py:892 -msgid "Uploaded book probably exists in the library, consider to change before upload new: " -msgstr "" - -#: cps/editbooks.py:986 -#, python-format -msgid "File %(filename)s could not saved to temp dir" -msgstr "" - -#: cps/editbooks.py:1005 -#, python-format -msgid "Failed to Move Cover File %(file)s: %(error)s" -msgstr "" - -#: cps/editbooks.py:1052 +#: cps/editbooks.py:291 #, python-format msgid "File %(file)s uploaded" msgstr "" -#: cps/editbooks.py:1077 +#: cps/editbooks.py:318 msgid "Source or destination format for conversion missing" msgstr "" -#: cps/editbooks.py:1085 +#: cps/editbooks.py:326 #, python-format msgid "Book successfully queued for converting to %(book_format)s" msgstr "" -#: cps/editbooks.py:1089 +#: cps/editbooks.py:330 #, python-format msgid "There was an error converting this book: %(res)s" msgstr "" +#: cps/editbooks.py:635 +msgid "Uploaded book probably exists in the library, consider to change before upload new: " +msgstr "" + +#: cps/editbooks.py:690 cps/editbooks.py:1015 +#, python-format +msgid "'%(langname)s' is not a valid language" +msgstr "" + +#: cps/editbooks.py:728 cps/editbooks.py:1162 +#, python-format +msgid "File extension '%(ext)s' is not allowed to be uploaded to this server" +msgstr "" + +#: cps/editbooks.py:732 cps/editbooks.py:1166 +msgid "File to be uploaded must have an extension" +msgstr "" + +#: cps/editbooks.py:740 +#, python-format +msgid "File %(filename)s could not saved to temp dir" +msgstr "" + +#: cps/editbooks.py:760 +#, python-format +msgid "Failed to Move Cover File %(file)s: %(error)s" +msgstr "" + +#: cps/editbooks.py:817 cps/editbooks.py:819 +msgid "Book Format Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:826 cps/editbooks.py:828 +msgid "Book Successfully Deleted" +msgstr "" + +#: cps/editbooks.py:880 +msgid "You are missing permissions to delete books" +msgstr "" + +#: cps/editbooks.py:930 +msgid "edit metadata" +msgstr "" + +#: cps/editbooks.py:979 +#, python-format +msgid "%(seriesindex)s is not a valid number, skipping" +msgstr "" + +#: cps/editbooks.py:1157 +msgid "User has no rights to upload additional file formats" +msgstr "" + +#: cps/editbooks.py:1178 +#, python-format +msgid "Failed to create path %(path)s (Permission denied)." +msgstr "" + +#: cps/editbooks.py:1183 +#, python-format +msgid "Failed to store file %(file)s." +msgstr "" + +#: cps/editbooks.py:1206 +#, python-format +msgid "File format %(ext)s added to %(book)s" +msgstr "" + #: cps/gdrive.py:58 msgid "Google Drive setup not completed, try to deactivate and activate Google Drive again" msgstr "" @@ -591,165 +644,173 @@ msgstr "" msgid "%(format)s format not found for book id: %(book)d" msgstr "" -#: cps/helper.py:86 cps/tasks/convert.py:73 +#: cps/helper.py:87 cps/tasks/convert.py:75 #, python-format msgid "%(format)s not found on Google Drive: %(fn)s" msgstr "" -#: cps/helper.py:91 +#: cps/helper.py:92 #, python-format msgid "%(format)s not found: %(fn)s" msgstr "" -#: cps/helper.py:96 cps/helper.py:220 cps/templates/detail.html:41 -#: cps/templates/detail.html:45 -msgid "Send to Kindle" +#: cps/helper.py:97 cps/helper.py:226 cps/templates/detail.html:43 +#: cps/templates/detail.html:47 +msgid "Send to eReader" msgstr "" -#: cps/helper.py:97 cps/helper.py:114 cps/helper.py:222 -msgid "This e-mail has been sent via Calibre-Web." +#: cps/helper.py:98 cps/helper.py:116 cps/helper.py:228 +msgid "This Email has been sent via Calibre-Web." msgstr "" -#: cps/helper.py:112 -msgid "Calibre-Web test e-mail" +#: cps/helper.py:114 +msgid "Calibre-Web Test Email" msgstr "" -#: cps/helper.py:113 -msgid "Test e-mail" +#: cps/helper.py:115 +msgid "Test Email" msgstr "" -#: cps/helper.py:130 +#: cps/helper.py:132 msgid "Get Started with Calibre-Web" msgstr "" -#: cps/helper.py:135 +#: cps/helper.py:137 #, python-format -msgid "Registration e-mail for user: %(name)s" +msgid "Registration Email for user: %(name)s" msgstr "" -#: cps/helper.py:146 cps/helper.py:152 +#: cps/helper.py:148 cps/helper.py:154 #, python-format -msgid "Convert %(orig)s to %(format)s and send to Kindle" +msgid "Convert %(orig)s to %(format)s and send to eReader" msgstr "" -#: cps/helper.py:171 cps/helper.py:175 cps/helper.py:179 +#: cps/helper.py:173 cps/helper.py:177 cps/helper.py:181 cps/helper.py:185 #, python-format -msgid "Send %(format)s to Kindle" +msgid "Send %(format)s to eReader" msgstr "" -#: cps/helper.py:219 cps/tasks/convert.py:90 +#: cps/helper.py:225 #, python-format -msgid "%(book)s send to Kindle" +msgid "%(book)s send to eReader" msgstr "" -#: cps/helper.py:224 +#: cps/helper.py:230 msgid "The requested file could not be read. Maybe wrong permissions?" msgstr "" -#: cps/helper.py:316 +#: cps/helper.py:345 +msgid "Read status could not set: {}" +msgstr "" + +#: cps/helper.py:368 #, python-format msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s" msgstr "" -#: cps/helper.py:322 +#: cps/helper.py:374 #, python-format msgid "Deleting book %(id)s failed: %(message)s" msgstr "" -#: cps/helper.py:333 +#: cps/helper.py:385 #, python-format msgid "Deleting book %(id)s from database only, book path in database not valid: %(path)s" msgstr "" -#: cps/helper.py:388 +#: cps/helper.py:450 #, python-format -msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgid "Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s" msgstr "" -#: cps/helper.py:403 -#, python-format -msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s" -msgstr "" - -#: cps/helper.py:428 cps/helper.py:438 cps/helper.py:446 +#: cps/helper.py:522 cps/helper.py:531 #, python-format msgid "File %(file)s not found on Google Drive" msgstr "" -#: cps/helper.py:467 +#: cps/helper.py:565 +#, python-format +msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s" +msgstr "" + +#: cps/helper.py:585 +msgid "Error in rename file in path: {}" +msgstr "" + +#: cps/helper.py:603 #, python-format msgid "Book path %(path)s not found on Google Drive" msgstr "" -#: cps/helper.py:507 cps/web.py:1654 -msgid "Found an existing account for this e-mail address" +#: cps/helper.py:644 +msgid "Found an existing account for this Email address" msgstr "" -#: cps/helper.py:515 +#: cps/helper.py:652 msgid "This username is already taken" msgstr "" -#: cps/helper.py:525 -msgid "Invalid e-mail address format" +#: cps/helper.py:664 +msgid "Invalid Email address format" msgstr "" -#: cps/helper.py:598 +#: cps/helper.py:815 +msgid "Python module 'advocate' is not installed but is needed for cover uploads" +msgstr "" + +#: cps/helper.py:825 msgid "Error Downloading Cover" msgstr "" -#: cps/helper.py:601 +#: cps/helper.py:828 msgid "Cover Format Error" msgstr "" -#: cps/helper.py:611 +#: cps/helper.py:831 +msgid "You are not allowed to access localhost or the local network for cover uploads" +msgstr "" + +#: cps/helper.py:841 msgid "Failed to create path for cover" msgstr "" -#: cps/helper.py:627 +#: cps/helper.py:857 msgid "Cover-file is not a valid image file, or could not be stored" msgstr "" -#: cps/helper.py:638 +#: cps/helper.py:868 msgid "Only jpg/jpeg/png/webp/bmp files are supported as coverfile" msgstr "" -#: cps/helper.py:651 +#: cps/helper.py:880 +msgid "Invalid cover file content" +msgstr "" + +#: cps/helper.py:884 msgid "Only jpg/jpeg files are supported as coverfile" msgstr "" -#: cps/helper.py:703 +#: cps/helper.py:936 msgid "Unrar binary file not found" msgstr "" -#: cps/helper.py:714 -msgid "Error excecuting UnRar" +#: cps/helper.py:947 +msgid "Error executing UnRar" msgstr "" -#: cps/helper.py:762 -msgid "Waiting" +#: cps/helper.py:1040 +msgid "Cover" msgstr "" -#: cps/helper.py:764 -msgid "Failed" +#: cps/helper.py:1042 cps/templates/admin.html:211 +msgid "Queue all books for metadata backup" msgstr "" -#: cps/helper.py:766 -msgid "Started" +#: cps/kobo_auth.py:89 +msgid "Please access Calibre-Web from non localhost to get valid api_endpoint for kobo device" msgstr "" -#: cps/helper.py:768 -msgid "Finished" -msgstr "" - -#: cps/helper.py:770 -msgid "Unknown Status" -msgstr "" - -#: cps/kobo_auth.py:131 -msgid "PLease access calibre-web from non localhost to get valid api_endpoint for kobo device" -msgstr "" - -#: cps/kobo_auth.py:134 cps/kobo_auth.py:162 +#: cps/kobo_auth.py:115 msgid "Kobo Setup" msgstr "" @@ -758,9 +819,9 @@ msgstr "" msgid "Register with %(provider)s" msgstr "" -#: cps/oauth_bb.py:138 cps/remotelogin.py:133 cps/web.py:1530 +#: cps/oauth_bb.py:138 cps/remotelogin.py:130 cps/web.py:1295 cps/web.py:1333 #, python-format -msgid "you are now logged in as: '%(nickname)s'" +msgid "Success! You are now logged in as: %(nickname)s" msgstr "" #: cps/oauth_bb.py:148 @@ -819,505 +880,597 @@ msgstr "" msgid "Google Oauth error: {}" msgstr "" -#: cps/opds.py:384 +#: cps/opds.py:273 msgid "{} Stars" msgstr "" -#: cps/remotelogin.py:65 cps/templates/layout.html:86 -#: cps/templates/login.html:4 cps/templates/login.html:21 cps/web.py:1579 +#: cps/remotelogin.py:62 cps/templates/layout.html:68 +#: cps/templates/layout.html:102 cps/templates/login.html:4 +#: cps/templates/login.html:21 cps/web.py:1344 msgid "Login" msgstr "" -#: cps/remotelogin.py:77 cps/remotelogin.py:111 +#: cps/remotelogin.py:74 cps/remotelogin.py:108 msgid "Token not found" msgstr "" -#: cps/remotelogin.py:86 cps/remotelogin.py:119 +#: cps/remotelogin.py:83 cps/remotelogin.py:116 msgid "Token has expired" msgstr "" -#: cps/remotelogin.py:95 +#: cps/remotelogin.py:92 msgid "Success! Please return to your device" msgstr "" -#: cps/render_template.py:39 cps/web.py:413 +#: cps/render_template.py:42 cps/web.py:410 msgid "Books" msgstr "" -#: cps/render_template.py:41 +#: cps/render_template.py:44 msgid "Show recent books" msgstr "" -#: cps/render_template.py:42 cps/templates/index.xml:25 +#: cps/render_template.py:45 cps/templates/index.xml:25 msgid "Hot Books" msgstr "" -#: cps/render_template.py:44 +#: cps/render_template.py:47 msgid "Show Hot Books" msgstr "" -#: cps/render_template.py:46 cps/render_template.py:51 +#: cps/render_template.py:49 cps/render_template.py:54 msgid "Downloaded Books" msgstr "" -#: cps/render_template.py:48 cps/render_template.py:53 +#: cps/render_template.py:51 cps/render_template.py:56 #: cps/templates/user_table.html:167 msgid "Show Downloaded Books" msgstr "" -#: cps/render_template.py:56 cps/templates/index.xml:32 cps/web.py:427 +#: cps/render_template.py:59 cps/templates/index.xml:32 cps/web.py:425 msgid "Top Rated Books" msgstr "" -#: cps/render_template.py:58 cps/templates/user_table.html:161 +#: cps/render_template.py:61 cps/templates/user_table.html:161 msgid "Show Top Rated Books" msgstr "" -#: cps/render_template.py:59 cps/templates/index.xml:54 -#: cps/templates/index.xml:58 cps/web.py:658 +#: cps/render_template.py:62 cps/templates/index.xml:54 +#: cps/templates/index.xml:58 cps/web.py:746 msgid "Read Books" msgstr "" -#: cps/render_template.py:61 -msgid "Show read and unread" +#: cps/render_template.py:64 +msgid "Show Read and Unread" msgstr "" -#: cps/render_template.py:63 cps/templates/index.xml:61 -#: cps/templates/index.xml:65 cps/web.py:661 +#: cps/render_template.py:66 cps/templates/index.xml:61 +#: cps/templates/index.xml:65 cps/web.py:749 msgid "Unread Books" msgstr "" -#: cps/render_template.py:65 +#: cps/render_template.py:68 msgid "Show unread" msgstr "" -#: cps/render_template.py:66 +#: cps/render_template.py:69 msgid "Discover" msgstr "" -#: cps/render_template.py:68 cps/templates/index.xml:50 -#: cps/templates/user_table.html:162 +#: cps/render_template.py:71 cps/templates/index.xml:50 +#: cps/templates/user_table.html:159 cps/templates/user_table.html:162 msgid "Show Random Books" msgstr "" -#: cps/render_template.py:69 cps/templates/book_table.html:67 -#: cps/templates/index.xml:83 cps/web.py:1035 +#: cps/render_template.py:72 cps/templates/book_table.html:67 +#: cps/templates/index.xml:83 cps/web.py:1106 msgid "Categories" msgstr "" -#: cps/render_template.py:71 cps/templates/user_table.html:158 -msgid "Show category selection" +#: cps/render_template.py:74 cps/templates/user_table.html:158 +msgid "Show Category Section" msgstr "" -#: cps/render_template.py:72 cps/templates/book_edit.html:90 +#: cps/render_template.py:75 cps/templates/book_edit.html:91 #: cps/templates/book_table.html:68 cps/templates/index.xml:90 -#: cps/templates/search_form.html:69 cps/web.py:930 cps/web.py:940 +#: cps/templates/search_form.html:69 cps/web.py:1002 cps/web.py:1009 msgid "Series" msgstr "" -#: cps/render_template.py:74 cps/templates/user_table.html:157 -msgid "Show series selection" +#: cps/render_template.py:77 cps/templates/user_table.html:157 +msgid "Show Series Section" msgstr "" -#: cps/render_template.py:75 cps/templates/book_table.html:66 +#: cps/render_template.py:78 cps/templates/book_table.html:66 #: cps/templates/index.xml:69 msgid "Authors" msgstr "" -#: cps/render_template.py:77 cps/templates/user_table.html:160 -msgid "Show author selection" +#: cps/render_template.py:80 cps/templates/user_table.html:160 +msgid "Show Author Section" msgstr "" -#: cps/render_template.py:79 cps/templates/book_table.html:72 -#: cps/templates/index.xml:76 cps/web.py:907 +#: cps/render_template.py:82 cps/templates/book_table.html:72 +#: cps/templates/index.xml:76 cps/web.py:973 msgid "Publishers" msgstr "" -#: cps/render_template.py:81 cps/templates/user_table.html:163 -msgid "Show publisher selection" +#: cps/render_template.py:84 cps/templates/user_table.html:163 +msgid "Show Publisher Section" msgstr "" -#: cps/render_template.py:82 cps/templates/book_table.html:70 +#: cps/render_template.py:85 cps/templates/book_table.html:70 #: cps/templates/index.xml:97 cps/templates/search_form.html:107 -#: cps/web.py:1012 +#: cps/web.py:1078 msgid "Languages" msgstr "" -#: cps/render_template.py:85 cps/templates/user_table.html:155 -msgid "Show language selection" +#: cps/render_template.py:88 cps/templates/user_table.html:155 +msgid "Show Language Section" msgstr "" -#: cps/render_template.py:86 cps/templates/index.xml:104 +#: cps/render_template.py:89 cps/templates/index.xml:104 msgid "Ratings" msgstr "" -#: cps/render_template.py:88 cps/templates/user_table.html:164 -msgid "Show ratings selection" +#: cps/render_template.py:91 cps/templates/user_table.html:164 +msgid "Show Ratings Section" msgstr "" -#: cps/render_template.py:89 cps/templates/index.xml:112 +#: cps/render_template.py:92 cps/templates/index.xml:112 msgid "File formats" msgstr "" -#: cps/render_template.py:91 cps/templates/user_table.html:165 -msgid "Show file formats selection" +#: cps/render_template.py:94 cps/templates/user_table.html:165 +msgid "Show File Formats Section" msgstr "" -#: cps/render_template.py:93 cps/web.py:685 +#: cps/render_template.py:96 cps/web.py:772 msgid "Archived Books" msgstr "" -#: cps/render_template.py:95 cps/templates/user_table.html:166 -msgid "Show archived books" +#: cps/render_template.py:98 cps/templates/user_table.html:166 +msgid "Show Archived Books" msgstr "" -#: cps/render_template.py:97 cps/web.py:761 +#: cps/render_template.py:101 cps/web.py:803 msgid "Books List" msgstr "" -#: cps/render_template.py:99 cps/templates/user_table.html:168 +#: cps/render_template.py:103 cps/templates/user_table.html:168 msgid "Show Books List" msgstr "" -#: cps/shelf.py:67 cps/shelf.py:121 -msgid "Invalid shelf specified" -msgstr "" - -#: cps/shelf.py:73 -msgid "Sorry you are not allowed to add a book to that shelf" -msgstr "" - -#: cps/shelf.py:82 -#, python-format -msgid "Book is already part of the shelf: %(shelfname)s" -msgstr "" - -#: cps/shelf.py:107 -#, python-format -msgid "Book has been added to shelf: %(sname)s" -msgstr "" - -#: cps/shelf.py:126 -#, python-format -msgid "You are not allowed to add a book to the the shelf: %(name)s" -msgstr "" - -#: cps/shelf.py:144 -#, python-format -msgid "Books are already part of the shelf: %(name)s" -msgstr "" - -#: cps/shelf.py:156 -#, python-format -msgid "Books have been added to shelf: %(sname)s" -msgstr "" - -#: cps/shelf.py:163 -#, python-format -msgid "Could not add books to shelf: %(sname)s" -msgstr "" - -#: cps/shelf.py:209 -#, python-format -msgid "Book has been removed from shelf: %(sname)s" -msgstr "" - -#: cps/shelf.py:218 -#, python-format -msgid "Sorry you are not allowed to remove a book from this shelf: %(sname)s" -msgstr "" - -#: cps/shelf.py:228 cps/templates/layout.html:142 -msgid "Create a Shelf" -msgstr "" - -#: cps/shelf.py:236 -msgid "Sorry you are not allowed to edit this shelf" -msgstr "" - -#: cps/shelf.py:238 -msgid "Edit a shelf" -msgstr "" - -#: cps/shelf.py:257 -#, python-format -msgid "Shelf %(title)s created" -msgstr "" - -#: cps/shelf.py:260 -#, python-format -msgid "Shelf %(title)s changed" -msgstr "" - -#: cps/shelf.py:274 -msgid "There was an error" -msgstr "" - -#: cps/shelf.py:296 -#, python-format -msgid "A public shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:307 -#, python-format -msgid "A private shelf with the name '%(title)s' already exists." -msgstr "" - -#: cps/shelf.py:376 -#, python-format -msgid "Change order of Shelf: '%(name)s'" -msgstr "" - -#: cps/shelf.py:446 -#, python-format -msgid "Shelf: '%(name)s'" -msgstr "" - -#: cps/shelf.py:450 -msgid "Error opening shelf. Shelf does not exist or is not accessible" -msgstr "" - -#: cps/updater.py:403 cps/updater.py:414 cps/updater.py:514 cps/updater.py:529 -msgid "Unexpected data while reading update information" -msgstr "" - -#: cps/updater.py:410 cps/updater.py:521 -msgid "No update available. You already have the latest version installed" -msgstr "" - -#: cps/updater.py:428 -msgid "A new update is available. Click on the button below to update to the latest version." -msgstr "" - -#: cps/updater.py:446 -msgid "Could not fetch update information" -msgstr "" - -#: cps/updater.py:456 -msgid "Click on the button below to update to the latest stable version." -msgstr "" - -#: cps/updater.py:465 cps/updater.py:479 cps/updater.py:490 -#, python-format -msgid "A new update is available. Click on the button below to update to version: %(version)s" -msgstr "" - -#: cps/updater.py:507 -msgid "No release information available" -msgstr "" - -#: cps/templates/index.html:5 cps/web.py:437 -msgid "Discover (Random Books)" -msgstr "" - -#: cps/web.py:463 -msgid "Hot Books (Most Downloaded)" -msgstr "" - -#: cps/web.py:496 -#, python-format -msgid "Downloaded books by %(user)s" -msgstr "" - -#: cps/web.py:527 -#, python-format -msgid "Author: %(name)s" -msgstr "" - -#: cps/web.py:542 -#, python-format -msgid "Publisher: %(name)s" -msgstr "" - -#: cps/web.py:555 -#, python-format -msgid "Series: %(serie)s" -msgstr "" - -#: cps/web.py:568 -#, python-format -msgid "Rating: %(rating)s stars" -msgstr "" - -#: cps/web.py:581 -#, python-format -msgid "File format: %(format)s" -msgstr "" - -#: cps/web.py:597 -#, python-format -msgid "Category: %(name)s" -msgstr "" - -#: cps/web.py:613 -#, python-format -msgid "Language: %(name)s" -msgstr "" - -#: cps/templates/layout.html:56 cps/web.py:719 cps/web.py:1364 -msgid "Advanced Search" -msgstr "" - -#: cps/templates/book_edit.html:239 cps/templates/feed.xml:33 -#: cps/templates/index.xml:11 cps/templates/layout.html:45 -#: cps/templates/layout.html:48 cps/templates/search_form.html:226 -#: cps/web.py:732 cps/web.py:1070 +#: cps/search.py:49 cps/search.py:393 cps/templates/book_edit.html:236 +#: cps/templates/feed.xml:33 cps/templates/index.xml:11 +#: cps/templates/layout.html:47 cps/templates/layout.html:50 +#: cps/templates/search_form.html:226 msgid "Search" msgstr "" -#: cps/templates/admin.html:16 cps/web.py:885 -msgid "Downloads" -msgstr "" - -#: cps/web.py:961 -msgid "Ratings list" -msgstr "" - -#: cps/web.py:982 -msgid "File formats list" -msgstr "" - -#: cps/templates/layout.html:75 cps/templates/tasks.html:7 cps/web.py:1049 -msgid "Tasks" -msgstr "" - -#: cps/web.py:1208 +#: cps/search.py:189 msgid "Published after " msgstr "" -#: cps/web.py:1215 +#: cps/search.py:196 msgid "Published before " msgstr "" -#: cps/web.py:1237 +#: cps/search.py:218 #, python-format msgid "Rating <= %(rating)s" msgstr "" -#: cps/web.py:1239 +#: cps/search.py:220 #, python-format msgid "Rating >= %(rating)s" msgstr "" -#: cps/web.py:1241 +#: cps/search.py:222 #, python-format msgid "Read Status = %(status)s" msgstr "" -#: cps/web.py:1346 +#: cps/search.py:324 msgid "Error on search for custom columns, please restart Calibre-Web" msgstr "" -#: cps/web.py:1441 +#: cps/search.py:343 cps/search.py:375 cps/templates/layout.html:58 +msgid "Advanced Search" +msgstr "" + +#: cps/shelf.py:49 cps/shelf.py:103 +msgid "Invalid shelf specified" +msgstr "" + +#: cps/shelf.py:55 +msgid "Sorry you are not allowed to add a book to that shelf" +msgstr "" + +#: cps/shelf.py:64 #, python-format -msgid "Book successfully queued for sending to %(kindlemail)s" +msgid "Book is already part of the shelf: %(shelfname)s" msgstr "" -#: cps/web.py:1445 +#: cps/shelf.py:89 #, python-format -msgid "Oops! There was an error sending this book: %(res)s" +msgid "Book has been added to shelf: %(sname)s" msgstr "" -#: cps/web.py:1447 -msgid "Please update your profile with a valid Send to Kindle E-mail Address." +#: cps/shelf.py:108 +msgid "You are not allowed to add a book to the shelf" msgstr "" -#: cps/web.py:1464 -msgid "E-Mail server is not configured, please contact your administrator!" +#: cps/shelf.py:126 +#, python-format +msgid "Books are already part of the shelf: %(name)s" msgstr "" -#: cps/templates/layout.html:87 cps/templates/register.html:17 cps/web.py:1465 -#: cps/web.py:1472 cps/web.py:1478 cps/web.py:1497 cps/web.py:1501 -#: cps/web.py:1507 +#: cps/shelf.py:138 +#, python-format +msgid "Books have been added to shelf: %(sname)s" +msgstr "" + +#: cps/shelf.py:145 +#, python-format +msgid "Could not add books to shelf: %(sname)s" +msgstr "" + +#: cps/shelf.py:191 +#, python-format +msgid "Book has been removed from shelf: %(sname)s" +msgstr "" + +#: cps/shelf.py:200 +msgid "Sorry you are not allowed to remove a book from this shelf" +msgstr "" + +#: cps/shelf.py:210 cps/templates/layout.html:158 +msgid "Create a Shelf" +msgstr "" + +#: cps/shelf.py:218 +msgid "Sorry you are not allowed to edit this shelf" +msgstr "" + +#: cps/shelf.py:220 +msgid "Edit a shelf" +msgstr "" + +#: cps/shelf.py:229 +msgid "Error deleting Shelf" +msgstr "" + +#: cps/shelf.py:231 +msgid "Shelf successfully deleted" +msgstr "" + +#: cps/shelf.py:281 +#, python-format +msgid "Change order of Shelf: '%(name)s'" +msgstr "" + +#: cps/shelf.py:313 +msgid "Sorry you are not allowed to create a public shelf" +msgstr "" + +#: cps/shelf.py:330 +#, python-format +msgid "Shelf %(title)s created" +msgstr "" + +#: cps/shelf.py:333 +#, python-format +msgid "Shelf %(title)s changed" +msgstr "" + +#: cps/shelf.py:347 +msgid "There was an error" +msgstr "" + +#: cps/shelf.py:369 +#, python-format +msgid "A public shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:380 +#, python-format +msgid "A private shelf with the name '%(title)s' already exists." +msgstr "" + +#: cps/shelf.py:462 +#, python-format +msgid "Shelf: '%(name)s'" +msgstr "" + +#: cps/shelf.py:466 +msgid "Error opening shelf. Shelf does not exist or is not accessible" +msgstr "" + +#: cps/tasks_status.py:48 cps/templates/layout.html:89 +#: cps/templates/tasks.html:7 +msgid "Tasks" +msgstr "" + +#: cps/tasks_status.py:64 +msgid "Waiting" +msgstr "" + +#: cps/tasks_status.py:66 +msgid "Failed" +msgstr "" + +#: cps/tasks_status.py:68 +msgid "Started" +msgstr "" + +#: cps/tasks_status.py:70 +msgid "Finished" +msgstr "" + +#: cps/tasks_status.py:72 +msgid "Ended" +msgstr "" + +#: cps/tasks_status.py:74 +msgid "Cancelled" +msgstr "" + +#: cps/tasks_status.py:76 +msgid "Unknown Status" +msgstr "" + +#: cps/updater.py:431 cps/updater.py:442 cps/updater.py:543 cps/updater.py:558 +msgid "Unexpected data while reading update information" +msgstr "" + +#: cps/updater.py:438 cps/updater.py:550 +msgid "No update available. You already have the latest version installed" +msgstr "" + +#: cps/updater.py:456 +msgid "A new update is available. Click on the button below to update to the latest version." +msgstr "" + +#: cps/updater.py:474 +msgid "Could not fetch update information" +msgstr "" + +#: cps/updater.py:484 +msgid "Click on the button below to update to the latest stable version." +msgstr "" + +#: cps/updater.py:493 cps/updater.py:507 cps/updater.py:518 +#, python-format +msgid "A new update is available. Click on the button below to update to version: %(version)s" +msgstr "" + +#: cps/updater.py:536 +msgid "No release information available" +msgstr "" + +#: cps/templates/index.html:6 cps/web.py:437 +msgid "Discover (Random Books)" +msgstr "" + +#: cps/web.py:473 +msgid "Hot Books (Most Downloaded)" +msgstr "" + +#: cps/web.py:504 +#, python-format +msgid "Downloaded books by %(user)s" +msgstr "" + +#: cps/web.py:537 +#, python-format +msgid "Author: %(name)s" +msgstr "" + +#: cps/web.py:573 +#, python-format +msgid "Publisher: %(name)s" +msgstr "" + +#: cps/web.py:601 +#, python-format +msgid "Series: %(serie)s" +msgstr "" + +#: cps/web.py:616 +msgid "Rating: None" +msgstr "" + +#: cps/web.py:625 +#, python-format +msgid "Rating: %(rating)s stars" +msgstr "" + +#: cps/web.py:643 +#, python-format +msgid "File format: %(format)s" +msgstr "" + +#: cps/web.py:680 +#, python-format +msgid "Category: %(name)s" +msgstr "" + +#: cps/web.py:707 +#, python-format +msgid "Language: %(name)s" +msgstr "" + +#: cps/templates/admin.html:16 cps/web.py:945 +msgid "Downloads" +msgstr "" + +#: cps/web.py:1038 +msgid "Ratings list" +msgstr "" + +#: cps/web.py:1065 +msgid "File formats list" +msgstr "" + +#: cps/web.py:1202 +msgid "Please configure the SMTP mail settings first." +msgstr "" + +#: cps/web.py:1207 +#, python-format +msgid "Success! Book queued for sending to %(eReadermail)s" +msgstr "" + +#: cps/web.py:1211 +#, python-format +msgid "Oops! There was an error sending book: %(res)s" +msgstr "" + +#: cps/web.py:1213 +msgid "Oops! Please update your profile with a valid eReader Email." +msgstr "" + +#: cps/web.py:1230 +msgid "Oops! Email server is not configured, please contact your administrator." +msgstr "" + +#: cps/templates/layout.html:69 cps/templates/layout.html:103 +#: cps/templates/login.html:27 cps/templates/register.html:17 cps/web.py:1231 +#: cps/web.py:1238 cps/web.py:1244 cps/web.py:1264 cps/web.py:1269 +#: cps/web.py:1275 msgid "Register" msgstr "" -#: cps/web.py:1499 -msgid "Your e-mail is not allowed to register" +#: cps/web.py:1266 +msgid "Oops! Your Email is not allowed." msgstr "" -#: cps/web.py:1502 -msgid "Confirmation e-mail was send to your e-mail account." +#: cps/web.py:1270 +msgid "Success! Confirmation Email has been sent." msgstr "" -#: cps/web.py:1519 -msgid "Cannot activate LDAP authentication" +#: cps/web.py:1284 +msgid "Oops! Cannot activate LDAP authentication" msgstr "" -#: cps/web.py:1538 +#: cps/web.py:1303 #, python-format -msgid "Fallback Login as: '%(nickname)s', LDAP Server not reachable, or user not known" +msgid "Fallback Login as: %(nickname)s, LDAP Server not reachable, or user not known" msgstr "" -#: cps/web.py:1544 +#: cps/web.py:1309 #, python-format -msgid "Could not login: %(message)s" +msgid "Oops! Login Failed: %(message)s" msgstr "" -#: cps/web.py:1548 cps/web.py:1573 -msgid "Wrong Username or Password" +#: cps/web.py:1313 cps/web.py:1338 +msgid "Oops! Invalid Username or Password." msgstr "" -#: cps/web.py:1555 -msgid "New Password was send to your email address" +#: cps/web.py:1320 +msgid "Success! New Password was sent to your Email." msgstr "" -#: cps/web.py:1561 -msgid "Please enter valid username to reset password" +#: cps/web.py:1326 +msgid "Oops! Please enter a valid username to reset password" msgstr "" -#: cps/web.py:1568 +#: cps/web.py:1400 cps/web.py:1449 #, python-format -msgid "You are now logged in as: '%(nickname)s'" +msgid "%(name)s's Profile" msgstr "" -#: cps/web.py:1634 cps/web.py:1683 -#, python-format -msgid "%(name)s's profile" +#: cps/web.py:1416 +msgid "Success! Profile Updated" msgstr "" -#: cps/web.py:1650 -msgid "Profile updated" +#: cps/web.py:1420 +msgid "Oops! An account already exists for this Email." msgstr "" #: cps/services/gmail.py:58 msgid "Found no valid gmail.json file with OAuth information" msgstr "" -#: cps/tasks/convert.py:137 +#: cps/tasks/convert.py:92 +#, python-format +msgid "%(book)s send to E-Reader" +msgstr "" + +#: cps/tasks/convert.py:153 #, python-format msgid "Calibre ebook-convert %(tool)s not found" msgstr "" -#: cps/tasks/convert.py:162 +#: cps/tasks/convert.py:186 #, python-format msgid "%(format)s format not found on disk" msgstr "" -#: cps/tasks/convert.py:166 +#: cps/tasks/convert.py:190 msgid "Ebook converter failed with unknown error" msgstr "" -#: cps/tasks/convert.py:176 +#: cps/tasks/convert.py:202 #, python-format msgid "Kepubify-converter failed: %(error)s" msgstr "" -#: cps/tasks/convert.py:198 +#: cps/tasks/convert.py:224 #, python-format msgid "Converted file not found or more than one file in folder %(folder)s" msgstr "" -#: cps/tasks/convert.py:221 +#: cps/tasks/convert.py:247 #, python-format msgid "Ebook-converter failed: %(error)s" msgstr "" -#: cps/tasks/convert.py:240 +#: cps/tasks/convert.py:270 #, python-format msgid "Calibre failed with error: %(error)s" msgstr "" +#: cps/tasks/convert.py:275 +msgid "Convert" +msgstr "" + +#: cps/tasks/database.py:28 +msgid "Reconnecting Calibre database" +msgstr "" + +#: cps/tasks/mail.py:266 +msgid "E-mail" +msgstr "" + +#: cps/tasks/metadata_backup.py:47 +msgid "Backing up Metadata" +msgstr "" + +#: cps/tasks/thumbnail.py:95 +#, python-format +msgid "Generated %(count)s cover thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:222 cps/tasks/thumbnail.py:435 +#: cps/tasks/thumbnail.py:503 +msgid "Cover Thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:281 +msgid "Generated {0} series thumbnails" +msgstr "" + +#: cps/tasks/thumbnail.py:446 +msgid "Clearing cover thumbnail cache" +msgstr "" + +#: cps/tasks/upload.py:38 cps/templates/admin.html:20 +#: cps/templates/layout.html:82 cps/templates/user_table.html:145 +msgid "Upload" +msgstr "" + #: cps/templates/admin.html:9 msgid "Users" msgstr "" @@ -1330,14 +1483,14 @@ msgstr "" #: cps/templates/admin.html:14 cps/templates/register.html:14 #: cps/templates/user_edit.html:15 cps/templates/user_table.html:135 -msgid "E-mail Address" +msgid "Email" msgstr "" #: cps/templates/admin.html:15 cps/templates/user_edit.html:28 -msgid "Send to Kindle E-mail Address" +msgid "Send to eReader Email" msgstr "" -#: cps/templates/admin.html:17 cps/templates/layout.html:78 +#: cps/templates/admin.html:17 cps/templates/layout.html:92 #: cps/templates/user_table.html:143 msgid "Admin" msgstr "" @@ -1347,211 +1500,228 @@ msgstr "" msgid "Password" msgstr "" -#: cps/templates/admin.html:19 cps/templates/layout.html:67 -#: cps/templates/user_table.html:145 -msgid "Upload" -msgstr "" - -#: cps/templates/admin.html:20 cps/templates/detail.html:18 -#: cps/templates/detail.html:27 cps/templates/shelf.html:6 +#: cps/templates/admin.html:22 cps/templates/detail.html:19 +#: cps/templates/detail.html:28 cps/templates/shelf.html:8 #: cps/templates/user_table.html:146 msgid "Download" msgstr "" -#: cps/templates/admin.html:21 +#: cps/templates/admin.html:23 msgid "View Books" msgstr "" -#: cps/templates/admin.html:22 cps/templates/user_table.html:131 +#: cps/templates/admin.html:24 cps/templates/user_table.html:131 #: cps/templates/user_table.html:148 msgid "Edit" msgstr "" -#: cps/templates/admin.html:23 cps/templates/book_edit.html:16 -#: cps/templates/book_table.html:97 cps/templates/modal_dialogs.html:63 +#: cps/templates/admin.html:25 cps/templates/book_edit.html:17 +#: cps/templates/book_table.html:100 cps/templates/modal_dialogs.html:63 #: cps/templates/modal_dialogs.html:116 cps/templates/user_edit.html:67 #: cps/templates/user_table.html:149 msgid "Delete" msgstr "" -#: cps/templates/admin.html:24 +#: cps/templates/admin.html:26 msgid "Public Shelf" msgstr "" -#: cps/templates/admin.html:47 -msgid "Add New User" -msgstr "" - -#: cps/templates/admin.html:49 +#: cps/templates/admin.html:55 msgid "Import LDAP Users" msgstr "" -#: cps/templates/admin.html:56 -msgid "E-mail Server Settings" +#: cps/templates/admin.html:62 +msgid "Email Server Settings" msgstr "" -#: cps/templates/admin.html:61 cps/templates/email_edit.html:31 +#: cps/templates/admin.html:67 cps/templates/email_edit.html:31 msgid "SMTP Hostname" msgstr "" -#: cps/templates/admin.html:65 cps/templates/email_edit.html:35 +#: cps/templates/admin.html:71 cps/templates/email_edit.html:35 msgid "SMTP Port" msgstr "" -#: cps/templates/admin.html:69 cps/templates/email_edit.html:39 +#: cps/templates/admin.html:75 cps/templates/email_edit.html:39 msgid "Encryption" msgstr "" -#: cps/templates/admin.html:73 cps/templates/email_edit.html:47 +#: cps/templates/admin.html:79 cps/templates/email_edit.html:47 msgid "SMTP Login" msgstr "" -#: cps/templates/admin.html:77 cps/templates/admin.html:88 +#: cps/templates/admin.html:83 cps/templates/admin.html:94 #: cps/templates/email_edit.html:55 -msgid "From E-mail" +msgid "From Email" msgstr "" -#: cps/templates/admin.html:84 -msgid "E-Mail Service" +#: cps/templates/admin.html:90 +msgid "Email Service" msgstr "" -#: cps/templates/admin.html:85 +#: cps/templates/admin.html:91 msgid "Gmail via Oauth2" msgstr "" -#: cps/templates/admin.html:100 +#: cps/templates/admin.html:106 msgid "Configuration" msgstr "" -#: cps/templates/admin.html:103 +#: cps/templates/admin.html:109 msgid "Calibre Database Directory" msgstr "" -#: cps/templates/admin.html:107 cps/templates/config_edit.html:68 +#: cps/templates/admin.html:113 cps/templates/config_edit.html:68 msgid "Log Level" msgstr "" -#: cps/templates/admin.html:111 +#: cps/templates/admin.html:117 msgid "Port" msgstr "" -#: cps/templates/admin.html:116 +#: cps/templates/admin.html:122 msgid "External Port" msgstr "" -#: cps/templates/admin.html:123 cps/templates/config_view_edit.html:28 +#: cps/templates/admin.html:129 cps/templates/config_view_edit.html:28 msgid "Books per Page" msgstr "" -#: cps/templates/admin.html:127 +#: cps/templates/admin.html:133 msgid "Uploads" msgstr "" -#: cps/templates/admin.html:131 +#: cps/templates/admin.html:137 msgid "Anonymous Browsing" msgstr "" -#: cps/templates/admin.html:135 +#: cps/templates/admin.html:141 msgid "Public Registration" msgstr "" -#: cps/templates/admin.html:139 +#: cps/templates/admin.html:145 msgid "Magic Link Remote Login" msgstr "" -#: cps/templates/admin.html:143 +#: cps/templates/admin.html:149 msgid "Reverse Proxy Login" msgstr "" -#: cps/templates/admin.html:148 cps/templates/config_edit.html:173 +#: cps/templates/admin.html:154 cps/templates/config_edit.html:173 msgid "Reverse Proxy Header Name" msgstr "" -#: cps/templates/admin.html:153 +#: cps/templates/admin.html:159 msgid "Edit Calibre Database Configuration" msgstr "" -#: cps/templates/admin.html:154 +#: cps/templates/admin.html:160 msgid "Edit Basic Configuration" msgstr "" -#: cps/templates/admin.html:155 +#: cps/templates/admin.html:161 msgid "Edit UI Configuration" msgstr "" -#: cps/templates/admin.html:160 -msgid "Administration" +#: cps/templates/admin.html:167 +msgid "Scheduled Tasks" msgstr "" -#: cps/templates/admin.html:161 -msgid "Download Debug Package" +#: cps/templates/admin.html:170 cps/templates/schedule_edit.html:12 +#: cps/templates/tasks.html:18 +msgid "Start Time" msgstr "" -#: cps/templates/admin.html:162 -msgid "View Logs" +#: cps/templates/admin.html:174 cps/templates/schedule_edit.html:20 +msgid "Maximum Duration" msgstr "" -#: cps/templates/admin.html:165 +#: cps/templates/admin.html:178 cps/templates/schedule_edit.html:29 +msgid "Generate Thumbnails" +msgstr "" + +#: cps/templates/admin.html:182 +msgid "Generate series cover thumbnails" +msgstr "" + +#: cps/templates/admin.html:186 cps/templates/admin.html:204 +#: cps/templates/schedule_edit.html:37 msgid "Reconnect Calibre Database" msgstr "" -#: cps/templates/admin.html:166 +#: cps/templates/admin.html:193 +msgid "Refresh Thumbnail Cache" +msgstr "" + +#: cps/templates/admin.html:199 +msgid "Administration" +msgstr "" + +#: cps/templates/admin.html:200 +msgid "Download Debug Package" +msgstr "" + +#: cps/templates/admin.html:201 +msgid "View Logs" +msgstr "" + +#: cps/templates/admin.html:207 msgid "Restart" msgstr "" -#: cps/templates/admin.html:167 +#: cps/templates/admin.html:208 msgid "Shutdown" msgstr "" -#: cps/templates/admin.html:172 -msgid "Update" +#: cps/templates/admin.html:216 +msgid "Version Information" msgstr "" -#: cps/templates/admin.html:176 +#: cps/templates/admin.html:220 msgid "Version" msgstr "" -#: cps/templates/admin.html:177 +#: cps/templates/admin.html:221 msgid "Details" msgstr "" -#: cps/templates/admin.html:183 -msgid "Current version" +#: cps/templates/admin.html:227 +msgid "Current Version" msgstr "" -#: cps/templates/admin.html:191 +#: cps/templates/admin.html:234 msgid "Check for Update" msgstr "" -#: cps/templates/admin.html:192 +#: cps/templates/admin.html:235 msgid "Perform Update" msgstr "" -#: cps/templates/admin.html:205 +#: cps/templates/admin.html:248 msgid "Are you sure you want to restart?" msgstr "" -#: cps/templates/admin.html:210 cps/templates/admin.html:224 -#: cps/templates/admin.html:244 cps/templates/config_db.html:70 -#: cps/templates/shelf.html:96 +#: cps/templates/admin.html:253 cps/templates/admin.html:267 +#: cps/templates/admin.html:287 cps/templates/config_db.html:70 msgid "OK" msgstr "" -#: cps/templates/admin.html:211 cps/templates/admin.html:225 -#: cps/templates/book_edit.html:217 cps/templates/book_table.html:124 +#: cps/templates/admin.html:254 cps/templates/admin.html:268 +#: cps/templates/book_edit.html:214 cps/templates/book_table.html:127 #: cps/templates/config_db.html:54 cps/templates/config_edit.html:359 -#: cps/templates/config_view_edit.html:169 cps/templates/modal_dialogs.html:64 +#: cps/templates/config_view_edit.html:175 cps/templates/modal_dialogs.html:64 #: cps/templates/modal_dialogs.html:99 cps/templates/modal_dialogs.html:117 -#: cps/templates/modal_dialogs.html:135 cps/templates/shelf.html:97 -#: cps/templates/shelf_edit.html:27 cps/templates/user_edit.html:137 +#: cps/templates/modal_dialogs.html:135 cps/templates/schedule_edit.html:41 +#: cps/templates/shelf_edit.html:27 cps/templates/tasks.html:46 +#: cps/templates/user_edit.html:144 msgid "Cancel" msgstr "" -#: cps/templates/admin.html:223 +#: cps/templates/admin.html:266 msgid "Are you sure you want to shutdown?" msgstr "" -#: cps/templates/admin.html:235 +#: cps/templates/admin.html:278 msgid "Updating, please do not reload this page" msgstr "" @@ -1563,119 +1733,118 @@ msgstr "" msgid "In Library" msgstr "" -#: cps/templates/author.html:26 cps/templates/index.html:68 -#: cps/templates/search.html:29 cps/templates/shelf.html:17 +#: cps/templates/author.html:26 cps/templates/index.html:74 +#: cps/templates/search.html:31 cps/templates/shelf.html:20 msgid "Sort according to book date, newest first" msgstr "" -#: cps/templates/author.html:27 cps/templates/index.html:69 -#: cps/templates/search.html:30 cps/templates/shelf.html:18 +#: cps/templates/author.html:27 cps/templates/index.html:75 +#: cps/templates/search.html:32 cps/templates/shelf.html:21 msgid "Sort according to book date, oldest first" msgstr "" -#: cps/templates/author.html:28 cps/templates/index.html:70 -#: cps/templates/search.html:31 cps/templates/shelf.html:19 +#: cps/templates/author.html:28 cps/templates/index.html:76 +#: cps/templates/search.html:33 cps/templates/shelf.html:22 msgid "Sort title in alphabetical order" msgstr "" -#: cps/templates/author.html:29 cps/templates/index.html:71 -#: cps/templates/search.html:32 cps/templates/shelf.html:20 +#: cps/templates/author.html:29 cps/templates/index.html:77 +#: cps/templates/search.html:34 cps/templates/shelf.html:23 msgid "Sort title in reverse alphabetical order" msgstr "" -#: cps/templates/author.html:30 cps/templates/index.html:74 -#: cps/templates/search.html:35 cps/templates/shelf.html:23 +#: cps/templates/author.html:30 cps/templates/index.html:80 +#: cps/templates/search.html:37 cps/templates/shelf.html:26 msgid "Sort according to publishing date, newest first" msgstr "" -#: cps/templates/author.html:31 cps/templates/index.html:75 -#: cps/templates/search.html:36 cps/templates/shelf.html:24 +#: cps/templates/author.html:31 cps/templates/index.html:81 +#: cps/templates/search.html:38 cps/templates/shelf.html:27 msgid "Sort according to publishing date, oldest first" msgstr "" -#: cps/templates/author.html:57 cps/templates/author.html:117 -#: cps/templates/discover.html:30 cps/templates/index.html:29 -#: cps/templates/index.html:106 cps/templates/search.html:65 -#: cps/templates/shelf.html:52 +#: cps/templates/author.html:56 cps/templates/author.html:115 +#: cps/templates/index.html:30 cps/templates/index.html:113 +#: cps/templates/search.html:67 cps/templates/shelf.html:55 msgid "reduce" msgstr "" -#: cps/templates/author.html:101 +#: cps/templates/author.html:99 msgid "More by" msgstr "" -#: cps/templates/book_edit.html:10 +#: cps/templates/book_edit.html:11 msgid "Delete Book" msgstr "" -#: cps/templates/book_edit.html:13 +#: cps/templates/book_edit.html:14 msgid "Delete formats:" msgstr "" -#: cps/templates/book_edit.html:24 +#: cps/templates/book_edit.html:25 msgid "Convert book format:" msgstr "" -#: cps/templates/book_edit.html:29 +#: cps/templates/book_edit.html:30 msgid "Convert from:" msgstr "" -#: cps/templates/book_edit.html:31 cps/templates/book_edit.html:38 +#: cps/templates/book_edit.html:32 cps/templates/book_edit.html:39 msgid "select an option" msgstr "" -#: cps/templates/book_edit.html:36 +#: cps/templates/book_edit.html:37 msgid "Convert to:" msgstr "" -#: cps/templates/book_edit.html:45 +#: cps/templates/book_edit.html:46 msgid "Convert book" msgstr "" -#: cps/templates/book_edit.html:55 cps/templates/search_form.html:8 +#: cps/templates/book_edit.html:56 cps/templates/search_form.html:8 msgid "Book Title" msgstr "" -#: cps/templates/book_edit.html:62 cps/templates/book_edit.html:274 -#: cps/templates/book_edit.html:292 cps/templates/search_form.html:12 +#: cps/templates/book_edit.html:63 cps/templates/book_edit.html:271 +#: cps/templates/book_edit.html:289 cps/templates/search_form.html:12 msgid "Author" msgstr "" -#: cps/templates/book_edit.html:67 cps/templates/book_edit.html:279 -#: cps/templates/book_edit.html:294 cps/templates/search_form.html:153 +#: cps/templates/book_edit.html:68 cps/templates/book_edit.html:276 +#: cps/templates/book_edit.html:291 cps/templates/search_form.html:153 msgid "Description" msgstr "" -#: cps/templates/book_edit.html:72 +#: cps/templates/book_edit.html:73 msgid "Identifiers" msgstr "" -#: cps/templates/book_edit.html:76 cps/templates/book_edit.html:303 +#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:300 msgid "Identifier Type" msgstr "" -#: cps/templates/book_edit.html:77 cps/templates/book_edit.html:304 +#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:301 msgid "Identifier Value" msgstr "" -#: cps/templates/book_edit.html:78 cps/templates/book_edit.html:305 +#: cps/templates/book_edit.html:79 cps/templates/book_edit.html:302 #: cps/templates/user_table.html:24 msgid "Remove" msgstr "" -#: cps/templates/book_edit.html:82 +#: cps/templates/book_edit.html:83 msgid "Add Identifier" msgstr "" -#: cps/templates/book_edit.html:86 cps/templates/search_form.html:51 +#: cps/templates/book_edit.html:87 cps/templates/search_form.html:51 msgid "Tags" msgstr "" -#: cps/templates/book_edit.html:94 +#: cps/templates/book_edit.html:95 msgid "Series ID" msgstr "" -#: cps/templates/book_edit.html:98 +#: cps/templates/book_edit.html:99 msgid "Rating" msgstr "" @@ -1687,81 +1856,82 @@ msgstr "" msgid "Upload Cover from Local Disk" msgstr "" -#: cps/templates/book_edit.html:114 +#: cps/templates/book_edit.html:113 msgid "Published Date" msgstr "" -#: cps/templates/book_edit.html:123 cps/templates/book_edit.html:276 -#: cps/templates/book_edit.html:293 cps/templates/detail.html:164 -#: cps/templates/search_form.html:16 +#: cps/templates/book_edit.html:122 cps/templates/book_edit.html:273 +#: cps/templates/book_edit.html:290 cps/templates/detail.html:166 +#: cps/templates/listenmp3.html:102 cps/templates/search_form.html:16 msgid "Publisher" msgstr "" -#: cps/templates/book_edit.html:127 cps/templates/detail.html:131 -#: cps/templates/user_edit.html:33 +#: cps/templates/book_edit.html:126 cps/templates/detail.html:133 +#: cps/templates/listenmp3.html:69 cps/templates/user_edit.html:33 msgid "Language" msgstr "" -#: cps/templates/book_edit.html:137 cps/templates/search_form.html:45 +#: cps/templates/book_edit.html:136 cps/templates/search_form.html:45 #: cps/templates/search_form.html:164 msgid "Yes" msgstr "" -#: cps/templates/book_edit.html:138 cps/templates/search_form.html:46 +#: cps/templates/book_edit.html:137 cps/templates/search_form.html:46 #: cps/templates/search_form.html:165 msgid "No" msgstr "" -#: cps/templates/book_edit.html:203 +#: cps/templates/book_edit.html:201 msgid "Upload Format" msgstr "" -#: cps/templates/book_edit.html:212 +#: cps/templates/book_edit.html:209 msgid "View Book on Save" msgstr "" -#: cps/templates/book_edit.html:215 cps/templates/book_edit.html:233 +#: cps/templates/book_edit.html:212 cps/templates/book_edit.html:230 msgid "Fetch Metadata" msgstr "" -#: cps/templates/book_edit.html:216 cps/templates/config_db.html:53 -#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:168 -#: cps/templates/email_edit.html:65 cps/templates/shelf_edit.html:25 -#: cps/templates/shelf_order.html:41 cps/templates/user_edit.html:135 +#: cps/templates/book_edit.html:213 cps/templates/config_db.html:53 +#: cps/templates/config_edit.html:358 cps/templates/config_view_edit.html:174 +#: cps/templates/email_edit.html:65 cps/templates/schedule_edit.html:40 +#: cps/templates/shelf_edit.html:25 cps/templates/shelf_order.html:41 +#: cps/templates/user_edit.html:142 msgid "Save" msgstr "" -#: cps/templates/book_edit.html:236 +#: cps/templates/book_edit.html:233 msgid "Keyword" msgstr "" -#: cps/templates/book_edit.html:237 +#: cps/templates/book_edit.html:234 msgid "Search keyword" msgstr "" -#: cps/templates/book_edit.html:243 +#: cps/templates/book_edit.html:240 msgid "Click the cover to load metadata to the form" msgstr "" -#: cps/templates/book_edit.html:250 cps/templates/book_edit.html:289 +#: cps/templates/book_edit.html:247 cps/templates/book_edit.html:286 msgid "Loading..." msgstr "" -#: cps/templates/book_edit.html:254 cps/templates/layout.html:64 -#: cps/templates/layout.html:188 cps/templates/modal_dialogs.html:34 -#: cps/templates/user_edit.html:156 +#: cps/templates/book_edit.html:251 cps/templates/layout.html:79 +#: cps/templates/layout.html:204 cps/templates/modal_dialogs.html:34 +#: cps/templates/user_edit.html:163 msgid "Close" msgstr "" -#: cps/templates/book_edit.html:281 cps/templates/book_edit.html:295 +#: cps/templates/book_edit.html:278 cps/templates/book_edit.html:292 msgid "Source" msgstr "" -#: cps/templates/book_edit.html:290 +#: cps/templates/book_edit.html:287 msgid "Search error!" msgstr "" -#: cps/templates/book_edit.html:291 +#: cps/templates/book_edit.html:288 msgid "No Result(s) found! Please try another keyword." msgstr "" @@ -1852,26 +2022,35 @@ msgstr "" msgid "Comments" msgstr "" -#: cps/templates/book_table.html:77 cps/templates/book_table.html:79 -#: cps/templates/book_table.html:81 cps/templates/book_table.html:83 -#: cps/templates/book_table.html:87 cps/templates/book_table.html:89 -#: cps/templates/book_table.html:91 cps/templates/book_table.html:93 +#: cps/templates/book_table.html:75 +msgid "Archive Status" +msgstr "" + +#: cps/templates/book_table.html:77 cps/templates/search_form.html:42 +msgid "Read Status" +msgstr "" + +#: cps/templates/book_table.html:80 cps/templates/book_table.html:82 +#: cps/templates/book_table.html:84 cps/templates/book_table.html:86 +#: cps/templates/book_table.html:90 cps/templates/book_table.html:92 +#: cps/templates/book_table.html:96 msgid "Enter " msgstr "" -#: cps/templates/book_table.html:110 cps/templates/modal_dialogs.html:46 +#: cps/templates/book_table.html:113 cps/templates/modal_dialogs.html:46 +#: cps/templates/tasks.html:36 msgid "Are you really sure?" msgstr "" -#: cps/templates/book_table.html:114 +#: cps/templates/book_table.html:117 msgid "Books with Title will be merged from:" msgstr "" -#: cps/templates/book_table.html:118 +#: cps/templates/book_table.html:121 msgid "Into Book with Title:" msgstr "" -#: cps/templates/book_table.html:123 +#: cps/templates/book_table.html:126 msgid "Merge" msgstr "" @@ -1963,6 +2142,10 @@ msgstr "" msgid "Enable Uploads" msgstr "" +#: cps/templates/config_edit.html:108 +msgid "(Please ensure users having also upload rights)" +msgstr "" + #: cps/templates/config_edit.html:112 msgid "Allowed Upload Fileformats" msgstr "" @@ -1976,7 +2159,7 @@ msgid "Enable Public Registration" msgstr "" #: cps/templates/config_edit.html:127 -msgid "Use E-Mail as Username" +msgid "Use Email as Username" msgstr "" #: cps/templates/config_edit.html:132 @@ -2043,11 +2226,6 @@ msgstr "" msgid "LDAP Encryption" msgstr "" -#: cps/templates/config_edit.html:204 cps/templates/config_view_edit.html:62 -#: cps/templates/email_edit.html:41 -msgid "None" -msgstr "" - #: cps/templates/config_edit.html:205 msgid "TLS" msgstr "" @@ -2183,7 +2361,7 @@ msgstr "" msgid "No. of Authors to Display Before Hiding (0=Disable Hiding)" msgstr "" -#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:113 +#: cps/templates/config_view_edit.html:40 cps/templates/readcbr.html:116 msgid "Theme" msgstr "" @@ -2215,136 +2393,138 @@ msgstr "" msgid "Default Settings for New Users" msgstr "" -#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:93 +#: cps/templates/config_view_edit.html:88 cps/templates/user_edit.html:96 msgid "Admin User" msgstr "" -#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:98 +#: cps/templates/config_view_edit.html:92 cps/templates/user_edit.html:101 msgid "Allow Downloads" msgstr "" -#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:102 +#: cps/templates/config_view_edit.html:96 cps/templates/user_edit.html:105 msgid "Allow eBook Viewer" msgstr "" -#: cps/templates/config_view_edit.html:100 cps/templates/user_edit.html:106 +#: cps/templates/config_view_edit.html:101 cps/templates/user_edit.html:110 msgid "Allow Uploads" msgstr "" -#: cps/templates/config_view_edit.html:104 cps/templates/user_edit.html:110 +#: cps/templates/config_view_edit.html:106 cps/templates/user_edit.html:115 msgid "Allow Edit" msgstr "" -#: cps/templates/config_view_edit.html:108 cps/templates/user_edit.html:114 +#: cps/templates/config_view_edit.html:111 cps/templates/user_edit.html:120 msgid "Allow Delete Books" msgstr "" -#: cps/templates/config_view_edit.html:112 cps/templates/user_edit.html:119 +#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:126 msgid "Allow Changing Password" msgstr "" -#: cps/templates/config_view_edit.html:116 cps/templates/user_edit.html:123 +#: cps/templates/config_view_edit.html:120 cps/templates/user_edit.html:130 msgid "Allow Editing Public Shelves" msgstr "" -#: cps/templates/config_view_edit.html:119 +#: cps/templates/config_view_edit.html:123 msgid "Default Language" msgstr "" -#: cps/templates/config_view_edit.html:127 +#: cps/templates/config_view_edit.html:131 msgid "Default Visible Language of Books" msgstr "" -#: cps/templates/config_view_edit.html:143 +#: cps/templates/config_view_edit.html:147 msgid "Default Visibilities for New Users" msgstr "" -#: cps/templates/config_view_edit.html:159 cps/templates/user_edit.html:81 +#: cps/templates/config_view_edit.html:163 cps/templates/user_edit.html:84 #: cps/templates/user_table.html:154 msgid "Show Random Books in Detail View" msgstr "" -#: cps/templates/config_view_edit.html:161 cps/templates/user_edit.html:84 +#: cps/templates/config_view_edit.html:166 cps/templates/user_edit.html:87 msgid "Add Allowed/Denied Tags" msgstr "" -#: cps/templates/config_view_edit.html:162 +#: cps/templates/config_view_edit.html:167 msgid "Add Allowed/Denied custom column values" msgstr "" -#: cps/templates/detail.html:60 cps/templates/detail.html:69 +#: cps/templates/detail.html:62 cps/templates/detail.html:71 msgid "Read in Browser" msgstr "" -#: cps/templates/detail.html:77 cps/templates/detail.html:94 +#: cps/templates/detail.html:79 cps/templates/detail.html:96 msgid "Listen in Browser" msgstr "" -#: cps/templates/detail.html:124 +#: cps/templates/detail.html:126 cps/templates/listenmp3.html:62 #, python-format msgid "Book %(index)s of %(range)s" msgstr "" -#: cps/templates/detail.html:173 +#: cps/templates/detail.html:175 cps/templates/listenmp3.html:111 msgid "Published" msgstr "" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Unread" msgstr "" -#: cps/templates/detail.html:221 +#: cps/templates/detail.html:223 cps/templates/listenmp3.html:158 msgid "Mark As Read" msgstr "" -#: cps/templates/detail.html:222 +#: cps/templates/detail.html:224 cps/templates/listenmp3.html:159 msgid "Read" msgstr "" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Restore from archive" msgstr "" -#: cps/templates/detail.html:231 +#: cps/templates/detail.html:233 cps/templates/listenmp3.html:166 msgid "Add to archive" msgstr "" -#: cps/templates/detail.html:232 +#: cps/templates/detail.html:234 cps/templates/listenmp3.html:167 msgid "Archived" msgstr "" -#: cps/templates/detail.html:243 +#: cps/templates/detail.html:245 cps/templates/listenmp3.html:177 msgid "Description:" msgstr "" -#: cps/templates/detail.html:256 cps/templates/search.html:14 +#: cps/templates/detail.html:258 cps/templates/listenmp3.html:190 +#: cps/templates/search.html:16 msgid "Add to shelf" msgstr "" -#: cps/templates/detail.html:267 cps/templates/detail.html:284 -#: cps/templates/feed.xml:79 cps/templates/layout.html:139 -#: cps/templates/search.html:20 +#: cps/templates/detail.html:269 cps/templates/detail.html:286 +#: cps/templates/feed.xml:79 cps/templates/layout.html:155 +#: cps/templates/listenmp3.html:201 cps/templates/listenmp3.html:218 +#: cps/templates/search.html:22 msgid "(Public)" msgstr "" -#: cps/templates/detail.html:298 +#: cps/templates/detail.html:300 msgid "Edit Metadata" msgstr "" #: cps/templates/email_edit.html:13 -msgid "Choose Server Type" +msgid "Email Account Type" msgstr "" #: cps/templates/email_edit.html:15 -msgid "Use Standard E-Mail Account" +msgid "Standard Email Account" msgstr "" #: cps/templates/email_edit.html:16 -msgid "Gmail Account with OAuth2 Verification" +msgid "Gmail Account" msgstr "" #: cps/templates/email_edit.html:22 -msgid "Setup Gmail Account as E-Mail Server" +msgid "Setup Gmail Account" msgstr "" #: cps/templates/email_edit.html:24 @@ -2368,10 +2548,10 @@ msgid "Attachment Size Limit" msgstr "" #: cps/templates/email_edit.html:66 -msgid "Save and Send Test E-mail" +msgid "Save and Send Test Email" msgstr "" -#: cps/templates/email_edit.html:70 cps/templates/layout.html:29 +#: cps/templates/email_edit.html:70 cps/templates/layout.html:26 #: cps/templates/shelf_order.html:42 cps/templates/user_table.html:174 msgid "Back" msgstr "" @@ -2397,45 +2577,61 @@ msgstr "" msgid "Denied Domains (Blacklist)" msgstr "" -#: cps/templates/feed.xml:21 cps/templates/layout.html:172 +#: cps/templates/feed.xml:21 cps/templates/layout.html:188 msgid "Next" msgstr "" -#: cps/templates/generate_kobo_auth_url.html:5 -msgid "Open the .kobo/Kobo eReader.conf file in a text editor and add (or edit):" +#: cps/templates/generate_kobo_auth_url.html:6 +msgid "Open the .kobo/Kobo/Kobo eReader.conf file in a text editor and add (or edit):" msgstr "" -#: cps/templates/http_error.html:31 +#: cps/templates/generate_kobo_auth_url.html:11 +msgid "Kobo Token:" +msgstr "" + +#: cps/templates/grid.html:21 +msgid "List" +msgstr "" + +#: cps/templates/http_error.html:34 msgid "Calibre-Web Instance is unconfigured, please contact your administrator" msgstr "" -#: cps/templates/http_error.html:41 +#: cps/templates/http_error.html:44 msgid "Create Issue" msgstr "" -#: cps/templates/http_error.html:48 +#: cps/templates/http_error.html:51 msgid "Return to Home" msgstr "" -#: cps/templates/http_error.html:50 +#: cps/templates/http_error.html:53 msgid "Logout User" msgstr "" -#: cps/templates/index.html:72 cps/templates/search.html:33 -#: cps/templates/shelf.html:21 +#: cps/templates/index.html:71 +msgid "Sort ascending according to download count" +msgstr "" + +#: cps/templates/index.html:72 +msgid "Sort descending according to download count" +msgstr "" + +#: cps/templates/index.html:78 cps/templates/search.html:35 +#: cps/templates/shelf.html:24 msgid "Sort authors in alphabetical order" msgstr "" -#: cps/templates/index.html:73 cps/templates/search.html:34 -#: cps/templates/shelf.html:22 +#: cps/templates/index.html:79 cps/templates/search.html:36 +#: cps/templates/shelf.html:25 msgid "Sort authors in reverse alphabetical order" msgstr "" -#: cps/templates/index.html:77 +#: cps/templates/index.html:83 msgid "Sort ascending according to series index" msgstr "" -#: cps/templates/index.html:78 +#: cps/templates/index.html:84 msgid "Sort descending according to series index" msgstr "" @@ -2499,7 +2695,7 @@ msgstr "" msgid "Books ordered by file formats" msgstr "" -#: cps/templates/index.xml:119 cps/templates/layout.html:137 +#: cps/templates/index.xml:119 cps/templates/layout.html:153 #: cps/templates/search_form.html:87 msgid "Shelves" msgstr "" @@ -2508,63 +2704,67 @@ msgstr "" msgid "Books organized in shelves" msgstr "" -#: cps/templates/layout.html:29 +#: cps/templates/layout.html:26 cps/templates/login.html:30 msgid "Home" msgstr "" -#: cps/templates/layout.html:35 +#: cps/templates/layout.html:32 msgid "Toggle Navigation" msgstr "" -#: cps/templates/layout.html:46 +#: cps/templates/layout.html:48 msgid "Search Library" msgstr "" -#: cps/templates/layout.html:64 cps/templates/layout.html:119 -msgid "Uploading..." -msgstr "" - -#: cps/templates/layout.html:64 -msgid "Error" -msgstr "" - -#: cps/templates/layout.html:64 -msgid "Upload done, processing, please wait..." -msgstr "" - -#: cps/templates/layout.html:78 cps/templates/read.html:71 -#: cps/templates/readcbr.html:84 cps/templates/readcbr.html:108 -msgid "Settings" -msgstr "" - -#: cps/templates/layout.html:80 +#: cps/templates/layout.html:66 cps/templates/layout.html:95 msgid "Account" msgstr "" -#: cps/templates/layout.html:82 +#: cps/templates/layout.html:72 cps/templates/layout.html:97 msgid "Logout" msgstr "" -#: cps/templates/layout.html:120 +#: cps/templates/layout.html:79 cps/templates/layout.html:135 +msgid "Uploading..." +msgstr "" + +#: cps/templates/layout.html:79 +msgid "Error" +msgstr "" + +#: cps/templates/layout.html:79 +msgid "Upload done, processing, please wait..." +msgstr "" + +#: cps/templates/layout.html:92 cps/templates/read.html:76 +#: cps/templates/readcbr.html:87 cps/templates/readcbr.html:111 +msgid "Settings" +msgstr "" + +#: cps/templates/layout.html:136 msgid "Please do not refresh the page" msgstr "" -#: cps/templates/layout.html:130 +#: cps/templates/layout.html:146 msgid "Browse" msgstr "" -#: cps/templates/layout.html:143 cps/templates/stats.html:3 +#: cps/templates/layout.html:159 cps/templates/stats.html:3 msgid "About" msgstr "" -#: cps/templates/layout.html:157 +#: cps/templates/layout.html:173 msgid "Previous" msgstr "" -#: cps/templates/layout.html:184 +#: cps/templates/layout.html:200 msgid "Book Details" msgstr "" +#: cps/templates/list.html:22 +msgid "Grid" +msgstr "" + #: cps/templates/login.html:18 msgid "Remember Me" msgstr "" @@ -2573,7 +2773,7 @@ msgstr "" msgid "Forgot Password?" msgstr "" -#: cps/templates/login.html:26 +#: cps/templates/login.html:34 msgid "Log in with Magic Link" msgstr "" @@ -2669,7 +2869,7 @@ msgstr "" msgid "Select" msgstr "" -#: cps/templates/modal_dialogs.html:134 +#: cps/templates/modal_dialogs.html:134 cps/templates/tasks.html:45 msgid "Ok" msgstr "" @@ -2681,127 +2881,139 @@ msgstr "" msgid "epub Reader" msgstr "" -#: cps/templates/read.html:74 +#: cps/templates/read.html:81 cps/templates/readcbr.html:119 +msgid "Light" +msgstr "" + +#: cps/templates/read.html:82 cps/templates/readcbr.html:120 +msgid "Dark" +msgstr "" + +#: cps/templates/read.html:83 +msgid "Sepia" +msgstr "" + +#: cps/templates/read.html:84 +msgid "Black" +msgstr "" + +#: cps/templates/read.html:88 msgid "Reflow text when sidebars are open." msgstr "" +#: cps/templates/read.html:93 +msgid "Font Sizes" +msgstr "" + #: cps/templates/readcbr.html:7 msgid "Comic Reader" msgstr "" -#: cps/templates/readcbr.html:89 +#: cps/templates/readcbr.html:92 msgid "Keyboard Shortcuts" msgstr "" -#: cps/templates/readcbr.html:92 +#: cps/templates/readcbr.html:95 msgid "Previous Page" msgstr "" -#: cps/templates/readcbr.html:93 cps/templates/readcbr.html:162 +#: cps/templates/readcbr.html:96 cps/templates/readcbr.html:165 msgid "Next Page" msgstr "" -#: cps/templates/readcbr.html:94 +#: cps/templates/readcbr.html:97 msgid "Scale to Best" msgstr "" -#: cps/templates/readcbr.html:95 +#: cps/templates/readcbr.html:98 msgid "Scale to Width" msgstr "" -#: cps/templates/readcbr.html:96 +#: cps/templates/readcbr.html:99 msgid "Scale to Height" msgstr "" -#: cps/templates/readcbr.html:97 +#: cps/templates/readcbr.html:100 msgid "Scale to Native" msgstr "" -#: cps/templates/readcbr.html:98 +#: cps/templates/readcbr.html:101 msgid "Rotate Right" msgstr "" -#: cps/templates/readcbr.html:99 +#: cps/templates/readcbr.html:102 msgid "Rotate Left" msgstr "" -#: cps/templates/readcbr.html:100 +#: cps/templates/readcbr.html:103 msgid "Flip Image" msgstr "" -#: cps/templates/readcbr.html:116 -msgid "Light" -msgstr "" - -#: cps/templates/readcbr.html:117 -msgid "Dark" -msgstr "" - -#: cps/templates/readcbr.html:122 +#: cps/templates/readcbr.html:125 msgid "Scale" msgstr "" -#: cps/templates/readcbr.html:125 +#: cps/templates/readcbr.html:128 msgid "Best" msgstr "" -#: cps/templates/readcbr.html:126 +#: cps/templates/readcbr.html:129 msgid "Width" msgstr "" -#: cps/templates/readcbr.html:127 +#: cps/templates/readcbr.html:130 msgid "Height" msgstr "" -#: cps/templates/readcbr.html:128 +#: cps/templates/readcbr.html:131 msgid "Native" msgstr "" -#: cps/templates/readcbr.html:133 +#: cps/templates/readcbr.html:136 msgid "Rotate" msgstr "" -#: cps/templates/readcbr.html:144 +#: cps/templates/readcbr.html:147 msgid "Flip" msgstr "" -#: cps/templates/readcbr.html:147 +#: cps/templates/readcbr.html:150 msgid "Horizontal" msgstr "" -#: cps/templates/readcbr.html:148 +#: cps/templates/readcbr.html:151 msgid "Vertical" msgstr "" -#: cps/templates/readcbr.html:153 +#: cps/templates/readcbr.html:156 msgid "Direction" msgstr "" -#: cps/templates/readcbr.html:156 +#: cps/templates/readcbr.html:159 msgid "Left to Right" msgstr "" -#: cps/templates/readcbr.html:157 +#: cps/templates/readcbr.html:160 msgid "Right to Left" msgstr "" -#: cps/templates/readcbr.html:165 +#: cps/templates/readcbr.html:168 msgid "Reset to Top" msgstr "" -#: cps/templates/readcbr.html:166 +#: cps/templates/readcbr.html:169 msgid "Remember Position" msgstr "" -#: cps/templates/readcbr.html:171 +#: cps/templates/readcbr.html:174 msgid "Scrollbar" msgstr "" -#: cps/templates/readcbr.html:174 +#: cps/templates/readcbr.html:177 msgid "Show" msgstr "" -#: cps/templates/readcbr.html:175 +#: cps/templates/readcbr.html:178 msgid "Hide" msgstr "" @@ -2809,7 +3021,7 @@ msgstr "" msgid "DJVU Reader" msgstr "" -#: cps/templates/readpdf.html:29 +#: cps/templates/readpdf.html:32 msgid "PDF Reader" msgstr "" @@ -2826,7 +3038,7 @@ msgid "Choose a username" msgstr "" #: cps/templates/register.html:15 -msgid "Your email address" +msgid "Your Email" msgstr "" #: cps/templates/remote_login.html:5 @@ -2845,15 +3057,19 @@ msgstr "" msgid "This verification link will expire in 10 minutes." msgstr "" -#: cps/templates/search.html:5 -msgid "No Results Found" +#: cps/templates/schedule_edit.html:33 +msgid "Generate Series Cover Thumbnails" msgstr "" #: cps/templates/search.html:6 +msgid "No Results Found" +msgstr "" + +#: cps/templates/search.html:7 msgid "Search Term:" msgstr "" -#: cps/templates/search.html:8 +#: cps/templates/search.html:9 msgid "Results for:" msgstr "" @@ -2865,10 +3081,6 @@ msgstr "" msgid "Published Date To" msgstr "" -#: cps/templates/search_form.html:42 -msgid "Read Status" -msgstr "" - #: cps/templates/search_form.html:59 msgid "Exclude Tags" msgstr "" @@ -2909,30 +3121,26 @@ msgstr "" msgid "To:" msgstr "" -#: cps/templates/shelf.html:11 +#: cps/templates/shelf.html:13 msgid "Delete this Shelf" msgstr "" -#: cps/templates/shelf.html:12 +#: cps/templates/shelf.html:14 msgid "Edit Shelf Properties" msgstr "" -#: cps/templates/shelf.html:14 +#: cps/templates/shelf.html:17 msgid "Arrange books manually" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Disable Change order" msgstr "" -#: cps/templates/shelf.html:15 +#: cps/templates/shelf.html:18 msgid "Enable Change order" msgstr "" -#: cps/templates/shelf.html:94 -msgid "Shelf will be deleted for all users" -msgstr "" - #: cps/templates/shelf_edit.html:14 msgid "Share with Everyone" msgstr "" @@ -2974,7 +3182,7 @@ msgid "System Statistics" msgstr "" #: cps/templates/stats.html:33 -msgid "Program Library" +msgid "Program" msgstr "" #: cps/templates/stats.html:34 @@ -3001,8 +3209,16 @@ msgstr "" msgid "Run Time" msgstr "" -#: cps/templates/tasks.html:18 -msgid "Start Time" +#: cps/templates/tasks.html:20 +msgid "Actions" +msgstr "" + +#: cps/templates/tasks.html:40 +msgid "This task will be cancelled. Any progress made by this task will be saved." +msgstr "" + +#: cps/templates/tasks.html:41 +msgid "If this is a scheduled task, it will be re-ran during the next scheduled time." msgstr "" #: cps/templates/user_edit.html:20 @@ -3033,19 +3249,23 @@ msgstr "" msgid "Create/View" msgstr "" -#: cps/templates/user_edit.html:85 +#: cps/templates/user_edit.html:70 +msgid "Force full kobo sync" +msgstr "" + +#: cps/templates/user_edit.html:88 msgid "Add allowed/Denied Custom Column Values" msgstr "" -#: cps/templates/user_edit.html:130 +#: cps/templates/user_edit.html:137 msgid "Sync only books in selected shelves with Kobo" msgstr "" -#: cps/templates/user_edit.html:140 cps/templates/user_table.html:169 +#: cps/templates/user_edit.html:147 cps/templates/user_table.html:169 msgid "Delete User" msgstr "" -#: cps/templates/user_edit.html:152 +#: cps/templates/user_edit.html:159 msgid "Generate Kobo Auth URL" msgstr "" @@ -3062,15 +3282,15 @@ msgid "Enter Username" msgstr "" #: cps/templates/user_table.html:135 -msgid "Enter E-mail Address" +msgid "Enter Email" msgstr "" #: cps/templates/user_table.html:136 -msgid "Enter Kindle E-mail Address" +msgid "Enter eReader Email" msgstr "" #: cps/templates/user_table.html:136 -msgid "Kindle E-mail" +msgid "eReader Email" msgstr "" #: cps/templates/user_table.html:137 @@ -3130,10 +3350,6 @@ msgid "Sync selected Shelves with Kobo" msgstr "" #: cps/templates/user_table.html:156 -msgid "Show read/unread selection" -msgstr "" - -#: cps/templates/user_table.html:159 -msgid "Show random books" +msgid "Show Read/Unread Section" msgstr "" diff --git a/optional-requirements.txt b/optional-requirements.txt index c9a05fc00..53b8ba735 100644 --- a/optional-requirements.txt +++ b/optional-requirements.txt @@ -1,41 +1,44 @@ # GDrive Integration -gevent>20.6.0,<22.0.0 -greenlet>=0.4.17,<1.2.0 -httplib2>=0.9.2,<0.20.0 +google-api-python-client>=1.7.11,<2.75.0 +gevent>20.6.0,<23.0.0 +greenlet>=0.4.17,<2.1.0 +httplib2>=0.9.2,<0.22.0 oauth2client>=4.0.0,<4.1.4 -uritemplate>=3.0.0,<3.1.0 +uritemplate>=3.0.0,<4.2.0 pyasn1-modules>=0.0.8,<0.3.0 pyasn1>=0.1.9,<0.5.0 -PyDrive2>=1.3.1,<1.9.0 +PyDrive2>=1.3.1,<1.16.0 PyYAML>=3.12 -rsa>=3.4.2,<4.8.0 -six>=1.10.0,<1.17.0 - -# Gdrive and Gmail integration -google-api-python-client>=1.7.11,<2.1.0 +rsa>=3.4.2,<4.10.0 # Gmail -google-auth-oauthlib>=0.4.3,<0.5.0 +google-auth-oauthlib>=0.4.3,<0.9.0 +google-api-python-client>=1.7.11,<2.75.0 # goodreads goodreads>=0.3.2,<0.4.0 -python-Levenshtein>=0.12.0,<0.13.0 +python-Levenshtein>=0.12.0,<0.21.0 # ldap login -python-ldap>=3.0.0,<3.4.0 +python-ldap>=3.0.0,<3.5.0 Flask-SimpleLDAP>=1.4.0,<1.5.0 -#oauth -Flask-Dance>=2.0.0,<5.1.0 -SQLAlchemy-Utils>=0.33.5,<0.38.0 +# oauth +Flask-Dance>=2.0.0,<6.3.0 +SQLAlchemy-Utils>=0.33.5,<0.40.0 -# extracting metadata -rarfile>=2.7 -scholarly>=1.2.0, <1.3 +# metadata extraction +rarfile>=3.2 +scholarly>=1.2.0,<1.8 +markdown2>=2.0.0,<2.5.0 +html2text>=2020.1.16,<2022.1.1 +python-dateutil>=2.1,<2.9.0 +beautifulsoup4>=4.0.1,<4.12.0 +cchardet>=2.0.0,<2.2.0 -# other -natsort>=2.2.0,<8.1.0 +# Comics +natsort>=2.2.0,<8.3.0 comicapi>=2.2.0,<2.3.0 -#Kobo integration -jsonschema>=3.2.0,<3.3.0 +# Kobo integration +jsonschema>=3.2.0,<4.18.0 diff --git a/requirements.txt b/requirements.txt index dc1b0d95f..d5c491fb8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,16 +1,20 @@ -Babel>=1.3, <3.0 -Flask-Babel>=0.11.1,<2.1.0 -Flask-Login>=0.3.2,<0.5.1 +APScheduler>=3.6.3,<3.11.0 +werkzeug<2.1.0 +Babel>=1.3,<3.0 +Flask-Babel>=0.11.1,<3.1.0 +Flask-Login>=0.3.2,<0.6.3 Flask-Principal>=0.3.2,<0.5.1 backports_abc>=0.4 -Flask>=1.0.2,<2.1.0 +Flask>=1.0.2,<2.3.0 iso-639>=0.4.5,<0.5.0 -PyPDF3>=1.0.0,<1.0.4 +PyPDF>=3.0.0,<3.3.0 pytz>=2016.10 -requests>=2.11.1,<2.25.0 +requests>=2.11.1,<2.28.0 SQLAlchemy>=1.3.0,<1.5.0 -tornado>=4.1,<6.2 +tornado>=4.1,<6.3 Wand>=0.4.4,<0.7.0 -unidecode>=0.04.19,<1.3.0 -lxml>=3.8.0,<4.7.0 -flask-wtf>=0.14.2,<0.16.0 +unidecode>=0.04.19,<1.4.0 +lxml>=3.8.0,<5.0.0 +flask-wtf>=0.14.2,<1.2.0 +chardet>=3.0.0,<4.1.0 +advocate>=1.0.0,<1.1.0 diff --git a/setup.cfg b/setup.cfg index 76f7e4052..3b208345c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,93 +1,101 @@ [metadata] name = calibreweb url = https://github.com/janeczku/calibre-web -project_urls = - Bug Tracker = https://github.com/janeczku/calibre-web/issues - Release Management = https://github.com/janeczku/calibre-web/releases - Documentation = https://github.com/janeczku/calibre-web/wiki - Source Code = https://github.com/janeczku/calibre-web +project_urls = + Bug Tracker = https://github.com/janeczku/calibre-web/issues + Release Management = https://github.com/janeczku/calibre-web/releases + Documentation = https://github.com/janeczku/calibre-web/wiki + Source Code = https://github.com/janeczku/calibre-web description = Web app for browsing, reading and downloading eBooks stored in a Calibre database. long_description = file: README.md -long_description_content_type= text/markdown +long_description_content_type = text/markdown author = @OzzieIsaacs author_email = Ozzie.Fernandez.Isaacs@googlemail.com maintainer = @OzzieIsaacs license = GPLv3+ license_file = LICENSE -classifiers = - Development Status :: 5 - Production/Stable - License :: OSI Approved :: GNU Affero General Public License v3 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.5 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Operating System :: OS Independent -keywords = - calibre - calibre-web - library -python_requires = >=3.0 +classifiers = + Development Status :: 5 - Production/Stable + License :: OSI Approved :: GNU Affero General Public License v3 + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 + Operating System :: OS Independent +keywords = + calibre + calibre-web + library +python_requires = >=3.5 [options.entry_points] -console_scripts = - cps = calibreweb:main +console_scripts = + cps = calibreweb:main + [options] include_package_data = True -install_requires = - Babel>=1.3, <3.0 - Flask-Babel>=0.11.1,<2.1.0 - Flask-Login>=0.3.2,<0.5.1 - Flask-Principal>=0.3.2,<0.5.1 - backports_abc>=0.4 - Flask>=1.0.2,<2.1.0 - iso-639>=0.4.5,<0.5.0 - PyPDF3>=1.0.0,<1.0.4 - pytz>=2016.10 - requests>=2.11.1,<2.25.0 - SQLAlchemy>=1.3.0,<1.5.0 - tornado>=4.1,<6.2 - Wand>=0.4.4,<0.7.0 - unidecode>=0.04.19,<1.3.0 - lxml>=3.8.0,<4.7.0 - flask-wtf>=0.14.2,<0.16.0 +install_requires = + APScheduler>=3.6.3,<3.11.0 + werkzeug<2.1.0 + Babel>=1.3,<3.0 + Flask-Babel>=0.11.1,<3.1.0 + Flask-Login>=0.3.2,<0.6.3 + Flask-Principal>=0.3.2,<0.5.1 + backports_abc>=0.4 + Flask>=1.0.2,<2.3.0 + iso-639>=0.4.5,<0.5.0 + PyPDF>=3.0.0,<3.3.0 + pytz>=2016.10 + requests>=2.11.1,<2.28.0 + SQLAlchemy>=1.3.0,<1.5.0 + tornado>=4.1,<6.3 + Wand>=0.4.4,<0.7.0 + unidecode>=0.04.19,<1.4.0 + lxml>=3.8.0,<5.0.0 + flask-wtf>=0.14.2,<1.2.0 + chardet>=3.0.0,<4.1.0 + advocate>=1.0.0,<1.1.0 + [options.extras_require] -gdrive = - google-api-python-client>=1.7.11,<2.1.0 - gevent>20.6.0,<22.0.0 - greenlet>=0.4.17,<1.2.0 - httplib2>=0.9.2,<0.20.0 - oauth2client>=4.0.0,<4.1.4 - uritemplate>=3.0.0,<3.1.0 - pyasn1-modules>=0.0.8,<0.3.0 - pyasn1>=0.1.9,<0.5.0 - PyDrive2>=1.3.1,<1.9.0 - PyYAML>=3.12 - rsa>=3.4.2,<4.8.0 - six>=1.10.0,<1.17.0 -gmail = - google-auth-oauthlib>=0.4.3,<0.5.0 - google-api-python-client>=1.7.11,<2.1.0 -goodreads = - goodreads>=0.3.2,<0.4.0 - python-Levenshtein>=0.12.0,<0.13.0 -ldap = - python-ldap>=3.0.0,<3.4.0 - Flask-SimpleLDAP>=1.4.0,<1.5.0 -oauth = - Flask-Dance>=2.0.0,<5.1.0 - SQLAlchemy-Utils>=0.33.5,<0.38.0 -metadata = - rarfile>=2.7 - scholarly>=1.2.0, <1.3 -comics = - natsort>=2.2.0,<7.2.0 - comicapi>= 2.2.0,<2.3.0 -kobo = - jsonschema>=3.2.0,<3.3.0 - - +gdrive = + google-api-python-client>=1.7.11,<2.75.0 + gevent>20.6.0,<23.0.0 + greenlet>=0.4.17,<2.1.0 + httplib2>=0.9.2,<0.22.0 + oauth2client>=4.0.0,<4.1.4 + uritemplate>=3.0.0,<4.2.0 + pyasn1-modules>=0.0.8,<0.3.0 + pyasn1>=0.1.9,<0.5.0 + PyDrive2>=1.3.1,<1.16.0 + PyYAML>=3.12 + rsa>=3.4.2,<4.10.0 +gmail = + google-auth-oauthlib>=0.4.3,<0.9.0 + google-api-python-client>=1.7.11,<2.75.0 +goodreads = + goodreads>=0.3.2,<0.4.0 + python-Levenshtein>=0.12.0,<0.21.0 +ldap = + python-ldap>=3.0.0,<3.5.0 + Flask-SimpleLDAP>=1.4.0,<1.5.0 +oauth = + Flask-Dance>=2.0.0,<6.3.0 + SQLAlchemy-Utils>=0.33.5,<0.40.0 +metadata = + rarfile>=3.2 + scholarly>=1.2.0,<1.8 + markdown2>=2.0.0,<2.5.0 + html2text>=2020.1.16,<2022.1.1 + python-dateutil>=2.1,<2.9.0 + beautifulsoup4>=4.0.1,<4.12.0 + cchardet>=2.0.0,<2.2.0 +comics = + natsort>=2.2.0,<8.3.0 + comicapi>=2.2.0,<2.3.0 +kobo = + jsonschema>=3.2.0,<4.18.0 diff --git a/test/Calibre-Web TestSummary.html b/test/Calibre-Web TestSummary.html deleted file mode 100755 index 10e2e0eee..000000000 --- a/test/Calibre-Web TestSummary.html +++ /dev/null @@ -1,2947 +0,0 @@ - - - - Calibre-Web Tests - - - - - - - - - - - - - - - - - - - -

      -

      Calibre-Web Tests

      -
      -
      -
      -
      -
      -
      - -
      -
      -
      -
      -
      -
      - -

      Start Time: 2020-08-30 15:47:09

      - -
      -
      -
      -
      - -

      Stop Time: 2020-08-30 17:06:27

      - -
      -
      -
      -
      -

      Duration: 1h 7 min

      -
      -
      -
      -
      -
      - -
      -
      -
      -
      -
      - - - - - - -
      -
      -
      {{_('Edit')}}
      {{_('Delete User')}}

      {{_('Delete User')}}
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Test Group/Test caseCountPassFailErrorSkipView
      TestAnonymous1313000 - Detail -
      -
      TestAnonymous - test_check_locale_guest
      -
      PASS
      -
      TestAnonymous - test_guest_about
      -
      PASS
      -
      TestAnonymous - test_guest_change_visibility_category
      -
      PASS
      -
      TestAnonymous - test_guest_change_visibility_format
      -
      PASS
      -
      TestAnonymous - test_guest_change_visibility_hot
      -
      PASS
      -
      TestAnonymous - test_guest_change_visibility_language
      -
      PASS
      -
      TestAnonymous - test_guest_change_visibility_publisher
      -
      PASS
      -
      TestAnonymous - test_guest_change_visibility_rated
      -
      PASS
      -
      TestAnonymous - test_guest_change_visibility_rating
      -
      PASS
      -
      TestAnonymous - test_guest_change_visibility_series
      -
      PASS
      -
      TestAnonymous - test_guest_random_books_available
      -
      PASS
      -
      TestAnonymous - test_guest_restricted_settings_visibility
      -
      PASS
      -
      TestAnonymous - test_guest_visibility_sidebar
      -
      PASS
      TestCli76001 - Detail -
      -
      TestCli - test_already_started
      -
      PASS
      -
      TestCli - test_bind_to_single_interface
      -
      PASS
      -
      TestCli - test_cli_SSL_files
      -
      PASS
      -
      TestCli - test_cli_different_folder
      -
      PASS
      -
      TestCli - test_cli_different_settings_database
      -
      PASS
      -
      TestCli - test_cli_gdrive_location
      -
      -
      - SKIP -
      - - - -
      -
      TestCli - test_environ_port_setting
      -
      PASS
      TestCoverEditBooks10100 - Detail -
      -
      TestCoverEditBooks - test_upload_jpg
      -
      -
      - FAIL -
      - - - -
      TestDeleteDatabase11000 - Detail -
      -
      TestDeleteDatabase - test_delete_books_in_database
      -
      PASS
      TestEbookConvert1111000 - Detail -
      -
      TestEbookConvert - test_convert_deactivate
      -
      PASS
      -
      TestEbookConvert - test_convert_email
      -
      PASS
      -
      TestEbookConvert - test_convert_failed_and_email
      -
      PASS
      -
      TestEbookConvert - test_convert_only
      -
      PASS
      -
      TestEbookConvert - test_convert_parameter
      -
      PASS
      -
      TestEbookConvert - test_convert_wrong_excecutable
      -
      PASS
      -
      TestEbookConvert - test_email_failed
      -
      PASS
      -
      TestEbookConvert - test_email_only
      -
      PASS
      -
      TestEbookConvert - test_kindle_send_not_configured
      -
      PASS
      -
      TestEbookConvert - test_ssl_smtp_setup_error
      -
      PASS
      -
      TestEbookConvert - test_starttls_smtp_setup_error
      -
      PASS
      TestEditAdditionalBooks55000 - Detail -
      -
      TestEditAdditionalBooks - test_delete_book
      -
      PASS
      -
      TestEditAdditionalBooks - test_upload_metadata_cbt
      -
      PASS
      -
      TestEditAdditionalBooks - test_upload_metadate_cbr
      -
      PASS
      -
      TestEditAdditionalBooks - test_writeonly_database
      -
      PASS
      -
      TestEditAdditionalBooks - test_writeonly_path
      -
      PASS
      TestEditBooks3330102 - Detail -
      -
      TestEditBooks - test_download_book
      -
      PASS
      -
      TestEditBooks - test_edit_author
      -
      PASS
      -
      TestEditBooks - test_edit_category
      -
      PASS
      -
      TestEditBooks - test_edit_comments
      -
      PASS
      -
      TestEditBooks - test_edit_custom_bool
      -
      PASS
      -
      TestEditBooks - test_edit_custom_categories
      -
      PASS
      -
      TestEditBooks - test_edit_custom_float
      -
      PASS
      -
      TestEditBooks - test_edit_custom_int
      -
      PASS
      -
      TestEditBooks - test_edit_custom_rating
      -
      PASS
      -
      TestEditBooks - test_edit_custom_single_select
      -
      PASS
      -
      TestEditBooks - test_edit_custom_text
      -
      PASS
      -
      TestEditBooks - test_edit_language
      -
      PASS
      -
      TestEditBooks - test_edit_publisher
      -
      PASS
      -
      TestEditBooks - test_edit_publishing_date
      -
      -
      - SKIP -
      - - - -
      -
      TestEditBooks - test_edit_rating
      -
      PASS
      -
      TestEditBooks - test_edit_series
      -
      PASS
      -
      TestEditBooks - test_edit_title
      -
      PASS
      -
      TestEditBooks - test_rename_uppercase_lowercase
      -
      -
      - SKIP -
      - - - -
      -
      TestEditBooks - test_typeahead_author
      -
      PASS
      -
      TestEditBooks - test_typeahead_functions
      -
      PASS
      -
      TestEditBooks - test_typeahead_language
      -
      PASS
      -
      TestEditBooks - test_typeahead_publisher
      -
      PASS
      -
      TestEditBooks - test_typeahead_series
      -
      PASS
      -
      TestEditBooks - test_typeahead_tag
      -
      PASS
      -
      TestEditBooks - test_upload_book_cbr
      -
      PASS
      -
      TestEditBooks - test_upload_book_cbt
      -
      PASS
      -
      TestEditBooks - test_upload_book_cbz
      -
      PASS
      -
      TestEditBooks - test_upload_book_epub
      -
      PASS
      -
      TestEditBooks - test_upload_book_fb2
      -
      PASS
      -
      TestEditBooks - test_upload_book_lit
      -
      PASS
      -
      TestEditBooks - test_upload_book_mobi
      -
      PASS
      -
      TestEditBooks - test_upload_book_pdf
      -
      PASS
      -
      TestEditBooks - test_upload_cover_hdd
      -
      -
      - FAIL -
      - - - -
      TestEditBooksGdrive11000 - Detail -
      -
      TestEditBooksGdrive - test_config_gdrive
      -
      PASS
      TestSTARTTLS33000 - Detail -
      -
      TestSTARTTLS - test_STARTTLS
      -
      PASS
      -
      TestSTARTTLS - test_STARTTLS_SSL_setup_error
      -
      PASS
      -
      TestSTARTTLS - test_STARTTLS_resend_password
      -
      PASS
      TestSSL44000 - Detail -
      -
      TestSSL - test_SSL_None_setup_error
      -
      PASS
      -
      TestSSL - test_SSL_STARTTLS_setup_error
      -
      PASS
      -
      TestSSL - test_SSL_logging_email
      -
      PASS
      -
      TestSSL - test_SSL_only
      -
      PASS
      TestGoodreads33000 - Detail -
      -
      TestGoodreads - test_author_page
      -
      PASS
      -
      TestGoodreads - test_author_page_invalid
      -
      PASS
      -
      TestGoodreads - test_goodreads_about
      -
      PASS
      TestCalibreHelper1616000 - Detail -
      -
      TestCalibreHelper - test_author_sort
      -
      PASS
      -
      TestCalibreHelper - test_author_sort_comma
      -
      PASS
      -
      TestCalibreHelper - test_author_sort_junior
      -
      PASS
      -
      TestCalibreHelper - test_author_sort_oneword
      -
      PASS
      -
      TestCalibreHelper - test_author_sort_roman
      -
      PASS
      -
      TestCalibreHelper - test_check_Limit_Length
      -
      PASS
      -
      TestCalibreHelper - test_check_char_replacement
      -
      PASS
      -
      TestCalibreHelper - test_check_chinese_Characters
      -
      PASS
      -
      TestCalibreHelper - test_check_deg_eur_replacement
      -
      PASS
      -
      TestCalibreHelper - test_check_doubleS
      -
      PASS
      -
      TestCalibreHelper - test_check_finish_Dot
      -
      PASS
      -
      TestCalibreHelper - test_check_high23
      -
      PASS
      -
      TestCalibreHelper - test_check_umlauts
      -
      PASS
      -
      TestCalibreHelper - test_random_password
      -
      PASS
      -
      TestCalibreHelper - test_split_authors
      -
      PASS
      -
      TestCalibreHelper - test_whitespaces
      -
      PASS
      TestKoboSync88000 - Detail -
      -
      TestKoboSync - test_kobo_about
      -
      PASS
      -
      TestKoboSync - test_shelves_add_remove_books
      -
      PASS
      -
      TestKoboSync - test_sync_changed_book
      -
      PASS
      -
      TestKoboSync - test_sync_invalid
      -
      PASS
      -
      TestKoboSync - test_sync_reading_state
      -
      PASS
      -
      TestKoboSync - test_sync_shelf
      -
      PASS
      -
      TestKoboSync - test_sync_unchanged
      -
      PASS
      -
      TestKoboSync - test_sync_upload
      -
      PASS
      TestLdapLogin1010000 - Detail -
      -
      TestLdapLogin - test_LDAP_SSL
      -
      PASS
      -
      TestLdapLogin - test_LDAP_STARTTLS
      -
      PASS
      -
      TestLdapLogin - test_LDAP_fallback_Login
      -
      PASS
      -
      TestLdapLogin - test_LDAP_import
      -
      PASS
      -
      TestLdapLogin - test_LDAP_login
      -
      PASS
      -
      TestLdapLogin - test_invalid_LDAP
      -
      PASS
      -
      TestLdapLogin - test_ldap_about
      -
      PASS
      -
      TestLdapLogin - test_ldap_authentication
      -
      PASS
      -
      TestLdapLogin - test_ldap_kobo_sync
      -
      PASS
      -
      TestLdapLogin - test_ldap_opds_download_book
      -
      PASS
      TestLogging76001 - Detail -
      -
      TestLogging - test_access_log_recover
      -
      PASS
      -
      TestLogging - test_debug_log
      -
      PASS
      -
      TestLogging - test_failed_login
      -
      PASS
      -
      TestLogging - test_failed_register
      -
      -
      - SKIP -
      - - - -
      -
      TestLogging - test_logfile_change
      -
      PASS
      -
      TestLogging - test_logfile_recover
      -
      PASS
      -
      TestLogging - test_logviewer
      -
      PASS
      TestLogin1111000 - Detail -
      -
      TestLogin - test_digest_login
      -
      PASS
      -
      TestLogin - test_login_capital_letters_user_unicode_password
      -
      PASS
      -
      TestLogin - test_login_delete_admin
      -
      PASS
      -
      TestLogin - test_login_empty_password
      -
      PASS
      -
      TestLogin - test_login_locale_select
      -
      PASS
      -
      TestLogin - test_login_protected
      -
      PASS
      -
      TestLogin - test_login_remember_me
      -
      PASS
      -
      TestLogin - test_login_rename_user
      -
      PASS
      -
      TestLogin - test_login_unicode_user_space_end_password
      -
      PASS
      -
      TestLogin - test_login_user_with_space_password_end_space
      -
      PASS
      -
      TestLogin - test_robots
      -
      PASS
      TestOAuthLogin22000 - Detail -
      -
      TestOAuthLogin - test_oauth_about
      -
      PASS
      -
      TestOAuthLogin - test_visible_oauth
      -
      PASS
      TestOPDSFeed2020000 - Detail -
      -
      TestOPDSFeed - test_opds
      -
      PASS
      -
      TestOPDSFeed - test_opds_author
      -
      PASS
      -
      TestOPDSFeed - test_opds_calibre_companion
      -
      PASS
      -
      TestOPDSFeed - test_opds_cover
      -
      PASS
      -
      TestOPDSFeed - test_opds_download_book
      -
      PASS
      -
      TestOPDSFeed - test_opds_formats
      -
      PASS
      -
      TestOPDSFeed - test_opds_guest_user
      -
      PASS
      -
      TestOPDSFeed - test_opds_hot
      -
      PASS
      -
      TestOPDSFeed - test_opds_language
      -
      PASS
      -
      TestOPDSFeed - test_opds_non_admin
      -
      PASS
      -
      TestOPDSFeed - test_opds_publisher
      -
      PASS
      -
      TestOPDSFeed - test_opds_random
      -
      PASS
      -
      TestOPDSFeed - test_opds_ratings
      -
      PASS
      -
      TestOPDSFeed - test_opds_read_unread
      -
      PASS
      -
      TestOPDSFeed - test_opds_search
      -
      PASS
      -
      TestOPDSFeed - test_opds_series
      -
      PASS
      -
      TestOPDSFeed - test_opds_shelf_access
      -
      PASS
      -
      TestOPDSFeed - test_opds_tags
      -
      PASS
      -
      TestOPDSFeed - test_opds_top_rated
      -
      PASS
      -
      TestOPDSFeed - test_recently_added
      -
      PASS
      TestRegister77000 - Detail -
      -
      TestRegister - test_forgot_password
      -
      PASS
      -
      TestRegister - test_limit_domain
      -
      PASS
      -
      TestRegister - test_register_no_server
      -
      PASS
      -
      TestRegister - test_registering_only_email
      -
      PASS
      -
      TestRegister - test_registering_user
      -
      PASS
      -
      TestRegister - test_registering_user_fail
      -
      PASS
      -
      TestRegister - test_user_change_password
      -
      PASS
      TestShelf109001 - Detail -
      -
      TestShelf - test_add_shelf_from_search
      -
      PASS
      -
      TestShelf - test_arrange_shelf
      -
      PASS
      -
      TestShelf - test_delete_book_of_shelf
      -
      PASS
      -
      TestShelf - test_private_shelf
      -
      PASS
      -
      TestShelf - test_public_private_shelf
      -
      PASS
      -
      TestShelf - test_public_shelf
      -
      PASS
      -
      TestShelf - test_rename_shelf
      -
      PASS
      -
      TestShelf - test_shelf_action_non_shelf_edit_role
      -
      PASS
      -
      TestShelf - test_shelf_database_change
      -
      -
      - SKIP -
      - - - -
      -
      TestShelf - test_shelf_long_name
      -
      PASS
      TestUpdater87001 - Detail -
      -
      TestUpdater - test_check_update_nightly_errors
      -
      PASS
      -
      TestUpdater - test_check_update_nightly_request_errors
      -
      PASS
      -
      TestUpdater - test_check_update_stable_errors
      -
      PASS
      -
      TestUpdater - test_check_update_stable_versions
      -
      PASS
      -
      TestUpdater - test_perform_update
      -
      PASS
      -
      TestUpdater - test_perform_update_stable_errors
      -
      PASS
      -
      TestUpdater - test_perform_update_timeout
      -
      -
      - SKIP -
      - - - -
      -
      TestUpdater - test_reconnect_database
      -
      PASS
      TestUserTemplate1919000 - Detail -
      -
      TestUserTemplate - test_allow_column_restriction
      -
      PASS
      -
      TestUserTemplate - test_allow_tag_restriction
      -
      PASS
      -
      TestUserTemplate - test_archived_format_template
      -
      PASS
      -
      TestUserTemplate - test_author_user_template
      -
      PASS
      -
      TestUserTemplate - test_best_user_template
      -
      PASS
      -
      TestUserTemplate - test_category_user_template
      -
      PASS
      -
      TestUserTemplate - test_deny_column_restriction
      -
      PASS
      -
      TestUserTemplate - test_deny_tag_restriction
      -
      PASS
      -
      TestUserTemplate - test_detail_random_user_template
      -
      PASS
      -
      TestUserTemplate - test_format_user_template
      -
      PASS
      -
      TestUserTemplate - test_hot_user_template
      -
      PASS
      -
      TestUserTemplate - test_language_user_template
      -
      PASS
      -
      TestUserTemplate - test_limit_book_languages
      -
      PASS
      -
      TestUserTemplate - test_publisher_user_template
      -
      PASS
      -
      TestUserTemplate - test_random_user_template
      -
      PASS
      -
      TestUserTemplate - test_read_user_template
      -
      PASS
      -
      TestUserTemplate - test_recent_user_template
      -
      PASS
      -
      TestUserTemplate - test_series_user_template
      -
      PASS
      -
      TestUserTemplate - test_ui_language_settings
      -
      PASS
      TestCalibreWebVisibilitys3030000 - Detail -
      -
      TestCalibreWebVisibilitys - test_about
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_SMTP_Settings
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_add_user
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_password
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_archived
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_authors
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_category
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_file_formats
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_hot
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_language
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_publisher
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_random
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_rated
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_rating
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_read
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_admin_change_visibility_series
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_allow_columns
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_allow_tags
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_archive_books
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_authors_max_settings
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_checked_logged_in
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_hide_custom_column
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_link_column_to_read_status
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_random_books_available
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_restrict_columns
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_restrict_tags
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_search_functions
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_search_string
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_user_email_available
      -
      PASS
      -
      TestCalibreWebVisibilitys - test_user_visibility_sidebar
      -
      PASS
      Total230222206 
      -
      -
      - -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Program libraryInstalled VersionTest class
      PlatformLinux 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64Basic
      Python3.8.2Basic
      Babel2.8.0Basic
      backports-abc0.5Basic
      Flask1.1.2Basic
      Flask-Babel1.0.0Basic
      Flask-Login0.5.0Basic
      Flask-Principal0.4.0Basic
      iso-6390.4.5Basic
      Jinja22.11.2Basic
      PyPDF21.26.0Basic
      pytz2020.1Basic
      requests2.23.0Basic
      singledispatch3.4.0.3Basic
      six1.15.0Basic
      SQLAlchemy1.3.19Basic
      tornado6.0.4Basic
      Unidecode1.1.1Basic
      Wand0.5.9Basic
      Werkzeug1.0.1Basic
      Pillow7.2.0TestCoverEditBooks
      comicapi2.1.1TestEditAdditionalBooks
      lxml4.5.2TestEditAdditionalBooks
      Pillow7.2.0TestEditAdditionalBooks
      rarfile4.0TestEditAdditionalBooks
      lxml4.5.2TestEditBooks
      Pillow7.2.0TestEditBooks
      google-api-python-client1.11.0TestEditBooksGdrive
      httplib20.18.1TestEditBooksGdrive
      oauth2client4.1.3TestEditBooksGdrive
      PyDrive1.3.1TestEditBooksGdrive
      PyYAML5.3.1TestEditBooksGdrive
      goodreads0.3.2TestGoodreads
      jsonschema3.2.0TestKoboSync
      Flask-SimpleLDAP1.4.0TestLdapLogin
      jsonschema3.2.0TestLdapLogin
      python-ldap3.3.1TestLdapLogin
      Flask-Dance3.0.0TestOAuthLogin
      SQLAlchemy-Utils0.36.8TestOAuthLogin
      -
      -
      -
      -
      - - - -
      - -
      -
      -

      Made with HTMLTestRunner from https://github.com/oldani/HtmlTestRunner

      -
      -
      - - - \ No newline at end of file diff --git a/test/Calibre-Web TestSummary_Linux.html b/test/Calibre-Web TestSummary_Linux.html index 1733a51a3..00d5d287a 100644 --- a/test/Calibre-Web TestSummary_Linux.html +++ b/test/Calibre-Web TestSummary_Linux.html @@ -37,20 +37,20 @@
      -

      Start Time: 2021-10-30 19:49:15

      +

      Start Time: 2023-02-09 19:47:18

      -

      Stop Time: 2021-10-30 23:31:02

      +

      Stop Time: 2023-02-10 02:15:25

      -

      Duration: 3h 2 min

      +

      Duration: 5h 32 min

      @@ -236,13 +236,13 @@ TestCli - 8 - 8 + 12 + 12 0 0 0 - Detail + Detail @@ -304,7 +304,7 @@ -
      TestCli - test_environ_port_setting
      +
      TestCli - test_dryrun_update
      PASS @@ -312,6 +312,33 @@ + +
      TestCli - test_enable_reconnect
      + + PASS + + + + + + +
      TestCli - test_environ_port_setting
      + + PASS + + + + + + +
      TestCli - test_no_database
      + + PASS + + + + +
      TestCli - test_settingsdb_not_writeable
      @@ -319,17 +346,26 @@ + + + +
      TestCli - test_writeonly_static_files
      + + PASS + + + TestCliGdrivedb - 2 - 2 + 4 + 4 0 0 0 - Detail + Detail @@ -337,7 +373,7 @@ -
      TestCliGdrivedb - test_cli_gdrive_location
      +
      TestCliGdrivedb - test_cli_gdrive_folder
      PASS @@ -345,6 +381,15 @@ + +
      TestCliGdrivedb - test_cli_gdrive_location
      + + PASS + + + + +
      TestCliGdrivedb - test_gdrive_db_nonwrite
      @@ -352,23 +397,41 @@ + + + +
      TestCliGdrivedb - test_no_database
      + + PASS + + + TestCoverEditBooks - 1 - 1 + 2 + 2 0 0 0 - Detail + Detail + +
      TestCoverEditBooks - test_invalid_jpg_hdd
      + + PASS + + + + +
      TestCoverEditBooks - test_upload_jpg
      @@ -404,13 +467,13 @@ TestEbookConvertCalibre - 14 - 14 + 15 + 15 0 0 0 - Detail + Detail @@ -418,7 +481,7 @@ -
      TestEbookConvertCalibre - test_convert_deactivate
      +
      TestEbookConvertCalibre - test_calibre_log
      PASS @@ -427,7 +490,7 @@ -
      TestEbookConvertCalibre - test_convert_email
      +
      TestEbookConvertCalibre - test_convert_deactivate
      PASS @@ -436,7 +499,7 @@ -
      TestEbookConvertCalibre - test_convert_failed_and_email
      +
      TestEbookConvertCalibre - test_convert_email
      PASS @@ -445,7 +508,7 @@ -
      TestEbookConvertCalibre - test_convert_only
      +
      TestEbookConvertCalibre - test_convert_failed_and_email
      PASS @@ -454,7 +517,7 @@ -
      TestEbookConvertCalibre - test_convert_options
      +
      TestEbookConvertCalibre - test_convert_only
      PASS @@ -463,7 +526,7 @@ -
      TestEbookConvertCalibre - test_convert_parameter
      +
      TestEbookConvertCalibre - test_convert_options
      PASS @@ -472,7 +535,7 @@ -
      TestEbookConvertCalibre - test_convert_wrong_excecutable
      +
      TestEbookConvertCalibre - test_convert_parameter
      PASS @@ -481,7 +544,7 @@ -
      TestEbookConvertCalibre - test_convert_xss
      +
      TestEbookConvertCalibre - test_convert_wrong_excecutable
      PASS @@ -490,7 +553,7 @@ -
      TestEbookConvertCalibre - test_email_failed
      +
      TestEbookConvertCalibre - test_convert_xss
      PASS @@ -499,7 +562,7 @@ -
      TestEbookConvertCalibre - test_email_only
      +
      TestEbookConvertCalibre - test_email_failed
      PASS @@ -508,7 +571,7 @@ -
      TestEbookConvertCalibre - test_kindle_send_not_configured
      +
      TestEbookConvertCalibre - test_email_only
      PASS @@ -517,7 +580,7 @@ -
      TestEbookConvertCalibre - test_ssl_smtp_setup_error
      +
      TestEbookConvertCalibre - test_kindle_send_not_configured
      PASS @@ -526,7 +589,7 @@ -
      TestEbookConvertCalibre - test_starttls_smtp_setup_error
      +
      TestEbookConvertCalibre - test_ssl_smtp_setup_error
      PASS @@ -534,6 +597,15 @@ + +
      TestEbookConvertCalibre - test_starttls_smtp_setup_error
      + + PASS + + + + +
      TestEbookConvertCalibre - test_user_convert_xss
      @@ -698,13 +770,13 @@ TestEditAdditionalBooks + 17 16 - 14 0 0 - 2 + 1 - Detail + Detail @@ -712,7 +784,7 @@ -
      TestEditAdditionalBooks - test_change_upload_formats
      +
      TestEditAdditionalBooks - test_cbz_comicinfo
      PASS @@ -721,7 +793,7 @@ -
      TestEditAdditionalBooks - test_delete_book
      +
      TestEditAdditionalBooks - test_change_upload_formats
      PASS @@ -730,7 +802,7 @@ -
      TestEditAdditionalBooks - test_delete_role
      +
      TestEditAdditionalBooks - test_delete_book
      PASS @@ -739,7 +811,7 @@ -
      TestEditAdditionalBooks - test_edit_book_identifier
      +
      TestEditAdditionalBooks - test_delete_role
      PASS @@ -748,7 +820,7 @@ -
      TestEditAdditionalBooks - test_edit_book_identifier_capital
      +
      TestEditAdditionalBooks - test_details_popup
      PASS @@ -757,7 +829,7 @@ -
      TestEditAdditionalBooks - test_edit_book_identifier_standard
      +
      TestEditAdditionalBooks - test_edit_book_identifier
      PASS @@ -766,7 +838,7 @@ -
      TestEditAdditionalBooks - test_edit_special_book_identifier
      +
      TestEditAdditionalBooks - test_edit_book_identifier_capital
      PASS @@ -775,7 +847,7 @@ -
      TestEditAdditionalBooks - test_title_sort
      +
      TestEditAdditionalBooks - test_edit_book_identifier_standard
      PASS @@ -784,7 +856,7 @@ -
      TestEditAdditionalBooks - test_upload_edit_role
      +
      TestEditAdditionalBooks - test_edit_special_book_identifier
      PASS @@ -793,7 +865,7 @@ -
      TestEditAdditionalBooks - test_upload_metadata_cbr
      +
      TestEditAdditionalBooks - test_title_sort
      PASS @@ -801,6 +873,33 @@ + +
      TestEditAdditionalBooks - test_upload_cbz_coverformats
      + + PASS + + + + + + +
      TestEditAdditionalBooks - test_upload_edit_role
      + + PASS + + + + + + +
      TestEditAdditionalBooks - test_upload_metadata_cbr
      + + PASS + + + + +
      TestEditAdditionalBooks - test_upload_metadata_cbt
      @@ -809,42 +908,7 @@ - - -
      TestEditAdditionalBooks - test_writeonly_calibre_database
      - - -
      - SKIP -
      - - - - - - - - - - -
      TestEditAdditionalBooks - test_writeonly_path
      - - PASS - - - - - +
      TestEditAdditionalBooks - test_xss_author_edit
      @@ -853,7 +917,7 @@ - +
      TestEditAdditionalBooks - test_xss_comment_edit
      @@ -862,7 +926,7 @@ - +
      TestEditAdditionalBooks - test_xss_custom_comment_edit
      @@ -874,13 +938,13 @@ TestEditBooks + 36 35 - 34 0 0 1 - Detail + Detail @@ -1210,6 +1274,15 @@ + +
      TestEditBooks - test_upload_cbz_coverformats
      + + PASS + + + + +
      TestEditBooks - test_upload_cover_hdd
      @@ -1219,6 +1292,144 @@ + + TestEditAuthors + 6 + 6 + 0 + 0 + 0 + + Detail + + + + + + + +
      TestEditAuthors - test_change_capital_co_author
      + + PASS + + + + + + +
      TestEditAuthors - test_change_capital_one_author_one_book
      + + PASS + + + + + + +
      TestEditAuthors - test_change_capital_one_author_two_books
      + + PASS + + + + + + +
      TestEditAuthors - test_change_capital_rename_co_author
      + + PASS + + + + + + +
      TestEditAuthors - test_change_capital_rename_two_co_authors
      + + PASS + + + + + + +
      TestEditAuthors - test_rename_capital_on_upload
      + + PASS + + + + + + + TestEditAuthorsGdrive + 6 + 6 + 0 + 0 + 0 + + Detail + + + + + + + +
      TestEditAuthorsGdrive - test_change_capital_co_author
      + + PASS + + + + + + +
      TestEditAuthorsGdrive - test_change_capital_one_author_one_book
      + + PASS + + + + + + +
      TestEditAuthorsGdrive - test_change_capital_one_author_two_books
      + + PASS + + + + + + +
      TestEditAuthorsGdrive - test_change_capital_rename_co_author
      + + PASS + + + + + + +
      TestEditAuthorsGdrive - test_change_capital_rename_two_co_authors
      + + PASS + + + + + + +
      TestEditAuthorsGdrive - test_rename_capital_on_upload
      + + PASS + + + + + TestEditBooksList 18 @@ -1227,13 +1438,13 @@ 0 0 - Detail + Detail - +
      TestEditBooksList - test_bookslist_edit_author
      @@ -1242,7 +1453,7 @@ - +
      TestEditBooksList - test_bookslist_edit_categories
      @@ -1251,7 +1462,7 @@ - +
      TestEditBooksList - test_bookslist_edit_comment
      @@ -1260,7 +1471,7 @@ - +
      TestEditBooksList - test_bookslist_edit_cust_category
      @@ -1269,7 +1480,7 @@ - +
      TestEditBooksList - test_bookslist_edit_cust_comment
      @@ -1278,7 +1489,7 @@ - +
      TestEditBooksList - test_bookslist_edit_cust_enum
      @@ -1287,7 +1498,7 @@ - +
      TestEditBooksList - test_bookslist_edit_cust_float
      @@ -1296,7 +1507,7 @@ - +
      TestEditBooksList - test_bookslist_edit_cust_int
      @@ -1305,7 +1516,7 @@ - +
      TestEditBooksList - test_bookslist_edit_cust_ratings
      @@ -1314,7 +1525,7 @@ - +
      TestEditBooksList - test_bookslist_edit_cust_text
      @@ -1323,7 +1534,7 @@ - +
      TestEditBooksList - test_bookslist_edit_languages
      @@ -1332,7 +1543,7 @@ - +
      TestEditBooksList - test_bookslist_edit_publisher
      @@ -1341,7 +1552,7 @@ - +
      TestEditBooksList - test_bookslist_edit_series
      @@ -1350,7 +1561,7 @@ - +
      TestEditBooksList - test_bookslist_edit_seriesindex
      @@ -1359,7 +1570,7 @@ - +
      TestEditBooksList - test_bookslist_edit_title
      @@ -1368,7 +1579,7 @@ - +
      TestEditBooksList - test_list_visibility
      @@ -1377,7 +1588,7 @@ - +
      TestEditBooksList - test_restricted_rights
      @@ -1386,7 +1597,7 @@ - +
      TestEditBooksList - test_search_books_list
      @@ -1397,20 +1608,44 @@ - TestEditBooksOnGdrive - 20 - 20 + TestLoadMetadata + 1 + 1 0 0 0 - Detail + Detail - + + +
      TestLoadMetadata - test_load_metadata
      + + PASS + + + + + + + TestEditBooksOnGdrive + 18 + 17 + 1 + 0 + 0 + + Detail + + + + + +
      TestEditBooksOnGdrive - test_download_book
      @@ -1419,7 +1654,7 @@ - +
      TestEditBooksOnGdrive - test_edit_author
      @@ -1428,7 +1663,7 @@ - +
      TestEditBooksOnGdrive - test_edit_category
      @@ -1437,7 +1672,7 @@ - +
      TestEditBooksOnGdrive - test_edit_comments
      @@ -1446,7 +1681,7 @@ - +
      TestEditBooksOnGdrive - test_edit_custom_bool
      @@ -1455,7 +1690,7 @@ - +
      TestEditBooksOnGdrive - test_edit_custom_categories
      @@ -1464,7 +1699,7 @@ - +
      TestEditBooksOnGdrive - test_edit_custom_float
      @@ -1473,7 +1708,7 @@ - +
      TestEditBooksOnGdrive - test_edit_custom_int
      @@ -1482,7 +1717,7 @@ - +
      TestEditBooksOnGdrive - test_edit_custom_rating
      @@ -1491,7 +1726,7 @@ - +
      TestEditBooksOnGdrive - test_edit_custom_single_select
      @@ -1500,7 +1735,7 @@ - +
      TestEditBooksOnGdrive - test_edit_custom_text
      @@ -1509,7 +1744,7 @@ - +
      TestEditBooksOnGdrive - test_edit_language
      @@ -1518,7 +1753,7 @@ - +
      TestEditBooksOnGdrive - test_edit_publisher
      @@ -1527,7 +1762,7 @@ - +
      TestEditBooksOnGdrive - test_edit_rating
      @@ -1536,7 +1771,7 @@ - +
      TestEditBooksOnGdrive - test_edit_series
      @@ -1545,25 +1780,36 @@ - +
      TestEditBooksOnGdrive - test_edit_title
      - PASS - - - - - - -
      TestEditBooksOnGdrive - test_upload_book_epub
      + +
      + FAIL +
      + + + - PASS - +
      TestEditBooksOnGdrive - test_upload_book_lit
      @@ -1572,18 +1818,33 @@ - + -
      TestEditBooksOnGdrive - test_upload_cover_hdd
      +
      TestEditBooksOnGdrive - test_watch_metadata
      PASS + + + + TestLoadMetadataScholar + 1 + 1 + 0 + 0 + 0 + + Detail + + + - + + -
      TestEditBooksOnGdrive - test_watch_metadata
      +
      TestLoadMetadataScholar - test_load_metadata
      PASS @@ -1599,13 +1860,13 @@ 0 0 - Detail + Detail - +
      TestSTARTTLS - test_STARTTLS
      @@ -1614,7 +1875,7 @@ - +
      TestSTARTTLS - test_STARTTLS_SSL_setup_error
      @@ -1623,7 +1884,7 @@ - +
      TestSTARTTLS - test_STARTTLS_resend_password
      @@ -1641,13 +1902,13 @@ 0 0 - Detail + Detail - +
      TestSSL - test_SSL_None_setup_error
      @@ -1656,7 +1917,7 @@ - +
      TestSSL - test_SSL_STARTTLS_setup_error
      @@ -1665,7 +1926,7 @@ - +
      TestSSL - test_SSL_logging_email
      @@ -1674,7 +1935,7 @@ - +
      TestSSL - test_SSL_non_admin_user
      @@ -1683,7 +1944,7 @@ - +
      TestSSL - test_SSL_only
      @@ -1692,7 +1953,7 @@ - +
      TestSSL - test_email_limit
      @@ -1701,7 +1962,7 @@ - +
      TestSSL - test_filepicker_two_file
      @@ -1719,13 +1980,13 @@ 0 0 - Detail + Detail - +
      TestBookDatabase - test_invalid_book_path
      @@ -1737,19 +1998,19 @@ TestErrorReadColumn - 1 - 1 + 2 + 2 0 0 0 - Detail + Detail - +
      TestErrorReadColumn - test_invalid_custom_column
      @@ -1757,23 +2018,32 @@ + + + +
      TestErrorReadColumn - test_invalid_custom_read_column
      + + PASS + + + - + TestFilePicker + 3 + 2 + 0 + 0 1 - 1 - 0 - 0 - 0 - Detail + Detail - +
      TestFilePicker - test_filepicker_limited_file
      @@ -1781,6 +2051,41 @@ + + + +
      TestFilePicker - test_filepicker_new_file
      + + +
      + SKIP +
      + + + + + + + + + + +
      TestFilePicker - test_two_filepickers
      + + PASS + + + @@ -1791,13 +2096,13 @@ 0 0 - Detail + Detail - +
      TestSetupGdrive - test_config_gdrive
      @@ -1815,13 +2120,13 @@ 0 0 - Detail + Detail - +
      TestGoodreads - test_author_page
      @@ -1830,7 +2135,7 @@ - +
      TestGoodreads - test_author_page_invalid
      @@ -1839,7 +2144,7 @@ - +
      TestGoodreads - test_goodreads_about
      @@ -1851,19 +2156,19 @@ TestKoboSync - 10 - 10 + 11 + 11 0 0 0 - Detail + Detail - +
      TestKoboSync - test_book_download
      @@ -1872,7 +2177,7 @@ - +
      TestKoboSync - test_kobo_about
      @@ -1881,7 +2186,7 @@ - +
      TestKoboSync - test_kobo_sync_selected_shelfs
      @@ -1890,7 +2195,16 @@ - + + +
      TestKoboSync - test_kobo_upload_book
      + + PASS + + + + +
      TestKoboSync - test_shelves_add_remove_books
      @@ -1899,7 +2213,7 @@ - +
      TestKoboSync - test_sync_changed_book
      @@ -1908,7 +2222,7 @@ - +
      TestKoboSync - test_sync_invalid
      @@ -1917,7 +2231,7 @@ - +
      TestKoboSync - test_sync_reading_state
      @@ -1926,7 +2240,7 @@ - +
      TestKoboSync - test_sync_shelf
      @@ -1935,7 +2249,7 @@ - +
      TestKoboSync - test_sync_unchanged
      @@ -1944,7 +2258,7 @@ - +
      TestKoboSync - test_sync_upload
      @@ -1956,28 +2270,46 @@ TestKoboSyncBig - 4 - 4 + 6 + 6 0 0 0 - Detail + Detail - + -
      TestKoboSyncBig - test_kobo_sync_selected_shelfs
      +
      TestKoboSyncBig - test_download_cover
      PASS - + + +
      TestKoboSyncBig - test_kobo_sync_multi_user
      + + PASS + + + + + + +
      TestKoboSyncBig - test_kobo_sync_selected_shelves
      + + PASS + + + + +
      TestKoboSyncBig - test_sync_changed_book
      @@ -1986,7 +2318,7 @@ - +
      TestKoboSyncBig - test_sync_reading_state
      @@ -1995,7 +2327,7 @@ - +
      TestKoboSyncBig - test_sync_shelf
      @@ -2013,13 +2345,13 @@ 0 0 - Detail + Detail - +
      TestLdapLogin - test_LDAP_SSL
      @@ -2028,7 +2360,7 @@ - +
      TestLdapLogin - test_LDAP_SSL_CERTIFICATE
      @@ -2037,7 +2369,7 @@ - +
      TestLdapLogin - test_LDAP_STARTTLS
      @@ -2046,7 +2378,7 @@ - +
      TestLdapLogin - test_LDAP_fallback_Login
      @@ -2055,7 +2387,7 @@ - +
      TestLdapLogin - test_LDAP_import
      @@ -2064,7 +2396,7 @@ - +
      TestLdapLogin - test_LDAP_import_memberfield
      @@ -2073,7 +2405,7 @@ - +
      TestLdapLogin - test_LDAP_login
      @@ -2082,7 +2414,7 @@ - +
      TestLdapLogin - test_invalid_LDAP
      @@ -2091,7 +2423,7 @@ - +
      TestLdapLogin - test_ldap_about
      @@ -2100,7 +2432,7 @@ - +
      TestLdapLogin - test_ldap_authentication
      @@ -2109,7 +2441,7 @@ - +
      TestLdapLogin - test_ldap_kobo_sync
      @@ -2118,7 +2450,7 @@ - +
      TestLdapLogin - test_ldap_opds_anonymous
      @@ -2127,7 +2459,7 @@ - +
      TestLdapLogin - test_ldap_opds_download_book
      @@ -2137,6 +2469,111 @@ + + TestCalibreWebListOrders + 10 + 10 + 0 + 0 + 0 + + Detail + + + + + + + +
      TestCalibreWebListOrders - test_author_sort
      + + PASS + + + + + + +
      TestCalibreWebListOrders - test_download_sort
      + + PASS + + + + + + +
      TestCalibreWebListOrders - test_format_sort
      + + PASS + + + + + + +
      TestCalibreWebListOrders - test_lang_sort
      + + PASS + + + + + + +
      TestCalibreWebListOrders - test_order_authors_all_links
      + + PASS + + + + + + +
      TestCalibreWebListOrders - test_order_series_all_links
      + + PASS + + + + + + +
      TestCalibreWebListOrders - test_publisher_sort
      + + PASS + + + + + + +
      TestCalibreWebListOrders - test_ratings_sort
      + + PASS + + + + + + +
      TestCalibreWebListOrders - test_series_sort
      + + PASS + + + + + + +
      TestCalibreWebListOrders - test_tags_sort
      + + PASS + + + + + TestLogging 9 @@ -2145,13 +2582,13 @@ 0 1 - Detail + Detail - +
      TestLogging - test_access_log_recover
      @@ -2160,7 +2597,7 @@ - +
      TestLogging - test_debug_log
      @@ -2169,7 +2606,7 @@ - +
      TestLogging - test_debuginfo_download
      @@ -2178,7 +2615,7 @@ - +
      TestLogging - test_failed_login
      @@ -2187,19 +2624,19 @@ - +
      TestLogging - test_failed_register
      - SKIP + SKIP
      -